5.7 KiB
posterminalAutomat
Source File:
src/automats/posterminalAutomat.js
Registration Key:'posterminal'(Automat.get('posterminal')/window.__AUTOMATS__.get('posterminal'))
1. Overview & Purpose
posterminalAutomat manages hardware Point-of-Sale (POS) terminals registered for the active company. In Dashfront, POS terminals can have specific category subsets enabled or disabled to control which products appear on specific physical checkouts or handheld POS devices.
Core Responsibilities
- Terminal Registry: Lists all POS terminals (
id,name,categoryIds). - Category Filter Management: Enabling or disabling categories for individual terminals (
enableAll,disableAll,enableCategory,disableCategory). - Terminal CRUD: Creating new hardware terminal entries and deleting retired ones.
- Autonomous Bootstrap: Automatically loads whenever
authAutomatauthenticates with a company and resets on logout.
2. State Structure
interface PosTerminal {
id: number;
name: string;
categoryIds?: Array<number>;
[key: string]: any;
}
interface PosterminalState {
/** Registered POS terminals for active company. */
terminals: Array<PosTerminal>;
/** Company ID these terminals belong to. */
companyId: number | string | null;
/** Async lifecycle status. */
status: 'idle' | 'loading' | 'succeeded' | 'failed';
/** Last error message if load failed. */
error: string | null;
}
Initial State
const initialState = {
terminals: [],
companyId: null,
status: 'idle',
error: null,
};
3. Configuration & Options
new Automat(initialState, actions, { name: 'posterminal' });
name:'posterminal'persist:false
4. Actions & Methods
Access actions via posterminalAutomat.actions.<method>().
load(): Promise<Array<PosTerminal>>
Determines the selected company ID from authAutomat or companyAutomat. Fetches terminals via GET /api/posterminal, updates state, and returns the terminals list.
create({ name: string }): Promise<PosTerminal>
Creates a new POS terminal via POST /api/posterminal and appends it to state.terminals.
delete(terminalId: number): Promise<void>
Deletes a terminal via DELETE /api/posterminal/:id and filters it out of state.terminals.
enableAll({ terminalId: number }): Promise<object>
Enables all categories on the given terminal via POST /api/posterminal/:id/category/enable-all. Patches categoryIds on the terminal in state.
disableAll({ terminalId: number }): Promise<object>
Disables all categories on the given terminal via POST /api/posterminal/:id/category/disable-all. Patches categoryIds on the terminal in state.
enableCategory({ terminalId: number, categoryId: number }): Promise<object>
Enables a specific category on the given terminal via POST /api/posterminal/:id/category/:catId/enable.
disableCategory({ terminalId: number, categoryId: number }): Promise<object>
Disables a specific category on the given terminal via DELETE /api/posterminal/:id/category/:catId/disable.
reset(): void
Resets the automat back to initialState.
5. Exported Standalone Selectors
selectPosterminals():() => Array<PosTerminal>— Returns the list of registered terminals.selectPosterminalStatus():() => string— Returns the current loading status.selectHasPosterminals():() => boolean— Returnstrueif one or more terminals exist.
6. Cross-Automat Subscriptions
posterminalAutomat coordinates with authAutomat at module load:
authAutomat.subscribe((auth) => {
const companyId = auth.user?.selectedCompanyId;
if (auth.status === 'authed' && companyId) {
void posterminalAutomat.actions.load();
} else if (auth.status === 'anon') {
posterminalAutomat.actions.reset();
}
});
7. Usage Examples
A. React PureComponent Terminal Management List
import { PureComponent } from 'react';
import posterminalAutomat, { selectPosterminals } from '../automats/posterminalAutomat';
export class TerminalSettings extends PureComponent {
constructor(props) {
super(props);
this.state = {
terminals: selectPosterminals(),
status: posterminalAutomat.state.status,
};
}
componentDidMount() {
this.unsub = posterminalAutomat.subscribe(this, ['terminals', 'status']);
}
componentWillUnmount() {
this.unsub?.();
}
handleCreate = async () => {
const name = window.prompt('Name des neuen POS-Terminals:');
if (name) {
await posterminalAutomat.actions.create({ name });
}
};
handleDelete = async (terminalId) => {
if (window.confirm('Terminal wirklich löschen?')) {
await posterminalAutomat.actions.delete(terminalId);
}
};
render() {
const { terminals, status } = this.state;
if (status === 'loading') return <div>Lade POS-Terminals...</div>;
return (
<div>
<h3>Registrierte POS-Terminals</h3>
<ul>
{terminals.map((t) => (
<li key={t.id}>
<strong>{t.name}</strong> (ID: {t.id})
<button onClick={() => this.handleDelete(t.id)}>Löschen</button>
</li>
))}
</ul>
<button onClick={this.handleCreate}>+ Neues Terminal anlegen</button>
</div>
);
}
}
8. Best Practices & Gotchas
- Category synchronization: Terminal category assignments are also referenced inside
categoryAutomat.actions.patchCategoryPosterminalIds. Both stores stay in sync when configuring POS terminals. - Terminal IDs: Use integer IDs when calling
delete,enableCategory, ordisableCategory.