Files
dashfront/src/pages/kunde/neu.jsx
seb 354f7e7466 Remove Auftrag Ausliefern/Retoure stubs and sort Kundengruppen by sort field.
Placeholder sub-pages are dropped from routing and nav until delivery/return flows exist; the new-customer group dropdown now matches the API sort order.
2026-08-07 06:24:21 +02:00

204 lines
5.8 KiB
JavaScript

import { PureComponent } from 'react';
import Autocomplete from '@mui/material/Autocomplete';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
import TextField from '@mui/material/TextField';
import { enqueueSnackbar } from 'notistack';
import BackendError from '../../components/BackendError';
import SingleLineTextEdit from '../../components/SingleLineTextEdit';
import { PanelTile, PanelTileGrid } from '../../components/panels';
import { StorageManagerContext } from '../../api/storageManagerContext';
import { router } from '../../appRouter';
import { requireDefined, requireObject } from '../../utils/apiShape';
import { backendErrorFrom } from '../../utils/backendError';
import { notifyError } from '../../utils/notify';
function sortGroups(groups) {
return [...groups].sort((a, b) => {
const bySort = a.sort - b.sort;
if (bySort !== 0) return bySort;
const byName = String(a.name).localeCompare(String(b.name), 'de');
if (byName !== 0) return byName;
return a.id - b.id;
});
}
class KundeNeuPage extends PureComponent {
static contextType = StorageManagerContext;
constructor(props) {
super(props);
this.state = {
status: 'loading',
error: null,
groups: [],
customergroupId: null,
name: '',
firstName: '',
saving: false,
};
this._cancelled = false;
this.handleRetry = this.handleRetry.bind(this);
this.handleGroupChange = this.handleGroupChange.bind(this);
this.handleSave = this.handleSave.bind(this);
}
componentDidMount() {
this._cancelled = false;
void this.loadGroups();
}
componentWillUnmount() {
this._cancelled = true;
}
async loadGroups() {
this.setState({ status: 'loading', error: null });
try {
const list =
this.context.customergroups ??
(await this.context.customergroupPromise);
if (this._cancelled) return;
this.setState({
status: 'ready',
groups: sortGroups(list),
});
} catch (err) {
if (this._cancelled) return;
this.setState({
status: 'failed',
error: backendErrorFrom(err),
});
}
}
handleRetry() {
void this.loadGroups();
}
handleGroupChange(_event, option) {
this.setState({ customergroupId: option?.id ?? null });
}
async handleSave() {
if (this.state.saving) return;
const { customergroupId, name, firstName } = this.state;
const trimmedName = name.trim();
const trimmedFirst = firstName.trim();
if (customergroupId == null) {
notifyError(new Error('Kundengruppe fehlt.'));
return;
}
if (!trimmedName) {
notifyError(new Error('Name fehlt.'));
return;
}
const body = {
customergroupId,
name: trimmedName,
};
if (trimmedFirst) body.firstName = trimmedFirst;
this.setState({ saving: true });
try {
const data = await this.context.entity.create(body);
requireObject(data, 'POST /api/entity');
requireObject(data.entity, 'entity');
requireDefined(data.entity.id, 'entity.id');
await this.context.updateEntity();
if (this._cancelled) return;
enqueueSnackbar('Kunde angelegt.', { variant: 'success' });
void router.navigate(`/kunde/${data.entity.id}`);
} catch (err) {
if (this._cancelled) return;
notifyError(err);
this.setState({ saving: false });
}
}
render() {
const {
status,
error,
groups,
customergroupId,
name,
firstName,
saving,
} = this.state;
if (status === 'failed') {
return <BackendError error={error} onRetry={this.handleRetry} />;
}
const selected =
groups.find((row) => row.id === customergroupId) ?? null;
const canSave =
customergroupId != null && name.trim() !== '' && !saving;
return (
<PanelTileGrid>
<PanelTile wide={2} minHeight={220} color="#bfdbfe" title="Neuer Kunde">
<Stack spacing={2}>
<Autocomplete
size="small"
options={groups}
value={selected}
loading={status === 'loading'}
disabled={saving || status === 'loading'}
getOptionLabel={(option) => String(option.name ?? '')}
isOptionEqualToValue={(option, value) => option.id === value.id}
onChange={this.handleGroupChange}
renderInput={(params) => (
<TextField
{...params}
label="Kundengruppe"
required
slotProps={{
...params.slotProps,
htmlInput: {
...params.slotProps?.htmlInput,
spellCheck: false,
autoComplete: 'off',
},
}}
/>
)}
/>
<SingleLineTextEdit
size="small"
label="Name"
required
value={name}
disabled={saving}
onChange={(next) => this.setState({ name: next })}
/>
<SingleLineTextEdit
size="small"
label="Vorname"
value={firstName}
disabled={saving}
onChange={(next) => this.setState({ firstName: next })}
/>
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button
variant="contained"
size="small"
disabled={!canSave}
onClick={() => void this.handleSave()}
>
{saving ? 'Speichern…' : 'Speichern'}
</Button>
</Box>
</Stack>
</PanelTile>
</PanelTileGrid>
);
}
}
export default KundeNeuPage;