5.5 KiB
supplierAutomat
Source File:
src/automats/supplierAutomat.js
Registration Key:'supplier'(Automat.get('supplier')/window.__AUTOMATS__.get('supplier'))
1. Overview & Purpose
supplierAutomat manages the supplier directory for the active company (GET /api/supplier). Suppliers are used when receiving deliveries, reconciling purchase invoices, and organizing supplier-specific article catalogs.
Core Responsibilities
- Company Scoping & Auth Sync: Caches suppliers for the selected company and automatically invalidates or re-fetches when switching companies or logging out.
- In-flight Deduplication: Multiple components invoking
load()concurrently share a single HTTP request promise (inflightLoad). - Full CRUD Support: Creating, updating (renaming), and deleting suppliers with automatic cache refresh.
- Silent Background Refreshes:
reload()updates supplier lists in the background without clearing current state.
2. State Structure
interface Supplier {
id: string | number;
name: string;
[key: string]: any;
}
interface SupplierState {
/** Company suppliers list. */
suppliers: Array<Supplier>;
/** Async lifecycle phase. */
status: 'idle' | 'loading' | 'ready' | 'failed';
/** Last error object if load failed. */
error: Error | null;
}
Initial State
const initialState = {
suppliers: [],
status: 'idle',
error: null,
};
3. Configuration & Options
new Automat(initialState, actions, { name: 'supplier' });
name:'supplier'persist:false
4. Actions & Methods
Access actions via supplierAutomat.actions.<method>().
load(): Promise<Array<Supplier>>
Loads the supplier list via GET /api/supplier. Deduplicates concurrent callers: if a request is already in flight, it returns the existing promise. Sets status to 'ready' on success.
reload(): Promise<Array<Supplier>>
Silently re-fetches the supplier list without setting status back to 'loading'. Preserves the current list until the new response arrives.
create(body: { name: string }): Promise<Supplier>
Creates a new supplier via POST /api/supplier, waits for reload(), and returns the newly created supplier object.
update(id: string | number, body: { name: string }): Promise<Supplier>
Updates supplier details via PATCH /api/supplier/:id, waits for reload(), and returns the updated supplier.
remove(id: string | number): Promise<void>
Deletes a supplier via DELETE /api/supplier/:id and triggers reload().
setSuppliers(suppliers: Array<Supplier>): void
Directly replaces the cached supplier array without a network round-trip.
clear(): void
Resets the state back to initialState.
5. Cross-Automat Subscriptions
supplierAutomat tracks authAutomat through syncWithAuth:
function authKey(authState) {
if (authState?.status !== 'authed' || !authState.user) return null;
const companyId = authState.user.selectedCompanyId;
return companyId == null ? null : String(companyId);
}
function syncWithAuth(authState) {
const key = authKey(authState);
if (key === lastAuthKey) return;
lastAuthKey = key;
if (key == null) {
supplierAutomat.actions.clear();
} else {
void supplierAutomat.actions.load().catch(() => {});
}
}
authAutomat.subscribe(syncWithAuth);
syncWithAuth(authAutomat.state);
Whenever the user authenticates with a company, suppliers load automatically; when logging out, they clear.
6. Usage Examples
A. React PureComponent Supplier Dropdown
import { PureComponent } from 'react';
import PropTypes from 'prop-types';
import supplierAutomat from '../automats/supplierAutomat';
export class SupplierDropdown extends PureComponent {
static propTypes = {
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
onChange: PropTypes.func.isRequired,
};
constructor(props) {
super(props);
this.state = {
suppliers: supplierAutomat.state.suppliers,
status: supplierAutomat.state.status,
};
}
componentDidMount() {
this.unsub = supplierAutomat.subscribe(this, ['suppliers', 'status']);
if (this.state.status === 'idle') {
supplierAutomat.actions.load().catch(console.error);
}
}
componentWillUnmount() {
this.unsub?.();
}
render() {
const { suppliers, status } = this.state;
const { value, onChange } = this.props;
if (status === 'loading') {
return <select disabled><option>Lieferanten laden...</option></select>;
}
return (
<select value={value ?? ''} onChange={(e) => onChange(e.target.value)}>
<option value="">-- Lieferant wählen --</option>
{suppliers.map((s) => (
<option key={s.id} value={s.id}>{s.name}</option>
))}
</select>
);
}
}
B. Creating a Supplier
import supplierAutomat from '../automats/supplierAutomat';
async function addNewSupplier(name) {
try {
const supplier = await supplierAutomat.actions.create({ name });
console.log('Supplier created:', supplier);
} catch (err) {
console.error('Failed to create supplier:', err);
}
}
7. Best Practices & Gotchas
- Automatic Refresh:
create,update, andremoveautomatically callreload(), so subscribers will receive the updated list without manual re-querying. - Inflight Safety: You can safely call
supplierAutomat.actions.load()in multiple components mounted at the same time without causing duplicate HTTP requests.