diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index f048f2e..1dfff58 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -3,8 +3,7 @@ import { Container, Box, Fade, - IconButton, - Tooltip, + Button, } from '@mui/material'; import { Edit as EditIcon, Check as CheckIcon } from '@mui/icons-material'; import { useQuery, useQueryClient } from '@tanstack/react-query'; @@ -272,19 +271,6 @@ function Dashboard() { - {/* Edit mode toggle */} - - - setEditMode((prev) => !prev)} - color={editMode ? 'primary' : 'default'} - > - {editMode ? : } - - - - + + {/* Edit mode toggle — bottom */} + + + ); } diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx index 846fe60..bf3bd04 100644 --- a/frontend/src/pages/Settings.tsx +++ b/frontend/src/pages/Settings.tsx @@ -20,9 +20,25 @@ import { ListItem, ListItemText, } from '@mui/material'; -import { Settings as SettingsIcon, Notifications, Palette, Language, SettingsBrightness, LightMode, DarkMode, Widgets, Cloud, LinkOff, Forum, Person, OpenInNew, ArrowUpward, ArrowDownward, Sort, Restore } from '@mui/icons-material'; +import { Settings as SettingsIcon, Notifications, Palette, Language, SettingsBrightness, LightMode, DarkMode, Widgets, Cloud, LinkOff, Forum, Person, OpenInNew, Sort, Restore, DragIndicator } from '@mui/icons-material'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; +import { + DndContext, + PointerSensor, + useSensor, + useSensors, + closestCenter, +} from '@dnd-kit/core'; +import type { DragEndEvent } from '@dnd-kit/core'; +import { + SortableContext, + verticalListSortingStrategy, + arrayMove, + useSortable, +} from '@dnd-kit/sortable'; +import { CSS } from '@dnd-kit/utilities'; +import { useNavigate } from 'react-router-dom'; import DashboardLayout from '../components/dashboard/DashboardLayout'; import { useThemeMode } from '../contexts/ThemeContext'; import { preferencesApi } from '../services/settings'; @@ -48,9 +64,37 @@ const ORDERABLE_NAV_ITEMS = [ { text: 'Wissen', path: '/wissen', permission: 'wissen:view' }, { text: 'Bestellungen', path: '/bestellungen', permission: 'bestellungen:view' }, { text: 'Interne Bestellungen', path: '/ausruestungsanfrage', permission: 'ausruestungsanfrage:view' }, + { text: 'Checklisten', path: '/checklisten', permission: 'checklisten:view' }, { text: 'Issues', path: '/issues', permission: 'issues:view_own' }, ]; +function SortableNavItem({ id, text }: { id: string; text: string }) { + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id }); + return ( + + + + + + + ); +} + function Settings() { const { themeMode, setThemeMode } = useThemeMode(); const queryClient = useQueryClient(); @@ -96,13 +140,23 @@ function Settings() { return 0; }); - const moveNavItem = (fromIdx: number, toIdx: number) => { - if (toIdx < 0 || toIdx >= orderedNavItems.length) return; - const newOrder = [...orderedNavItems]; - const [moved] = newOrder.splice(fromIdx, 1); - newOrder.splice(toIdx, 0, moved); + const [localNavItems, setLocalNavItems] = useState(orderedNavItems); + useEffect(() => { setLocalNavItems(orderedNavItems); }, [menuOrder.join(',')]); + + const navSensors = useSensors( + useSensor(PointerSensor, { activationConstraint: { distance: 5 } }), + ); + + const handleNavDragEnd = (event: DragEndEvent) => { + const { active, over } = event; + if (!over || active.id === over.id) return; + const oldIdx = localNavItems.findIndex((i) => i.path === active.id); + const newIdx = localNavItems.findIndex((i) => i.path === over.id); + if (oldIdx === -1 || newIdx === -1) return; + const newItems = arrayMove(localNavItems, oldIdx, newIdx); + setLocalNavItems(newItems); const current = preferences ?? {}; - mutation.mutate({ ...current, menuOrder: newOrder.map((i) => i.path) }); + mutation.mutate({ ...current, menuOrder: newItems.map((i) => i.path) }); }; const resetMenuOrder = () => { @@ -270,41 +324,22 @@ function Settings() { ) : ( - - {orderedNavItems.map((item, idx) => ( - - moveNavItem(idx, idx - 1)} - disabled={idx === 0 || mutation.isPending} - aria-label="Nach oben" - > - - - moveNavItem(idx, idx + 1)} - disabled={idx === orderedNavItems.length - 1 || mutation.isPending} - aria-label="Nach unten" - > - - - - } - > - - - ))} - + + i.path)} + strategy={verticalListSortingStrategy} + > + + {localNavItems.map((item) => ( + + ))} + + + )}