# `unitAutomat` > **Source File**: [`src/automats/unitAutomat.js`](file:///home/seb/src/dashfront/src/automats/unitAutomat.js) > **Registration Key**: `'unit'` (`Automat.get('unit')` / `window.__AUTOMATS__.get('unit')`) --- ## 1. Overview & Purpose `unitAutomat` manages the active company's allowed units of measure (e.g. Stück, kg, Meter, Liter). Units are attached to articles and delivery lineitems to ensure consistent units of measure and price calculation across the catalog and invoices. ### Core Responsibilities - **Company Scoping**: Caches all measurement units for the currently selected company. - **Alphabetical Sorting**: Automatically sorts units by their display symbol or SI code using German collation. - **Autonomous Bootstrap**: Automatically loads whenever `authAutomat` transitions to `'authed'` with a selected company, and resets when the session ends. - **Full Unit Maintenance**: Upserting (creating or modifying) and deleting units by SI key. --- ## 2. State Structure ```ts interface Unit { si: string; // International standard code (e.g. 'C62', 'KGM', 'LTR') symbol?: string; // Display symbol (e.g. 'Stk', 'kg', 'l') name?: string; // Full name (e.g. 'Stück', 'Kilogramm') [key: string]: any; } interface UnitState { /** Alphabetically sorted list of measurement units. */ units: Array; /** Async lifecycle status. */ status: 'idle' | 'loading' | 'succeeded' | 'failed'; /** Last error message if load failed. */ error: string | null; } ``` ### Initial State ```js const initialState = { units: [], status: 'idle', error: null, }; ``` --- ## 3. Configuration & Options ```js new Automat(initialState, actions, { name: 'unit' }); ``` - **`name`**: `'unit'` - **`persist`**: `false` --- ## 4. Actions & Methods Access actions via `unitAutomat.actions.()`. ### `load(): Promise>` Fetches all units for the active company via `GET /api/unit`. Sorts them, updates state, and sets status to `'succeeded'`. ### `upsert(body: object): Promise>` Creates or updates a unit via `POST /api/unit/upsert`. Merges the updated unit into `state.units` by matching on its `si` property, re-sorts the list, updates state, and returns the full updated list. ### `delete(si: string): Promise` Deletes a unit by SI code via `DELETE /api/unit/:si` and filters it out of `state.units`. ### `reset(): void` Resets the state back to `initialState`. --- ## 5. Cross-Automat Subscriptions `unitAutomat` tracks authentication changes automatically: ```js 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(); } }); ``` --- ## 6. Usage Examples ### A. React `PureComponent` Unit Select Dropdown ```jsx import { PureComponent } from 'react'; import PropTypes from 'prop-types'; import unitAutomat from '../automats/unitAutomat'; export class UnitSelect extends PureComponent { static propTypes = { value: PropTypes.string, onChange: PropTypes.func.isRequired, }; constructor(props) { super(props); this.state = { units: unitAutomat.state.units, status: unitAutomat.state.status, }; } componentDidMount() { this.unsub = unitAutomat.subscribe(this, ['units', 'status']); if (this.state.status === 'idle') { unitAutomat.actions.load().catch(console.error); } } componentWillUnmount() { this.unsub?.(); } render() { const { units, status } = this.state; const { value, onChange } = this.props; if (status === 'loading') { return ; } return ( ); } } ``` ### B. Upserting a Unit ```js import unitAutomat from '../automats/unitAutomat'; async function addCustomUnit(si, symbol, name) { try { await unitAutomat.actions.upsert({ si, symbol, name }); console.log('Unit saved successfully'); } catch (err) { console.error('Failed to save unit:', err); } } ``` --- ## 7. Best Practices & Gotchas 1. **Unique Key**: Units are uniquely identified by their `si` property (not an integer ID). 2. **Sort Guarantee**: Units in `state.units` are sorted alphabetically based on `u.symbol ?? u.si`.