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 Stack from '@mui/material/Stack'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; import TableContainer from '@mui/material/TableContainer'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; import Typography from '@mui/material/Typography'; import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined'; import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; import { enqueueSnackbar } from 'notistack'; import BackendError from '../BackendError'; import { PanelTile, PanelTileGrid } from '../panels'; import { StorageManagerContext } from '../../api/storageManagerContext'; import { backendErrorFrom } from '../../utils/backendError'; import { notifyError } from '../../utils/notify'; import withNavigate from '../withNavigate'; import { formatDate, loadParties, manifestConfig, numberDisplay, partyDisplayName, sortDocs, } from './manifestConfig'; class ManifestList extends PureComponent { static contextType = StorageManagerContext; constructor(props) { super(props); this.cfg = manifestConfig(props.kind); this.state = { status: 'loading', error: null, docs: [], partiesById: {}, busyId: null, }; this._cancelled = false; this.handleRetry = this.handleRetry.bind(this); this.handleCreate = this.handleCreate.bind(this); } componentDidMount() { this._cancelled = false; void this.load(); } componentWillUnmount() { this._cancelled = true; } async load() { const cfg = this.cfg; this.setState({ status: 'loading', error: null }); try { const [docs, parties] = await Promise.all([ cfg.listPromise(this.context), loadParties(this.props.kind, this.context), ]); if (this._cancelled) return; this.setState({ status: 'ready', docs: sortDocs(docs), partiesById: cfg.partiesByIdFromList(parties), }); } catch (err) { if (this._cancelled) return; this.setState({ status: 'failed', error: backendErrorFrom(err) }); } } handleRetry() { void this.load(); } /** Same path as AppShell sub-nav: live useNavigate via withNavigate. */ go(to) { const { navigate } = this.props; if (typeof navigate === 'function') { navigate(to); return; } window.location.assign(to); } handleCreate() { this.go(this.cfg.createPath); } handleEdit(doc) { this.go(this.cfg.editPath(doc.id)); } async handleDelete(doc) { if (this.state.busyId != null) return; if (!window.confirm(this.cfg.confirmDelete(doc.number))) return; const cfg = this.cfg; this.setState({ busyId: doc.id }); try { await this.context[cfg.api].delete(doc.id); const list = await this.context[cfg.updateCache](); if (this._cancelled) return; this.setState({ docs: sortDocs(list), busyId: null, }); enqueueSnackbar(cfg.deletedMsg, { variant: 'success' }); } catch (err) { if (this._cancelled) return; notifyError(err); this.setState({ busyId: null }); } } partyName(partyId) { if (partyId == null) return null; return partyDisplayName( this.props.kind, this.state.partiesById[partyId], ); } render() { const { status, error, docs, busyId } = this.state; const cfg = this.cfg; const partyField = cfg.partyField; if (status === 'loading') { return ( ); } if (status === 'failed') { return ; } return ( {docs.length === 0 ? ( {cfg.emptyList} ) : ( Nummer {cfg.externalNumber ? ( Referenz ) : null} {cfg.dateLabel} {cfg.partyLabel} {docs.map((row) => ( this.handleEdit(row)} > {row.number} {cfg.externalNumber ? ( {numberDisplay(row.externalNumber)} ) : null} {formatDate(row.date)} {this.partyName(row[partyField])} e.stopPropagation()} > this.handleEdit(row)} > void this.handleDelete(row)} > ))}
)}
); } } export default withNavigate(ManifestList);