but
This commit is contained in:
@@ -79,7 +79,7 @@ function createCache(label, load) {
|
||||
export class StorageManager extends ApiClient {
|
||||
/** @type {EventSource | null} */
|
||||
#events = null;
|
||||
/** @type {ReturnType<typeof createCache> | null} */
|
||||
/** @type {ReturnType<StorageManager['#createDeferredCache']> | null} */
|
||||
#articleIndexCache = null;
|
||||
/** @type {Map<string, Set<(article: object) => void>>} sku → article listeners */
|
||||
#articleWatchers = new Map();
|
||||
@@ -386,14 +386,24 @@ export class StorageManager extends ApiClient {
|
||||
|
||||
#initCaches() {
|
||||
const authMeCache = createCache('GET /auth/me', () => this.#loadAuthMe());
|
||||
const deliveryCache = createCache('GET /delivery', () => this.#loadDeliveries());
|
||||
const customergroupCache = createCache('GET /customergroup', () =>
|
||||
const deliveryCache = this.#createDeferredCache('GET /delivery', () =>
|
||||
this.#loadDeliveries(),
|
||||
);
|
||||
const customergroupCache = this.#createDeferredCache('GET /customergroup', () =>
|
||||
this.#loadCustomergroups(),
|
||||
);
|
||||
const entityCache = createCache('GET /entity', () => this.#loadEntities());
|
||||
const numberCache = createCache('GET /number', () => this.#loadNumbers());
|
||||
const quoteCache = createCache('GET /quote', () => this.#loadQuotes());
|
||||
const orderCache = createCache('GET /order', () => this.#loadOrders());
|
||||
const entityCache = this.#createDeferredCache('GET /entity', () =>
|
||||
this.#loadEntities(),
|
||||
);
|
||||
const numberCache = this.#createDeferredCache('GET /number', () =>
|
||||
this.#loadNumbers(),
|
||||
);
|
||||
const quoteCache = this.#createDeferredCache('GET /quote', () =>
|
||||
this.#loadQuotes(),
|
||||
);
|
||||
const orderCache = this.#createDeferredCache('GET /order', () =>
|
||||
this.#loadOrders(),
|
||||
);
|
||||
|
||||
// articleIndex is auth-gated — create a deferred cache that only loads after auth
|
||||
this.#articleIndexCache = this.#createDeferredCache(
|
||||
@@ -478,7 +488,7 @@ export class StorageManager extends ApiClient {
|
||||
/** Settled GET /category/tree body, or undefined. */
|
||||
categoryTree: { get: () => categoryTreeCache.value },
|
||||
|
||||
// ── Remaining non-auth-gated caches ─────────────────────────────────────
|
||||
// ── Deferred caches (auth-gated) ─────────────────────────────────────────
|
||||
deliveryPromise: { get: () => deliveryCache.promise },
|
||||
updateDelivery: { value: deliveryCache.update },
|
||||
/** Settled GET /delivery list, or undefined. */
|
||||
@@ -513,58 +523,132 @@ export class StorageManager extends ApiClient {
|
||||
reconnectEvents: { value: () => this.#reconnectEvents() },
|
||||
});
|
||||
|
||||
// Trigger articleIndex load once auth is established
|
||||
authAutomat.subscribe((auth) => {
|
||||
if (auth.status === 'authed' && auth.user?.selectedCompanyId) {
|
||||
if (!articleIndexCache.value) {
|
||||
void articleIndexCache.update?.().catch(() => {});
|
||||
let lastCompanyId = null;
|
||||
|
||||
const syncWithAuth = (auth) => {
|
||||
const companyId =
|
||||
auth.status === 'authed' && auth.user?.selectedCompanyId != null
|
||||
? String(auth.user.selectedCompanyId)
|
||||
: null;
|
||||
|
||||
if (companyId === lastCompanyId) return;
|
||||
const prevCompanyId = lastCompanyId;
|
||||
lastCompanyId = companyId;
|
||||
|
||||
if (!companyId) {
|
||||
// Unauthenticated or logged out
|
||||
this.#disconnectEvents();
|
||||
articleIndexCache.clear();
|
||||
categoryTreeCache.clear();
|
||||
deliveryCache.clear();
|
||||
customergroupCache.clear();
|
||||
entityCache.clear();
|
||||
numberCache.clear();
|
||||
quoteCache.clear();
|
||||
orderCache.clear();
|
||||
artikelAutomat.actions.clear();
|
||||
} else {
|
||||
// Company established or switched
|
||||
if (prevCompanyId) {
|
||||
articleIndexCache.clear();
|
||||
categoryTreeCache.clear();
|
||||
deliveryCache.clear();
|
||||
customergroupCache.clear();
|
||||
entityCache.clear();
|
||||
numberCache.clear();
|
||||
quoteCache.clear();
|
||||
orderCache.clear();
|
||||
artikelAutomat.actions.clear();
|
||||
}
|
||||
this.#reconnectEvents();
|
||||
void articleIndexCache.trigger().catch(() => {});
|
||||
void deliveryCache.trigger().catch(() => {});
|
||||
void customergroupCache.trigger().catch(() => {});
|
||||
void entityCache.trigger().catch(() => {});
|
||||
void numberCache.trigger().catch(() => {});
|
||||
void quoteCache.trigger().catch(() => {});
|
||||
void orderCache.trigger().catch(() => {});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
authAutomat.subscribe(syncWithAuth);
|
||||
syncWithAuth(authAutomat.state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a cache that does NOT load immediately but waits for an explicit trigger.
|
||||
* Differs from createCache in that the initial load promise is not started.
|
||||
* Create a cache that does NOT load immediately but waits for an explicit trigger
|
||||
* or loads on-demand once authenticated.
|
||||
*/
|
||||
#createDeferredCache(label, load) {
|
||||
let current;
|
||||
let resolveInitial;
|
||||
let rejectInitial;
|
||||
let promise = new Promise((res, rej) => {
|
||||
resolveInitial = res;
|
||||
rejectInitial = rej;
|
||||
});
|
||||
let loadPromise = null;
|
||||
|
||||
async function update() {
|
||||
const trigger = () => {
|
||||
if (loadPromise) return loadPromise;
|
||||
loadPromise = (async () => {
|
||||
try {
|
||||
const data = await load();
|
||||
current = data;
|
||||
return data;
|
||||
} catch (err) {
|
||||
console.error(`[storageMgr] ${label} failed`, err);
|
||||
loadPromise = null;
|
||||
throw err;
|
||||
}
|
||||
})();
|
||||
return loadPromise;
|
||||
};
|
||||
|
||||
const update = async () => {
|
||||
try {
|
||||
const data = await load();
|
||||
current = data;
|
||||
promise = Promise.resolve(data);
|
||||
resolveInitial?.(data);
|
||||
resolveInitial = null;
|
||||
loadPromise = Promise.resolve(data);
|
||||
return data;
|
||||
} catch (err) {
|
||||
console.error(`[storageMgr] update ${label} failed`, err);
|
||||
rejectInitial?.(err);
|
||||
rejectInitial = null;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function replace(data) {
|
||||
const replace = (data) => {
|
||||
current = data;
|
||||
promise = Promise.resolve(data);
|
||||
resolveInitial?.(data);
|
||||
resolveInitial = null;
|
||||
loadPromise = Promise.resolve(data);
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
const clear = () => {
|
||||
current = undefined;
|
||||
loadPromise = null;
|
||||
};
|
||||
|
||||
return {
|
||||
update,
|
||||
replace,
|
||||
get promise() { return promise; },
|
||||
get value() { return current; },
|
||||
clear,
|
||||
trigger,
|
||||
get promise() {
|
||||
if (!loadPromise) {
|
||||
if (authAutomat.state.status === 'authed' && authAutomat.state.user?.selectedCompanyId) {
|
||||
return trigger();
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const unsub = authAutomat.subscribe((auth) => {
|
||||
if (auth.status === 'authed' && auth.user?.selectedCompanyId) {
|
||||
unsub();
|
||||
trigger().then(resolve, reject);
|
||||
} else if (auth.status === 'anon') {
|
||||
unsub();
|
||||
reject(new Error(`Cannot load ${label}: unauthenticated`));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
return loadPromise;
|
||||
},
|
||||
get value() {
|
||||
return current;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -652,24 +736,6 @@ export class StorageManager extends ApiClient {
|
||||
}));
|
||||
}
|
||||
|
||||
async #loadBrands() {
|
||||
const data = await this.brand.list();
|
||||
requireObject(data, 'GET /api/brand');
|
||||
return requireArray(data.brands, 'brands');
|
||||
}
|
||||
|
||||
async #loadUnits() {
|
||||
const data = await this.unit.list();
|
||||
requireObject(data, 'GET /api/unit');
|
||||
return requireArray(data.units, 'units');
|
||||
}
|
||||
|
||||
async #loadCompanies() {
|
||||
const data = await this.company.list();
|
||||
requireObject(data, 'GET /api/company');
|
||||
return requireArray(data.companies, 'companies');
|
||||
}
|
||||
|
||||
async #loadCategoryTree() {
|
||||
const data = await this.category.tree();
|
||||
requireObject(data, 'GET /api/category/tree');
|
||||
@@ -679,12 +745,6 @@ export class StorageManager extends ApiClient {
|
||||
return data;
|
||||
}
|
||||
|
||||
async #loadPosterminals() {
|
||||
const data = await this.posterminal.list();
|
||||
requireObject(data, 'GET /api/posterminal');
|
||||
return requireArray(data.posterminals, 'posterminals');
|
||||
}
|
||||
|
||||
async #loadDeliveries() {
|
||||
const data = await this.delivery.list();
|
||||
requireObject(data, 'GET /api/delivery');
|
||||
|
||||
Reference in New Issue
Block a user