This commit is contained in:
seb
2026-10-11 02:41:36 +02:00
parent 3379a63baf
commit c75521dc25

View File

@@ -7,10 +7,10 @@
* `'authed'` with a `selectedCompanyId`, and `actions.reset()` on `'anon'`. * `'authed'` with a `selectedCompanyId`, and `actions.reset()` on `'anon'`.
* - `sseAutomat`: Subscribes to the single `'brand'` event carrying * - `sseAutomat`: Subscribes to the single `'brand'` event carrying
* `{ sender, brandId }` — any create/rename/delete/picture change triggers * `{ sender, brandId }` — any create/rename/delete/picture change triggers
* `actions.reload()`, which silently re-fetches the list. Subscribed views * `actions.load(true)`, which silently re-fetches the list. Subscribed views
* (e.g. `ArtikelMarkenPage` via `brandAutomat.subscribe(...)`) then * (e.g. `ArtikelMarkenPage` via `brandAutomat.subscribe(...)`) then
* re-render from the updated state. This is the reload pattern. Events sent * re-render from the updated state. Events sent by this tab (matching `sender`)
* by this tab (matching `sender`) are ignored. * are ignored.
* - UI / Settings: Mutating actions (`create`, `rename`, `remove`, `addImage`, `deleteImage`). * - UI / Settings: Mutating actions (`create`, `rename`, `remove`, `addImage`, `deleteImage`).
*/ */
@@ -78,43 +78,25 @@ const actions = {
brandAutomat.setState({ filter, filteredBrands: applyFilter(brandAutomat.state.brands, filter) }); brandAutomat.setState({ filter, filteredBrands: applyFilter(brandAutomat.state.brands, filter) });
}, },
/** Load all brands for the selected company (pages through the API). */ /**
async load() { * Load all brands for the selected company (pages through the API).
if (inflightLoad) return inflightLoad; * @param {boolean} [silent=false] If true, re-fetches without setting status to 'loading'.
brandAutomat.setState({ status: 'loading', error: null }); */
return (inflightLoad = fetchAllBrands() async load(silent = false) {
.then(({ brands }) => updateStateWithBrands(brands, { status: 'succeeded' }))
.catch((err) => {
brandAutomat.setState({ status: 'failed', error: err?.message ?? String(err) });
throw err;
})
.finally(() => { inflightLoad = null; }));
},
/** Silently re-fetches all brands while keeping current state visible. */
async reload() {
if (inflightLoad) return inflightLoad; if (inflightLoad) return inflightLoad;
if (!silent) {
brandAutomat.setState({ status: 'loading', error: null });
}
return (inflightLoad = fetchAllBrands() return (inflightLoad = fetchAllBrands()
.then(({ brands }) => updateStateWithBrands(brands, { status: 'succeeded', error: null })) .then(({ brands }) => updateStateWithBrands(brands, { status: 'succeeded', error: null }))
.catch((err) => { .catch((err) => {
brandAutomat.setState({ error: err?.message ?? String(err) }); const error = err?.message ?? String(err);
brandAutomat.setState(silent ? { error } : { status: 'failed', error });
throw err; throw err;
}) })
.finally(() => { inflightLoad = null; })); .finally(() => { inflightLoad = null; }));
}, },
/**
* Returns the brand state, loading brands first if uninitialized.
*
* @returns {Promise<BrandState>} Current brand state.
*/
async getOrLoad() {
if (brandAutomat.state.status !== 'succeeded') {
await brandAutomat.actions.reload();
}
return brandAutomat.state;
},
/** Create a brand (insert). */ /** Create a brand (insert). */
async create(body) { async create(body) {
const res = await brandApi.create(body); const res = await brandApi.create(body);
@@ -140,14 +122,14 @@ const actions = {
/** Add / update brand image. */ /** Add / update brand image. */
async addImage(id, file) { async addImage(id, file) {
const res = await brandApi.addImage(id, file); const res = await brandApi.addImage(id, file);
await brandAutomat.actions.reload(); await brandAutomat.actions.load(true);
return res.brand; return res.brand;
}, },
/** Delete brand image. */ /** Delete brand image. */
async deleteImage(id) { async deleteImage(id) {
const res = await brandApi.deleteImage(id); const res = await brandApi.deleteImage(id);
await brandAutomat.actions.reload(); await brandAutomat.actions.load(true);
return res.brand; return res.brand;
}, },
@@ -174,7 +156,7 @@ sseAutomat.actions.on('brand', (event) => {
const payload = JSON.parse(event?.data ?? '{}'); const payload = JSON.parse(event?.data ?? '{}');
if (payload?.sender && payload.sender === getSseClientId()) return; if (payload?.sender && payload.sender === getSseClientId()) return;
} catch { } } catch { }
void brandAutomat.actions.reload().catch(() => { }); void brandAutomat.actions.load(true).catch(() => { });
}); });
export default brandAutomat; export default brandAutomat;