new features
This commit is contained in:
@@ -21,11 +21,13 @@ import {
|
||||
Select,
|
||||
MenuItem,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
InputLabel,
|
||||
CircularProgress,
|
||||
Alert,
|
||||
Popover,
|
||||
Stack,
|
||||
Switch,
|
||||
Tooltip,
|
||||
} from '@mui/material';
|
||||
import {
|
||||
@@ -83,6 +85,7 @@ const EMPTY_FORM: CreateBuchungInput = {
|
||||
buchungsArt: 'intern',
|
||||
kontaktPerson: '',
|
||||
kontaktTelefon: '',
|
||||
ganztaegig: false,
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -218,6 +221,7 @@ function FahrzeugBuchungen() {
|
||||
const [form, setForm] = useState<CreateBuchungInput>({ ...EMPTY_FORM });
|
||||
const [dialogLoading, setDialogLoading] = useState(false);
|
||||
const [dialogError, setDialogError] = useState<string | null>(null);
|
||||
const [overrideOutOfService, setOverrideOutOfService] = useState(false);
|
||||
const [availability, setAvailability] = useState<{
|
||||
available: boolean;
|
||||
reason?: string;
|
||||
@@ -254,6 +258,7 @@ function FahrzeugBuchungen() {
|
||||
setForm({ ...EMPTY_FORM });
|
||||
setDialogError(null);
|
||||
setAvailability(null);
|
||||
setOverrideOutOfService(false);
|
||||
setDialogOpen(true);
|
||||
};
|
||||
|
||||
@@ -265,6 +270,7 @@ function FahrzeugBuchungen() {
|
||||
setForm({ ...EMPTY_FORM, fahrzeugId: vehicleId, beginn: dateStr, ende: dateEndStr });
|
||||
setDialogError(null);
|
||||
setAvailability(null);
|
||||
setOverrideOutOfService(false);
|
||||
setDialogOpen(true);
|
||||
};
|
||||
|
||||
@@ -276,27 +282,33 @@ function FahrzeugBuchungen() {
|
||||
...form,
|
||||
beginn: new Date(form.beginn).toISOString(),
|
||||
ende: new Date(form.ende).toISOString(),
|
||||
ganztaegig: form.ganztaegig || false,
|
||||
};
|
||||
if (editingBooking) {
|
||||
await bookingApi.update(editingBooking.id, payload);
|
||||
notification.showSuccess('Buchung aktualisiert');
|
||||
} else {
|
||||
await bookingApi.create(payload);
|
||||
await bookingApi.create({ ...payload, ignoreOutOfService: overrideOutOfService } as any);
|
||||
notification.showSuccess('Buchung erstellt');
|
||||
}
|
||||
setDialogOpen(false);
|
||||
loadData();
|
||||
} catch (e: unknown) {
|
||||
const axiosError = e as { response?: { status?: number; data?: { message?: string; reason?: string } }; message?: string };
|
||||
if (axiosError?.response?.status === 409) {
|
||||
const reason = axiosError?.response?.data?.reason;
|
||||
if (reason === 'out_of_service') {
|
||||
setDialogError(axiosError?.response?.data?.message || 'Fahrzeug ist im gewählten Zeitraum außer Dienst');
|
||||
try {
|
||||
const axiosError = e as { response?: { status?: number; data?: { message?: string; reason?: string } }; message?: string };
|
||||
if (axiosError?.response?.status === 409) {
|
||||
const reason = axiosError?.response?.data?.reason;
|
||||
if (reason === 'out_of_service') {
|
||||
setDialogError(axiosError?.response?.data?.message || 'Fahrzeug ist im gewählten Zeitraum außer Dienst');
|
||||
} else {
|
||||
setDialogError(axiosError?.response?.data?.message || 'Fahrzeug ist im gewählten Zeitraum bereits gebucht');
|
||||
}
|
||||
} else {
|
||||
setDialogError('Fahrzeug ist im gewählten Zeitraum bereits gebucht');
|
||||
const msg = axiosError?.response?.data?.message || axiosError?.message || 'Fehler beim Speichern';
|
||||
setDialogError(msg);
|
||||
}
|
||||
} else {
|
||||
setDialogError(axiosError?.message || 'Fehler beim Speichern');
|
||||
} catch {
|
||||
setDialogError(e instanceof Error ? e.message : 'Fehler beim Speichern');
|
||||
}
|
||||
} finally {
|
||||
setDialogLoading(false);
|
||||
@@ -495,11 +507,6 @@ function FahrzeugBuchungen() {
|
||||
<Typography variant="body2" fontWeight={600}>
|
||||
{vehicle.bezeichnung}
|
||||
</Typography>
|
||||
{vehicle.amtliches_kennzeichen && (
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{vehicle.amtliches_kennzeichen}
|
||||
</Typography>
|
||||
)}
|
||||
</TableCell>
|
||||
{weekDays.map((day) => {
|
||||
const cellBookings = getBookingsForCell(vehicle.id, day);
|
||||
@@ -774,16 +781,39 @@ function FahrzeugBuchungen() {
|
||||
}
|
||||
/>
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={form.ganztaegig || false}
|
||||
onChange={(e) => {
|
||||
const checked = e.target.checked;
|
||||
setForm((f) => {
|
||||
if (checked && f.beginn) {
|
||||
const dateStr = f.beginn.split('T')[0];
|
||||
return { ...f, ganztaegig: true, beginn: `${dateStr}T00:00`, ende: f.ende ? `${(f.ende.split('T')[0])}T23:59` : `${dateStr}T23:59` };
|
||||
}
|
||||
return { ...f, ganztaegig: checked };
|
||||
});
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label="Ganztägig"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
size="small"
|
||||
label="Beginn"
|
||||
type="datetime-local"
|
||||
type={form.ganztaegig ? 'date' : 'datetime-local'}
|
||||
required
|
||||
value={form.beginn}
|
||||
onChange={(e) =>
|
||||
setForm((f) => ({ ...f, beginn: e.target.value }))
|
||||
}
|
||||
value={form.ganztaegig ? (form.beginn?.split('T')[0] || '') : form.beginn}
|
||||
onChange={(e) => {
|
||||
if (form.ganztaegig) {
|
||||
setForm((f) => ({ ...f, beginn: `${e.target.value}T00:00` }));
|
||||
} else {
|
||||
setForm((f) => ({ ...f, beginn: e.target.value }));
|
||||
}
|
||||
}}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
/>
|
||||
|
||||
@@ -791,12 +821,16 @@ function FahrzeugBuchungen() {
|
||||
fullWidth
|
||||
size="small"
|
||||
label="Ende"
|
||||
type="datetime-local"
|
||||
type={form.ganztaegig ? 'date' : 'datetime-local'}
|
||||
required
|
||||
value={form.ende}
|
||||
onChange={(e) =>
|
||||
setForm((f) => ({ ...f, ende: e.target.value }))
|
||||
}
|
||||
value={form.ganztaegig ? (form.ende?.split('T')[0] || '') : form.ende}
|
||||
onChange={(e) => {
|
||||
if (form.ganztaegig) {
|
||||
setForm((f) => ({ ...f, ende: `${e.target.value}T23:59` }));
|
||||
} else {
|
||||
setForm((f) => ({ ...f, ende: e.target.value }));
|
||||
}
|
||||
}}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
/>
|
||||
|
||||
@@ -818,16 +852,34 @@ function FahrzeugBuchungen() {
|
||||
size="small"
|
||||
/>
|
||||
) : availability.reason === 'out_of_service' ? (
|
||||
<Chip
|
||||
icon={<Block />}
|
||||
label={
|
||||
availability.ausserDienstBis
|
||||
? `Außer Dienst bis ${new Date(availability.ausserDienstBis).toLocaleDateString('de-DE')} (geschätzt)`
|
||||
: 'Fahrzeug ist außer Dienst'
|
||||
}
|
||||
color="error"
|
||||
size="small"
|
||||
/>
|
||||
<Box>
|
||||
<Chip
|
||||
icon={<Block />}
|
||||
label={
|
||||
availability.ausserDienstBis
|
||||
? `Außer Dienst bis ${new Date(availability.ausserDienstBis).toLocaleDateString('de-DE')} (geschätzt)`
|
||||
: 'Fahrzeug ist außer Dienst'
|
||||
}
|
||||
color="error"
|
||||
size="small"
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={overrideOutOfService}
|
||||
onChange={(e) => setOverrideOutOfService(e.target.checked)}
|
||||
color="warning"
|
||||
size="small"
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Typography variant="body2" color="warning.main">
|
||||
Trotz Außer-Dienst-Status buchen
|
||||
</Typography>
|
||||
}
|
||||
sx={{ mt: 0.5 }}
|
||||
/>
|
||||
</Box>
|
||||
) : (
|
||||
<Chip
|
||||
icon={<Warning />}
|
||||
|
||||
Reference in New Issue
Block a user