u
This commit is contained in:
@@ -4,10 +4,19 @@ import TableBody from '@mui/material/TableBody';
|
||||
import TableCell from '@mui/material/TableCell';
|
||||
import TableHead from '@mui/material/TableHead';
|
||||
import TableRow from '@mui/material/TableRow';
|
||||
import Link from '@mui/material/Link';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { articleHistoryAutomat } from '../../../automats/articleDetailAutomat';
|
||||
import sseAutomat from '../../../automats/sseAutomat';
|
||||
import shipmentAutomat from '../../../automats/shipmentAutomat';
|
||||
import { shipment as shipmentApi } from '../../../api';
|
||||
import { ShipmentDetailDialog } from '../../manifest';
|
||||
import withNavigate from '../../withNavigate';
|
||||
import { notifyError } from '../../../utils/notify';
|
||||
import ResultsPagination from '../ResultsPagination';
|
||||
import {
|
||||
SCRIM_SOFT,
|
||||
} from '../../../colors';
|
||||
|
||||
const PAGE_SIZE = 20;
|
||||
|
||||
@@ -15,9 +24,15 @@ function formatDate(iso) {
|
||||
return new Date(iso).toLocaleString('de-DE');
|
||||
}
|
||||
|
||||
import {
|
||||
SCRIM_SOFT,
|
||||
} from '../../../colors';
|
||||
function decodeMeta(meta) {
|
||||
if (!meta) return null;
|
||||
if (typeof meta === 'object') return meta;
|
||||
try {
|
||||
return JSON.parse(meta);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const HISTORY_DATE_CELL_BORDER = `1px solid ${SCRIM_SOFT}`;
|
||||
|
||||
@@ -30,11 +45,17 @@ const dateCellSx = {
|
||||
verticalAlign: 'middle',
|
||||
};
|
||||
|
||||
export default class ArticleHistoryTab extends PureComponent {
|
||||
class ArticleHistoryTab extends PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { all: [], skip: 0 };
|
||||
this.state = {
|
||||
all: [],
|
||||
skip: 0,
|
||||
selectedShipment: null,
|
||||
loadingShipment: false,
|
||||
};
|
||||
this.handlePageChange = this.handlePageChange.bind(this);
|
||||
this.handleCloseShipment = this.handleCloseShipment.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -88,8 +109,122 @@ export default class ArticleHistoryTab extends PureComponent {
|
||||
this.setState({ skip: (page - 1) * PAGE_SIZE });
|
||||
}
|
||||
|
||||
handleCloseShipment() {
|
||||
this.setState({ selectedShipment: null });
|
||||
}
|
||||
|
||||
handleOpenShipment = async (shipmentNumber, shipmentId = null) => {
|
||||
if (shipmentId) {
|
||||
this.setState({ selectedShipment: { id: shipmentId, number: shipmentNumber } });
|
||||
return;
|
||||
}
|
||||
if (!shipmentNumber) return;
|
||||
|
||||
this.setState({ loadingShipment: true });
|
||||
try {
|
||||
const cached = shipmentAutomat.state.items?.find(
|
||||
(s) => s && String(s.number).toLowerCase() === String(shipmentNumber).toLowerCase()
|
||||
);
|
||||
if (cached?.id) {
|
||||
this.setState({ selectedShipment: cached, loadingShipment: false });
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await shipmentApi.list({ search: shipmentNumber });
|
||||
const shipments = Array.isArray(res?.shipments) ? res.shipments : [];
|
||||
const match = shipments.find(
|
||||
(s) => String(s.number).toLowerCase() === String(shipmentNumber).toLowerCase()
|
||||
) || shipments[0];
|
||||
|
||||
if (match?.id) {
|
||||
this.setState({ selectedShipment: match, loadingShipment: false });
|
||||
} else {
|
||||
enqueueSnackbar(`Lieferschein „${shipmentNumber}“ nicht gefunden.`, { variant: 'warning' });
|
||||
this.setState({ loadingShipment: false });
|
||||
}
|
||||
} catch (err) {
|
||||
this.setState({ loadingShipment: false });
|
||||
notifyError(err);
|
||||
}
|
||||
};
|
||||
|
||||
renderEntryText(entry) {
|
||||
const meta = decodeMeta(entry.meta);
|
||||
const shipmentNumber = meta?.shipmentNumber || (meta?.type === 'shipment' ? meta?.manifestNumber : null);
|
||||
const regexMatch = !shipmentNumber && entry.text ? entry.text.match(/Lieferschein\s+([A-Za-z0-9\-_]+)/) : null;
|
||||
const effectiveShipmentNumber = shipmentNumber || regexMatch?.[1] || null;
|
||||
|
||||
if (!effectiveShipmentNumber || !entry.text) {
|
||||
return entry.text;
|
||||
}
|
||||
|
||||
const shipmentId = meta?.shipmentId ?? meta?.manifestId ?? meta?.id ?? null;
|
||||
const targetPattern = `Lieferschein ${effectiveShipmentNumber}`;
|
||||
const idx = entry.text.indexOf(targetPattern);
|
||||
|
||||
const linkElement = (label) => (
|
||||
<Link
|
||||
component="button"
|
||||
type="button"
|
||||
variant="body2"
|
||||
onClick={() => this.handleOpenShipment(effectiveShipmentNumber, shipmentId)}
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
verticalAlign: 'baseline',
|
||||
textAlign: 'left',
|
||||
cursor: 'pointer',
|
||||
color: 'primary.main',
|
||||
textDecoration: 'underline',
|
||||
fontFamily: 'inherit',
|
||||
fontSize: 'inherit',
|
||||
p: 0,
|
||||
m: 0,
|
||||
border: 'none',
|
||||
background: 'none',
|
||||
display: 'inline',
|
||||
'&:hover': {
|
||||
color: 'primary.dark',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</Link>
|
||||
);
|
||||
|
||||
if (idx !== -1) {
|
||||
const before = entry.text.slice(0, idx);
|
||||
const after = entry.text.slice(idx + targetPattern.length);
|
||||
return (
|
||||
<>
|
||||
{before}
|
||||
{linkElement(targetPattern)}
|
||||
{after}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const numIdx = entry.text.indexOf(effectiveShipmentNumber);
|
||||
if (numIdx !== -1) {
|
||||
const before = entry.text.slice(0, numIdx);
|
||||
const after = entry.text.slice(numIdx + effectiveShipmentNumber.length);
|
||||
return (
|
||||
<>
|
||||
{before}
|
||||
{linkElement(effectiveShipmentNumber)}
|
||||
{after}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{linkElement(`Lieferschein ${effectiveShipmentNumber}`)} {entry.text}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { all, skip } = this.state;
|
||||
const { all, skip, selectedShipment } = this.state;
|
||||
const total = all.length;
|
||||
const history = this.pageOf(all, skip);
|
||||
|
||||
@@ -98,54 +233,69 @@ export default class ArticleHistoryTab extends PureComponent {
|
||||
const showPagination = total > PAGE_SIZE;
|
||||
|
||||
return (
|
||||
<Table
|
||||
size="small"
|
||||
sx={{
|
||||
'& td': { borderBottom: 'none', bgcolor: 'transparent' },
|
||||
'& th': { bgcolor: 'transparent' },
|
||||
}}
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell
|
||||
sx={{
|
||||
...dateDividerSx,
|
||||
width: '1%',
|
||||
whiteSpace: 'nowrap',
|
||||
verticalAlign: 'middle',
|
||||
}}
|
||||
>
|
||||
Datum
|
||||
</TableCell>
|
||||
<TableCell
|
||||
sx={dateCellSx}
|
||||
>
|
||||
{showPagination ? (
|
||||
<ResultsPagination
|
||||
offset={skip}
|
||||
totalCount={total}
|
||||
pageSize={PAGE_SIZE}
|
||||
pageCount={pageCount}
|
||||
currentPage={currentPage}
|
||||
onPageChange={this.handlePageChange}
|
||||
/>
|
||||
) : null}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{history.map((entry) => (
|
||||
<TableRow key={entry.id}>
|
||||
<>
|
||||
<Table
|
||||
size="small"
|
||||
sx={{
|
||||
'& td': { borderBottom: 'none', bgcolor: 'transparent' },
|
||||
'& th': { bgcolor: 'transparent' },
|
||||
}}
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell
|
||||
sx={{ verticalAlign: 'top', whiteSpace: 'nowrap', width: '1%' }}
|
||||
sx={{
|
||||
...dateDividerSx,
|
||||
width: '1%',
|
||||
whiteSpace: 'nowrap',
|
||||
verticalAlign: 'middle',
|
||||
}}
|
||||
>
|
||||
{formatDate(entry.date)}
|
||||
Datum
|
||||
</TableCell>
|
||||
<TableCell
|
||||
sx={dateCellSx}
|
||||
>
|
||||
{showPagination ? (
|
||||
<ResultsPagination
|
||||
offset={skip}
|
||||
totalCount={total}
|
||||
pageSize={PAGE_SIZE}
|
||||
pageCount={pageCount}
|
||||
currentPage={currentPage}
|
||||
onPageChange={this.handlePageChange}
|
||||
/>
|
||||
) : null}
|
||||
</TableCell>
|
||||
<TableCell sx={{ whiteSpace: 'pre-wrap' }}>{entry.text}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{history.map((entry) => (
|
||||
<TableRow key={entry.id}>
|
||||
<TableCell
|
||||
sx={{ verticalAlign: 'top', whiteSpace: 'nowrap', width: '1%' }}
|
||||
>
|
||||
{formatDate(entry.date)}
|
||||
</TableCell>
|
||||
<TableCell sx={{ whiteSpace: 'pre-wrap' }}>
|
||||
{this.renderEntryText(entry)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
{selectedShipment && (
|
||||
<ShipmentDetailDialog
|
||||
open={Boolean(selectedShipment)}
|
||||
shipment={selectedShipment}
|
||||
onClose={this.handleCloseShipment}
|
||||
onNavigate={this.props.navigate}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withNavigate(ArticleHistoryTab);
|
||||
|
||||
Reference in New Issue
Block a user