u
This commit is contained in:
@@ -29,6 +29,7 @@ import { shipment as shipmentApi } from '../../api';
|
||||
import { backendErrorFrom } from '../../utils/backendError';
|
||||
import { notifyError } from '../../utils/notify';
|
||||
import { getMaxDocumentNumber } from '../../utils/documentNumber';
|
||||
import PartyFilterPanel, { PartyFilterButton, PartyFilterChip } from './PartyFilterPanel';
|
||||
import withNavigate from '../withNavigate';
|
||||
import ShipmentDetailDialog from './ShipmentDetailDialog';
|
||||
import { getNextShipmentNumber } from './OrderShipmentDialog';
|
||||
@@ -661,7 +662,14 @@ class ShipmentSearchField extends PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { inputRef, onCreate } = this.props;
|
||||
const {
|
||||
inputRef,
|
||||
onCreate,
|
||||
customerFilterOpen,
|
||||
onToggleCustomerFilter,
|
||||
selectedCustomer,
|
||||
onClearCustomerFilter,
|
||||
} = this.props;
|
||||
const { input, stateFilter, seekMonths, seekYears } = this.state;
|
||||
const monthActive = seekMonths > 0;
|
||||
const monthLabel = !monthActive ? '-1 Monat' : `-${seekMonths} Monat${seekMonths > 1 ? 'e' : ''}`;
|
||||
@@ -697,6 +705,17 @@ class ShipmentSearchField extends PureComponent {
|
||||
value={input}
|
||||
onChange={(next) => shipmentAutomat.actions.setFilter(next)}
|
||||
/>
|
||||
<PartyFilterButton
|
||||
title="Kunden"
|
||||
open={customerFilterOpen}
|
||||
onClick={onToggleCustomerFilter}
|
||||
/>
|
||||
{selectedCustomer && (
|
||||
<PartyFilterChip
|
||||
label={partyDisplayName('order', selectedCustomer)}
|
||||
onDelete={onClearCustomerFilter}
|
||||
/>
|
||||
)}
|
||||
<Button variant="contained" onClick={onCreate}>
|
||||
Lieferschein erstellen
|
||||
</Button>
|
||||
@@ -854,8 +873,11 @@ export class ShipmentList extends PureComponent {
|
||||
total: shipmentAutomat.state.total ?? 0,
|
||||
unfilteredTotal: shipmentAutomat.state.unfilteredTotal ?? 0,
|
||||
filterKey: shipmentAutomat.getFilterKey?.() ?? '',
|
||||
entityId: shipmentAutomat.state.entityId ?? null,
|
||||
customerFilterOpen: false,
|
||||
orders: orderAutomat.state?.items || [],
|
||||
partiesById: {},
|
||||
partiesList: [],
|
||||
selectedShipment: null,
|
||||
newShipmentModalOpen: false,
|
||||
busyId: null,
|
||||
@@ -867,6 +889,8 @@ export class ShipmentList extends PureComponent {
|
||||
this.handleCloseShipment = this.handleCloseShipment.bind(this);
|
||||
this.handleDeleteShipment = this.handleDeleteShipment.bind(this);
|
||||
this.handlePageChange = this.handlePageChange.bind(this);
|
||||
this.handleToggleCustomerFilter = this.handleToggleCustomerFilter.bind(this);
|
||||
this.handleSelectCustomer = this.handleSelectCustomer.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -876,6 +900,7 @@ export class ShipmentList extends PureComponent {
|
||||
total: state.total ?? 0,
|
||||
unfilteredTotal: state.unfilteredTotal ?? 0,
|
||||
filterKey: shipmentAutomat.getFilterKey(state),
|
||||
entityId: state.entityId ?? null,
|
||||
}));
|
||||
|
||||
this.unsubOrder = orderAutomat.subscribe(this, (state) => ({
|
||||
@@ -919,11 +944,22 @@ export class ShipmentList extends PureComponent {
|
||||
this.unsubNumber?.();
|
||||
}
|
||||
|
||||
handleToggleCustomerFilter() {
|
||||
this.setState((prev) => ({ customerFilterOpen: !prev.customerFilterOpen }));
|
||||
}
|
||||
|
||||
handleSelectCustomer(entityId) {
|
||||
shipmentAutomat.actions.setEntityId(entityId);
|
||||
}
|
||||
|
||||
async loadParties() {
|
||||
try {
|
||||
const parties = await loadParties('order');
|
||||
if (!this._cancelled) {
|
||||
this.setState({ partiesById: cfg.partiesByIdFromList(parties) });
|
||||
this.setState({
|
||||
partiesById: cfg.partiesByIdFromList(parties),
|
||||
partiesList: parties || [],
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
// Non-fatal
|
||||
@@ -975,8 +1011,11 @@ export class ShipmentList extends PureComponent {
|
||||
total,
|
||||
unfilteredTotal,
|
||||
filterKey,
|
||||
entityId,
|
||||
customerFilterOpen,
|
||||
orders,
|
||||
partiesById,
|
||||
partiesList,
|
||||
selectedShipment,
|
||||
newShipmentModalOpen,
|
||||
busyId,
|
||||
@@ -988,10 +1027,31 @@ export class ShipmentList extends PureComponent {
|
||||
rowContext.onDelete = this.handleDeleteShipment;
|
||||
rowContext.headerItem = this.headerItem;
|
||||
|
||||
const customerCounts = {};
|
||||
if (Array.isArray(items)) {
|
||||
for (const s of items) {
|
||||
if (s?.entityId) {
|
||||
customerCounts[s.entityId] = (customerCounts[s.entityId] || 0) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
const selectedCustomer = entityId ? (partiesById[entityId] || { id: entityId, name: `Kunde #${entityId}` }) : null;
|
||||
|
||||
const searchField = (
|
||||
<ShipmentSearchField
|
||||
inputRef={this.searchRef}
|
||||
onCreate={() => this.setState({ newShipmentModalOpen: true })}
|
||||
customerFilterOpen={customerFilterOpen}
|
||||
onToggleCustomerFilter={this.handleToggleCustomerFilter}
|
||||
selectedCustomer={selectedCustomer}
|
||||
onClearCustomerFilter={() => this.handleSelectCustomer(null)}
|
||||
/>
|
||||
);
|
||||
|
||||
if (items === null && shipmentAutomat.state.status === 'failed') {
|
||||
return (
|
||||
<>
|
||||
<ShipmentSearchField inputRef={this.searchRef} onCreate={() => this.setState({ newShipmentModalOpen: true })} />
|
||||
{searchField}
|
||||
<PanelTileGrid>
|
||||
<PanelTile wide={3} minHeight={0} color={GREEN_PANEL} sx={{ p: 2 }}>
|
||||
<BackendError error={backendErrorFrom(shipmentAutomat.state.error)} onRetry={this.handleRetry} />
|
||||
@@ -1003,69 +1063,80 @@ export class ShipmentList extends PureComponent {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ShipmentSearchField
|
||||
inputRef={this.searchRef}
|
||||
onCreate={() => this.setState({ newShipmentModalOpen: true })}
|
||||
/>
|
||||
|
||||
<PanelTileGrid>
|
||||
<PanelTile wide={3} minHeight={0} color={GREEN_PANEL} sx={{ pb: 0, position: 'relative' }}>
|
||||
<FillSpace
|
||||
aboveRef={[this.searchRef]}
|
||||
reserveBottom={32}
|
||||
minPageSize={8}
|
||||
minHeight={0}
|
||||
resetKey={filterKey}
|
||||
items={items || []}
|
||||
totalCount={items ? items.length : 0}
|
||||
unfilteredTotal={unfilteredTotal}
|
||||
headerItem={this.headerItem}
|
||||
renderItem={ShipmentRow}
|
||||
virtualScrollbar
|
||||
header={
|
||||
<Box
|
||||
sx={{
|
||||
...rowGridSx,
|
||||
height: 36,
|
||||
minHeight: 36,
|
||||
px: 2,
|
||||
borderBottom: '1px solid',
|
||||
borderColor: 'divider',
|
||||
}}
|
||||
>
|
||||
{renderInvisibleDummyRow(this.headerItem)}
|
||||
<Box sx={{ gridColumn: 1, gridRow: 2, ...headerCellSx }}>Lieferschein / Ref</Box>
|
||||
<Box sx={{ gridColumn: 2, gridRow: 2, ...headerCellSx }}>Datum</Box>
|
||||
<Box sx={{ gridColumn: 3, gridRow: 2, ...headerCellSx }}>Auftrag</Box>
|
||||
<Box sx={{ gridColumn: 4, gridRow: 2, ...headerCellSx }}>Kunde</Box>
|
||||
<Box sx={{ gridColumn: 5, gridRow: 2, display: 'flex', justifyContent: 'center', textAlign: 'center', ...headerCellSx }}>Pos.</Box>
|
||||
<Box sx={{ gridColumn: 6, gridRow: 2, ...headerCellSx }}>Paket / Tracking</Box>
|
||||
<Box sx={{ gridColumn: 7, gridRow: 2, display: 'flex', justifyContent: 'center', textAlign: 'center', ...headerCellSx }}>Status</Box>
|
||||
<Box sx={{ gridColumn: 8, gridRow: 2, ...headerCellSx }} />
|
||||
</Box>
|
||||
}
|
||||
onPageChange={this.handlePageChange}
|
||||
{searchField}
|
||||
<Box sx={{ display: 'flex', gap: 2.5, alignItems: 'stretch' }}>
|
||||
{customerFilterOpen && (
|
||||
<PartyFilterPanel
|
||||
title="Kunden"
|
||||
parties={partiesList}
|
||||
selectedId={entityId}
|
||||
onSelect={this.handleSelectCustomer}
|
||||
onClose={this.handleToggleCustomerFilter}
|
||||
counts={customerCounts}
|
||||
searchPlaceholder="Kunde suchen…"
|
||||
/>
|
||||
{items === null && (
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 52,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 32,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
pointerEvents: 'none',
|
||||
zIndex: 2,
|
||||
}}
|
||||
>
|
||||
<CircularProgress size={32} />
|
||||
</Box>
|
||||
)}
|
||||
</PanelTile>
|
||||
</PanelTileGrid>
|
||||
)}
|
||||
<Box sx={{ flexGrow: 1, minWidth: 0 }}>
|
||||
<PanelTileGrid>
|
||||
<PanelTile wide={3} minHeight={0} color={GREEN_PANEL} sx={{ pb: 0, position: 'relative' }}>
|
||||
<FillSpace
|
||||
aboveRef={[this.searchRef]}
|
||||
reserveBottom={32}
|
||||
minPageSize={8}
|
||||
minHeight={0}
|
||||
resetKey={filterKey}
|
||||
items={items || []}
|
||||
totalCount={items ? items.length : 0}
|
||||
unfilteredTotal={unfilteredTotal}
|
||||
headerItem={this.headerItem}
|
||||
renderItem={ShipmentRow}
|
||||
virtualScrollbar
|
||||
header={
|
||||
<Box
|
||||
sx={{
|
||||
...rowGridSx,
|
||||
height: 36,
|
||||
minHeight: 36,
|
||||
px: 2,
|
||||
borderBottom: '1px solid',
|
||||
borderColor: 'divider',
|
||||
}}
|
||||
>
|
||||
{renderInvisibleDummyRow(this.headerItem)}
|
||||
<Box sx={{ gridColumn: 1, gridRow: 2, ...headerCellSx }}>Lieferschein / Ref</Box>
|
||||
<Box sx={{ gridColumn: 2, gridRow: 2, ...headerCellSx }}>Datum</Box>
|
||||
<Box sx={{ gridColumn: 3, gridRow: 2, ...headerCellSx }}>Auftrag</Box>
|
||||
<Box sx={{ gridColumn: 4, gridRow: 2, ...headerCellSx }}>Kunde</Box>
|
||||
<Box sx={{ gridColumn: 5, gridRow: 2, display: 'flex', justifyContent: 'center', textAlign: 'center', ...headerCellSx }}>Pos.</Box>
|
||||
<Box sx={{ gridColumn: 6, gridRow: 2, ...headerCellSx }}>Paket / Tracking</Box>
|
||||
<Box sx={{ gridColumn: 7, gridRow: 2, display: 'flex', justifyContent: 'center', textAlign: 'center', ...headerCellSx }}>Status</Box>
|
||||
<Box sx={{ gridColumn: 8, gridRow: 2, ...headerCellSx }} />
|
||||
</Box>
|
||||
}
|
||||
onPageChange={this.handlePageChange}
|
||||
/>
|
||||
{items === null && (
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 52,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 32,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
pointerEvents: 'none',
|
||||
zIndex: 2,
|
||||
}}
|
||||
>
|
||||
<CircularProgress size={32} />
|
||||
</Box>
|
||||
)}
|
||||
</PanelTile>
|
||||
</PanelTileGrid>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Modal: View / Manage Shipment Details */}
|
||||
{selectedShipment && (
|
||||
|
||||
Reference in New Issue
Block a user