149 lines
4.2 KiB
JavaScript
149 lines
4.2 KiB
JavaScript
import { PureComponent } from 'react';
|
||
import Box from '@mui/material/Box';
|
||
import Button from '@mui/material/Button';
|
||
import AppDialog from '../AppDialog';
|
||
import DialogActions from '@mui/material/DialogActions';
|
||
import DialogContent from '@mui/material/DialogContent';
|
||
import DialogTitle from '@mui/material/DialogTitle';
|
||
import IconButton from '@mui/material/IconButton';
|
||
import Typography from '@mui/material/Typography';
|
||
import Alert from '@mui/material/Alert';
|
||
import CloseIcon from '@mui/icons-material/Close';
|
||
import ArticleSearch from '../article/ArticleSearch';
|
||
|
||
export default class ArticleSearchDialog extends PureComponent {
|
||
constructor(props) {
|
||
super(props);
|
||
this.state = {
|
||
assigningSku: null,
|
||
error: null,
|
||
};
|
||
}
|
||
|
||
componentDidUpdate(prevProps) {
|
||
if (!prevProps.open && this.props.open) {
|
||
this.setState({ assigningSku: null, error: null });
|
||
}
|
||
}
|
||
|
||
handleSelect = async (article) => {
|
||
const { onAssign, line, kind = 'delivery' } = this.props;
|
||
const isDelivery = kind === 'delivery';
|
||
if (!onAssign || !article?.sku) return;
|
||
|
||
if (article.isParent || article.is_parent) {
|
||
this.setState({ error: 'Ein Vaterartikel kann nicht auf Belege gebucht werden.' });
|
||
return;
|
||
}
|
||
|
||
this.setState({ assigningSku: article.sku, error: null });
|
||
try {
|
||
await onAssign(article, line);
|
||
} catch (err) {
|
||
this.setState({
|
||
assigningSku: null,
|
||
error:
|
||
err?.message ||
|
||
(isDelivery
|
||
? 'Fehler beim Verknüpfen des Lieferanten-Artikels.'
|
||
: 'Fehler beim Zuordnen des Artikels.'),
|
||
});
|
||
}
|
||
};
|
||
|
||
render() {
|
||
const { open, onClose, line, kind = 'delivery' } = this.props;
|
||
const { assigningSku, error } = this.state;
|
||
const isDelivery = kind === 'delivery';
|
||
const rawSku = line?.sku != null ? String(line.sku).trim() : '';
|
||
|
||
return (
|
||
<AppDialog
|
||
open={Boolean(open)}
|
||
onClose={assigningSku ? undefined : onClose}
|
||
maxWidth="md"
|
||
fullWidth
|
||
aria-labelledby="article-search-dialog-title"
|
||
slotProps={{
|
||
paper: {
|
||
sx: {
|
||
height: '80vh',
|
||
minHeight: '80vh',
|
||
maxHeight: '80vh',
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
overflow: 'hidden',
|
||
},
|
||
},
|
||
}}
|
||
>
|
||
<DialogTitle
|
||
id="article-search-dialog-title"
|
||
sx={{
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'space-between',
|
||
pb: 1,
|
||
flexShrink: 0,
|
||
}}
|
||
>
|
||
<Box>
|
||
<Typography variant="h6" component="div" fontWeight={600}>
|
||
{line ? 'Existierenden Artikel zuordnen' : 'Artikel auswählen'}
|
||
</Typography>
|
||
<Typography variant="caption" color="text.secondary">
|
||
{isDelivery ? 'Lieferanten-SKU' : 'SKU'}: <strong>{rawSku || '–'}</strong>
|
||
{line?.name ? ` · ${line.name}` : ''}
|
||
</Typography>
|
||
</Box>
|
||
<IconButton
|
||
size="small"
|
||
aria-label="Schließen"
|
||
disabled={Boolean(assigningSku)}
|
||
onClick={onClose}
|
||
>
|
||
<CloseIcon fontSize="small" />
|
||
</IconButton>
|
||
</DialogTitle>
|
||
|
||
<DialogContent
|
||
dividers
|
||
sx={{
|
||
p: 2,
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
flex: 1,
|
||
minHeight: 0,
|
||
overflow: 'hidden',
|
||
}}
|
||
>
|
||
{error && (
|
||
<Alert severity="error" sx={{ mb: 2, flexShrink: 0 }}>
|
||
{error}
|
||
</Alert>
|
||
)}
|
||
|
||
<ArticleSearch
|
||
mode="list"
|
||
autoFocus
|
||
allowParent={false}
|
||
busySku={assigningSku}
|
||
actionLabel={assigningSku ? 'Zuordnen…' : 'Zuordnen'}
|
||
onSelect={this.handleSelect}
|
||
/>
|
||
</DialogContent>
|
||
|
||
<DialogActions sx={{ px: 2, py: 1.5 }}>
|
||
<Button
|
||
size="small"
|
||
disabled={Boolean(assigningSku)}
|
||
onClick={onClose}
|
||
>
|
||
Abbrechen
|
||
</Button>
|
||
</DialogActions>
|
||
</AppDialog>
|
||
);
|
||
}
|
||
}
|