106 lines
2.7 KiB
JavaScript
106 lines
2.7 KiB
JavaScript
/**
|
|
* @file unitAutomat.js
|
|
* @description Manages allowable units of measure (Stück, kg, Liter, etc.)
|
|
* for the active company.
|
|
*
|
|
* Upstream Triggers:
|
|
* - `authAutomat`: Subscribes to auth state changes — calls `actions.load()` on
|
|
* `'authed'` with a `selectedCompanyId`, and `actions.reset()` on `'anon'`.
|
|
* - UI / Settings: Mutating actions (`upsert`, `delete`).
|
|
*/
|
|
|
|
import { Automat } from 'react-automat';
|
|
import { unit as unitApi } from '../api';
|
|
import authAutomat from './authAutomat';
|
|
|
|
/**
|
|
* @typedef {Object} UnitState
|
|
* @property {Array<object>} units
|
|
* @property {'idle'|'loading'|'succeeded'|'failed'} status
|
|
* @property {string|null} error
|
|
*/
|
|
|
|
/** @type {UnitState} */
|
|
const initialState = {
|
|
units: [],
|
|
status: 'idle',
|
|
error: null,
|
|
};
|
|
|
|
function sortUnits(units) {
|
|
return [...units].sort((a, b) => {
|
|
const left = a.symbol ?? a.si ?? '';
|
|
const right = b.symbol ?? b.si ?? '';
|
|
return String(left).localeCompare(String(right), 'de');
|
|
});
|
|
}
|
|
|
|
let unitAutomat;
|
|
|
|
const actions = {
|
|
/** Load all units for the selected company. */
|
|
async load() {
|
|
unitAutomat.setState({ status: 'loading', error: null });
|
|
try {
|
|
const res = await unitApi.list();
|
|
const units = sortUnits(Array.isArray(res.units) ? res.units : []);
|
|
unitAutomat.setState({ units, status: 'succeeded' });
|
|
return units;
|
|
} catch (err) {
|
|
unitAutomat.setState({ status: 'failed', error: err?.message ?? String(err) });
|
|
throw err;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Upsert (create or update) a unit.
|
|
* @param {object} body
|
|
*/
|
|
async upsert(body) {
|
|
const res = await unitApi.upsert(body);
|
|
const row = res.unit;
|
|
const units = sortUnits([
|
|
...unitAutomat.state.units.filter((u) => u.si !== row.si),
|
|
row,
|
|
]);
|
|
unitAutomat.setState({ units });
|
|
return units;
|
|
},
|
|
|
|
/**
|
|
* Delete a unit by SI symbol.
|
|
* @param {string} si
|
|
*/
|
|
async delete(si) {
|
|
await unitApi.delete(si);
|
|
unitAutomat.setState({
|
|
units: unitAutomat.state.units.filter((u) => u.si !== si),
|
|
});
|
|
},
|
|
|
|
/** Reset to idle state (called on logout / company switch). */
|
|
reset() {
|
|
unitAutomat.setState(initialState);
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Global unit state container.
|
|
* Loads automatically when authAutomat reaches 'authed' with a selectedCompanyId.
|
|
*
|
|
* @type {Automat<UnitState>}
|
|
*/
|
|
unitAutomat = new Automat(initialState, actions, { name: 'unit' });
|
|
|
|
// Subscribe to auth changes
|
|
authAutomat.subscribe((auth) => {
|
|
const companyId = auth.user?.selectedCompanyId;
|
|
if (auth.status === 'authed' && companyId) {
|
|
void unitAutomat.actions.load();
|
|
} else if (auth.status === 'anon') {
|
|
unitAutomat.actions.reset();
|
|
}
|
|
});
|
|
|
|
export default unitAutomat;
|