186 lines
5.7 KiB
Markdown
186 lines
5.7 KiB
Markdown
# `posterminalAutomat`
|
|
|
|
> **Source File**: [`src/automats/posterminalAutomat.js`](file:///home/seb/src/dashfront/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 `authAutomat` authenticates with a company and resets on logout.
|
|
|
|
---
|
|
|
|
## 2. State Structure
|
|
|
|
```ts
|
|
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
|
|
```js
|
|
const initialState = {
|
|
terminals: [],
|
|
companyId: null,
|
|
status: 'idle',
|
|
error: null,
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Configuration & Options
|
|
|
|
```js
|
|
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` — Returns `true` if one or more terminals exist.
|
|
|
|
---
|
|
|
|
## 6. Cross-Automat Subscriptions
|
|
|
|
`posterminalAutomat` coordinates with `authAutomat` at module load:
|
|
|
|
```js
|
|
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
|
|
|
|
```jsx
|
|
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
|
|
|
|
1. **Category synchronization**: Terminal category assignments are also referenced inside `categoryAutomat.actions.patchCategoryPosterminalIds`. Both stores stay in sync when configuring POS terminals.
|
|
2. **Terminal IDs**: Use integer IDs when calling `delete`, `enableCategory`, or `disableCategory`.
|