From d1fed74f3bd3d476d46718150c031dae9864beb8 Mon Sep 17 00:00:00 2001 From: Matthias Hochmeister Date: Thu, 12 Mar 2026 18:09:59 +0100 Subject: [PATCH] resolve issues with new features --- .../src/components/shared/ChatAwareFab.tsx | 47 +++++++++++++++++++ frontend/src/pages/AusruestungDetail.tsx | 10 ++-- frontend/src/pages/FahrzeugDetail.tsx | 10 ++-- frontend/src/pages/Fahrzeuge.tsx | 10 ++-- frontend/src/pages/Kalender.tsx | 18 ++----- frontend/src/pages/Mitglieder.tsx | 19 ++------ frontend/src/pages/Veranstaltungen.tsx | 10 ++-- 7 files changed, 69 insertions(+), 55 deletions(-) create mode 100644 frontend/src/components/shared/ChatAwareFab.tsx diff --git a/frontend/src/components/shared/ChatAwareFab.tsx b/frontend/src/components/shared/ChatAwareFab.tsx new file mode 100644 index 0000000..bd94706 --- /dev/null +++ b/frontend/src/components/shared/ChatAwareFab.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { Fab } from '@mui/material'; +import type { SxProps, Theme } from '@mui/material/styles'; +import { useLayout } from '../../contexts/LayoutContext'; + +interface ChatAwareFabProps { + onClick: () => void; + children: React.ReactNode; + color?: 'primary' | 'secondary' | 'default' | 'error' | 'info' | 'success' | 'warning'; + size?: 'small' | 'medium' | 'large'; + 'aria-label'?: string; + sx?: SxProps; +} + +/** + * A Fab that automatically shifts right to avoid overlapping the chat panel. + * Must be rendered inside DashboardLayout (i.e. inside LayoutProvider). + */ +const ChatAwareFab = React.forwardRef( + ({ onClick, children, color = 'primary', size, 'aria-label': ariaLabel, sx }, ref) => { + const { chatPanelOpen } = useLayout(); + return ( + + {children} + + ); + }, +); + +ChatAwareFab.displayName = 'ChatAwareFab'; + +export default ChatAwareFab; diff --git a/frontend/src/pages/AusruestungDetail.tsx b/frontend/src/pages/AusruestungDetail.tsx index 0f31e4c..3bc9091 100644 --- a/frontend/src/pages/AusruestungDetail.tsx +++ b/frontend/src/pages/AusruestungDetail.tsx @@ -12,7 +12,6 @@ import { DialogContentText, DialogTitle, Divider, - Fab, FormControl, Grid, IconButton, @@ -44,7 +43,7 @@ import { } from '@mui/icons-material'; import { Link as RouterLink, useNavigate, useParams } from 'react-router-dom'; import DashboardLayout from '../components/dashboard/DashboardLayout'; -import { useLayout } from '../contexts/LayoutContext'; +import ChatAwareFab from '../components/shared/ChatAwareFab'; import { equipmentApi } from '../services/equipment'; import { fromGermanDate } from '../utils/dateInput'; import { @@ -352,7 +351,6 @@ interface WartungTabProps { } const WartungTab: React.FC = ({ equipmentId, wartungslog, onAdded, canWrite }) => { - const { chatPanelOpen } = useLayout(); const [dialogOpen, setDialogOpen] = useState(false); const [saving, setSaving] = useState(false); const [saveError, setSaveError] = useState(null); @@ -444,15 +442,13 @@ const WartungTab: React.FC = ({ equipmentId, wartungslog, onAdd )} {canWrite && ( - { setForm(emptyForm); setSaveError(null); setDialogOpen(true); }} > - + )} setDialogOpen(false)} maxWidth="sm" fullWidth> diff --git a/frontend/src/pages/FahrzeugDetail.tsx b/frontend/src/pages/FahrzeugDetail.tsx index 0b83fe5..d1a1251 100644 --- a/frontend/src/pages/FahrzeugDetail.tsx +++ b/frontend/src/pages/FahrzeugDetail.tsx @@ -12,7 +12,6 @@ import { DialogContentText, DialogTitle, Divider, - Fab, FormControl, Grid, IconButton, @@ -55,7 +54,7 @@ import { } from '@mui/icons-material'; import { useNavigate, useParams } from 'react-router-dom'; import DashboardLayout from '../components/dashboard/DashboardLayout'; -import { useLayout } from '../contexts/LayoutContext'; +import ChatAwareFab from '../components/shared/ChatAwareFab'; import { vehiclesApi } from '../services/vehicles'; import { fromGermanDate } from '../utils/dateInput'; import { equipmentApi } from '../services/equipment'; @@ -323,7 +322,6 @@ const WARTUNG_ART_ICONS: Record = { }; const WartungTab: React.FC = ({ fahrzeugId, wartungslog, onAdded, canWrite }) => { - const { chatPanelOpen } = useLayout(); const [dialogOpen, setDialogOpen] = useState(false); const [saving, setSaving] = useState(false); const [saveError, setSaveError] = useState(null); @@ -396,15 +394,13 @@ const WartungTab: React.FC = ({ fahrzeugId, wartungslog, onAdde )} {canWrite && ( - { setForm(emptyForm); setDialogOpen(true); }} > - + )} setDialogOpen(false)} maxWidth="sm" fullWidth> diff --git a/frontend/src/pages/Fahrzeuge.tsx b/frontend/src/pages/Fahrzeuge.tsx index ef29f01..ecd3b5d 100644 --- a/frontend/src/pages/Fahrzeuge.tsx +++ b/frontend/src/pages/Fahrzeuge.tsx @@ -9,7 +9,6 @@ import { Chip, CircularProgress, Container, - Fab, Grid, InputAdornment, TextField, @@ -29,7 +28,7 @@ import { } from '@mui/icons-material'; import { useNavigate } from 'react-router-dom'; import DashboardLayout from '../components/dashboard/DashboardLayout'; -import { useLayout } from '../contexts/LayoutContext'; +import ChatAwareFab from '../components/shared/ChatAwareFab'; import { vehiclesApi } from '../services/vehicles'; import { equipmentApi } from '../services/equipment'; import type { VehicleEquipmentWarning } from '../types/equipment.types'; @@ -272,7 +271,6 @@ const VehicleCard: React.FC = ({ vehicle, onClick, warnings = function Fahrzeuge() { const navigate = useNavigate(); const { isAdmin } = usePermissions(); - const { chatPanelOpen } = useLayout(); const [vehicles, setVehicles] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -414,14 +412,12 @@ function Fahrzeuge() { )} {isAdmin && ( - navigate('/fahrzeuge/neu')} > - + )} diff --git a/frontend/src/pages/Kalender.tsx b/frontend/src/pages/Kalender.tsx index 0242220..a9fc4b6 100644 --- a/frontend/src/pages/Kalender.tsx +++ b/frontend/src/pages/Kalender.tsx @@ -13,7 +13,6 @@ import { DialogContentText, DialogTitle, Divider, - Fab, FormControl, FormControlLabel, FormGroup, @@ -70,7 +69,7 @@ import { } from '@mui/icons-material'; import { useNavigate, useSearchParams } from 'react-router-dom'; import DashboardLayout from '../components/dashboard/DashboardLayout'; -import { useLayout } from '../contexts/LayoutContext'; +import ChatAwareFab from '../components/shared/ChatAwareFab'; import { toGermanDate, toGermanDateTime, fromGermanDate, fromGermanDateTime, isValidGermanDate, isValidGermanDateTime } from '../utils/dateInput'; import { useAuth } from '../contexts/AuthContext'; import { useNotification } from '../contexts/NotificationContext'; @@ -1682,7 +1681,6 @@ export default function Kalender() { const [searchParams] = useSearchParams(); const { user } = useAuth(); const notification = useNotification(); - const { chatPanelOpen } = useLayout(); const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('sm')); @@ -2554,16 +2552,14 @@ export default function Kalender() { {/* FAB: Create Veranstaltung */} {canWriteEvents && ( - { setVeranstEditing(null); setVeranstFormOpen(true); }} > - + )} {/* Day Popover */} @@ -2927,13 +2923,9 @@ export default function Kalender() { {/* FAB */} {canCreateBookings && ( - + - + )} {/* Booking detail popover */} diff --git a/frontend/src/pages/Mitglieder.tsx b/frontend/src/pages/Mitglieder.tsx index 005e22c..cafc1b3 100644 --- a/frontend/src/pages/Mitglieder.tsx +++ b/frontend/src/pages/Mitglieder.tsx @@ -7,7 +7,6 @@ import { InputAdornment, Chip, Avatar, - Fab, Tooltip, Alert, CircularProgress, @@ -33,7 +32,7 @@ import { } from '@mui/icons-material'; import { useNavigate } from 'react-router-dom'; import DashboardLayout from '../components/dashboard/DashboardLayout'; -import { useLayout } from '../contexts/LayoutContext'; +import ChatAwareFab from '../components/shared/ChatAwareFab'; import { useAuth } from '../contexts/AuthContext'; import { membersService } from '../services/members'; import { @@ -74,8 +73,7 @@ function useDebounce(value: T, delay: number): T { // ---------------------------------------------------------------- function Mitglieder() { const navigate = useNavigate(); - const { user } = useAuth(); - const { chatPanelOpen } = useLayout(); const canWrite = useCanWrite(); + const { user } = useAuth(); const canWrite = useCanWrite(); // --- redirect non-admin/non-kommando users to their own profile --- useEffect(() => { @@ -428,20 +426,13 @@ function Mitglieder() { {/* FAB — only visible to Kommandant/Admin */} {canWrite && ( - navigate('/mitglieder/neu')} - sx={{ - position: 'fixed', - bottom: 32, - right: chatPanelOpen ? 376 : 80, - transition: 'right 225ms cubic-bezier(0.4, 0, 0.6, 1)', - zIndex: (theme) => theme.zIndex.speedDial, - }} + sx={{ zIndex: (theme) => theme.zIndex.speedDial }} > - + )} diff --git a/frontend/src/pages/Veranstaltungen.tsx b/frontend/src/pages/Veranstaltungen.tsx index 436dfda..1fe64fd 100644 --- a/frontend/src/pages/Veranstaltungen.tsx +++ b/frontend/src/pages/Veranstaltungen.tsx @@ -23,7 +23,6 @@ import { Switch, Checkbox, FormGroup, - Fab, Stack, List, ListItem, @@ -51,7 +50,7 @@ import { Delete as DeleteIcon, } from '@mui/icons-material'; import DashboardLayout from '../components/dashboard/DashboardLayout'; -import { useLayout } from '../contexts/LayoutContext'; +import ChatAwareFab from '../components/shared/ChatAwareFab'; import { toGermanDate, toGermanDateTime, fromGermanDate, fromGermanDateTime } from '../utils/dateInput'; import { useAuth } from '../contexts/AuthContext'; import { useNotification } from '../contexts/NotificationContext'; @@ -1005,7 +1004,6 @@ function EventListView({ events, canWrite, onEdit, onCancel, onDelete }: ListVie export default function Veranstaltungen() { const { user } = useAuth(); - const { chatPanelOpen } = useLayout(); const notification = useNotification(); const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('sm')); @@ -1316,14 +1314,12 @@ export default function Veranstaltungen() { {/* FAB for creating events */} {canWrite && ( - { setEditingEvent(null); setFormOpen(true); }} > - + )} {/* Day Popover */}