277 lines
7.4 KiB
TypeScript
277 lines
7.4 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import {
|
|
Calendar,
|
|
MessageSquare,
|
|
BotIcon as Robot,
|
|
Bell,
|
|
Users,
|
|
LogOut,
|
|
UserCog,
|
|
Clock,
|
|
PenLine,
|
|
Video,
|
|
Radio as RadioIcon,
|
|
Megaphone,
|
|
Heart,
|
|
Target,
|
|
Mail,
|
|
Telescope,
|
|
Lightbulb,
|
|
Circle,
|
|
Menu,
|
|
} from "lucide-react";
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import { Sidebar } from "./sidebar";
|
|
import { useSession, signIn, signOut } from "next-auth/react";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu";
|
|
import { format } from 'date-fns';
|
|
import { fr } from 'date-fns/locale';
|
|
import dynamic from "next/dynamic";
|
|
|
|
// Dynamically import heavy components
|
|
const UserMenu = dynamic(() => import("./navbar/user-menu"), {
|
|
ssr: true,
|
|
loading: () => <div className="w-10 h-10 rounded-full bg-gray-200" />
|
|
});
|
|
|
|
const SidebarComponent = dynamic(() => import("./sidebar").then(mod => ({ default: mod.Sidebar })), {
|
|
ssr: false
|
|
});
|
|
|
|
const NavigationItems = dynamic(() => import("./navbar/navigation-items"), {
|
|
ssr: true
|
|
});
|
|
|
|
const requestNotificationPermission = async () => {
|
|
try {
|
|
const permission = await Notification.requestPermission();
|
|
return permission === "granted";
|
|
} catch (error) {
|
|
console.error("Error requesting notification permission:", error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
export function MainNav() {
|
|
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
|
const { data: session, status } = useSession();
|
|
const [userStatus, setUserStatus] = useState<'online' | 'busy' | 'away'>('online');
|
|
|
|
console.log("Session:", session);
|
|
console.log("Status:", status);
|
|
|
|
// Updated function to get user initials
|
|
const getUserInitials = () => {
|
|
if (session?.user?.name) {
|
|
// Split the full name and get initials
|
|
const names = session.user.name.split(' ');
|
|
if (names.length >= 2) {
|
|
return `${names[0][0]}${names[names.length - 1][0]}`.toUpperCase();
|
|
}
|
|
// If only one name, use first two letters
|
|
return names[0].slice(0, 2).toUpperCase();
|
|
}
|
|
return "?";
|
|
};
|
|
|
|
// Function to get display name
|
|
const getDisplayName = () => {
|
|
return session?.user?.name || "User";
|
|
};
|
|
|
|
// Function to get user role
|
|
const getUserRole = () => {
|
|
if (session?.user?.role) {
|
|
if (Array.isArray(session.user.role)) {
|
|
// Filter out technical roles and format remaining ones
|
|
return session.user.role
|
|
.filter(role =>
|
|
!['offline_access', 'uma_authorization', 'default-roles-cercle'].includes(role)
|
|
)
|
|
.map(role => {
|
|
// Transform role names
|
|
switch(role) {
|
|
case 'ROLE_Mentors':
|
|
return 'Mentor';
|
|
case 'ROLE_apprentice':
|
|
return 'Apprentice';
|
|
case 'ROLE_Admin':
|
|
return 'Admin';
|
|
default:
|
|
return role.replace('ROLE_', '');
|
|
}
|
|
})
|
|
.join(', ');
|
|
}
|
|
return session.user.role;
|
|
}
|
|
return "";
|
|
};
|
|
|
|
// Function to check if user has a specific role
|
|
const hasRole = (requiredRoles: string[]) => {
|
|
if (!session?.user?.role) {
|
|
console.log('No user roles found');
|
|
return false;
|
|
}
|
|
|
|
const userRoles = Array.isArray(session.user.role) ? session.user.role : [session.user.role];
|
|
console.log('Raw user roles:', userRoles);
|
|
|
|
// Clean up user roles by removing prefixes and converting to lowercase
|
|
const cleanUserRoles = userRoles.map(role =>
|
|
role.replace(/^[\/]/, '') // Remove leading slash
|
|
.replace(/^ROLE_/, '') // Remove ROLE_ prefix
|
|
.toLowerCase()
|
|
);
|
|
console.log('Clean user roles:', cleanUserRoles);
|
|
|
|
// Clean required roles
|
|
const cleanRequiredRoles = requiredRoles.map(role => role.toLowerCase());
|
|
console.log('Clean required roles:', cleanRequiredRoles);
|
|
|
|
// Check if user has any of the required roles
|
|
const hasAnyRole = cleanRequiredRoles.some(role => cleanUserRoles.includes(role));
|
|
console.log('Has any role:', hasAnyRole);
|
|
|
|
return hasAnyRole;
|
|
};
|
|
|
|
// Status configurations
|
|
const statusConfig = {
|
|
online: {
|
|
color: 'text-green-500',
|
|
label: 'Online',
|
|
notifications: true
|
|
},
|
|
busy: {
|
|
color: 'text-orange-500',
|
|
label: 'Busy',
|
|
notifications: false
|
|
},
|
|
away: {
|
|
color: 'text-gray-500',
|
|
label: 'Away',
|
|
notifications: false
|
|
},
|
|
};
|
|
|
|
// Handle status change
|
|
const handleStatusChange = async (newStatus: 'online' | 'busy' | 'away') => {
|
|
setUserStatus(newStatus);
|
|
|
|
if (newStatus !== 'online') {
|
|
// If status is busy or away, check and request notification permission if needed
|
|
const hasPermission = await requestNotificationPermission();
|
|
|
|
if (hasPermission) {
|
|
// Disable notifications
|
|
if ('serviceWorker' in navigator) {
|
|
const registration = await navigator.serviceWorker.ready;
|
|
await registration.pushManager.getSubscription()?.then(subscription => {
|
|
if (subscription) {
|
|
subscription.unsubscribe();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
} else {
|
|
// Re-enable notifications if going back online
|
|
requestNotificationPermission();
|
|
}
|
|
};
|
|
|
|
// Base menu items (available for everyone)
|
|
const baseMenuItems = [
|
|
{
|
|
title: "QG",
|
|
icon: Target,
|
|
href: '/qg',
|
|
},
|
|
];
|
|
|
|
// Role-specific menu items
|
|
const roleSpecificItems = [
|
|
{
|
|
title: "ShowCase",
|
|
icon: Lightbulb,
|
|
href: '/showcase',
|
|
requiredRoles: ["Expression"],
|
|
},
|
|
{
|
|
title: "Equipes",
|
|
icon: UserCog,
|
|
href: '/equipes',
|
|
requiredRoles: ["Admin", "Entrepreneurship"],
|
|
},
|
|
{
|
|
title: "TheMessage",
|
|
icon: Mail,
|
|
href: '/the-message',
|
|
requiredRoles: ["Mediation", "Expression"],
|
|
},
|
|
];
|
|
|
|
// Get visible menu items based on user roles
|
|
const visibleMenuItems = [
|
|
...baseMenuItems,
|
|
...roleSpecificItems.filter(item => hasRole(item.requiredRoles))
|
|
];
|
|
|
|
// Format current date and time
|
|
const now = new Date();
|
|
const formattedDate = format(now, "d MMMM yyyy", { locale: fr });
|
|
const formattedTime = format(now, "HH:mm");
|
|
|
|
return (
|
|
<>
|
|
<header className="sticky top-0 z-40 w-full bg-white dark:bg-gray-950 border-b">
|
|
<div className="container flex h-16 items-center px-4 sm:px-8">
|
|
<button
|
|
onClick={() => setIsSidebarOpen(!isSidebarOpen)}
|
|
className="mr-4 p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-md"
|
|
aria-label="Toggle menu"
|
|
>
|
|
<Menu className="h-5 w-5" />
|
|
</button>
|
|
|
|
<div className="flex items-center">
|
|
<Link href="/" className="flex items-center">
|
|
<Image
|
|
src="/logo.png"
|
|
alt="Neah Logo"
|
|
width={28}
|
|
height={28}
|
|
className="mr-2"
|
|
/>
|
|
<span className="font-bold text-xl">Neah</span>
|
|
</Link>
|
|
</div>
|
|
|
|
<div className="ml-auto flex items-center space-x-4">
|
|
<NavigationItems session={session} />
|
|
<UserMenu session={session} status={status} />
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
{isSidebarOpen && (
|
|
<SidebarComponent
|
|
isOpen={isSidebarOpen}
|
|
onClose={() => setIsSidebarOpen(false)}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|