Neah/components/main-nav.tsx
2025-05-03 12:11:21 +02:00

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)}
/>
)}
</>
);
}