import { PureComponent } from 'react'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import CircularProgress from '@mui/material/CircularProgress'; import IconButton from '@mui/material/IconButton'; import List from '@mui/material/List'; import ListItem from '@mui/material/ListItem'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined'; import StorefrontIcon from '@mui/icons-material/Storefront'; import { enqueueSnackbar } from 'notistack'; import BackendError from '../../components/BackendError'; import SingleLineTextEdit from 'dashgui/SingleLineTextEdit'; import { PanelTile, PanelTileGrid } from 'dashgui/panels'; import { StorageManagerContext } from '../../api/storageManagerContext'; import { requireDefined, requireObject } from '../../utils/apiShape'; import { backendErrorFrom } from '../../utils/backendError'; import { notifyError } from '../../utils/notify'; import { setLastDeliveryPath } from '../../automats'; function sortSuppliers(suppliers) { return [...suppliers].sort((a, b) => String(a.name).localeCompare(String(b.name), 'de'), ); } function draftsFrom(suppliers) { return Object.fromEntries(suppliers.map((row) => [row.id, row.name])); } class LieferungLieferantenPage extends PureComponent { static contextType = StorageManagerContext; constructor(props) { super(props); this.state = { status: 'loading', error: null, suppliers: [], drafts: {}, newName: '', busyKey: null, }; this._cancelled = false; this.handleCreate = this.handleCreate.bind(this); this.handleRetry = this.handleRetry.bind(this); this.loadSuppliers = this.loadSuppliers.bind(this); } componentDidMount() { setLastDeliveryPath(null); this._cancelled = false; void this.loadSuppliers(); } componentWillUnmount() { this._cancelled = true; } applySuppliers(suppliers) { const sorted = sortSuppliers(suppliers); this.setState({ status: 'ready', error: null, suppliers: sorted, drafts: draftsFrom(sorted), }); } async loadSuppliers() { this.setState({ status: 'loading', error: null }); try { const list = this.context.suppliers ?? (await this.context.supplierPromise); if (this._cancelled) return; this.applySuppliers(list); } catch (err) { if (this._cancelled) return; this.setState({ status: 'failed', error: backendErrorFrom(err) }); } } handleRetry() { void this.loadSuppliers(); } async refreshFromServer() { const list = await this.context.updateSupplier(); if (this._cancelled) return; this.applySuppliers(list); } async handleCreate() { const name = this.state.newName.trim(); if (!name || this.state.busyKey != null) return; this.setState({ busyKey: 'new' }); try { const data = await this.context.supplier.create({ name }); requireObject(data, 'POST /api/supplier'); requireObject(data.supplier, 'supplier'); requireDefined(data.supplier.id, 'supplier.id'); await this.refreshFromServer(); if (this._cancelled) return; this.setState({ newName: '', busyKey: null }); enqueueSnackbar('Lieferant angelegt.', { variant: 'success' }); } catch (err) { if (this._cancelled) return; notifyError(err); this.setState({ busyKey: null }); } } async handleRename(supplier) { const draft = String(this.state.drafts[supplier.id] ?? '').trim(); if (!draft) { this.setState((prev) => ({ drafts: { ...prev.drafts, [supplier.id]: supplier.name }, })); return; } if (draft === supplier.name || this.state.busyKey != null) return; this.setState({ busyKey: supplier.id }); try { const data = await this.context.supplier.update(supplier.id, { name: draft }); requireObject(data, 'PATCH /api/supplier/:id'); requireObject(data.supplier, 'supplier'); requireDefined(data.supplier.id, 'supplier.id'); await this.refreshFromServer(); if (this._cancelled) return; this.setState({ busyKey: null }); enqueueSnackbar('Lieferant gespeichert.', { variant: 'success' }); } catch (err) { if (this._cancelled) return; notifyError(err); this.setState((prev) => ({ busyKey: null, drafts: { ...prev.drafts, [supplier.id]: supplier.name }, })); } } async handleDelete(supplier) { if (this.state.busyKey != null) return; if (!window.confirm(`Lieferant „${supplier.name}“ wirklich löschen?`)) { return; } this.setState({ busyKey: supplier.id }); try { await this.context.supplier.delete(supplier.id); await this.refreshFromServer(); if (this._cancelled) return; this.setState({ busyKey: null }); enqueueSnackbar('Lieferant gelöscht.', { variant: 'success' }); } catch (err) { if (this._cancelled) return; notifyError(err); this.setState({ busyKey: null }); } } render() { const { status, error, suppliers, drafts, newName, busyKey } = this.state; const busy = busyKey != null; if (status === 'loading') { return ( ); } if (status === 'failed') { return ( ); } return ( Lieferanten der ausgewählten Firma. {suppliers.length === 0 ? ( Noch keine Lieferanten. ) : ( suppliers.map((supplier) => ( this.setState((prev) => ({ drafts: { ...prev.drafts, [supplier.id]: next }, })) } onBlur={() => void this.handleRename(supplier)} onKeyDown={(event) => { if (event.key === 'Enter') { event.preventDefault(); event.target.blur(); } if (event.key === 'Escape') { event.preventDefault(); this.setState((prev) => ({ drafts: { ...prev.drafts, [supplier.id]: supplier.name }, })); event.target.blur(); } }} sx={{ flex: 1 }} /> void this.handleDelete(supplier)} > )) )} this.setState({ newName: next })} onKeyDown={(event) => { if (event.key === 'Enter') { event.preventDefault(); void this.handleCreate(); } }} sx={{ flex: 1 }} /> ); } } export default LieferungLieferantenPage;