This commit is contained in:
seb
2026-10-28 00:46:23 +01:00
parent 0453680c59
commit e45f35e97b
6 changed files with 90 additions and 65 deletions

View File

@@ -68,28 +68,27 @@ export default class ArticleUnitEditorDialog extends Component {
super(props); super(props);
this.state = { this.state = {
busy: false, busy: false,
units: [], units: companyAutomat.state.units,
unitsLoading: false, unitsLoading: companyAutomat.state.unitsStatus === 'loading',
form: emptyForm(), form: emptyForm(),
selectedSi: null, selectedSi: null,
}; };
} }
componentDidMount() {
this.unsub = companyAutomat.subscribe(this, (state) => ({
units: state.units,
unitsLoading: state.unitsStatus === 'loading',
}));
}
componentWillUnmount() {
this.unsub?.();
}
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
if (this.props.open && !prevProps.open) { if (this.props.open && !prevProps.open) {
this.setState({ form: emptyForm(), selectedSi: null }); this.setState({ form: emptyForm(), selectedSi: null });
void this.loadUnits();
}
}
async loadUnits() {
this.setState({ unitsLoading: true });
try {
const units = await companyAutomat.actions.loadUnits();
this.setState({ units, unitsLoading: false });
} catch (err) {
this.setState({ unitsLoading: false });
notifyError(err);
} }
} }
@@ -116,23 +115,22 @@ export default class ArticleUnitEditorDialog extends Component {
if (!formValid(form)) return; if (!formValid(form)) return;
this.setState({ busy: true }); this.setState({ busy: true });
try { try {
const data = await unitApi.upsert({ const payload = {
si: String(form.si ?? '').trim(), si: String(form.si ?? '').trim(),
basesi: String(form.basesi ?? '').trim(), basesi: String(form.basesi ?? '').trim(),
basesifactor: parseFactor(form.basesifactor), basesifactor: parseFactor(form.basesifactor),
symbol: String(form.symbol ?? '').trim(), symbol: String(form.symbol ?? '').trim(),
name: String(form.name ?? '').trim(), name: String(form.name ?? '').trim(),
}); };
requireObject(data, 'PUT /api/unit'); const units = await companyAutomat.actions.upsertUnit(payload);
requireObject(data.unit, 'unit'); const saved = units.find((u) => u.si === payload.si) ?? payload;
const units = await companyAutomat.actions.loadUnits();
this.setState({ this.setState({
busy: false, busy: false,
units, units,
form: formFromUnit(data.unit), form: formFromUnit(saved),
selectedSi: data.unit.si, selectedSi: saved.si,
}); });
this.props.onUnitUpserted?.(data.unit); this.props.onUnitUpserted?.(saved);
} catch (err) { } catch (err) {
this.setState({ busy: false }); this.setState({ busy: false });
notifyError(err); notifyError(err);
@@ -144,9 +142,13 @@ export default class ArticleUnitEditorDialog extends Component {
if (!selectedSi || selectedSi === DEFAULT_UNIT_SI) return; if (!selectedSi || selectedSi === DEFAULT_UNIT_SI) return;
this.setState({ busy: true }); this.setState({ busy: true });
try { try {
await unitApi.delete(selectedSi); await companyAutomat.actions.deleteUnit(selectedSi);
const units = await companyAutomat.actions.loadUnits(); this.setState({
this.setState({ busy: false, units, form: emptyForm(), selectedSi: null }); busy: false,
units: companyAutomat.state.units,
form: emptyForm(),
selectedSi: null,
});
this.props.onUnitDeleted?.(selectedSi); this.props.onUnitDeleted?.(selectedSi);
} catch (err) { } catch (err) {
this.setState({ busy: false }); this.setState({ busy: false });

View File

@@ -82,9 +82,7 @@ class AuswahlMerkmaleTab extends PureComponent {
} }
}, ['attributes', 'attributesStatus', 'attributesError']); }, ['attributes', 'attributesStatus', 'attributesError']);
if (companyAutomat.state.attributesStatus !== 'succeeded') { if (companyAutomat.state.attributesStatus === 'succeeded') {
void this.load();
} else {
this._initAttrSortable(); this._initAttrSortable();
this._initValSortable(); this._initValSortable();
} }

View File

@@ -65,9 +65,7 @@ class TextMerkmaleTab extends PureComponent {
} }
}, ['properties', 'propertiesStatus', 'propertiesError']); }, ['properties', 'propertiesStatus', 'propertiesError']);
if (companyAutomat.state.propertiesStatus !== 'succeeded') { if (companyAutomat.state.propertiesStatus === 'succeeded') {
void this.load();
} else {
this._initPropSortable(); this._initPropSortable();
} }
} }

View File

@@ -45,8 +45,6 @@ export default class CompanySettingsPanel extends Component {
}); });
if (companyAutomat.state.current) { if (companyAutomat.state.current) {
this.syncFormFromCompany(companyAutomat.state.current); this.syncFormFromCompany(companyAutomat.state.current);
} else {
void this.loadCompany();
} }
} }

View File

@@ -1,4 +1,4 @@
import { Component } from 'react'; import { PureComponent } from 'react';
import Alert from '@mui/material/Alert'; import Alert from '@mui/material/Alert';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
@@ -17,7 +17,7 @@ import { enqueueSnackbar } from 'notistack';
import BackendError from '../BackendError'; import BackendError from '../BackendError';
import { number as numberApi } from '../../api'; import { number as numberApi } from '../../api';
import companyAutomat from '../../automats/companyAutomat'; import companyAutomat from '../../automats/companyAutomat';
import { requireArray, requireDefined, requireObject } from '../../utils/apiShape'; import { requireDefined, requireObject } from '../../utils/apiShape';
import { backendErrorFrom } from '../../utils/backendError'; import { backendErrorFrom } from '../../utils/backendError';
import { notifyError } from '../../utils/notify'; import { notifyError } from '../../utils/notify';
@@ -31,44 +31,76 @@ function parseNext(value) {
return Number.isInteger(n) && n >= 0 ? n : null; return Number.isInteger(n) && n >= 0 ? n : null;
} }
export default class NumberSettingsPanel extends Component { function buildDrafts(numbers, prevDrafts = {}) {
return Object.fromEntries(
(Array.isArray(numbers) ? numbers : []).map((row) => {
const existing = prevDrafts[row.id];
return [
row.id,
existing?.busy
? existing
: {
prefix: row.prefix ?? '',
padding: row.padding != null ? String(row.padding) : '',
next: row.next != null ? String(row.next) : '',
busy: false,
saveError: null,
},
];
}),
);
}
export default class NumberSettingsPanel extends PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
const numbers = Array.isArray(companyAutomat.state.numbers)
? companyAutomat.state.numbers
: [];
const numbersStatus = companyAutomat.state.numbersStatus;
this.state = { this.state = {
status: 'loading', status:
error: null, numbersStatus === 'ready'
numbers: [], ? 'ready'
: numbersStatus === 'failed'
? 'failed'
: 'loading',
error: companyAutomat.state.numbersError
? backendErrorFrom(companyAutomat.state.numbersError)
: null,
numbers,
// id → { prefix, padding, next, busy, saveError } // id → { prefix, padding, next, busy, saveError }
drafts: {}, drafts: buildDrafts(numbers),
}; };
this.handleRetry = this.handleRetry.bind(this); this.handleRetry = this.handleRetry.bind(this);
this.handleSave = this.handleSave.bind(this); this.handleSave = this.handleSave.bind(this);
} }
componentDidMount() { componentDidMount() {
void this.load(); this._unmounted = false;
this.unsub = companyAutomat.subscribe(this, (state) => {
const numbers = Array.isArray(state.numbers) ? state.numbers : [];
return {
status:
state.numbersStatus === 'ready'
? 'ready'
: state.numbersStatus === 'failed'
? 'failed'
: 'loading',
error: state.numbersError ? backendErrorFrom(state.numbersError) : null,
numbers,
drafts:
numbers !== this.state.numbers
? buildDrafts(numbers, this.state.drafts)
: this.state.drafts,
};
});
} }
async load() { async load() {
this.setState({ status: 'loading', error: null }); this.setState({ status: 'loading', error: null });
try { try {
const numbers = requireArray( await companyAutomat.actions.reloadNumbers();
await companyAutomat.actions.reloadNumbers(),
'numbers',
);
const drafts = Object.fromEntries(
numbers.map((row) => [
row.id,
{
prefix: row.prefix ?? '',
padding: row.padding != null ? String(row.padding) : '',
next: row.next != null ? String(row.next) : '',
busy: false,
saveError: null,
},
]),
);
this.setState({ status: 'ready', numbers, drafts });
} catch (err) { } catch (err) {
notifyError(err); notifyError(err);
this.setState({ status: 'failed', error: backendErrorFrom(err) }); this.setState({ status: 'failed', error: backendErrorFrom(err) });
@@ -145,8 +177,9 @@ export default class NumberSettingsPanel extends Component {
requireObject(data.number, 'number'); requireObject(data.number, 'number');
const updated = requireDefined(data.number, 'number'); const updated = requireDefined(data.number, 'number');
const numbers = this.state.numbers.map((n) => (n.id === id ? { ...n, ...body } : n)); const numbers = companyAutomat.actions.replaceNumbers(
await companyAutomat.actions.reloadNumbers(); this.state.numbers.map((n) => (n.id === id ? { ...n, ...updated } : n)),
);
this.setState({ this.setState({
numbers, numbers,
drafts: { drafts: {
@@ -174,6 +207,7 @@ export default class NumberSettingsPanel extends Component {
componentWillUnmount() { componentWillUnmount() {
this._unmounted = true; this._unmounted = true;
this.unsub?.();
} }
render() { render() {

View File

@@ -78,9 +78,6 @@ export default class PosTerminalSettingsPanel extends Component {
if (categoryAutomat.state.treeStatus === 'idle') { if (categoryAutomat.state.treeStatus === 'idle') {
void categoryAutomat.actions.loadTree(); void categoryAutomat.actions.loadTree();
} }
if (companyAutomat.state.terminalsStatus !== 'succeeded') {
void this.loadTerminals();
}
} }
componentWillUnmount() { componentWillUnmount() {
@@ -120,7 +117,6 @@ export default class PosTerminalSettingsPanel extends Component {
await whenCategoryTreeReady(); await whenCategoryTreeReady();
} }
await companyAutomat.actions.loadTerminals();
this.setState({ newTerminalName: '' }); this.setState({ newTerminalName: '' });
enqueueSnackbar('Terminal hinzugefügt.', { variant: 'success' }); enqueueSnackbar('Terminal hinzugefügt.', { variant: 'success' });
} catch (err) { } catch (err) {
@@ -134,7 +130,6 @@ export default class PosTerminalSettingsPanel extends Component {
this.setState({ deletingId: terminal.id }); this.setState({ deletingId: terminal.id });
try { try {
await companyAutomat.actions.deleteTerminal(terminal.id); await companyAutomat.actions.deleteTerminal(terminal.id);
await companyAutomat.actions.loadTerminals();
enqueueSnackbar('Terminal gelöscht.', { variant: 'info' }); enqueueSnackbar('Terminal gelöscht.', { variant: 'info' });
} catch (err) { } catch (err) {
notifyError(err); notifyError(err);