featur add fahrmeister

This commit is contained in:
Matthias Hochmeister
2026-02-27 21:46:50 +01:00
parent da4a56ba6b
commit dbe4f52871
17 changed files with 426 additions and 152 deletions

View File

@@ -62,6 +62,7 @@ import {
WartungslogArt,
PruefungErgebnis,
} from '../types/vehicle.types';
import { usePermissions } from '../hooks/usePermissions';
// ── Tab Panel ─────────────────────────────────────────────────────────────────
@@ -114,9 +115,10 @@ function inspectionBadgeColor(tage: number | null): 'success' | 'warning' | 'err
interface UebersichtTabProps {
vehicle: FahrzeugDetail;
onStatusUpdated: () => void;
canChangeStatus: boolean;
}
const UebersichtTab: React.FC<UebersichtTabProps> = ({ vehicle, onStatusUpdated }) => {
const UebersichtTab: React.FC<UebersichtTabProps> = ({ vehicle, onStatusUpdated, canChangeStatus }) => {
const [statusDialogOpen, setStatusDialogOpen] = useState(false);
const [newStatus, setNewStatus] = useState<FahrzeugStatus>(vehicle.status);
const [bemerkung, setBemerkung] = useState(vehicle.status_bemerkung ?? '');
@@ -177,6 +179,7 @@ const UebersichtTab: React.FC<UebersichtTabProps> = ({ vehicle, onStatusUpdated
setBemerkung(vehicle.status_bemerkung ?? '');
setStatusDialogOpen(true);
}}
sx={{ display: canChangeStatus ? undefined : 'none' }}
>
Status ändern
</Button>
@@ -195,6 +198,8 @@ const UebersichtTab: React.FC<UebersichtTabProps> = ({ vehicle, onStatusUpdated
{ label: 'Typ (DIN 14502)', value: vehicle.typ_schluessel },
{ label: 'Besatzung (Soll)', value: vehicle.besatzung_soll },
{ label: 'Standort', value: vehicle.standort },
{ label: '§57a fällig am', value: fmtDate(vehicle.paragraph57a_faellig_am) !== '—' ? fmtDate(vehicle.paragraph57a_faellig_am) : null },
{ label: 'Nächste Wartung', value: fmtDate(vehicle.naechste_wartung_am) !== '—' ? fmtDate(vehicle.naechste_wartung_am) : null },
].map(({ label, value }) => (
<Grid item xs={12} sm={6} md={4} key={label}>
<Typography variant="caption" color="text.secondary" textTransform="uppercase">
@@ -311,6 +316,7 @@ interface PruefungenTabProps {
fahrzeugId: string;
pruefungen: FahrzeugPruefung[];
onAdded: () => void;
canWrite: boolean;
}
const ERGEBNIS_LABELS: Record<PruefungErgebnis, string> = {
@@ -327,7 +333,7 @@ const ERGEBNIS_COLORS: Record<PruefungErgebnis, 'success' | 'warning' | 'error'
ausstehend: 'default',
};
const PruefungenTab: React.FC<PruefungenTabProps> = ({ fahrzeugId, pruefungen, onAdded }) => {
const PruefungenTab: React.FC<PruefungenTabProps> = ({ fahrzeugId, pruefungen, onAdded, canWrite }) => {
const [dialogOpen, setDialogOpen] = useState(false);
const [saving, setSaving] = useState(false);
const [saveError, setSaveError] = useState<string | null>(null);
@@ -431,15 +437,17 @@ const PruefungenTab: React.FC<PruefungenTabProps> = ({ fahrzeugId, pruefungen, o
)}
{/* FAB */}
<Fab
color="primary"
size="small"
aria-label="Prüfung hinzufügen"
sx={{ position: 'fixed', bottom: 32, right: 32 }}
onClick={() => { setForm(emptyForm); setDialogOpen(true); }}
>
<Add />
</Fab>
{canWrite && (
<Fab
color="primary"
size="small"
aria-label="Prüfung hinzufügen"
sx={{ position: 'fixed', bottom: 32, right: 32 }}
onClick={() => { setForm(emptyForm); setDialogOpen(true); }}
>
<Add />
</Fab>
)}
{/* Add inspection dialog */}
<Dialog open={dialogOpen} onClose={() => setDialogOpen(false)} maxWidth="sm" fullWidth>
@@ -549,6 +557,7 @@ interface WartungTabProps {
fahrzeugId: string;
wartungslog: FahrzeugWartungslog[];
onAdded: () => void;
canWrite: boolean;
}
const WARTUNG_ART_ICONS: Record<string, React.ReactElement> = {
@@ -559,7 +568,7 @@ const WARTUNG_ART_ICONS: Record<string, React.ReactElement> = {
default: <Build color="action" />,
};
const WartungTab: React.FC<WartungTabProps> = ({ fahrzeugId, wartungslog, onAdded }) => {
const WartungTab: React.FC<WartungTabProps> = ({ fahrzeugId, wartungslog, onAdded, canWrite }) => {
const [dialogOpen, setDialogOpen] = useState(false);
const [saving, setSaving] = useState(false);
const [saveError, setSaveError] = useState<string | null>(null);
@@ -634,15 +643,17 @@ const WartungTab: React.FC<WartungTabProps> = ({ fahrzeugId, wartungslog, onAdde
</Stack>
)}
<Fab
color="primary"
size="small"
aria-label="Wartung eintragen"
sx={{ position: 'fixed', bottom: 32, right: 32 }}
onClick={() => { setForm(emptyForm); setDialogOpen(true); }}
>
<Add />
</Fab>
{canWrite && (
<Fab
color="primary"
size="small"
aria-label="Wartung eintragen"
sx={{ position: 'fixed', bottom: 32, right: 32 }}
onClick={() => { setForm(emptyForm); setDialogOpen(true); }}
>
<Add />
</Fab>
)}
<Dialog open={dialogOpen} onClose={() => setDialogOpen(false)} maxWidth="sm" fullWidth>
<DialogTitle>Wartung / Service eintragen</DialogTitle>
@@ -746,6 +757,7 @@ const WartungTab: React.FC<WartungTabProps> = ({ fahrzeugId, wartungslog, onAdde
function FahrzeugDetail() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const { isAdmin, canChangeStatus } = usePermissions();
const [vehicle, setVehicle] = useState<FahrzeugDetail | null>(null);
const [loading, setLoading] = useState(true);
@@ -860,7 +872,7 @@ function FahrzeugDetail() {
{/* Tab content */}
<TabPanel value={activeTab} index={0}>
<UebersichtTab vehicle={vehicle} onStatusUpdated={fetchVehicle} />
<UebersichtTab vehicle={vehicle} onStatusUpdated={fetchVehicle} canChangeStatus={canChangeStatus} />
</TabPanel>
<TabPanel value={activeTab} index={1}>
@@ -868,6 +880,7 @@ function FahrzeugDetail() {
fahrzeugId={vehicle.id}
pruefungen={vehicle.pruefungen}
onAdded={fetchVehicle}
canWrite={isAdmin}
/>
</TabPanel>
@@ -876,6 +889,7 @@ function FahrzeugDetail() {
fahrzeugId={vehicle.id}
wartungslog={vehicle.wartungslog}
onAdded={fetchVehicle}
canWrite={isAdmin}
/>
</TabPanel>