add features
This commit is contained in:
@@ -563,7 +563,7 @@ const WartungTab: React.FC<WartungTabProps> = ({ equipmentId, wartungslog, onAdd
|
||||
function AusruestungDetailPage() {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const navigate = useNavigate();
|
||||
const { isAdmin, canChangeStatus } = usePermissions();
|
||||
const { isAdmin, canManageCategory } = usePermissions();
|
||||
const notification = useNotification();
|
||||
|
||||
const [equipment, setEquipment] = useState<AusruestungDetail | null>(null);
|
||||
@@ -630,6 +630,16 @@ function AusruestungDetailPage() {
|
||||
equipment.pruefung_tage_bis_faelligkeit !== null &&
|
||||
equipment.pruefung_tage_bis_faelligkeit < 0;
|
||||
|
||||
// Derive an inline category object so canManageCategory can do the motorisiert check
|
||||
const equipmentKategorie = {
|
||||
id: equipment.kategorie_id,
|
||||
name: equipment.kategorie_name,
|
||||
kurzname: equipment.kategorie_kurzname,
|
||||
sortierung: 0,
|
||||
motorisiert: equipment.kategorie_motorisiert,
|
||||
};
|
||||
const canWrite = canManageCategory(equipmentKategorie);
|
||||
|
||||
const subtitle = [
|
||||
equipment.kategorie_name,
|
||||
equipment.seriennummer ? `SN: ${equipment.seriennummer}` : null,
|
||||
@@ -665,7 +675,7 @@ function AusruestungDetailPage() {
|
||||
label={AusruestungStatusLabel[equipment.status]}
|
||||
color={STATUS_CHIP_COLOR[equipment.status]}
|
||||
/>
|
||||
{canChangeStatus && (
|
||||
{canWrite && (
|
||||
<Tooltip title="Gerät bearbeiten">
|
||||
<IconButton
|
||||
size="small"
|
||||
@@ -714,7 +724,7 @@ function AusruestungDetailPage() {
|
||||
<UebersichtTab
|
||||
equipment={equipment}
|
||||
onStatusUpdated={fetchEquipment}
|
||||
canChangeStatus={canChangeStatus}
|
||||
canChangeStatus={canWrite}
|
||||
/>
|
||||
</TabPanel>
|
||||
|
||||
@@ -723,7 +733,7 @@ function AusruestungDetailPage() {
|
||||
equipmentId={equipment.id}
|
||||
wartungslog={equipment.wartungslog ?? []}
|
||||
onAdded={fetchEquipment}
|
||||
canWrite={canChangeStatus}
|
||||
canWrite={canWrite}
|
||||
/>
|
||||
</TabPanel>
|
||||
|
||||
|
||||
@@ -82,11 +82,11 @@ function toDateInput(iso: string | null | undefined): string {
|
||||
function AusruestungForm() {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const navigate = useNavigate();
|
||||
const { canChangeStatus } = usePermissions();
|
||||
const { canManageEquipment } = usePermissions();
|
||||
const isEditMode = Boolean(id);
|
||||
|
||||
// -- Permission guard: only authorized users may create or edit equipment ----
|
||||
if (!canChangeStatus) {
|
||||
if (!canManageEquipment) {
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<Container maxWidth="lg">
|
||||
|
||||
@@ -13,8 +13,6 @@ import UpcomingEventsWidget from '../components/dashboard/UpcomingEventsWidget';
|
||||
import AtemschutzDashboardCard from '../components/atemschutz/AtemschutzDashboardCard';
|
||||
import EquipmentDashboardCard from '../components/equipment/EquipmentDashboardCard';
|
||||
import VehicleDashboardCard from '../components/vehicles/VehicleDashboardCard';
|
||||
import PersonalWarningsBanner from '../components/dashboard/PersonalWarningsBanner';
|
||||
|
||||
function Dashboard() {
|
||||
const { user } = useAuth();
|
||||
const canViewAtemschutz = user?.groups?.some(g =>
|
||||
@@ -56,17 +54,6 @@ function Dashboard() {
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Personal Warnings Banner — full width, conditionally rendered */}
|
||||
{user && (
|
||||
<Box sx={{ gridColumn: '1 / -1' }}>
|
||||
<Fade in={!dataLoading} timeout={600} style={{ transitionDelay: '150ms' }}>
|
||||
<Box>
|
||||
<PersonalWarningsBanner user={user} />
|
||||
</Box>
|
||||
</Fade>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Vehicle Status Card */}
|
||||
<Box>
|
||||
<Fade in={!dataLoading} timeout={600} style={{ transitionDelay: '300ms' }}>
|
||||
|
||||
@@ -837,6 +837,19 @@ function VeranstaltungFormDialog({
|
||||
}, [open, editingEvent]);
|
||||
|
||||
const handleChange = (field: keyof CreateVeranstaltungInput, value: unknown) => {
|
||||
if (field === 'kategorie_id' && !editingEvent) {
|
||||
// Auto-fill zielgruppen / alle_gruppen from the selected category (only for new events)
|
||||
const kat = kategorien.find((k) => k.id === value);
|
||||
if (kat) {
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
kategorie_id: value as string | null,
|
||||
alle_gruppen: kat.alle_gruppen,
|
||||
zielgruppen: kat.alle_gruppen ? [] : kat.zielgruppen,
|
||||
}));
|
||||
return;
|
||||
}
|
||||
}
|
||||
setForm((prev) => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ interface KategorieFormData {
|
||||
beschreibung: string;
|
||||
farbe: string;
|
||||
icon: string;
|
||||
alle_gruppen: boolean;
|
||||
zielgruppen: string[];
|
||||
}
|
||||
|
||||
@@ -56,6 +57,7 @@ const EMPTY_FORM: KategorieFormData = {
|
||||
beschreibung: '',
|
||||
farbe: '#1976d2',
|
||||
icon: '',
|
||||
alle_gruppen: false,
|
||||
zielgruppen: [],
|
||||
};
|
||||
|
||||
@@ -80,7 +82,8 @@ function KategorieDialog({ open, onClose, onSaved, editing, groups }: KategorieD
|
||||
beschreibung: editing.beschreibung ?? '',
|
||||
farbe: editing.farbe,
|
||||
icon: editing.icon ?? '',
|
||||
zielgruppen: editing.zielgruppen ?? [],
|
||||
alle_gruppen: editing.alle_gruppen ?? false,
|
||||
zielgruppen: editing.alle_gruppen ? [] : (editing.zielgruppen ?? []),
|
||||
});
|
||||
} else {
|
||||
setForm({ ...EMPTY_FORM });
|
||||
@@ -112,7 +115,8 @@ function KategorieDialog({ open, onClose, onSaved, editing, groups }: KategorieD
|
||||
beschreibung: form.beschreibung.trim() || undefined,
|
||||
farbe: form.farbe,
|
||||
icon: form.icon.trim() || undefined,
|
||||
zielgruppen: form.zielgruppen,
|
||||
alle_gruppen: form.alle_gruppen,
|
||||
zielgruppen: form.alle_gruppen ? [] : form.zielgruppen,
|
||||
};
|
||||
if (editing) {
|
||||
await eventsApi.updateKategorie(editing.id, payload);
|
||||
@@ -188,7 +192,22 @@ function KategorieDialog({ open, onClose, onSaved, editing, groups }: KategorieD
|
||||
placeholder="z.B. EmojiEvents"
|
||||
helperText="Name eines MUI Material Icons"
|
||||
/>
|
||||
{/* Group checkboxes */}
|
||||
{/* alle_gruppen toggle */}
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={form.alle_gruppen}
|
||||
onChange={(e) => setForm((prev) => ({
|
||||
...prev,
|
||||
alle_gruppen: e.target.checked,
|
||||
zielgruppen: e.target.checked ? [] : prev.zielgruppen,
|
||||
}))}
|
||||
size="small"
|
||||
/>
|
||||
}
|
||||
label="Alle Mitglieder"
|
||||
/>
|
||||
{/* Group checkboxes — disabled when alle_gruppen is set */}
|
||||
{groups.length > 0 && (
|
||||
<Box>
|
||||
<Typography variant="subtitle2" sx={{ mb: 0.5 }}>
|
||||
@@ -203,6 +222,7 @@ function KategorieDialog({ open, onClose, onSaved, editing, groups }: KategorieD
|
||||
checked={form.zielgruppen.includes(group.id)}
|
||||
onChange={() => handleGroupToggle(group.id)}
|
||||
size="small"
|
||||
disabled={form.alle_gruppen}
|
||||
/>
|
||||
}
|
||||
label={group.label}
|
||||
@@ -435,7 +455,15 @@ export default function VeranstaltungKategorien() {
|
||||
{/* Gruppen */}
|
||||
<TableCell>
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
|
||||
{(kat.zielgruppen ?? []).length === 0
|
||||
{kat.alle_gruppen ? (
|
||||
<Chip
|
||||
label="Alle Mitglieder"
|
||||
size="small"
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
sx={{ fontSize: '0.75rem' }}
|
||||
/>
|
||||
) : (kat.zielgruppen ?? []).length === 0
|
||||
? <Typography variant="body2" color="text.secondary">—</Typography>
|
||||
: (kat.zielgruppen ?? []).map((gId) => {
|
||||
const group = groups.find((g) => g.id === gId);
|
||||
|
||||
@@ -610,6 +610,19 @@ function EventFormDialog({
|
||||
}, [open, editingEvent]);
|
||||
|
||||
const handleChange = (field: keyof CreateVeranstaltungInput, value: unknown) => {
|
||||
if (field === 'kategorie_id' && !editingEvent) {
|
||||
// Auto-fill zielgruppen / alle_gruppen from the selected category (only for new events)
|
||||
const kat = kategorien.find((k) => k.id === value);
|
||||
if (kat) {
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
kategorie_id: value as string | null,
|
||||
alle_gruppen: kat.alle_gruppen,
|
||||
zielgruppen: kat.alle_gruppen ? [] : kat.zielgruppen,
|
||||
}));
|
||||
return;
|
||||
}
|
||||
}
|
||||
setForm((prev) => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user