import { PureComponent, createRef } from 'react'; import Autocomplete from '@mui/material/Autocomplete'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import CircularProgress from '@mui/material/CircularProgress'; import Stack from '@mui/material/Stack'; import TextField from '@mui/material/TextField'; import Chip from '@mui/material/Chip'; import UploadFileIcon from '@mui/icons-material/UploadFile'; import Inventory2OutlinedIcon from '@mui/icons-material/Inventory2Outlined'; import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined'; import SingleLineTextEdit from 'dashgui/SingleLineTextEdit'; import { PanelTile } from 'dashgui/panels'; import FileDropzone from '../FileDropzone'; import AttachmentList from './AttachmentList'; import { hasArticleLines, manifestConfig, partyDisplayName } from './manifestConfig'; import { notifyErrorMessage } from '../../utils/notify'; class ManifestHeader extends PureComponent { constructor(props) { super(props); this.fileInputRef = createRef(); this.handlePartyChange = this.handlePartyChange.bind(this); this.handleUploadClick = this.handleUploadClick.bind(this); this.handleFileChange = this.handleFileChange.bind(this); this.handleFileDrop = this.handleFileDrop.bind(this); } handlePartyChange(_event, option) { this.props.onPartyChange(option?.id ?? null); } hasArticles() { return Boolean( this.props.hasArticles ?? (Array.isArray(this.props.lines) && hasArticleLines(this.props.lines)), ); } handleUploadClick() { if (this.hasArticles()) { notifyErrorMessage( 'Datei-Upload nicht möglich, solange Artikel vorhanden sind. Bitte entfernen Sie zuerst alle Zeilen.', ); return; } this.fileInputRef.current?.click(); } handleFileDrop(file) { if (this.hasArticles()) { notifyErrorMessage( 'Datei-Upload nicht möglich, solange Artikel vorhanden sind. Bitte entfernen Sie zuerst alle Zeilen.', ); return; } this.props.onPdfUpload?.(file); } handleFileChange(event) { const file = event.target.files?.[0]; event.target.value = ''; if (!file) return; if (this.hasArticles()) { notifyErrorMessage( 'Datei-Upload nicht möglich, solange Artikel vorhanden sind. Bitte entfernen Sie zuerst alle Zeilen.', ); return; } this.props.onPdfUpload?.(file); } render() { const { kind, headerColor, dateLabel, partyLabel, parties, partiesLoading, partyId, date, number, externalNumber, saving, pdfUploading, attachments, onPdfUpload, onPdfRescan, onPdfDelete, onPdfClick, onAttachmentClick, onDateChange, onNumberChange, onExternalNumberChange, onSave, actionsColor, docId, ledgerSummary, onOpenBookDialog, } = this.props; const hasArticles = this.hasArticles(); // Delivery: number is server-allocated/read-only; the caller reference // lives in the editable externalNumber field. const cfg = manifestConfig(kind); const useExternalNumber = Boolean(cfg.externalNumber); const selected = parties.find((row) => row.id === partyId) ?? null; const isDateEmpty = !date || String(date).trim() === ''; const isPartyEmpty = partyId == null || partyId === ''; return ( <> {/* Tile 1: 3-wide Kopfdaten Tile */} onDateChange(e.target.value)} autoComplete="off" slotProps={{ inputLabel: { shrink: true }, htmlInput: { spellCheck: false }, }} sx={{ flex: { xs: '1 1 100%', sm: '1 1 150px' }, minWidth: { sm: 130 }, }} /> partyDisplayName(kind, option)} isOptionEqualToValue={(option, value) => option.id === value.id} onChange={this.handlePartyChange} sx={{ flex: { xs: '1 1 100%', sm: '2 1 200px' }, minWidth: { sm: 160 }, }} renderInput={(params) => ( )} /> {useExternalNumber ? ( ) : null} {docId != null && kind === 'delivery' && ledgerSummary && ( ) : ( ) } label={ ledgerSummary.status === 'booked' ? `Lager: Gebucht (${ledgerSummary.bookedPositions}/${ledgerSummary.totalPositions})` : ledgerSummary.status === 'partial' ? `Lager: Teilweise (${ledgerSummary.bookedPositions}/${ledgerSummary.totalPositions})` : ledgerSummary.status === 'empty' ? 'Lager: Keine Pos.' : `Lager: Offen (${ledgerSummary.totalPositions} Pos.)` } color={ ledgerSummary.status === 'booked' ? 'success' : ledgerSummary.status === 'partial' ? 'warning' : 'default' } variant="outlined" onClick={onOpenBookDialog} sx={{ cursor: onOpenBookDialog ? 'pointer' : 'default', fontWeight: 600, height: 32, px: 0.5, }} /> )} {/* Tile 2: 1-wide Action Tile (4th tile in row) with Speichern & Datei hochladen */} {docId != null && kind === 'delivery' && onOpenBookDialog && ( )} {onPdfUpload ? ( {({ isDragging }) => ( )} ) : null} {onPdfUpload ? ( ) : null} ); } } export default ManifestHeader;