resolve issues with new features

This commit is contained in:
Matthias Hochmeister
2026-03-12 18:09:59 +01:00
parent dc33d388a9
commit d1fed74f3b
7 changed files with 69 additions and 55 deletions

View File

@@ -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<Theme>;
}
/**
* 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<HTMLButtonElement, ChatAwareFabProps>(
({ onClick, children, color = 'primary', size, 'aria-label': ariaLabel, sx }, ref) => {
const { chatPanelOpen } = useLayout();
return (
<Fab
ref={ref}
color={color}
size={size}
aria-label={ariaLabel}
onClick={onClick}
sx={[
{
position: 'fixed',
bottom: 32,
right: chatPanelOpen ? 376 : 80,
transition: 'right 225ms cubic-bezier(0.4, 0, 0.6, 1)',
},
...(Array.isArray(sx) ? sx : sx ? [sx] : []),
]}
>
{children}
</Fab>
);
},
);
ChatAwareFab.displayName = 'ChatAwareFab';
export default ChatAwareFab;

View File

@@ -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<WartungTabProps> = ({ equipmentId, wartungslog, onAdded, canWrite }) => {
const { chatPanelOpen } = useLayout();
const [dialogOpen, setDialogOpen] = useState(false);
const [saving, setSaving] = useState(false);
const [saveError, setSaveError] = useState<string | null>(null);
@@ -444,15 +442,13 @@ const WartungTab: React.FC<WartungTabProps> = ({ equipmentId, wartungslog, onAdd
)}
{canWrite && (
<Fab
color="primary"
<ChatAwareFab
size="small"
aria-label="Wartung eintragen"
sx={{ position: 'fixed', bottom: 32, right: chatPanelOpen ? 376 : 80, transition: 'right 225ms cubic-bezier(0.4, 0, 0.6, 1)' }}
onClick={() => { setForm(emptyForm); setSaveError(null); setDialogOpen(true); }}
>
<Add />
</Fab>
</ChatAwareFab>
)}
<Dialog open={dialogOpen} onClose={() => setDialogOpen(false)} maxWidth="sm" fullWidth>

View File

@@ -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<string, React.ReactElement> = {
};
const WartungTab: React.FC<WartungTabProps> = ({ fahrzeugId, wartungslog, onAdded, canWrite }) => {
const { chatPanelOpen } = useLayout();
const [dialogOpen, setDialogOpen] = useState(false);
const [saving, setSaving] = useState(false);
const [saveError, setSaveError] = useState<string | null>(null);
@@ -396,15 +394,13 @@ const WartungTab: React.FC<WartungTabProps> = ({ fahrzeugId, wartungslog, onAdde
)}
{canWrite && (
<Fab
color="primary"
<ChatAwareFab
size="small"
aria-label="Wartung eintragen"
sx={{ position: 'fixed', bottom: 32, right: chatPanelOpen ? 376 : 80, transition: 'right 225ms cubic-bezier(0.4, 0, 0.6, 1)' }}
onClick={() => { setForm(emptyForm); setDialogOpen(true); }}
>
<Add />
</Fab>
</ChatAwareFab>
)}
<Dialog open={dialogOpen} onClose={() => setDialogOpen(false)} maxWidth="sm" fullWidth>

View File

@@ -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<VehicleCardProps> = ({ vehicle, onClick, warnings =
function Fahrzeuge() {
const navigate = useNavigate();
const { isAdmin } = usePermissions();
const { chatPanelOpen } = useLayout();
const [vehicles, setVehicles] = useState<FahrzeugListItem[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
@@ -414,14 +412,12 @@ function Fahrzeuge() {
)}
{isAdmin && (
<Fab
color="primary"
<ChatAwareFab
aria-label="Fahrzeug hinzufügen"
sx={{ position: 'fixed', bottom: 32, right: chatPanelOpen ? 376 : 80, transition: 'right 225ms cubic-bezier(0.4, 0, 0.6, 1)' }}
onClick={() => navigate('/fahrzeuge/neu')}
>
<Add />
</Fab>
</ChatAwareFab>
)}
</Container>
</DashboardLayout>

View File

@@ -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 && (
<Fab
color="primary"
sx={{ position: 'fixed', bottom: 32, right: chatPanelOpen ? 376 : 80, transition: 'right 225ms cubic-bezier(0.4, 0, 0.6, 1)' }}
<ChatAwareFab
onClick={() => {
setVeranstEditing(null);
setVeranstFormOpen(true);
}}
>
<Add />
</Fab>
</ChatAwareFab>
)}
{/* Day Popover */}
@@ -2927,13 +2923,9 @@ export default function Kalender() {
{/* FAB */}
{canCreateBookings && (
<Fab
color="primary"
sx={{ position: 'fixed', bottom: 32, right: chatPanelOpen ? 376 : 80, transition: 'right 225ms cubic-bezier(0.4, 0, 0.6, 1)' }}
onClick={openBookingCreate}
>
<ChatAwareFab onClick={openBookingCreate}>
<Add />
</Fab>
</ChatAwareFab>
)}
{/* Booking detail popover */}

View File

@@ -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<T>(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 && (
<Tooltip title="Neues Mitglied anlegen">
<Fab
color="primary"
<ChatAwareFab
aria-label="Neues Mitglied anlegen"
onClick={() => 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 }}
>
<AddIcon />
</Fab>
</ChatAwareFab>
</Tooltip>
)}
</DashboardLayout>

View File

@@ -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 && (
<Fab
color="primary"
<ChatAwareFab
aria-label="Veranstaltung erstellen"
sx={{ position: 'fixed', bottom: 32, right: chatPanelOpen ? 376 : 80, transition: 'right 225ms cubic-bezier(0.4, 0, 0.6, 1)' }}
onClick={() => { setEditingEvent(null); setFormOpen(true); }}
>
<Add />
</Fab>
</ChatAwareFab>
)}
{/* Day Popover */}