import { PureComponent } from 'react';
import Alert from '@mui/material/Alert';
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 withNavigate from '../../components/withNavigate';
import { backendErrorFrom } from '../../utils/backendError';
import { notifyError } from '../../utils/notify';
import { setLastDeliveryPath } from '../../automats/navigationAutomat';
import companyAutomat from '../../automats/companyAutomat';
import { deliveryDraftAutomat } from '../../automats/deliveryEditorAutomat';
import {
GREEN_PANEL,
} from '../../colors';
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]));
}
function getInitialParams(props) {
const searchParams = typeof window !== 'undefined' ? new URLSearchParams(window.location.search) : null;
const prefill =
props.location?.state?.name ??
props.location?.state?.newName ??
searchParams?.get('name') ??
searchParams?.get('newName') ??
deliveryDraftAutomat.state.unmatchedSupplierName ??
'';
const returnTo =
props.location?.state?.returnTo ??
searchParams?.get('returnTo') ??
null;
return { prefill: prefill.trim(), returnTo };
}
class LieferungLieferantenPage extends PureComponent {
constructor(props) {
super(props);
const { prefill } = getInitialParams(props);
const initialSuppliers = sortSuppliers(companyAutomat.state.suppliers ?? []);
this.state = {
status: companyAutomat.state.suppliersStatus,
error: companyAutomat.state.suppliersError
? backendErrorFrom(companyAutomat.state.suppliersError)
: null,
suppliers: initialSuppliers,
drafts: draftsFrom(initialSuppliers),
newName: prefill,
busyKey: null,
};
this._cancelled = false;
this.handleCreate = this.handleCreate.bind(this);
this.handleRetry = this.handleRetry.bind(this);
}
componentDidMount() {
const { returnTo, prefill } = getInitialParams(this.props);
if (!returnTo) {
setLastDeliveryPath(null);
}
if (prefill && !this.state.newName) {
this.setState({ newName: prefill });
}
this._cancelled = false;
this.unsub = companyAutomat.subscribe(
this,
(state) => {
const sorted = sortSuppliers(state.suppliers ?? []);
return {
status: state.suppliersStatus,
error: state.suppliersError ? backendErrorFrom(state.suppliersError) : null,
suppliers: sorted,
drafts: draftsFrom(sorted),
};
},
['suppliers', 'suppliersStatus', 'suppliersError'],
);
}
componentDidUpdate(prevProps) {
if (prevProps.location !== this.props.location) {
const { prefill } = getInitialParams(this.props);
if (prefill && prefill !== this.state.newName) {
this.setState({ newName: prefill });
}
}
}
componentWillUnmount() {
this._cancelled = true;
this.unsub?.();
}
handleRetry() {
void companyAutomat.actions.loadSuppliers().catch((err) => notifyError(err));
}
async handleCreate() {
const name = this.state.newName.trim();
if (!name || this.state.busyKey != null) return;
const { returnTo } = getInitialParams(this.props);
this.setState({ busyKey: 'new' });
try {
const newSupplier = await companyAutomat.actions.createSupplier({ name });
// Assign the new supplier to the active delivery draft & clear unmatched name
deliveryDraftAutomat.actions.setDeliveryEntity(newSupplier.id);
deliveryDraftAutomat.actions.setUnmatchedSupplierName(null);
if (this._cancelled) return;
this.setState({ newName: '', busyKey: null });
enqueueSnackbar(`Lieferant „${newSupplier.name || name}“ angelegt.`, { variant: 'success' });
if (returnTo && this.props.navigate) {
this.props.navigate(returnTo);
}
} 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 {
await companyAutomat.actions.updateSupplier(supplier.id, { name: draft });
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 companyAutomat.actions.removeSupplier(supplier.id);
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;
const { returnTo } = getInitialParams(this.props);
if (status === 'loading' || status === 'idle') {
return (
);
}
if (status === 'failed') {
return (
);
}
return (
{returnTo ? (
this.props.navigate?.(returnTo)}
>
Zurück zur Lieferung
}
>
{newName
? `Lieferantenname „${newName}“ aus Dokument übernommen.`
: 'Neuen Lieferanten für die Lieferung anlegen.'}
) : null}
{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 withNavigate(LieferungLieferantenPage);