new features

This commit is contained in:
Matthias Hochmeister
2026-03-23 16:09:42 +01:00
parent e9a9478aac
commit 8c66492b27
40 changed files with 2016 additions and 117 deletions

View File

@@ -61,6 +61,7 @@ import {
AusruestungStatusLabel,
UpdateAusruestungStatusPayload,
CreateAusruestungWartungslogPayload,
UpdateAusruestungWartungslogPayload,
} from '../types/equipment.types';
import { usePermissions } from '../hooks/usePermissions';
import { useNotification } from '../contexts/NotificationContext';
@@ -422,6 +423,7 @@ const WartungTab: React.FC<WartungTabProps> = ({ equipmentId, wartungslog, onAdd
const [dialogOpen, setDialogOpen] = useState(false);
const [saving, setSaving] = useState(false);
const [saveError, setSaveError] = useState<string | null>(null);
const [editingEntry, setEditingEntry] = useState<AusruestungWartungslog | null>(null);
const emptyForm: CreateAusruestungWartungslogPayload = {
datum: '',
@@ -430,10 +432,33 @@ const WartungTab: React.FC<WartungTabProps> = ({ equipmentId, wartungslog, onAdd
ergebnis: undefined,
kosten: undefined,
pruefende_stelle: undefined,
naechste_pruefung_am: undefined,
};
const [form, setForm] = useState<CreateAusruestungWartungslogPayload>(emptyForm);
const openAddDialog = () => {
setEditingEntry(null);
setForm(emptyForm);
setSaveError(null);
setDialogOpen(true);
};
const openEditDialog = (entry: AusruestungWartungslog) => {
setEditingEntry(entry);
setForm({
datum: entry.datum ? new Date(entry.datum).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' }) : '',
art: entry.art,
beschreibung: entry.beschreibung,
ergebnis: entry.ergebnis ?? undefined,
kosten: entry.kosten ?? undefined,
pruefende_stelle: entry.pruefende_stelle ?? undefined,
naechste_pruefung_am: undefined,
});
setSaveError(null);
setDialogOpen(true);
};
const handleSubmit = async () => {
if (!form.datum || !form.art || !form.beschreibung.trim()) {
setSaveError('Datum, Art und Beschreibung sind erforderlich.');
@@ -442,14 +467,33 @@ const WartungTab: React.FC<WartungTabProps> = ({ equipmentId, wartungslog, onAdd
try {
setSaving(true);
setSaveError(null);
await equipmentApi.addWartungslog(equipmentId, {
...form,
datum: fromGermanDate(form.datum) || form.datum,
pruefende_stelle: form.pruefende_stelle || undefined,
ergebnis: form.ergebnis || undefined,
});
const datumIso = fromGermanDate(form.datum) || form.datum;
const naechstePruefungIso = form.naechste_pruefung_am
? (fromGermanDate(form.naechste_pruefung_am) || form.naechste_pruefung_am)
: undefined;
if (editingEntry) {
const payload: UpdateAusruestungWartungslogPayload = {
datum: datumIso,
art: form.art,
beschreibung: form.beschreibung,
ergebnis: form.ergebnis || null,
pruefende_stelle: form.pruefende_stelle || null,
naechste_pruefung_am: naechstePruefungIso || null,
};
await equipmentApi.updateWartungslog(equipmentId, editingEntry.id, payload);
} else {
await equipmentApi.addWartungslog(equipmentId, {
...form,
datum: datumIso,
pruefende_stelle: form.pruefende_stelle || undefined,
ergebnis: form.ergebnis || undefined,
naechste_pruefung_am: naechstePruefungIso,
});
}
setDialogOpen(false);
setForm(emptyForm);
setEditingEntry(null);
onAdded();
} catch {
setSaveError('Wartungseintrag konnte nicht gespeichert werden.');
@@ -463,6 +507,8 @@ const WartungTab: React.FC<WartungTabProps> = ({ equipmentId, wartungslog, onAdd
(a, b) => new Date(b.datum).getTime() - new Date(a.datum).getTime()
);
const showNaechstePruefung = form.ergebnis === 'bestanden';
return (
<Box>
{sorted.length === 0 ? (
@@ -496,13 +542,19 @@ const WartungTab: React.FC<WartungTabProps> = ({ equipmentId, wartungslog, onAdd
)}
</Box>
<Typography variant="body2">{entry.beschreibung}</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mt: 0.25 }}>
{[
entry.kosten != null && `${Number(entry.kosten).toFixed(2)} EUR`,
entry.pruefende_stelle && entry.pruefende_stelle,
].filter(Boolean).join(' · ')}
</Typography>
{entry.pruefende_stelle && (
<Typography variant="body2" color="text.secondary" sx={{ mt: 0.25 }}>
{entry.pruefende_stelle}
</Typography>
)}
</Box>
{canWrite && (
<Tooltip title="Bearbeiten">
<IconButton size="small" onClick={() => openEditDialog(entry)}>
<Edit fontSize="small" />
</IconButton>
</Tooltip>
)}
</Box>
);
})}
@@ -513,14 +565,14 @@ const WartungTab: React.FC<WartungTabProps> = ({ equipmentId, wartungslog, onAdd
<ChatAwareFab
size="small"
aria-label="Wartung eintragen"
onClick={() => { setForm(emptyForm); setSaveError(null); setDialogOpen(true); }}
onClick={openAddDialog}
>
<Add />
</ChatAwareFab>
)}
<Dialog open={dialogOpen} onClose={() => setDialogOpen(false)} maxWidth="sm" fullWidth>
<DialogTitle>Wartung / Prüfung eintragen</DialogTitle>
<DialogTitle>{editingEntry ? 'Wartungseintrag bearbeiten' : 'Wartung / Prüfung eintragen'}</DialogTitle>
<DialogContent>
{saveError && <Alert severity="error" sx={{ mb: 2 }}>{saveError}</Alert>}
<Grid container spacing={2} sx={{ mt: 0.5 }}>
@@ -585,21 +637,6 @@ const WartungTab: React.FC<WartungTabProps> = ({ equipmentId, wartungslog, onAdd
</FormControl>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
label="Kosten (EUR)"
type="number"
fullWidth
value={form.kosten ?? ''}
onChange={(e) =>
setForm((f) => ({
...f,
kosten: e.target.value ? Number(e.target.value) : undefined,
}))
}
inputProps={{ min: 0, step: 0.01 }}
/>
</Grid>
<Grid item xs={12}>
<TextField
label="Prüfende Stelle"
fullWidth
@@ -608,6 +645,19 @@ const WartungTab: React.FC<WartungTabProps> = ({ equipmentId, wartungslog, onAdd
placeholder="Name der prüfenden Stelle oder Person"
/>
</Grid>
{showNaechstePruefung && (
<Grid item xs={12} sm={6}>
<TextField
label="Nächste Prüfung fällig am"
fullWidth
placeholder="TT.MM.JJJJ"
value={form.naechste_pruefung_am ?? ''}
onChange={(e) => setForm((f) => ({ ...f, naechste_pruefung_am: e.target.value }))}
InputLabelProps={{ shrink: true }}
helperText="Wird als nächster Prüftermin übernommen"
/>
</Grid>
)}
</Grid>
</DialogContent>
<DialogActions>