/** * @file companyAutomat.js * @description Manages configuration details of the currently selected company * (tax rates, currency, language, legal details, and root category ID). * * Upstream Triggers: * - `authAutomat`: Subscribes to auth state changes — triggers `actions.load()` * when status is `'authed'` with a `selectedCompanyId`, and `actions.reset()` on `'anon'`. * - UI / Settings: Calls `update(payload)` or manual `load()`. * * Downstream Triggers: * - `categoryAutomat`: Subscribes to `companyAutomat` — triggers `actions.loadTree()` * whenever `company.current.id` or `rootCategoryId` changes/becomes available; * resets when company is unset. * - `posterminalAutomat`: Reads `companyAutomat.state.current?.id` as a fallback company ID. */ import { Automat } from 'react-automat'; import { company as companyApi } from '../api'; import authAutomat from './authAutomat'; import { normalizeCompany } from '../utils/companyForm'; /** * @typedef {Object} CompanyState * @property {object|null} current Normalized company object for the selected company. * @property {'idle'|'loading'|'succeeded'|'failed'} status * @property {string|null} error */ /** @type {CompanyState} */ const initialState = { current: null, status: 'idle', error: null, }; let companyAutomat; const actions = { /** * Load the company data for the currently selected company. * @returns {Promise} */ async load() { const companyId = authAutomat.state.user?.selectedCompanyId; if (!companyId) return null; companyAutomat.setState({ status: 'loading', error: null }); try { const data = await companyApi.getById(companyId); const normalized = normalizeCompany(data.company); companyAutomat.setState({ current: normalized, status: 'succeeded' }); return normalized; } catch (err) { companyAutomat.setState({ status: 'failed', error: err?.message ?? String(err) }); throw err; } }, /** * Update company details and refresh cached data. * @param {object} payload */ async update(payload) { const companyId = authAutomat.state.user?.selectedCompanyId; if (!companyId) throw new Error('Kein Unternehmen ausgewählt.'); companyAutomat.setState({ status: 'loading', error: null }); try { await companyApi.update(companyId, payload); const data = await companyApi.getById(companyId); const normalized = normalizeCompany(data.company, payload); companyAutomat.setState({ current: normalized, status: 'succeeded' }); return normalized; } catch (err) { companyAutomat.setState({ status: 'failed', error: err?.message ?? String(err) }); throw err; } }, /** Reset to idle (called on logout / company switch). */ reset() { companyAutomat.setState(initialState); }, }; /** * Global company state container. * Loads automatically when authAutomat reaches 'authed' with a selectedCompanyId. * * @type {Automat} */ companyAutomat = new Automat(initialState, actions, { name: 'company' }); // Subscribe to auth changes — load when authed, reset when logged out / anon authAutomat.subscribe((auth) => { const companyId = auth.user?.selectedCompanyId; if (auth.status === 'authed' && companyId) { void companyAutomat.actions.load(); } else if (auth.status === 'anon') { companyAutomat.actions.reset(); } }); // Selectors (plain functions for use outside React) export const selectCurrentCompany = () => companyAutomat.state.current; export const selectCompanyId = () => companyAutomat.state.current?.id ?? null; export const selectCompanyStatus = () => companyAutomat.state.status; export const selectCompanyName = () => companyAutomat.state.current?.name; export const selectCompanyIso639 = () => companyAutomat.state.current?.iso639; export const selectCompanyLanguageId = () => companyAutomat.state.current?.languageId ?? null; export const selectCompanyTaxrate = () => companyAutomat.state.current?.taxrate ?? null; export const selectCompanyReducedTaxrate = () => companyAutomat.state.current?.reducedtaxrate ?? null; export const selectCompanyTaxfreerate = () => companyAutomat.state.current?.taxfreerate ?? null; export const selectCompanyRootCategoryId = () => companyAutomat.state.current?.rootCategoryId ?? null; export default companyAutomat;