Files
dashfront/src/automats/brandAutomat.js
2026-09-27 16:19:08 +02:00

113 lines
2.7 KiB
JavaScript

import { Automat } from 'react-automat';
import { brand as brandApi } from '../api';
import authAutomat from './authAutomat';
/**
* @typedef {Object} BrandState
* @property {Array<object>} brands
* @property {'idle'|'loading'|'succeeded'|'failed'} status
* @property {string|null} error
*/
/** @type {BrandState} */
const initialState = {
brands: [],
status: 'idle',
error: null,
};
function sortBrands(brands) {
return [...brands].sort((a, b) =>
String(a.name ?? '').localeCompare(String(b.name ?? ''), 'de'),
);
}
let brandAutomat;
const actions = {
/** Load all brands for the selected company. */
async load() {
brandAutomat.setState({ status: 'loading', error: null });
try {
const res = await brandApi.list();
const brands = sortBrands(Array.isArray(res.brands) ? res.brands : []);
brandAutomat.setState({ brands, status: 'succeeded' });
return brands;
} catch (err) {
brandAutomat.setState({ status: 'failed', error: err?.message ?? String(err) });
throw err;
}
},
/**
* Upsert a brand (create or update by name).
* @param {{ name: string, gsprpinfo?: string }} body
*/
async upsert(body) {
const res = await brandApi.upsert(body);
const row = res.brand;
const brands = sortBrands([
...brandAutomat.state.brands.filter((b) => b.id !== row.id),
row,
]);
brandAutomat.setState({ brands });
return row;
},
/**
* Delete a brand by id.
* @param {number} id
*/
async remove(id) {
await brandApi.delete(id);
const brands = brandAutomat.state.brands.filter((b) => b.id !== id);
brandAutomat.setState({ brands });
},
/**
* Add / update brand image.
* @param {number} id
* @param {Blob|File} file
*/
async addImage(id, file) {
const res = await brandApi.addImage(id, file);
await brandAutomat.actions.load();
return res.brand;
},
/**
* Delete brand image.
* @param {number} id
*/
async deleteImage(id) {
const res = await brandApi.deleteImage(id);
await brandAutomat.actions.load();
return res.brand;
},
/** Reset to idle state (called on logout / company switch). */
reset() {
brandAutomat.setState(initialState);
},
};
/**
* Global brand state container.
* Loads automatically when authAutomat reaches 'authed' with a selectedCompanyId.
*
* @type {Automat<BrandState>}
*/
brandAutomat = new Automat(initialState, actions, { name: 'brand' });
// Subscribe to auth changes
authAutomat.subscribe((auth) => {
const companyId = auth.user?.selectedCompanyId;
if (auth.status === 'authed' && companyId) {
void brandAutomat.actions.load();
} else if (auth.status === 'anon') {
brandAutomat.actions.reset();
}
});
export default brandAutomat;