resolve issues with new features
This commit is contained in:
@@ -17,6 +17,7 @@ import { Link } from 'react-router-dom';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { configApi } from '../../services/config';
|
||||
import { notificationsApi } from '../../services/notifications';
|
||||
import { nextcloudApi } from '../../services/nextcloud';
|
||||
import { safeOpenUrl } from '../../utils/safeOpenUrl';
|
||||
import ChatRoomList from './ChatRoomList';
|
||||
import ChatMessageView from './ChatMessageView';
|
||||
@@ -36,12 +37,27 @@ const ChatPanelInner: React.FC = () => {
|
||||
});
|
||||
const nextcloudUrl = externalLinks?.nextcloud;
|
||||
|
||||
// Keep a ref to rooms so the effect can access the latest list without
|
||||
// re-running every time room data refreshes.
|
||||
const roomsRef = React.useRef(rooms);
|
||||
roomsRef.current = rooms;
|
||||
|
||||
React.useEffect(() => {
|
||||
if (chatPanelOpen) {
|
||||
// Dismiss our internal notification-centre entries
|
||||
notificationsApi.dismissByType('nextcloud_talk').then(() => {
|
||||
queryClient.invalidateQueries({ queryKey: ['notifications'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['unreadNotificationCount'] });
|
||||
}).catch(() => {});
|
||||
|
||||
// Also mark all unread rooms as read directly in Nextcloud so that
|
||||
// Nextcloud's own notification badges clear as well.
|
||||
roomsRef.current
|
||||
.filter((r) => r.unreadMessages > 0)
|
||||
.forEach((r) => {
|
||||
nextcloudApi.markAsRead(r.token).catch(() => {});
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: ['nextcloud', 'rooms'] });
|
||||
}
|
||||
}, [chatPanelOpen, queryClient]);
|
||||
|
||||
|
||||
@@ -27,14 +27,16 @@ import {
|
||||
ExpandLess,
|
||||
} from '@mui/icons-material';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useLayout, DRAWER_WIDTH, DRAWER_WIDTH_COLLAPSED } from '../../contexts/LayoutContext';
|
||||
import { useAuth } from '../../contexts/AuthContext';
|
||||
import { vehiclesApi } from '../../services/vehicles';
|
||||
|
||||
export { DRAWER_WIDTH, DRAWER_WIDTH_COLLAPSED };
|
||||
|
||||
interface SubItem {
|
||||
text: string;
|
||||
tabIndex: number;
|
||||
path: string;
|
||||
}
|
||||
|
||||
interface NavigationItem {
|
||||
@@ -45,17 +47,17 @@ interface NavigationItem {
|
||||
}
|
||||
|
||||
const kalenderSubItems: SubItem[] = [
|
||||
{ text: 'Veranstaltungen', tabIndex: 0 },
|
||||
{ text: 'Fahrzeugbuchungen', tabIndex: 1 },
|
||||
{ text: 'Veranstaltungen', path: '/kalender?tab=0' },
|
||||
{ text: 'Fahrzeugbuchungen', path: '/kalender?tab=1' },
|
||||
];
|
||||
|
||||
const adminSubItems: SubItem[] = [
|
||||
{ text: 'Services', tabIndex: 0 },
|
||||
{ text: 'System', tabIndex: 1 },
|
||||
{ text: 'Benutzer', tabIndex: 2 },
|
||||
{ text: 'Broadcast', tabIndex: 3 },
|
||||
{ text: 'Banner', tabIndex: 4 },
|
||||
{ text: 'Wartung', tabIndex: 5 },
|
||||
{ text: 'Services', path: '/admin?tab=0' },
|
||||
{ text: 'System', path: '/admin?tab=1' },
|
||||
{ text: 'Benutzer', path: '/admin?tab=2' },
|
||||
{ text: 'Broadcast', path: '/admin?tab=3' },
|
||||
{ text: 'Banner', path: '/admin?tab=4' },
|
||||
{ text: 'Wartung', path: '/admin?tab=5' },
|
||||
];
|
||||
|
||||
const baseNavigationItems: NavigationItem[] = [
|
||||
@@ -123,9 +125,34 @@ function Sidebar({ mobileOpen, onMobileClose }: SidebarProps) {
|
||||
|
||||
const isAdmin = user?.groups?.includes('dashboard_admin') ?? false;
|
||||
|
||||
const navigationItems = useMemo(() => {
|
||||
return isAdmin ? [...baseNavigationItems, adminItem, adminSettingsItem] : baseNavigationItems;
|
||||
}, [isAdmin]);
|
||||
// Fetch vehicle list for dynamic dropdown sub-items
|
||||
const { data: vehicleList } = useQuery({
|
||||
queryKey: ['vehicles', 'sidebar'],
|
||||
queryFn: () => vehiclesApi.getAll(),
|
||||
staleTime: 2 * 60 * 1000,
|
||||
});
|
||||
|
||||
const vehicleSubItems: SubItem[] = useMemo(
|
||||
() =>
|
||||
(vehicleList ?? []).map((v) => ({
|
||||
text: v.kurzname ?? v.bezeichnung,
|
||||
path: `/fahrzeuge/${v.id}`,
|
||||
})),
|
||||
[vehicleList],
|
||||
);
|
||||
|
||||
const navigationItems = useMemo((): NavigationItem[] => {
|
||||
const fahrzeugeItem: NavigationItem = {
|
||||
text: 'Fahrzeuge',
|
||||
icon: <DirectionsCar />,
|
||||
path: '/fahrzeuge',
|
||||
subItems: vehicleSubItems.length > 0 ? vehicleSubItems : undefined,
|
||||
};
|
||||
const items = baseNavigationItems.map((item) =>
|
||||
item.path === '/fahrzeuge' ? fahrzeugeItem : item,
|
||||
);
|
||||
return isAdmin ? [...items, adminItem, adminSettingsItem] : items;
|
||||
}, [isAdmin, vehicleSubItems]);
|
||||
|
||||
// Expand state for items with sub-items — auto-expand when route matches
|
||||
const [expandedItems, setExpandedItems] = useState<Record<string, boolean>>({});
|
||||
@@ -169,7 +196,7 @@ function Sidebar({ mobileOpen, onMobileClose }: SidebarProps) {
|
||||
>
|
||||
<ListItemButton
|
||||
selected={isActive}
|
||||
onClick={() => handleNavigation(hasSubItems ? `${item.path}?tab=0` : item.path)}
|
||||
onClick={() => handleNavigation(hasSubItems ? item.subItems![0].path : item.path)}
|
||||
aria-label={`Zu ${item.text} navigieren`}
|
||||
sx={{
|
||||
justifyContent: sidebarCollapsed ? 'center' : 'initial',
|
||||
@@ -219,14 +246,11 @@ function Sidebar({ mobileOpen, onMobileClose }: SidebarProps) {
|
||||
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
||||
<List disablePadding>
|
||||
{item.subItems!.map((sub) => {
|
||||
const subPath = `${item.path}?tab=${sub.tabIndex}`;
|
||||
const isSubActive =
|
||||
location.pathname === item.path &&
|
||||
location.search === `?tab=${sub.tabIndex}`;
|
||||
const isSubActive = location.pathname + location.search === sub.path;
|
||||
return (
|
||||
<ListItemButton
|
||||
key={sub.tabIndex}
|
||||
onClick={() => handleNavigation(subPath)}
|
||||
key={sub.path}
|
||||
onClick={() => handleNavigation(sub.path)}
|
||||
selected={isSubActive}
|
||||
sx={{
|
||||
pl: 4,
|
||||
|
||||
Reference in New Issue
Block a user