5.6 KiB
companyAutomat
Source File:
src/automats/companyAutomat.js
Registration Key:'company'(Automat.get('company')/window.__AUTOMATS__.get('company'))
1. Overview & Purpose
companyAutomat stores the active company configuration and metadata for the authenticated user's selected tenant. It provides essential company-wide parameters needed throughout Dashfront, such as default tax rates (standard and reduced), legal company details, default language, and the root category ID of the catalog hierarchy.
Core Responsibilities
- Company Configuration: Caches legal details, tax rates (
taxrate,reducedtaxrate), and catalog root category ID (rootCategoryId). - Data Normalization: Normalizes backend company payloads via
normalizeCompany()for predictable shape in forms and calculations. - Cross-Automat Triggering: Changes in
companyAutomatdrivecategoryAutomatto fetch the company's category tree. - Autonomous Bootstrap: Automatically loads whenever
authAutomathas an activeselectedCompanyIdand resets on logout.
2. State Structure
interface NormalizedCompany {
id: number | string;
name: string;
rootCategoryId: number | string | null;
taxrate: number; // Standard VAT rate (e.g. 19.00)
reducedtaxrate: number; // Reduced VAT rate (e.g. 7.00)
iso639: string; // Default language code (e.g. 'de')
street?: string;
zip?: string;
city?: string;
country?: string;
iban?: string;
bic?: string;
taxId?: string;
vatId?: string;
[key: string]: any;
}
interface CompanyState {
/** Normalized details of currently selected company. */
current: NormalizedCompany | null;
/** Async lifecycle status. */
status: 'idle' | 'loading' | 'succeeded' | 'failed';
/** Last error message if load/update failed. */
error: string | null;
}
Initial State
const initialState = {
current: null,
status: 'idle',
error: null,
};
3. Configuration & Options
new Automat(initialState, actions, { name: 'company' });
name:'company'persist:false
4. Actions & Methods
Access actions via companyAutomat.actions.<method>().
load(): Promise<NormalizedCompany | null>
Determines the selected company ID from authAutomat.state.user?.selectedCompanyId. If none is selected, returns null. Otherwise, queries GET /api/company/:id, normalizes the data, updates state.current, and sets status to 'succeeded'.
update(payload: object): Promise<NormalizedCompany>
Persists updated company settings via PUT /api/company/:id, re-fetches authoritative data, normalizes it, updates state.current, and returns the updated company object.
reset(): void
Resets state back to initialState.
5. Exported Standalone Selectors
Exported plain helper functions for querying company state without requiring a React component:
| Selector | Return Type | Description |
|---|---|---|
selectCurrentCompany() |
NormalizedCompany | null |
Returns the entire current company object. |
selectCompanyId() |
string | number | null |
The ID of the currently selected company. |
selectCompanyStatus() |
'idle'|'loading'|'succeeded'|'failed' |
Current status of the company store. |
selectCompanyName() |
string | undefined |
Company legal or trade name. |
selectCompanyIso639() |
string | undefined |
ISO language code (e.g. 'de'). |
selectCompanyTaxrate() |
number | null |
Standard VAT rate (e.g. 19.0). |
selectCompanyReducedTaxrate() |
number | null |
Reduced VAT rate (e.g. 7.0). |
selectCompanyRootCategoryId() |
number | string | null |
ID of the root category node. |
6. Cross-Automat Subscriptions
companyAutomat automatically tracks authentication changes:
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();
}
});
7. Usage Examples
A. React PureComponent Tax Rate Calculation
import { PureComponent } from 'react';
import companyAutomat, { selectCompanyTaxrate } from '../automats/companyAutomat';
export class PriceDisplay extends PureComponent {
constructor(props) {
super(props);
this.state = {
taxrate: selectCompanyTaxrate() ?? 19.0,
};
}
componentDidMount() {
this.unsub = companyAutomat.subscribe(this, (state) => ({
taxrate: state.current?.taxrate ?? 19.0,
}));
}
componentWillUnmount() {
this.unsub?.();
}
render() {
const { netPrice } = this.props;
const grossPrice = netPrice * (1 + this.state.taxrate / 100);
return (
<div>
<span>Netto: {netPrice.toFixed(2)} €</span>
<strong>Brutto (inkl. {this.state.taxrate}% MwSt): {grossPrice.toFixed(2)} €</strong>
</div>
);
}
}
B. Pure Function / Utility Usage
import { selectCompanyId, selectCompanyRootCategoryId } from '../automats/companyAutomat';
export function getCompanyUploadUrl() {
const companyId = selectCompanyId();
if (!companyId) throw new Error('Kein Unternehmen aktiv.');
return `/api/company/${companyId}/upload`;
}
8. Best Practices & Gotchas
- Tax Calculations: Always query
selectCompanyTaxrate()orselectCompanyReducedTaxrate()instead of hardcoding19%or7%. - Catalog Roots: Don't assume root category is
1ornull; always useselectCompanyRootCategoryId().