212 lines
6.3 KiB
JavaScript
212 lines
6.3 KiB
JavaScript
import { Component } 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 Alert from '@mui/material/Alert';
|
|
import BackendError from '../BackendError';
|
|
import SingleLineTextEdit from 'dashgui/SingleLineTextEdit';
|
|
import { backendErrorFrom, isBackendFailure } from '../../utils/backendError';
|
|
|
|
const BULK_MODE = 'bulk';
|
|
const SINGLE_MODE = 'single';
|
|
|
|
/** Split a bulk textarea into non-empty, trimmed names (one per line). */
|
|
function parseBulkNames(text) {
|
|
return String(text ?? '')
|
|
.split(/\r?\n/)
|
|
.map((line) => line.trim())
|
|
.filter(Boolean);
|
|
}
|
|
|
|
/**
|
|
* New-article dialog.
|
|
* Single mode: one name. Bulk mode ("Sammelanlegen"): one name per line.
|
|
* Props: open, onClose, onSubmit({ names: string[] }).
|
|
*/
|
|
class ArticleNameDialog extends Component {
|
|
constructor(props) {
|
|
super(props);
|
|
this.state = {
|
|
mode: SINGLE_MODE,
|
|
name: '',
|
|
bulkText: '',
|
|
busy: false,
|
|
error: null,
|
|
};
|
|
this.handleClose = this.handleClose.bind(this);
|
|
this.handleSingleSubmit = this.handleSingleSubmit.bind(this);
|
|
this.handleBulkSubmit = this.handleBulkSubmit.bind(this);
|
|
this.openBulk = this.openBulk.bind(this);
|
|
}
|
|
|
|
componentDidUpdate(prevProps) {
|
|
if (this.props.open && !prevProps.open) {
|
|
this.setState({
|
|
mode: SINGLE_MODE,
|
|
name: '',
|
|
bulkText: '',
|
|
busy: false,
|
|
error: null,
|
|
});
|
|
}
|
|
}
|
|
|
|
handleClose() {
|
|
if (this.state.busy) return;
|
|
this.props.onClose();
|
|
}
|
|
|
|
async handleSingleSubmit(event) {
|
|
event.preventDefault();
|
|
const name = this.state.name.trim();
|
|
if (!name) {
|
|
this.setState({ error: 'Bitte Name eingeben.' });
|
|
return;
|
|
}
|
|
|
|
this.setState({ busy: true, error: null });
|
|
try {
|
|
await this.props.onSubmit({ names: [name] });
|
|
this.props.onClose();
|
|
} catch (err) {
|
|
this.setState({ error: backendErrorFrom(err), busy: false });
|
|
}
|
|
}
|
|
|
|
async handleBulkSubmit(event) {
|
|
event.preventDefault();
|
|
const names = parseBulkNames(this.state.bulkText);
|
|
if (names.length === 0) {
|
|
this.setState({ error: 'Bitte mindestens einen Namen eingeben.' });
|
|
return;
|
|
}
|
|
|
|
this.setState({ busy: true, error: null });
|
|
try {
|
|
await this.props.onSubmit({ names });
|
|
this.props.onClose();
|
|
} catch (err) {
|
|
this.setState({ error: backendErrorFrom(err), busy: false });
|
|
}
|
|
}
|
|
|
|
openBulk() {
|
|
if (this.state.busy) return;
|
|
this.setState({ mode: BULK_MODE, error: null });
|
|
}
|
|
|
|
render() {
|
|
const { open } = this.props;
|
|
const { mode, name, bulkText, busy, error } = this.state;
|
|
const isBulk = mode === BULK_MODE;
|
|
const canSubmitSingle = name.trim() !== '';
|
|
const bulkNames = parseBulkNames(bulkText);
|
|
const canSubmitBulk = bulkNames.length > 0;
|
|
|
|
return (
|
|
<AppDialog open={open} onClose={this.handleClose} maxWidth="xs" fullWidth>
|
|
<DialogTitle>Neuer Artikel</DialogTitle>
|
|
|
|
{!isBulk && (
|
|
<Box component="form" onSubmit={this.handleSingleSubmit} noValidate>
|
|
<DialogContent>
|
|
{error ? (
|
|
isBackendFailure(error) ? (
|
|
<BackendError error={error} sx={{ mb: 2 }} />
|
|
) : (
|
|
<Alert severity="error" sx={{ mb: 2 }}>
|
|
{typeof error === 'string' ? error : error.message}
|
|
</Alert>
|
|
)
|
|
) : null}
|
|
|
|
<SingleLineTextEdit
|
|
required
|
|
autoFocus
|
|
label="Name"
|
|
value={name}
|
|
disabled={busy}
|
|
onChange={(nextName) => this.setState({ name: nextName })}
|
|
/>
|
|
</DialogContent>
|
|
<DialogActions sx={{ px: 3, pb: 2 }}>
|
|
<Button type="button" onClick={this.openBulk} disabled={busy}>
|
|
Sammelanlegen
|
|
</Button>
|
|
<Box sx={{ flexGrow: 1 }} />
|
|
<Button type="button" onClick={this.handleClose} disabled={busy}>
|
|
Abbrechen
|
|
</Button>
|
|
<Button
|
|
type="submit"
|
|
variant="contained"
|
|
disabled={busy || !canSubmitSingle}
|
|
>
|
|
Anlegen
|
|
</Button>
|
|
</DialogActions>
|
|
</Box>
|
|
)}
|
|
|
|
{isBulk && (
|
|
<Box component="form" onSubmit={this.handleBulkSubmit} noValidate>
|
|
<DialogContent>
|
|
{error ? (
|
|
isBackendFailure(error) ? (
|
|
<BackendError error={error} sx={{ mb: 2 }} />
|
|
) : (
|
|
<Alert severity="error" sx={{ mb: 2 }}>
|
|
{typeof error === 'string' ? error : error.message}
|
|
</Alert>
|
|
)
|
|
) : null}
|
|
|
|
<SingleLineTextEdit
|
|
autoFocus
|
|
multiline
|
|
minRows={6}
|
|
label="Namen (einer pro Zeile)"
|
|
placeholder={'Artikel A\nArtikel B\nArtikel C'}
|
|
value={bulkText}
|
|
disabled={busy}
|
|
onChange={(nextText) => this.setState({ bulkText: nextText })}
|
|
helperText={
|
|
bulkNames.length > 0
|
|
? `${bulkNames.length} Artikel werden angelegt.`
|
|
: 'Ein Name pro Zeile eingeben.'
|
|
}
|
|
/>
|
|
</DialogContent>
|
|
<DialogActions sx={{ px: 3, pb: 2 }}>
|
|
<Button
|
|
type="button"
|
|
onClick={() => this.setState({ mode: SINGLE_MODE, error: null })}
|
|
disabled={busy}
|
|
>
|
|
Einzel
|
|
</Button>
|
|
<Box sx={{ flexGrow: 1 }} />
|
|
<Button type="button" onClick={this.handleClose} disabled={busy}>
|
|
Abbrechen
|
|
</Button>
|
|
<Button
|
|
type="submit"
|
|
variant="contained"
|
|
disabled={busy || !canSubmitBulk}
|
|
>
|
|
Anlegen ({bulkNames.length})
|
|
</Button>
|
|
</DialogActions>
|
|
</Box>
|
|
)}
|
|
</AppDialog>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default ArticleNameDialog;
|
|
|