diff --git a/frontend/src/pages/AusruestungDetail.tsx b/frontend/src/pages/AusruestungDetail.tsx index a1367f4..e89c6a7 100644 --- a/frontend/src/pages/AusruestungDetail.tsx +++ b/frontend/src/pages/AusruestungDetail.tsx @@ -1,7 +1,6 @@ import React, { useEffect, useState, useCallback } from 'react'; import { Alert, - Autocomplete, Box, Button, Chip, @@ -55,8 +54,6 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import DashboardLayout from '../components/dashboard/DashboardLayout'; import ChatAwareFab from '../components/shared/ChatAwareFab'; import { equipmentApi } from '../services/equipment'; -import { ausruestungTypenApi } from '../services/ausruestungTypen'; -import type { AusruestungTyp } from '../services/ausruestungTypen'; import { fromGermanDate } from '../utils/dateInput'; import { AusruestungDetail, @@ -412,109 +409,6 @@ const UebersichtTab: React.FC = ({ equipment, onStatusUpdate - - - - ); -}; - -// -- Typen Section (equipment type assignment) -------------------------------- - -interface TypenSectionProps { - equipmentId: string; - canWrite: boolean; -} - -const TypenSection: React.FC = ({ equipmentId, canWrite }) => { - const queryClient = useQueryClient(); - const { showSuccess, showError } = useNotification(); - const [editing, setEditing] = useState(false); - const [selectedTypen, setSelectedTypen] = useState([]); - - const { data: assignedTypen = [] } = useQuery({ - queryKey: ['ausruestungTypen', 'equipment', equipmentId], - queryFn: () => ausruestungTypenApi.getTypesForEquipment(equipmentId), - }); - - const { data: allTypen = [] } = useQuery({ - queryKey: ['ausruestungTypen'], - queryFn: ausruestungTypenApi.getAll, - enabled: editing, - }); - - const saveMutation = useMutation({ - mutationFn: (typIds: number[]) => - ausruestungTypenApi.setTypesForEquipment(equipmentId, typIds), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['ausruestungTypen', 'equipment', equipmentId] }); - showSuccess('Typen aktualisiert'); - setEditing(false); - }, - onError: () => showError('Typen konnten nicht gespeichert werden'), - }); - - const startEditing = () => { - setSelectedTypen(assignedTypen); - setEditing(true); - }; - - const handleSave = () => { - saveMutation.mutate(selectedTypen.map((t) => t.id)); - }; - - return ( - - - Typen - {canWrite && !editing && ( - - )} - - {editing ? ( - - o.name} - value={selectedTypen} - onChange={(_, newVal) => setSelectedTypen(newVal)} - isOptionEqualToValue={(o, v) => o.id === v.id} - renderTags={(value, getTagProps) => - value.map((option, index) => ( - - )) - } - renderInput={(params) => } - sx={{ mb: 1 }} - /> - - - - - - ) : ( - - {assignedTypen.length === 0 ? ( - Keine Typen zugeordnet - ) : ( - assignedTypen.map((t) => ( - - )) - )} - - )} ); }; diff --git a/frontend/src/pages/AusruestungEinstellungen.tsx b/frontend/src/pages/AusruestungEinstellungen.tsx index 5b9dbb3..520cf3f 100644 --- a/frontend/src/pages/AusruestungEinstellungen.tsx +++ b/frontend/src/pages/AusruestungEinstellungen.tsx @@ -1,8 +1,10 @@ import { useState } from 'react'; import { Alert, + Autocomplete, Box, Button, + Chip, CircularProgress, Container, Dialog, @@ -10,6 +12,7 @@ import { DialogContent, DialogContentText, DialogTitle, + Divider, IconButton, Paper, Table, @@ -27,6 +30,7 @@ import { useNavigate } from 'react-router-dom'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import DashboardLayout from '../components/dashboard/DashboardLayout'; import { ausruestungTypenApi, AusruestungTyp } from '../services/ausruestungTypen'; +import { equipmentApi } from '../services/equipment'; import { usePermissions } from '../hooks/usePermissions'; import { useNotification } from '../contexts/NotificationContext'; @@ -302,9 +306,129 @@ function AusruestungEinstellungen() { + + + ); } export default AusruestungEinstellungen; + +// ── Per-equipment type assignment ────────────────────────────────────────────── + +function EquipmentTypeAssignment({ allTypes }: { allTypes: AusruestungTyp[] }) { + const { showSuccess, showError } = useNotification(); + const { data: equipment = [], isLoading } = useQuery({ + queryKey: ['equipment'], + queryFn: equipmentApi.getAll, + }); + + const [assignDialog, setAssignDialog] = useState<{ equipmentId: string; equipmentName: string } | null>(null); + const [selected, setSelected] = useState([]); + const [saving, setSaving] = useState(false); + const [equipmentTypesMap, setEquipmentTypesMap] = useState>({}); + + const openAssign = async (equipmentId: string, equipmentName: string) => { + let current = equipmentTypesMap[equipmentId]; + if (!current) { + try { current = await ausruestungTypenApi.getTypesForEquipment(equipmentId); } + catch { current = []; } + setEquipmentTypesMap((m) => ({ ...m, [equipmentId]: current })); + } + setSelected(current); + setAssignDialog({ equipmentId, equipmentName }); + }; + + const handleSave = async () => { + if (!assignDialog) return; + try { + setSaving(true); + await ausruestungTypenApi.setTypesForEquipment(assignDialog.equipmentId, selected.map((t) => t.id)); + setEquipmentTypesMap((m) => ({ ...m, [assignDialog.equipmentId]: selected })); + setAssignDialog(null); + showSuccess('Typen gespeichert'); + } catch { + showError('Fehler beim Speichern'); + } finally { + setSaving(false); + } + }; + + return ( + <> + Typzuweisung je Gerät + {isLoading ? ( + + ) : ( + + + + + + Gerät + Zugewiesene Typen + Aktionen + + + + {equipment.map((e) => { + const types = equipmentTypesMap[e.id]; + return ( + + {e.bezeichnung} + + {types === undefined ? ( + + ) : types.length === 0 ? ( + Keine + ) : ( + + {types.map((t) => )} + + )} + + + + openAssign(e.id, e.bezeichnung)}> + + + + + + ); + })} + +
+
+
+ )} + + setAssignDialog(null)} maxWidth="sm" fullWidth> + + Typen für {assignDialog?.equipmentName} + setAssignDialog(null)}> + + + o.name} + value={selected} + onChange={(_e, val) => setSelected(val)} + isOptionEqualToValue={(a, b) => a.id === b.id} + renderInput={(params) => } + /> + + + + + + + + ); +}