![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/.cursor-server/data/User/History/-114a86d1/ |
'use client';
import { useRouter } from 'next/router';
import { useState, useEffect, useRef } from 'react';
import { useSession, signOut } from 'next-auth/react';
import Link from 'next/link';
import Head from 'next/head';
import CookieConsent from './CookieConsent';
import { motion, AnimatePresence } from 'framer-motion';
import { FaHome, FaGavel, FaFilePdf, FaExternalLinkAlt } from 'react-icons/fa';
import { useTheme } from '../context/ThemeContext';
import StructuredData, { createOrganizationStructuredData } from './StructuredData';
import {
Scale,
Phone,
FileText,
User,
Home,
Info,
HelpCircle,
UserPlus,
Mail,
Menu,
X,
MessageSquare,
Users,
Star,
BarChart3,
CreditCard,
DollarSign,
Settings,
Building,
ChevronDown,
ChevronRight,
Lock,
Gavel,
MessageCircle,
Store,
AppWindow,
Bell,
Database,
ThumbsUp,
Smile,
Flag,
Search
} from 'lucide-react';
import ImpersonationBanner from './ImpersonationBanner';
import { useImpersonation } from '../hooks/useImpersonation';
import SessionDebug from './SessionDebug';
import Image from 'next/image';
import ImpersonationModal from './ImpersonationModal';
import PrivacySettingsModal from './PrivacySettingsModal';
import PaymentQuickAccess from './payments/PaymentQuickAccess';
import { formatDistanceToNow } from 'date-fns';
import Footer from './Footer';
interface LayoutWithSidebarProps {
children: React.ReactNode;
}
const LayoutWithSidebar: React.FC<LayoutWithSidebarProps> = ({ children }) => {
const router = useRouter();
const { data: session, status } = useSession();
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [isClient, setIsClient] = useState(false);
const { theme } = useTheme();
const [showCalendar, setShowCalendar] = useState(false);
const { stopImpersonation } = useImpersonation();
const [businessProfileId, setBusinessProfileId] = useState<string | null>(null);
const [openSections, setOpenSections] = useState<{ [key: string]: boolean }>({});
const [showImpersonationModal, setShowImpersonationModal] = useState(false);
const [showProfileMenu, setShowProfileMenu] = useState(false);
const profileMenuRef = useRef<HTMLDivElement>(null);
const [notifications, setNotifications] = useState([]);
const [unreadCount, setUnreadCount] = useState(0);
const [showNotifications, setShowNotifications] = useState(false);
const notificationsRef = useRef<HTMLDivElement>(null);
const [showPrivacySettings, setShowPrivacySettings] = useState(false);
const [language, setLanguage] = useState<'fr' | 'en'>('fr');
const [showSearch, setShowSearch] = useState(false);
const handleLanguageToggle = () => {
const newLang = language === 'fr' ? 'en' : 'fr';
setLanguage(newLang);
};
useEffect(() => {
setIsClient(true);
if (status === 'authenticated') {
fetch('/api/user/business-profile')
.then(res => res.ok ? res.json() : null)
.then(data => {
if (data && data.id) setBusinessProfileId(data.id);
});
}
}, [status]);
// Handle clicking outside profile menu to close it
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (profileMenuRef.current && !profileMenuRef.current.contains(event.target as Node)) {
setShowProfileMenu(false);
}
};
if (showProfileMenu) {
document.addEventListener('mousedown', handleClickOutside);
}
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [showProfileMenu]);
// Define navigation sections
const publicNavigation = [
{ name: 'Home', href: '/', icon: Home },
{ name: 'About', href: '/about', icon: Info },
{ name: 'Bordeaux Case', href: '/class-action', icon: FileText },
{ name: 'ποΈ Judicial Directory', href: '/judicial-directory', icon: Users },
{ name: 'βοΈ Law Firms', href: '/business-profiles', icon: Building },
{ name: 'π₯ Society Members', href: '/profiles', icon: Users },
{ name: 'Justice Roles', href: '/justice-roles', icon: Users },
{ name: 'Legal Basis', href: '/resources', icon: Scale },
{ name: 'FAQ', href: '/faq', icon: HelpCircle },
{ name: 'Contact', href: '/contact', icon: Mail },
{ name: 'Join Our Team', href: '/join', icon: UserPlus },
{ name: 'Group Chat', href: '/group-chat', icon: MessageSquare },
{ name: 'ποΈ Society Demo', href: '/society-demo', icon: Users },
{ name: 'ποΈ Society Access', href: '/society-access', icon: Users },
{ name: 'π Class Action', href: '/class-action', icon: FileText },
{ name: 'βοΈ Legal Notice', href: '/legal-notice', icon: FileText },
{ name: 'π§ Additional Capabilities', href: '/additional-capabilities', icon: Settings },
{ name: 'π
Calendar Demo', href: '/calendar-demo', icon: BarChart3 },
{ name: 'βοΈ Legal Suite', href: '/legal-suite', icon: Scale },
{ name: 'π Dashboard', href: '/dashboard', icon: BarChart3 },
{ name: 'βΏ Accessibility', href: '/accessibility', icon: Info },
{ name: 'π₯ Who We Are', href: '/who', icon: Users },
{ name: 'π Privacy Policy', href: '/privacy-policy', icon: FileText },
{ name: 'πͺ Cookie Policy', href: '/cookie-policy', icon: FileText },
{ name: 'π Terms', href: '/terms', icon: FileText },
];
const clientNavigation = [
{ name: 'Dashboard', href: '/client/dashboard', icon: BarChart3 },
{ name: 'π Case Management', href: '/admin/cases', icon: FileText },
{ name: 'My Cases', href: '/user/cases', icon: FileText },
{ name: 'My Documents', href: '/documents', icon: FileText },
{ name: 'Messages', href: '/messages', icon: MessageSquare },
{ name: 'My Profile', href: '/user/profile', icon: User },
{ name: 'Unified Profile', href: '/profile/unified', icon: Settings },
{ name: 'Applications', href: '/user/applications', icon: FileText },
{ name: 'Subscription Plans', href: '/user/subscription', icon: Star },
];
const lawyerNavigation = [
{ name: 'Lawyer Dashboard', href: '/lawyer/dashboard', icon: BarChart3 },
{ name: 'π Case Management', href: '/admin/cases', icon: FileText },
{ name: 'π Case Analytics', href: '/analytics/cases', icon: BarChart3 },
{ name: 'My Clients', href: '/lawyer/clients', icon: Users },
{ name: 'My Cases', href: '/lawyer/cases', icon: FileText },
{ name: 'Team Management', href: '/lawyer/team', icon: Users },
{ name: 'Business Profile', href: '/user/business-profile', icon: Building },
{ name: 'Business Analytics', href: '/user/business-analytics', icon: BarChart3 },
];
const juristNavigation = [
{ name: 'Jurist Dashboard', href: '/jurist/dashboard', icon: BarChart3 },
{ name: 'π Case Management', href: '/admin/cases', icon: FileText },
{ name: 'Legal Research', href: '/jurist/research', icon: FileText },
{ name: 'Scholarly Publications', href: '/jurist/publications', icon: FileText },
{ name: 'Theory Development', href: '/jurist/theory', icon: BarChart3 },
{ name: 'Academic Collaboration', href: '/jurist/collaboration', icon: Users },
];
const judgeNavigation = [
{ name: 'Judge Dashboard', href: '/judge/dashboard', icon: BarChart3 },
{ name: 'π Case Management', href: '/admin/cases', icon: FileText },
{ name: 'Case Oversight', href: '/judge/cases', icon: FileText },
{ name: 'Court Administration', href: '/judge/administration', icon: Scale },
{ name: 'Judicial Tools', href: '/judge/tools', icon: Settings },
];
const mediatorNavigation = [
{ name: 'Mediator Dashboard', href: '/mediator/dashboard', icon: BarChart3 },
{ name: 'π Case Management', href: '/admin/cases', icon: FileText },
{ name: 'Active Mediations', href: '/mediator/cases', icon: FileText },
{ name: 'Settlement Tracking', href: '/mediator/settlements', icon: BarChart3 },
{ name: 'Mediation Tools', href: '/mediator/tools', icon: Settings },
];
const consultantNavigation = [
{ name: 'Consultant Dashboard', href: '/consultant/dashboard', icon: BarChart3 },
{ name: 'π Case Management', href: '/admin/cases', icon: FileText },
{ name: 'Client Advisory', href: '/consultant/clients', icon: Users },
{ name: 'Strategic Planning', href: '/consultant/planning', icon: BarChart3 },
{ name: 'Expert Network', href: '/consultant/network', icon: Users },
];
const investigatorNavigation = [
{ name: 'Investigator Dashboard', href: '/investigator/dashboard', icon: BarChart3 },
{ name: 'π Case Management', href: '/admin/cases', icon: FileText },
{ name: 'Active Investigations', href: '/investigator/cases', icon: FileText },
{ name: 'Evidence Tracking', href: '/investigator/evidence', icon: FileText },
{ name: 'Investigation Tools', href: '/investigator/tools', icon: Settings },
];
const expertWitnessNavigation = [
{ name: 'Expert Dashboard', href: '/expert/dashboard', icon: BarChart3 },
{ name: 'π Case Management', href: '/admin/cases', icon: FileText },
{ name: 'Expert Testimony', href: '/expert/testimony', icon: FileText },
{ name: 'Case Collaboration', href: '/expert/cases', icon: Users },
{ name: 'Credential Management', href: '/expert/credentials', icon: Settings },
];
const supportStaffNavigation = [
{ name: 'Support Dashboard', href: '/support/dashboard', icon: BarChart3 },
{ name: 'π Case Management', href: '/admin/cases', icon: FileText },
{ name: 'Task Management', href: '/support/tasks', icon: FileText },
{ name: 'Document Processing', href: '/support/documents', icon: FileText },
{ name: 'Team Collaboration', href: '/support/team', icon: Users },
];
const studentNavigation = [
{ name: 'Student Dashboard', href: '/student/dashboard', icon: BarChart3 },
{ name: 'π Case Management', href: '/admin/cases', icon: FileText },
{ name: 'Educational Resources', href: '/student/resources', icon: FileText },
{ name: 'Mentorship Programs', href: '/student/mentorship', icon: Users },
{ name: 'Practical Experience', href: '/student/experience', icon: BarChart3 },
];
const notaryNavigation = [
{ name: 'Notary Dashboard', href: '/notary/dashboard', icon: BarChart3 },
{ name: 'π Case Management', href: '/admin/cases', icon: FileText },
{ name: 'Notarial Services', href: '/notary/services', icon: FileText },
{ name: 'Document Authentication', href: '/notary/authentication', icon: FileText },
{ name: 'Record Keeping', href: '/notary/records', icon: FileText },
];
const adminNavigation = [
{ name: 'Admin Dashboard', href: '/admin/dashboard', icon: User },
{ name: 'π Case Management', href: '/admin/cases', icon: FileText },
{ name: 'π Case Analytics', href: '/analytics/cases', icon: BarChart3 },
{ name: 'Case Assignments', href: '/admin/case-assignments', icon: Scale },
{ name: 'Analytics Dashboard', href: '/admin/analytics-dashboard', icon: BarChart3 },
{ name: 'Manage Users', href: '/admin/users', icon: User },
{ name: 'π’ Public Notifications', href: '/admin/notifications', icon: FileText },
{ name: 'π§ Newsletter Management', href: '/admin/newsletter', icon: Mail },
{ name: 'βοΈ Admin Options', href: '/admin/options', icon: FileText },
{ name: 'π’ Business Profiles', href: '/admin/business-profiles', icon: Building },
{ name: 'π€ System Automation', href: '/admin/system-automation', icon: Settings },
{ name: 'π Cases Directory', href: '/admin/cases', icon: FileText },
{ name: 'π§ Newsletter Templates', href: '/admin/newsletter/templates', icon: Mail },
{ name: 'π Registration Management', href: '/admin/registrations', icon: FileText },
{ name: 'π Application Management', href: '/admin/applications', icon: FileText },
{ name: 'ποΈ Barreau Scraper', href: '/admin/barreau-scraper', icon: Database },
{ name: 'β
VΓ©rifications Manuelles', href: '/admin/manual-verifications', icon: FileText }
];
// Special SUPERADMIN navigation that shows all dashboards
const superAdminNavigation = [
{ name: 'π Super Admin Dashboard', href: '/admin/super', icon: Star },
{ name: 'π₯ All User Dashboards', href: '/user/dashboard', icon: User },
{ name: 'βοΈ All Lawyer Dashboards', href: '/lawyer/dashboard', icon: Scale },
{ name: 'π All Jurist Dashboards', href: '/jurist/dashboard', icon: FileText },
{ name: 'ποΈ All Judge Dashboards', href: '/judge/dashboard', icon: User },
{ name: 'π€ All Mediator Dashboards', href: '/mediator/dashboard', icon: Users },
{ name: 'πΌ All Consultant Dashboards', href: '/consultant/dashboard', icon: Settings },
{ name: 'π All Investigator Dashboards', href: '/investigator/dashboard', icon: FileText },
{ name: 'π― All Expert Dashboards', href: '/expert/dashboard', icon: Star },
{ name: 'π οΈ All Support Dashboards', href: '/support/dashboard', icon: Settings },
{ name: 'π All Student Dashboards', href: '/student/dashboard', icon: User },
{ name: 'π All Notary Dashboards', href: '/notary/dashboard', icon: FileText },
{ name: 'π’ All Client Dashboards', href: '/client/dashboard', icon: Building },
];
// Grouped navigation for rendering
const groupedNavigation: { label: string; key: string; items: any[] }[] = [
{ label: 'Public', key: 'public', items: publicNavigation },
];
if (status === 'authenticated' && session) {
groupedNavigation.push({ label: 'π§βπΌ Client', key: 'client', items: clientNavigation });
const showAllRoles = session.user.role === 'SUPERADMIN';
// Debug logging removed for cleaner console
if (showAllRoles || session.user.role === 'LAWYER') groupedNavigation.push({ label: 'βοΈ Lawyer', key: 'lawyer', items: lawyerNavigation });
if (showAllRoles || session.user.role === 'JURIST') groupedNavigation.push({ label: 'π Jurist', key: 'jurist', items: juristNavigation });
if (showAllRoles || session.user.role === 'JUDGE') groupedNavigation.push({ label: 'π©ββοΈ Judge', key: 'judge', items: judgeNavigation });
if (showAllRoles || session.user.role === 'MEDIATOR') groupedNavigation.push({ label: 'ποΈ Mediator', key: 'mediator', items: mediatorNavigation });
if (showAllRoles || session.user.role === 'LEGAL_CONSULTANT') groupedNavigation.push({ label: 'πΌ Consultant', key: 'consultant', items: consultantNavigation });
if (showAllRoles || session.user.role === 'INVESTIGATOR') groupedNavigation.push({ label: 'π΅οΈ Investigator', key: 'investigator', items: investigatorNavigation });
if (showAllRoles || session.user.role === 'EXPERT_WITNESS') groupedNavigation.push({ label: 'π― Expert Witness', key: 'expert', items: expertWitnessNavigation });
if (showAllRoles || [
'SECRETARY', 'ASSISTANT', 'CLERK', 'COURT_CLERK', 'PARALEGAL',
].includes(session.user.role)) groupedNavigation.push({ label: 'π οΈ Support Staff', key: 'support', items: supportStaffNavigation });
if (showAllRoles || [
'LAW_STUDENT', 'LEGAL_INTERN',
].includes(session.user.role)) groupedNavigation.push({ label: 'π Student', key: 'student', items: studentNavigation });
if (showAllRoles || session.user.role === 'NOTARY') groupedNavigation.push({ label: 'π Notary', key: 'notary', items: notaryNavigation });
if (showAllRoles || session.user.role === 'ADMIN' || session.user.role === 'SUPERADMIN') groupedNavigation.push({ label: 'π‘οΈ Admin', key: 'admin', items: adminNavigation });
// Add SUPERADMIN specific navigation
if (session.user.role === 'SUPERADMIN') {
groupedNavigation.push({ label: 'π SUPER ADMIN', key: 'super-admin', items: superAdminNavigation });
}
// Debug logging removed for cleaner console
}
// Add-on navigation (not grouped)
let addOnNavigation = [
{ name: 'π° Financial Dashboard', href: '/financial-dashboard', icon: DollarSign },
{ name: 'π³ Payment Demo', href: '/payment-demo', icon: CreditCard },
{ name: 'ποΈ Society Dashboard', href: '/society-dashboard', icon: Users },
{ name: 'π Documents', href: '/documents', icon: FileText },
];
if (businessProfileId) {
addOnNavigation.push(
{ name: ' Business Profile', href: `/business/${businessProfileId}
{ name: 'π Business Analytics', href: '/user/business-analytics', icon: BarChart3 }
);
}
addOnNavigation.push(
{ name: 'Manage Business Profile', href: '/user/business-profile', icon: Settings },
{ name: 'Subscription Plans', href: '/user/subscription', icon: Star },
{ name: 'My Profile', href: '/user/profile', icon: User },
{ name: 'My Applications', href: '/user/dashboard', icon: FileText }
);
if (session && session.user && (session.user.role === 'SUPERADMIN')) {
addOnNavigation.push(
{ name: 'π Super Admin', href: '/admin/super', icon: Star }
);
}
addOnNavigation.push(
{ name: 'βοΈ Hire Lawyer', href: '/hire/case-selection', icon: Scale },
{ name: 'π¬ Book Consultation', href: '/hire/consultation', icon: MessageSquare },
{ name: 'π Debug Session', href: '/api/debug-session', icon: Settings }
);
// Floating New Case Button (for users with permission)
const showNewCaseButton = status === 'authenticated' && session && [
'CLIENT', 'USER', 'ADMIN', 'SUPERADMIN'
].includes(session.user.role);
// Date formatting
const today = new Date();
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
const dayName = days[today.getDay()];
const monthName = months[today.getMonth()];
const dayNum = today.getDate();
const year = today.getFullYear();
const nth = (d: number) => ['th','st','nd','rd'][(d%10>3||(d%100-d%10)==10)?0:d%10];
const daySuffix = nth(dayNum);
const fullDate = dayName + ', ' + monthName + ' ' + dayNum + daySuffix + ', ' + year + ' A.D.';
// Smart logout function that handles impersonation
const handleLogout = async () => {
try {
// If user is impersonating, stop impersonation instead of logging out
if (session?.user?.isImpersonating) {
await stopImpersonation();
// Close mobile menu if open
setIsMobileMenuOpen(false);
return; // Don't proceed with normal logout
}
// Normal logout for non-impersonating users
signOut({ redirect: false }).then(() => {
router.push('/');
setIsMobileMenuOpen(false);
});
} catch (error) {
// Handle the case where stop impersonation fails gracefully
if (session?.user?.isImpersonating) {
window.location.href = '/admin/dashboard';
setIsMobileMenuOpen(false);
return;
}
// Fallback to normal logout for other errors
signOut({ redirect: false }).then(() => {
router.push('/');
setIsMobileMenuOpen(false);
});
}
};
// Fetch notifications
const fetchNotifications = async () => {
const res = await fetch('/api/notifications');
if (res.ok) {
const data = await res.json();
setNotifications(data);
setUnreadCount(data.filter((n: any) => !n.isRead).length);
}
};
// Poll for notifications every 15s
useEffect(() => {
fetchNotifications();
const interval = setInterval(fetchNotifications, 15000);
return () => clearInterval(interval);
}, []);
// Listen for real-time notification updates
useEffect(() => {
const handleNotificationUpdate = () => {
fetchNotifications();
};
window.addEventListener('notification-updated', handleNotificationUpdate);
return () => window.removeEventListener('notification-updated', handleNotificationUpdate);
}, []);
// Close dropdown on outside click
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (notificationsRef.current && !notificationsRef.current.contains(event.target as Node)) {
setShowNotifications(false);
}
};
if (showNotifications) {
document.addEventListener('mousedown', handleClickOutside);
}
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [showNotifications]);
// Mark all as read
const markAllAsRead = async () => {
const unreadIds = notifications.filter((n: any) => !n.isRead).map((n: any) => n.id);
if (unreadIds.length > 0) {
await fetch('/api/notifications', {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ids: unreadIds })
});
fetchNotifications();
}
};
if (!isClient || status === 'loading') {
return null;
}
// Collapsible section component
const CollapsibleSection = ({ label, sectionKey, children }: { label: string; sectionKey: string; children: React.ReactNode }) => (
<div>
<button
className="flex items-center w-full px-2 py-2 text-left font-semibold text-white hover:bg-white/10 rounded-lg transition-colors mb-1"
onClick={() => setOpenSections((prev) => ({ ...prev, [sectionKey]: !prev[sectionKey] }))}
aria-expanded={!!openSections[sectionKey]}
>
{openSections[sectionKey] ? <ChevronDown className="h-4 w-4 mr-2" /> : <ChevronRight className="h-4 w-4 mr-2" />}
{label}
</button>
<div className={openSections[sectionKey] ? 'block' : 'hidden'}>
{children}
</div>
</div>
);
const navIcons = [
{ label: 'Home', href: '/', icon: Home },
{ label: 'Cases', href: '/live-cases', icon: Gavel },
{ label: 'Messages', href: '/messages', icon: MessageCircle },
{ label: 'Groups', href: '/groups', icon: Users },
{ label: 'Marketplace', href: '/marketplace', icon: Store },
{ label: 'Documents', href: '/documents', icon: FileText, pdf: true },
];
return (
<>
<StructuredData
type="organization"
data={createOrganizationStructuredData()}
/>
<div className="min-h-screen bg-gray-50">
{/* Mobile menu button - floating */}
<button
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
className="lg:hidden fixed top-4 right-4 z-50 p-2 rounded-full bg-primary text-white shadow-lg hover:bg-primary-dark transition-colors"
>
{isMobileMenuOpen ? (
<X className="h-6 w-6" />
) : (
<Menu className="h-6 w-6" />
)}
</button>
{/* Mobile menu */}
<AnimatePresence>
{isMobileMenuOpen && (
<motion.div
initial={{ opacity: 0, x: -300 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -300 }}
transition={{ duration: 0.2 }}
className="lg:hidden fixed inset-0 z-40"
>
<div className="fixed inset-0 bg-gray-600 bg-opacity-75" onClick={() => setIsMobileMenuOpen(false)} />
<div className="fixed inset-y-0 left-0 max-w-xs w-full bg-gradient-to-b from-primary to-primary-dark shadow-xl">
<div className="h-full flex flex-col py-6 px-4">
<div className="flex items-center justify-center mb-8">
<Link href="/" onClick={() => setIsMobileMenuOpen(false)}>
<img src="/images/Logo_w.png" alt="Logo" className="max-w-full h-auto wave" />
</Link>
</div>
{/* Debug session info */}
<SessionDebug />
<nav className="flex-1 space-y-2">
{groupedNavigation.map((group) =>
group.key === 'public' ? (
group.items.map((item, idx) => (
<Link
key={typeof item.name === 'string' ? item.name : 'nav-item-' + group.key + '-' + idx}
href={item.href}
onClick={() => setIsMobileMenuOpen(false)}
className="flex items-center space-x-2 p-2 rounded-lg text-white hover:bg-white/10 transition-colors"
>
<item.icon className="h-5 w-5" />
<span>{item.name}</span>
</Link>
))
) : (
<CollapsibleSection key={group.key} label={group.label} sectionKey={group.key}>
{group.items.map((item, idx) => (
<Link
key={typeof item.name === 'string' ? item.name : 'nav-item-' + group.key + '-' + idx}
href={item.href}
onClick={() => setIsMobileMenuOpen(false)}
className="flex items-center space-x-2 p-2 rounded-lg text-white hover:bg-white/10 transition-colors ml-4"
>
<item.icon className="h-5 w-5" />
<span>{item.name}</span>
</Link>
))}
</CollapsibleSection>
)
)}
{addOnNavigation.map((item, idx) => (
<Link
key={typeof item.name === 'string' ? item.name : 'addon-item-' + idx}
href={item.href}
onClick={() => setIsMobileMenuOpen(false)}
className="flex items-center space-x-2 p-2 rounded-lg text-white hover:bg-white/10 transition-colors"
>
<item.icon className="h-5 w-5" />
<span>{item.name}</span>
</Link>
))}
{session ? (
<button
onClick={handleLogout}
className="w-full flex items-center space-x-2 p-2 rounded-lg text-white hover:bg-white/10 transition-colors"
>
<Lock className="h-5 w-5" />
<span>{session.user?.isImpersonating ? 'Stop Impersonating' : 'Logout'}</span>
</button>
) : (
<Link
href={language === 'en' ? '/en/auth/login' : '/auth/login'}
onClick={() => setIsMobileMenuOpen(false)}
className="flex items-center space-x-2 p-2 rounded-lg text-white hover:bg-white/10 transition-colors"
>
<Lock className="h-5 w-5" />
<span>Login</span>
</Link>
)}
</nav>
</div>
</div>
</motion.div>
)}
</AnimatePresence>
{/* Desktop sidebar */}
<aside className="hidden lg:block fixed inset-y-0 left-0 w-64 bg-gradient-to-b from-primary to-primary-dark text-white shadow-lg">
<div className="flex flex-col h-full">
<div className="flex items-center justify-center p-4">
<Link href="/">
<img src="/images/Logo_w.png" alt="Logo" className="max-w-full h-auto wave" />
</Link>
</div>
{/* Debug session info for desktop */}
<div className="px-4 pb-2">
<SessionDebug />
</div>
<nav className="flex-1 px-4 space-y-2 overflow-y-auto">
{/* Public links always visible */}
{groupedNavigation.map((group) =>
group.key === 'public' ? (
group.items.map((item, idx) => (
<Link
key={typeof item.name === 'string' ? item.name : 'nav-item-' + group.key + '-' + idx}
href={item.href}
className="flex items-center space-x-3 p-3 rounded-lg hover:bg-white/10 transition-colors"
>
<item.icon className="h-5 w-5 flex-shrink-0" />
<span className="text-sm font-medium">{item.name}</span>
</Link>
))
) : (
<CollapsibleSection key={group.key} label={group.label} sectionKey={group.key}>
{group.items.map((item, idx) => (
<Link
key={typeof item.name === 'string' ? item.name : 'nav-item-' + group.key + '-' + idx}
href={item.href}
className="flex items-center space-x-3 p-3 rounded-lg hover:bg-white/10 transition-colors ml-4"
>
<item.icon className="h-5 w-5 flex-shrink-0" />
<span className="text-sm font-medium">{item.name}</span>
</Link>
))}
</CollapsibleSection>
)
)}
{/* Add-on navigation always at the bottom */}
<div className="mt-4 border-t border-white/10 pt-2">
{addOnNavigation.map((item, idx) => (
<Link
key={typeof item.name === 'string' ? item.name : 'addon-item-' + idx}
href={item.href}
className="flex items-center space-x-3 p-3 rounded-lg hover:bg-white/10 transition-colors"
>
<item.icon className="h-5 w-5 flex-shrink-0" />
<span className="text-sm font-medium">{item.name}</span>
</Link>
))}
</div>
{session ? (
<button
onClick={handleLogout}
className="w-full flex items-center space-x-3 p-3 rounded-lg hover:bg-white/10 transition-colors"
>
<Lock className="h-5 w-5 flex-shrink-0" />
<span className="text-sm font-medium">{session.user?.isImpersonating ? 'Stop Impersonating' : 'Logout'}</span>
</button>
) : (
<Link
href={language === 'en' ? '/en/auth/login' : '/auth/login'}
className="flex items-center space-x-3 p-3 rounded-lg hover:bg-white/10 transition-colors"
>
<Lock className="h-5 w-5 flex-shrink-0" />
<span className="text-sm font-medium">Login</span>
</Link>
)}
</nav>
<div className="p-4 border-t border-white/10">
<div className="text-xs text-white/60 text-center">
Β© {new Date().getFullYear()} LibertΓ© MΓͺme en Cellule
</div>
</div>
{/* Floating New Case Button */}
{showNewCaseButton && (
<button
onClick={() => window.location.href = '/hire/new-case'}
className="fixed bottom-8 left-8 z-50 flex items-center px-5 py-3 bg-blue-600 text-white rounded-full shadow-lg hover:bg-blue-700 transition-colors text-lg font-semibold"
style={{ boxShadow: '0 4px 24px rgba(0,0,0,0.15)' }}
>
+ New Case
</button>
)}
</div>
</aside>
{/* Main content */}
<main className="lg:pl-64 flex flex-col min-h-screen">
{/* Impersonation Banner */}
<ImpersonationBanner />
{/* Top Bar */}
<header className="sticky top-0 z-50 w-full h-14 bg-primary flex items-center px-2 md:px-6 justify-between border-b border-gray-200 shadow">
{/* Left: Logo & Search */}
<div className="flex items-center gap-2 min-w-0">
<div className="relative hidden md:block">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400" />
<input
type="text"
placeholder="Search professionals, cases, documents..."
onClick={() => router.push('/search')}
className="bg-white/80 rounded-full pl-10 pr-4 py-1 focus:outline-none text-sm w-64 cursor-pointer"
readOnly
/>
</div>
</div>
{/* Center: Navigation Icons */}
<nav className="flex gap-6 md:gap-8">
{navIcons.map(({ label, href, icon: Icon, pdf }) => (
<Link
key={label}
href={href}
className={
${pdf ? 'hover:bg-red-50' : 'hover:bg-white/20'}
title={label}
>
<Icon
size={26}
className={
${pdf ? 'text-white group-hover:text-red-500' : 'text-white group-hover:text-primary-light'}
/>
<span className="sr-only">{label}</span>
</Link>
))}
</nav>
{/* Right: Utilities & Profile */}
<div className="flex items-center gap-2 md:gap-3">
<button className="p-2 rounded-full hover:bg-white/20 transition relative">
<AppWindow size={22} className="text-white" />
</button>
<button className="p-2 rounded-full hover:bg-white/20 transition relative">
<MessageCircle size={22} className="text-white" />
<span className="absolute -top-1 -right-1 bg-blue-500 text-white text-xs rounded-full px-1.5">2</span>
</button>
{/* Notifications Button */}
<div className="relative" ref={notificationsRef}>
<button
onClick={() => setShowNotifications(v => !v)}
className="p-2 rounded-full hover:bg-white/20 transition flex items-center relative"
title="Notifications"
>
<Bell size={22} className="text-white" />
{unreadCount > 0 && (
<motion.div
initial={{ scale: 0 }}
animate={{ scale: 1 }}
className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full w-5 h-5 flex items-center justify-center font-medium"
>
{unreadCount > 99 ? '99+' : unreadCount}
</motion.div>
)}
</button>
<AnimatePresence>
{showNotifications && (
<motion.div
initial={{ opacity: 0, scale: 0.95, y: -10 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: -10 }}
className="absolute right-0 mt-2 w-80 bg-white shadow-lg rounded-lg border border-gray-200 z-50"
>
<div className="p-4">
<div className="flex items-center justify-between mb-3">
<h3 className="text-sm font-semibold text-gray-900">Notifications</h3>
{unreadCount > 0 && (
<button
onClick={markAllAsRead}
className="text-xs text-blue-600 hover:text-blue-800"
>
Mark all as read
</button>
)}
</div>
<div className="max-h-64 overflow-y-auto space-y-2">
{notifications.length === 0 ? (
<div className="text-center py-4 text-gray-500 text-sm">
No notifications
</div>
) : (
notifications.map((n: any, idx) => {
const notificationClass = !n.isRead ? 'bg-blue-50' : 'hover:bg-gray-50';
return (
<div key={idx} className={'flex items-start space-x-3 p-2 rounded-lg ' + notificationClass}>
<div className="flex-shrink-0 mt-1">
{n.type === 'message' && <MessageSquare className="h-5 w-5 text-blue-500" />}
{n.type === 'case' && <FileText className="h-5 w-5 text-green-500" />}
{n.type === 'payment' && <DollarSign className="h-5 w-5 text-yellow-500" />}
{n.type === 'reaction' && <Smile className="h-5 w-5 text-green-500" />}
{n.type === 'report' && <Flag className="h-5 w-5 text-red-500" />}
{/* Add more types as needed */}
</div>
<div className="flex-1 min-w-0">
<div className={`font-medium text-sm ${!n.isRead ? 'text-gray-900' : 'text-gray-700'}
<div className="text-xs text-gray-500 truncate">{n.message}</div>
<div className="text-xs text-gray-400 mt-0.5">{formatDistanceToNow(new Date(n.createdAt), { addSuffix: true })}</div>
</div>
{!n.isRead && <span className="mt-1 w-2 h-2 bg-yellow-400 rounded-full" />}
</div>
);
})
)}
</div>
<div className="px-4 py-2 border-t border-gray-100 bg-gray-50 text-right">
<Link href={language === 'en' ? '/en/notifications' : '/notifications'} className="text-xs text-blue-600 hover:underline">View all notifications</Link>
</div>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
{/* Payment Quick Access */}
{session && (
<PaymentQuickAccess
userId={session.user?.id || ''}
userRole={session.user?.role || 'USER'}
/>
)}
{/* Settings Button */}
{session && (
<button
onClick={() => setShowPrivacySettings(true)}
className="p-2 rounded-full hover:bg-white/20 transition"
title="Privacy Settings"
>
<Settings size={22} className="text-white" />
</button>
)}
{/* Profile Dropdown */}
<div className="relative" ref={profileMenuRef}>
<button
onClick={() => setShowProfileMenu(!showProfileMenu)}
className="p-1 rounded-full hover:bg-white/20 transition flex items-center"
>
{session?.user?.image ? (
<Image src={session.user.image} alt="Profile" width={32} height={32} className="rounded-full border" />
) : (
<User size={28} className="rounded-full border text-white" />
)}
</button>
{/* Dropdown on click */}
{showProfileMenu && (
<div
className="flex flex-col absolute right-0 mt-2 w-44 bg-white shadow-lg rounded-xl py-2 z-50 border border-gray-100"
onMouseEnter={() => {
if ((window as any).profileMenuTimeout) {
clearTimeout((window as any).profileMenuTimeout);
(window as any).profileMenuTimeout = null;
}
}}
onMouseLeave={() => {
(window as any).profileMenuTimeout = setTimeout(() => setShowProfileMenu(false), 300);
}}
>
{session ? (
<>
<div className="px-4 py-2 border-b border-gray-100">
<div className="font-semibold text-gray-800 text-sm truncate">{session.user?.name || 'User'}</div>
<div className="text-xs text-gray-500 truncate">{session.user?.email}</div>
</div>
<Link href={language === 'en' ? '/en/user/profile' : '/user/profile'} className="px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">Profile</Link>
<Link href={language === 'en' ? '/en/user/dashboard' : '/user/dashboard'} className="px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">Dashboard</Link>
<Link href={language === 'en' ? '/en/user/payments' : '/user/payments'} className="px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 flex items-center">
<DollarSign className="h-4 w-4 mr-2" />
Payments & Billing
</Link>
<Link href={language === 'en' ? '/en/user/subscription' : '/user/subscription'} className="px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 flex items-center">
<CreditCard className="h-4 w-4 mr-2" />
Subscription
</Link>
{session.user?.role === 'SUPERADMIN' && (
<>
<button
onClick={() => setShowImpersonationModal(true)}
className="px-4 py-2 text-sm text-blue-600 hover:bg-blue-50 text-left flex items-center"
>
<span className="mr-2">π€</span>
Impersonate User
</button>
<div className="border-t border-gray-100 my-1" />
{/* Superadmin role menus */}
{[
{ label: 'Client', nav: clientNavigation },
{ label: 'Lawyer', nav: lawyerNavigation },
{ label: 'Jurist', nav: juristNavigation },
{ label: 'Judge', nav: judgeNavigation },
{ label: 'Mediator', nav: mediatorNavigation },
{ label: 'Consultant', nav: consultantNavigation },
{ label: 'Investigator', nav: investigatorNavigation },
{ label: 'Expert Witness', nav: expertWitnessNavigation },
{ label: 'Support Staff', nav: supportStaffNavigation },
{ label: 'Student', nav: studentNavigation },
{ label: 'Notary', nav: notaryNavigation },
{ label: 'Admin', nav: adminNavigation },
].map(({ label, nav }) => {
const Icon = nav[0]?.icon || User;
return (
<div key={label} className="relative group">
<button
className="w-full px-4 py-2 text-sm text-purple-700 hover:bg-purple-50 text-left flex items-center justify-between"
onClick={() => setOpenSections((prev) => ({ ...prev, [label]: !prev[label] }))}
onMouseEnter={() => setOpenSections((prev) => ({ ...prev, [label]: true }))}
onMouseLeave={() => setOpenSections((prev) => ({ ...prev, [label]: false }))}
>
<Icon className="h-4 w-4 mr-2" />
{label}
<span className="ml-auto">β</span>
</button>
{openSections[label] && (
<div
className="absolute right-full top-0 mt-0 mr-1 w-56 bg-white shadow-lg rounded-xl py-2 z-50 border border-gray-100"
onMouseEnter={() => setOpenSections((prev) => ({ ...prev, [label]: true }))}
onMouseLeave={() => setOpenSections((prev) => ({ ...prev, [label]: false }))}
>
{nav.map((item) => (
<Link
key={item.href}
href={item.href}
className="px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center"
>
<item.icon className="h-4 w-4 mr-2" />
{item.name}
</Link>
))}
</div>
)}
</div>
);
})}
</>
)}
<button
onClick={() => signOut({ callbackUrl: '/' })}
className="px-4 py-2 text-sm text-red-600 hover:bg-red-50 text-left"
>
Sign out
</button>
</>
) : (
<>
<div className="px-4 py-2 border-b border-gray-100">
<div className="font-semibold text-gray-800 text-sm">Guest User</div>
<div className="text-xs text-gray-500">Not signed in</div>
</div>
<Link href={language === 'en' ? '/en/auth/login' : '/auth/login'} className="px-4 py-2 text-sm text-blue-600 hover:bg-blue-50 text-left">
Sign in
</Link>
<Link href={language === 'en' ? '/en/auth/signup' : '/auth/signup'} className="px-4 py-2 text-sm text-green-600 hover:bg-green-50 text-left">
Create Account
</Link>
</>
)}
</div>
)}
</div>
</div>
{/* Mobile: Hamburger menu (optional, can be expanded later) */}
<div className="md:hidden ml-2">
<button className="p-2 rounded-full hover:bg-white/20 transition">
<Menu size={24} className="text-white" />
</button>
</div>
</header>
{/* Calendar Modal */}
{showCalendar && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50" onClick={() => setShowCalendar(false)}>
<div className="bg-white rounded-lg p-6 max-w-md w-full mx-4" onClick={(e) => e.stopPropagation()}>
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-semibold">Today's Date & Notes</h3>
<button
onClick={() => setShowCalendar(false)}
className="text-gray-500 hover:text-gray-700"
>
β
</button>
</div>
<div className="mb-4">
<p className="text-gray-600 text-sm">{fullDate}</p>
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-2">
Notes for today:
</label>
<textarea
placeholder="Add your notes here..."
className="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent"
rows={4}
defaultValue={typeof window !== 'undefined' ? localStorage.getItem(`notes-${today.toDateString()}
onChange={(e) => {
if (typeof window !== 'undefined') {
localStorage.setItem(`notes-${today.toDateString()}
}
}}
/>
</div>
<div className="flex justify-end gap-2">
<button
onClick={() => setShowCalendar(false)}
className="px-4 py-2 bg-gray-200 text-gray-800 rounded-md hover:bg-gray-300 transition-colors"
>
Close
</button>
</div>
</div>
</div>
)}
{/* Main content area */}
<div className="flex-1 w-full">
{children}
</div>
<CookieConsent />
<SessionDebug />
</main>
{/* Footer */}
<Footer />
{/* Impersonation Modal */}
<ImpersonationModal
isOpen={showImpersonationModal}
onClose={() => setShowImpersonationModal(false)}
/>
{/* Privacy Settings Modal */}
<PrivacySettingsModal
isOpen={showPrivacySettings}
onClose={() => setShowPrivacySettings(false)}
/>
</div>
</>
);
};
export default LayoutWithSidebar;