feat(persoenliche-ausruestung): show catalog category, remove size/date columns, make zustand admin-configurable
This commit is contained in:
@@ -28,6 +28,7 @@ import {
|
||||
ExpandMore,
|
||||
PictureAsPdf as PdfIcon,
|
||||
Settings as SettingsIcon,
|
||||
Checkroom as CheckroomIcon,
|
||||
} from '@mui/icons-material';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { Navigate } from 'react-router-dom';
|
||||
@@ -35,6 +36,8 @@ import DashboardLayout from '../components/dashboard/DashboardLayout';
|
||||
import { usePermissionContext } from '../contexts/PermissionContext';
|
||||
import { useNotification } from '../contexts/NotificationContext';
|
||||
import { settingsApi } from '../services/settings';
|
||||
import { personalEquipmentApi } from '../services/personalEquipment';
|
||||
import type { ZustandOption } from '../types/personalEquipment.types';
|
||||
|
||||
interface LinkCollection {
|
||||
id: string;
|
||||
@@ -219,6 +222,27 @@ function AdminSettings() {
|
||||
}
|
||||
};
|
||||
|
||||
// Zustand options state + query + mutation
|
||||
const [zustandOptions, setZustandOptions] = useState<ZustandOption[]>([]);
|
||||
const { data: zustandOptionsData } = useQuery<ZustandOption[]>({
|
||||
queryKey: ['persoenliche-ausruestung', 'zustand-options'],
|
||||
queryFn: () => personalEquipmentApi.getZustandOptions(),
|
||||
enabled: canAccess,
|
||||
});
|
||||
useEffect(() => {
|
||||
if (zustandOptionsData) setZustandOptions(zustandOptionsData);
|
||||
}, [zustandOptionsData]);
|
||||
const zustandMutation = useMutation({
|
||||
mutationFn: (options: ZustandOption[]) => personalEquipmentApi.updateZustandOptions(options),
|
||||
onSuccess: () => {
|
||||
showSuccess('Zustandsoptionen gespeichert');
|
||||
queryClient.invalidateQueries({ queryKey: ['persoenliche-ausruestung', 'zustand-options'] });
|
||||
},
|
||||
onError: () => {
|
||||
showError('Fehler beim Speichern der Zustandsoptionen');
|
||||
},
|
||||
});
|
||||
|
||||
if (!canAccess) {
|
||||
return <Navigate to="/dashboard" replace />;
|
||||
}
|
||||
@@ -572,7 +596,98 @@ function AdminSettings() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Section 5: Info */}
|
||||
{/* Section 5: Zustandsoptionen (Persönliche Ausrüstung) */}
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
||||
<CheckroomIcon color="primary" sx={{ mr: 2 }} />
|
||||
<Typography variant="h6">Zustandsoptionen — Persönliche Ausrüstung</Typography>
|
||||
</Box>
|
||||
<Divider sx={{ mb: 2 }} />
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
|
||||
Konfigurierbare Zustandswerte für die persönliche Ausrüstung. Schlüssel wird intern gespeichert, Label wird angezeigt.
|
||||
</Typography>
|
||||
<Stack spacing={2}>
|
||||
{zustandOptions.map((opt, idx) => (
|
||||
<Box key={idx} sx={{ display: 'flex', gap: 2, alignItems: 'center' }}>
|
||||
<TextField
|
||||
label="Schlüssel"
|
||||
value={opt.key}
|
||||
onChange={(e) =>
|
||||
setZustandOptions((prev) =>
|
||||
prev.map((o, i) => (i === idx ? { ...o, key: e.target.value } : o))
|
||||
)
|
||||
}
|
||||
size="small"
|
||||
sx={{ flex: 1 }}
|
||||
/>
|
||||
<TextField
|
||||
label="Label"
|
||||
value={opt.label}
|
||||
onChange={(e) =>
|
||||
setZustandOptions((prev) =>
|
||||
prev.map((o, i) => (i === idx ? { ...o, label: e.target.value } : o))
|
||||
)
|
||||
}
|
||||
size="small"
|
||||
sx={{ flex: 1 }}
|
||||
/>
|
||||
<FormControl size="small" sx={{ minWidth: 130 }}>
|
||||
<InputLabel>Farbe</InputLabel>
|
||||
<Select
|
||||
value={opt.color}
|
||||
label="Farbe"
|
||||
onChange={(e) =>
|
||||
setZustandOptions((prev) =>
|
||||
prev.map((o, i) => (i === idx ? { ...o, color: e.target.value } : o))
|
||||
)
|
||||
}
|
||||
>
|
||||
<MenuItem value="success">Grün</MenuItem>
|
||||
<MenuItem value="warning">Gelb</MenuItem>
|
||||
<MenuItem value="error">Rot</MenuItem>
|
||||
<MenuItem value="default">Grau</MenuItem>
|
||||
<MenuItem value="info">Blau</MenuItem>
|
||||
<MenuItem value="primary">Primär</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<IconButton
|
||||
color="error"
|
||||
onClick={() =>
|
||||
setZustandOptions((prev) => prev.filter((_, i) => i !== idx))
|
||||
}
|
||||
aria-label="Option entfernen"
|
||||
size="small"
|
||||
>
|
||||
<Delete />
|
||||
</IconButton>
|
||||
</Box>
|
||||
))}
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
<Button
|
||||
startIcon={<Add />}
|
||||
onClick={() =>
|
||||
setZustandOptions((prev) => [...prev, { key: '', label: '', color: 'default' }])
|
||||
}
|
||||
variant="outlined"
|
||||
size="small"
|
||||
>
|
||||
Option hinzufügen
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => zustandMutation.mutate(zustandOptions)}
|
||||
variant="contained"
|
||||
size="small"
|
||||
disabled={zustandMutation.isPending}
|
||||
>
|
||||
Speichern
|
||||
</Button>
|
||||
</Box>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Section 6: Info */}
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
||||
|
||||
@@ -11,8 +11,7 @@ import { useNotification } from '../contexts/NotificationContext';
|
||||
import { usePermissionContext } from '../contexts/PermissionContext';
|
||||
import { ausruestungsanfrageApi } from '../services/ausruestungsanfrage';
|
||||
import { personalEquipmentApi } from '../services/personalEquipment';
|
||||
import { ZUSTAND_LABELS, ZUSTAND_COLORS } from '../types/personalEquipment.types';
|
||||
import type { PersoenlicheAusruestungZustand } from '../types/personalEquipment.types';
|
||||
import type { ZustandOption } from '../types/personalEquipment.types';
|
||||
import type {
|
||||
AusruestungAnfrageFormItem,
|
||||
AusruestungEigenschaft,
|
||||
@@ -97,6 +96,15 @@ export default function AusruestungsanfrageNeu() {
|
||||
queryFn: () => ausruestungsanfrageApi.getItems({ aktiv: true }),
|
||||
});
|
||||
|
||||
const { data: zustandOptions = [] } = useQuery<ZustandOption[]>({
|
||||
queryKey: ['persoenliche-ausruestung', 'zustand-options'],
|
||||
queryFn: () => personalEquipmentApi.getZustandOptions(),
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
|
||||
const getZustandLabel = (key: string) => zustandOptions.find(o => o.key === key)?.label ?? key;
|
||||
const getZustandColor = (key: string) => zustandOptions.find(o => o.key === key)?.color ?? 'default';
|
||||
|
||||
const { data: orderUsers = [] } = useQuery({
|
||||
queryKey: ['ausruestungsanfrage', 'orderUsers'],
|
||||
queryFn: () => ausruestungsanfrageApi.getOrderUsers(),
|
||||
@@ -367,8 +375,8 @@ export default function AusruestungsanfrageNeu() {
|
||||
</Box>
|
||||
)}
|
||||
<Chip
|
||||
label={ZUSTAND_LABELS[item.zustand as PersoenlicheAusruestungZustand]}
|
||||
color={ZUSTAND_COLORS[item.zustand as PersoenlicheAusruestungZustand]}
|
||||
label={getZustandLabel(item.zustand)}
|
||||
color={getZustandColor(item.zustand) as any}
|
||||
size="small"
|
||||
/>
|
||||
{!!assignedSelections[item.id] && (
|
||||
@@ -380,8 +388,8 @@ export default function AusruestungsanfrageNeu() {
|
||||
value={assignedSelections[item.id]}
|
||||
onChange={(e) => setAssignedSelections(prev => ({ ...prev, [item.id]: e.target.value }))}
|
||||
>
|
||||
{Object.entries(ZUSTAND_LABELS).map(([key, label]) => (
|
||||
<MenuItem key={key} value={key}>{label}</MenuItem>
|
||||
{zustandOptions.map((opt) => (
|
||||
<MenuItem key={opt.key} value={opt.key}>{opt.label}</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
)}
|
||||
|
||||
@@ -44,8 +44,7 @@ import { usePermissionContext } from '../contexts/PermissionContext';
|
||||
import { membersService } from '../services/members';
|
||||
import { atemschutzApi } from '../services/atemschutz';
|
||||
import { personalEquipmentApi } from '../services/personalEquipment';
|
||||
import { ZUSTAND_LABELS, ZUSTAND_COLORS } from '../types/personalEquipment.types';
|
||||
import type { PersoenlicheAusruestung } from '../types/personalEquipment.types';
|
||||
import type { PersoenlicheAusruestung, ZustandOption } from '../types/personalEquipment.types';
|
||||
import { toGermanDate, fromGermanDate } from '../utils/dateInput';
|
||||
import {
|
||||
MemberWithProfile,
|
||||
@@ -233,6 +232,7 @@ function MitgliedDetail() {
|
||||
// Personal equipment data
|
||||
const [personalEquipment, setPersonalEquipment] = useState<PersoenlicheAusruestung[]>([]);
|
||||
const [personalEquipmentLoading, setPersonalEquipmentLoading] = useState(false);
|
||||
const [zustandOptions, setZustandOptions] = useState<ZustandOption[]>([]);
|
||||
|
||||
// FDISK-synced sub-section data
|
||||
const [befoerderungen, setBefoerderungen] = useState<Befoerderung[]>([]);
|
||||
@@ -291,6 +291,9 @@ function MitgliedDetail() {
|
||||
.then(setPersonalEquipment)
|
||||
.catch(() => setPersonalEquipment([]))
|
||||
.finally(() => setPersonalEquipmentLoading(false));
|
||||
personalEquipmentApi.getZustandOptions()
|
||||
.then(setZustandOptions)
|
||||
.catch(() => {});
|
||||
}, [userId]);
|
||||
|
||||
// Load FDISK-synced sub-section data
|
||||
@@ -976,8 +979,8 @@ function MitgliedDetail() {
|
||||
)}
|
||||
</Box>
|
||||
<Chip
|
||||
label={ZUSTAND_LABELS[item.zustand]}
|
||||
color={ZUSTAND_COLORS[item.zustand]}
|
||||
label={zustandOptions.find(o => o.key === item.zustand)?.label ?? item.zustand}
|
||||
color={(zustandOptions.find(o => o.key === item.zustand)?.color ?? 'default') as any}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
/>
|
||||
|
||||
@@ -23,13 +23,7 @@ import { usePermissionContext } from '../contexts/PermissionContext';
|
||||
import ChatAwareFab from '../components/shared/ChatAwareFab';
|
||||
import { PageHeader } from '../components/templates';
|
||||
import { KatalogTab } from '../components/shared/KatalogTab';
|
||||
import {
|
||||
ZUSTAND_LABELS,
|
||||
ZUSTAND_COLORS,
|
||||
} from '../types/personalEquipment.types';
|
||||
import type { PersoenlicheAusruestungZustand } from '../types/personalEquipment.types';
|
||||
|
||||
const ZUSTAND_OPTIONS = Object.entries(ZUSTAND_LABELS) as [PersoenlicheAusruestungZustand, string][];
|
||||
import type { ZustandOption } from '../types/personalEquipment.types';
|
||||
|
||||
function PersoenlicheAusruestungPage() {
|
||||
const navigate = useNavigate();
|
||||
@@ -52,6 +46,15 @@ function PersoenlicheAusruestungPage() {
|
||||
staleTime: 2 * 60 * 1000,
|
||||
});
|
||||
|
||||
const { data: zustandOptions = [] } = useQuery<ZustandOption[]>({
|
||||
queryKey: ['persoenliche-ausruestung', 'zustand-options'],
|
||||
queryFn: () => personalEquipmentApi.getZustandOptions(),
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
|
||||
const getZustandLabel = (key: string) => zustandOptions.find(o => o.key === key)?.label ?? key;
|
||||
const getZustandColor = (key: string) => zustandOptions.find(o => o.key === key)?.color ?? 'default';
|
||||
|
||||
const { data: membersList } = useQuery({
|
||||
queryKey: ['members-list-compact'],
|
||||
queryFn: () => membersService.getMembers({ pageSize: 500 }),
|
||||
@@ -126,8 +129,8 @@ function PersoenlicheAusruestungPage() {
|
||||
sx={{ minWidth: 140 }}
|
||||
>
|
||||
<MenuItem value="">Alle</MenuItem>
|
||||
{ZUSTAND_OPTIONS.map(([key, label]) => (
|
||||
<MenuItem key={key} value={key}>{label}</MenuItem>
|
||||
{zustandOptions.map((opt) => (
|
||||
<MenuItem key={opt.key} value={opt.key}>{opt.label}</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
{canSeeAll && (
|
||||
@@ -178,15 +181,13 @@ function PersoenlicheAusruestungPage() {
|
||||
<th>Bezeichnung</th>
|
||||
<th>Kategorie</th>
|
||||
{canSeeAll && <th>Benutzer</th>}
|
||||
<th>Größe</th>
|
||||
<th>Zustand</th>
|
||||
<th>Anschaffung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{isLoading ? (
|
||||
<tr>
|
||||
<td colSpan={canSeeAll ? 6 : 5}>
|
||||
<td colSpan={canSeeAll ? 4 : 3}>
|
||||
<Typography color="text.secondary" sx={{ py: 4, textAlign: 'center' }}>
|
||||
Lade Daten…
|
||||
</Typography>
|
||||
@@ -194,7 +195,7 @@ function PersoenlicheAusruestungPage() {
|
||||
</tr>
|
||||
) : filtered.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={canSeeAll ? 6 : 5}>
|
||||
<td colSpan={canSeeAll ? 4 : 3}>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', py: 6 }}>
|
||||
<CheckroomIcon sx={{ fontSize: 48, color: 'text.disabled', mb: 1 }} />
|
||||
<Typography color="text.secondary">
|
||||
@@ -230,7 +231,7 @@ function PersoenlicheAusruestungPage() {
|
||||
)}
|
||||
</td>
|
||||
<td>
|
||||
<Typography variant="body2">{item.kategorie ?? '—'}</Typography>
|
||||
<Typography variant="body2">{item.artikel_kategorie_name ?? item.kategorie ?? '—'}</Typography>
|
||||
</td>
|
||||
{canSeeAll && (
|
||||
<td>
|
||||
@@ -239,24 +240,14 @@ function PersoenlicheAusruestungPage() {
|
||||
</Typography>
|
||||
</td>
|
||||
)}
|
||||
<td>
|
||||
<Typography variant="body2">{item.groesse ?? '—'}</Typography>
|
||||
</td>
|
||||
<td>
|
||||
<Chip
|
||||
label={ZUSTAND_LABELS[item.zustand]}
|
||||
color={ZUSTAND_COLORS[item.zustand]}
|
||||
label={getZustandLabel(item.zustand)}
|
||||
color={getZustandColor(item.zustand) as any}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<Typography variant="body2">
|
||||
{item.anschaffung_datum
|
||||
? new Date(item.anschaffung_datum).toLocaleDateString('de-AT')
|
||||
: '—'}
|
||||
</Typography>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
|
||||
@@ -12,8 +12,7 @@ import { PageHeader } from '../components/templates';
|
||||
import { usePermissionContext } from '../contexts/PermissionContext';
|
||||
import { useNotification } from '../contexts/NotificationContext';
|
||||
import { personalEquipmentApi } from '../services/personalEquipment';
|
||||
import { ZUSTAND_LABELS, ZUSTAND_COLORS } from '../types/personalEquipment.types';
|
||||
import type { PersoenlicheAusruestungZustand } from '../types/personalEquipment.types';
|
||||
import type { ZustandOption } from '../types/personalEquipment.types';
|
||||
|
||||
export default function PersoenlicheAusruestungDetail() {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
@@ -30,6 +29,15 @@ export default function PersoenlicheAusruestungDetail() {
|
||||
enabled: !!id,
|
||||
});
|
||||
|
||||
const { data: zustandOptions = [] } = useQuery<ZustandOption[]>({
|
||||
queryKey: ['persoenliche-ausruestung', 'zustand-options'],
|
||||
queryFn: () => personalEquipmentApi.getZustandOptions(),
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
|
||||
const getZustandLabel = (key: string) => zustandOptions.find(o => o.key === key)?.label ?? key;
|
||||
const getZustandColor = (key: string) => zustandOptions.find(o => o.key === key)?.color ?? 'default';
|
||||
|
||||
const canEdit = hasPermission('persoenliche_ausruestung:edit');
|
||||
const canDelete = hasPermission('persoenliche_ausruestung:delete');
|
||||
|
||||
@@ -61,14 +69,14 @@ export default function PersoenlicheAusruestungDetail() {
|
||||
<PageHeader
|
||||
title={item.bezeichnung}
|
||||
backTo="/persoenliche-ausruestung"
|
||||
subtitle={item.kategorie || undefined}
|
||||
subtitle={item.artikel_kategorie_name || item.kategorie || undefined}
|
||||
/>
|
||||
|
||||
{/* Status + actions row */}
|
||||
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center', mb: 3 }}>
|
||||
<Chip
|
||||
label={ZUSTAND_LABELS[item.zustand as PersoenlicheAusruestungZustand]}
|
||||
color={ZUSTAND_COLORS[item.zustand as PersoenlicheAusruestungZustand]}
|
||||
label={getZustandLabel(item.zustand)}
|
||||
color={getZustandColor(item.zustand) as any}
|
||||
variant="outlined"
|
||||
/>
|
||||
<Box sx={{ flex: 1 }} />
|
||||
@@ -92,10 +100,8 @@ export default function PersoenlicheAusruestungDetail() {
|
||||
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 1.5 }}>
|
||||
{([
|
||||
['Benutzer', item.user_display_name || item.benutzer_name],
|
||||
['Größe', item.groesse],
|
||||
['Seriennummer', item.seriennummer],
|
||||
['Inventarnummer', item.inventarnummer],
|
||||
['Anschaffungsdatum', item.anschaffung_datum ? new Date(item.anschaffung_datum).toLocaleDateString('de-AT') : null],
|
||||
['Erstellt am', new Date(item.erstellt_am).toLocaleDateString('de-AT')],
|
||||
] as [string, string | null | undefined][]).map(([label, value]) => value ? (
|
||||
<Box key={label}>
|
||||
|
||||
@@ -21,14 +21,11 @@ import { membersService } from '../services/members';
|
||||
import { usePermissionContext } from '../contexts/PermissionContext';
|
||||
import { useNotification } from '../contexts/NotificationContext';
|
||||
import { PageHeader } from '../components/templates';
|
||||
import { ZUSTAND_LABELS } from '../types/personalEquipment.types';
|
||||
import type {
|
||||
PersoenlicheAusruestungZustand,
|
||||
ZustandOption,
|
||||
UpdatePersoenlicheAusruestungPayload,
|
||||
} from '../types/personalEquipment.types';
|
||||
|
||||
const ZUSTAND_OPTIONS = Object.entries(ZUSTAND_LABELS) as [PersoenlicheAusruestungZustand, string][];
|
||||
|
||||
interface EigenschaftRow {
|
||||
id?: number;
|
||||
eigenschaft_id?: number | null;
|
||||
@@ -72,14 +69,19 @@ export default function PersoenlicheAusruestungEdit() {
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
|
||||
const { data: zustandOptions = [] } = useQuery<ZustandOption[]>({
|
||||
queryKey: ['persoenliche-ausruestung', 'zustand-options'],
|
||||
queryFn: () => personalEquipmentApi.getZustandOptions(),
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
|
||||
const [catalogEigenschaftValues, setCatalogEigenschaftValues] = useState<Record<number, string>>({});
|
||||
|
||||
// Form state
|
||||
const [bezeichnung, setBezeichnung] = useState('');
|
||||
const [seriennummer, setSeriennummer] = useState('');
|
||||
const [inventarnummer, setInventarnummer] = useState('');
|
||||
const [anschaffungDatum, setAnschaffungDatum] = useState('');
|
||||
const [zustand, setZustand] = useState<PersoenlicheAusruestungZustand>('gut');
|
||||
const [zustand, setZustand] = useState('gut');
|
||||
const [notizen, setNotizen] = useState('');
|
||||
const [userId, setUserId] = useState<{ id: string; name: string } | null>(null);
|
||||
const [eigenschaften, setEigenschaften] = useState<EigenschaftRow[]>([]);
|
||||
@@ -90,7 +92,6 @@ export default function PersoenlicheAusruestungEdit() {
|
||||
setBezeichnung(item.bezeichnung);
|
||||
setSeriennummer(item.seriennummer ?? '');
|
||||
setInventarnummer(item.inventarnummer ?? '');
|
||||
setAnschaffungDatum(item.anschaffung_datum ? item.anschaffung_datum.split('T')[0] : '');
|
||||
setZustand(item.zustand);
|
||||
setNotizen(item.notizen ?? '');
|
||||
if (item.eigenschaften) {
|
||||
@@ -139,7 +140,6 @@ export default function PersoenlicheAusruestungEdit() {
|
||||
groesse: null,
|
||||
seriennummer: seriennummer || null,
|
||||
inventarnummer: inventarnummer || null,
|
||||
anschaffung_datum: anschaffungDatum || null,
|
||||
zustand,
|
||||
notizen: notizen || null,
|
||||
eigenschaften: item.artikel_id
|
||||
@@ -231,24 +231,15 @@ export default function PersoenlicheAusruestungEdit() {
|
||||
onChange={(e) => setInventarnummer(e.target.value)}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="Anschaffungsdatum"
|
||||
type="date"
|
||||
size="small"
|
||||
value={anschaffungDatum}
|
||||
onChange={(e) => setAnschaffungDatum(e.target.value)}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="Zustand"
|
||||
select
|
||||
size="small"
|
||||
value={zustand}
|
||||
onChange={(e) => setZustand(e.target.value as PersoenlicheAusruestungZustand)}
|
||||
onChange={(e) => setZustand(e.target.value)}
|
||||
>
|
||||
{ZUSTAND_OPTIONS.map(([key, label]) => (
|
||||
<MenuItem key={key} value={key}>{label}</MenuItem>
|
||||
{zustandOptions.map((opt) => (
|
||||
<MenuItem key={opt.key} value={opt.key}>{opt.label}</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
|
||||
|
||||
@@ -17,15 +17,12 @@ import { membersService } from '../services/members';
|
||||
import { usePermissionContext } from '../contexts/PermissionContext';
|
||||
import { useNotification } from '../contexts/NotificationContext';
|
||||
import { PageHeader } from '../components/templates';
|
||||
import { ZUSTAND_LABELS } from '../types/personalEquipment.types';
|
||||
import type {
|
||||
PersoenlicheAusruestungZustand,
|
||||
ZustandOption,
|
||||
CreatePersoenlicheAusruestungPayload,
|
||||
} from '../types/personalEquipment.types';
|
||||
import type { AusruestungArtikel } from '../types/ausruestungsanfrage.types';
|
||||
|
||||
const ZUSTAND_OPTIONS = Object.entries(ZUSTAND_LABELS) as [PersoenlicheAusruestungZustand, string][];
|
||||
|
||||
export default function PersoenlicheAusruestungNeu() {
|
||||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
@@ -37,7 +34,7 @@ export default function PersoenlicheAusruestungNeu() {
|
||||
const [formArtikel, setFormArtikel] = useState<AusruestungArtikel | null>(null);
|
||||
const [formUserId, setFormUserId] = useState<{ id: string; name: string } | null>(null);
|
||||
const [formBenutzerName, setFormBenutzerName] = useState('');
|
||||
const [formZustand, setFormZustand] = useState<PersoenlicheAusruestungZustand>('gut');
|
||||
const [formZustand, setFormZustand] = useState('gut');
|
||||
const [formNotizen, setFormNotizen] = useState('');
|
||||
const [eigenschaftValues, setEigenschaftValues] = useState<Record<number, string>>({});
|
||||
|
||||
@@ -47,6 +44,12 @@ export default function PersoenlicheAusruestungNeu() {
|
||||
staleTime: 10 * 60 * 1000,
|
||||
});
|
||||
|
||||
const { data: zustandOptions = [] } = useQuery<ZustandOption[]>({
|
||||
queryKey: ['persoenliche-ausruestung', 'zustand-options'],
|
||||
queryFn: () => personalEquipmentApi.getZustandOptions(),
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
|
||||
const { data: artikelEigenschaften = [] } = useQuery({
|
||||
queryKey: ['ausruestungsanfrage', 'eigenschaften', formArtikel?.id],
|
||||
queryFn: () => ausruestungsanfrageApi.getArtikelEigenschaften(formArtikel!.id),
|
||||
@@ -169,10 +172,10 @@ export default function PersoenlicheAusruestungNeu() {
|
||||
select
|
||||
size="small"
|
||||
value={formZustand}
|
||||
onChange={(e) => setFormZustand(e.target.value as PersoenlicheAusruestungZustand)}
|
||||
onChange={(e) => setFormZustand(e.target.value)}
|
||||
>
|
||||
{ZUSTAND_OPTIONS.map(([key, label]) => (
|
||||
<MenuItem key={key} value={key}>{label}</MenuItem>
|
||||
{zustandOptions.map((opt) => (
|
||||
<MenuItem key={opt.key} value={opt.key}>{opt.label}</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user