'use client';
import { PropsWithChildren, Suspense, useRef, useEffect, useState } from 'react';
import Link from 'next/link';
import { usePathname, useSearchParams, useRouter } from 'next/navigation';
import { SignOut } from '@/utils/auth-helpers/server';
import { handleRequest } from '@/utils/auth-helpers/client';
import { createBrowserClient } from '@supabase/ssr';
import {
FaBars,
FaCalendarAlt,
FaClipboardList,
FaQuestionCircle,
FaRegCalendarCheck,
FaCheck,
FaUser,
FaSignOutAlt,
FaUserCircle,
FaUserTag,
FaChair,
FaUtensils
} from 'react-icons/fa';
const pathToTitle: { [key: string]: string } = {
'/admin/reservations': 'Резервации',
'/admin/schedule': 'График',
'/admin/tasks': 'Задачи',
'/admin/events': 'Евенти',
'/admin/quiz': 'Куизове',
'/admin/profiles': 'Потребители',
'/admin/deals': 'Оферти',
'/admin/layout': 'Бар Маси',
'/admin/menu': 'Меню за Маси'
};
// Create a client component that uses useSearchParams
function AdminLayoutClient({ children }: PropsWithChildren) {
const currentPath = usePathname();
const searchParams = useSearchParams();
const drawerCheckboxRef = useRef<HTMLInputElement>(null);
const router = useRouter();
const [userRole, setUserRole] = useState<string | null>(null);
const [firstName, setFirstName] = useState<string>('');
const [isLoading, setIsLoading] = useState(true);
// Check if we're on a quiz page with a slide parameter or on the menu page
const isQuizWithSlide = currentPath?.startsWith('/admin/quiz/') && searchParams?.has('slide');
const isMenuPage = currentPath?.includes('/admin/menu');
const shouldRemovePadding = isQuizWithSlide || isMenuPage;
// Get the title safely
const pageTitle = currentPath ? pathToTitle[currentPath] || 'Админ панел' : 'Админ панел';
useEffect(() => {
const fetchUserData = async () => {
const supabase = createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
router.push('/signin');
return;
}
// Fetch user role
const { data: userRole } = await supabase
.from('user_roles')
.select('role')
.eq('user_id', user.id)
.single();
// Fetch user profile
const { data: profile } = await supabase
.from('profiles')
.select('first_name')
.eq('user_id', user.id)
.single();
setUserRole(userRole?.role || null);
setFirstName(profile?.first_name || '');
setIsLoading(false);
};
fetchUserData();
}, [router]);
const closeDrawer = () => {
if (drawerCheckboxRef.current) {
drawerCheckboxRef.current.checked = false;
}
};
const handleSignOut = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
await handleRequest(e, SignOut, router);
};
const getRoleBadgeColor = (role: string | null) => {
switch (role?.toLowerCase()) {
case 'admin':
return 'badge-primary';
case 'team':
return 'badge-secondary';
case 'user':
return 'badge-accent';
default:
return 'badge-ghost';
}
};
return (
<div className="admin-layout min-h-screen bg-gray-50">
{/* Only show the navbar if not on a quiz slide page */}
{!isQuizWithSlide && (
<div className="navbar bg-white shadow-sm px-4 lg:hidden h-16">
<div className="flex-1">
<label
htmlFor="my-drawer-2"
className="btn btn-ghost drawer-button lg:hidden"
>
<FaBars className="text-gray-600" />
</label>
<h1 className="text-xl font-bold text-gray-800 ml-2">
{pageTitle}
</h1>
</div>
</div>
)}
<div className={`drawer ${isQuizWithSlide ? '' : 'lg:drawer-open'} min-h-[calc(100vh-4rem)]`}>
<input
id="my-drawer-2"
type="checkbox"
className="drawer-toggle"
ref={drawerCheckboxRef}
/>
<div className="drawer-content">
<main className={`${shouldRemovePadding ? 'p-0' : 'p-6'} ${shouldRemovePadding ? '' : 'lg:pl-72'} min-h-[calc(100vh-4rem)]`}>
{!shouldRemovePadding && (
<div className="hidden lg:block mb-6">
<h1 className="text-2xl font-bold text-gray-800">
{pageTitle}
</h1>
</div>
)}
{children}
</main>
</div>
{/* Hide sidebar if on quiz with slide */}
{!shouldRemovePadding && (
<div className="drawer-side">
<label
htmlFor="my-drawer-2"
aria-label="close sidebar"
className="drawer-overlay"
></label>
<div className="menu min-h-full w-64 bg-white shadow-lg flex flex-col fixed">
<div className="p-4 border-b border-gray-100">
<div className="flex items-center space-x-3 mb-3">
<div className="w-10 h-10 rounded-full bg-orange-100 flex items-center justify-center">
<FaUserCircle className="text-2xl text-orange-600" />
</div>
<div className="flex-1 min-w-0">
<Link
href="/account"
className="text-sm font-medium text-gray-900 hover:text-orange-600 truncate block"
onClick={closeDrawer}
>
{isLoading ? 'Зареждане...' : firstName || 'Профил'}
</Link>
{userRole && (
<div className="flex items-center gap-1.5 mt-0.5">
<FaUserTag className="text-xs text-orange-600" />
<div className={`badge ${getRoleBadgeColor(userRole)} badge-sm font-medium`}>
{userRole}
</div>
</div>
)}
</div>
<form
onSubmit={handleSignOut}
className="flex-shrink-0"
>
<input type="hidden" name="pathName" value={currentPath || ''} />
<button
type="submit"
className="btn btn-ghost btn-sm px-2 hover:bg-orange-50"
title="Излез"
>
<FaSignOutAlt className="text-lg text-gray-600 hover:text-orange-600" />
</button>
</form>
</div>
</div>
<div className="flex-1 overflow-y-auto py-4">
<Suspense fallback={<></>}>
<MenuItems currentPath={currentPath || ''} onNavigate={closeDrawer} />
</Suspense>
</div>
</div>
</div>
)}
</div>
</div>
);
}
function MenuItems({
currentPath,
onNavigate
}: {
currentPath: string;
onNavigate: () => void;
}) {
const searchParams = useSearchParams();
const dateParam = searchParams?.get('date') || null;
const menuItems = [
{
href: '/admin/reservations',
icon: <FaRegCalendarCheck className="text-lg" />,
label: 'Резервации'
},
{
href: '/admin/schedule',
icon: <FaClipboardList className="text-lg" />,
label: 'График'
},
{
href: '/admin/tasks',
icon: <FaCheck className="text-lg" />,
label: 'Задачи'
},
{
href: '/admin/profiles',
icon: <FaUser className="text-lg" />,
label: 'Потребители'
},
{
href: '/admin/quiz',
icon: <FaQuestionCircle className="text-lg" />,
label: 'Куизове'
},
{
href: '/admin/events',
icon: <FaCalendarAlt className="text-lg" />,
label: 'Евенти'
},
{
href: '/admin/deals',
icon: <FaUserTag className="text-lg" />,
label: 'Оферти'
},
{
href: '/admin/layout',
icon: <FaChair className="text-lg" />,
label: 'Бар Маси'
},
{
href: '/admin/menu',
icon: <FaUtensils className="text-lg" />,
label: 'Меню за Маси'
}
];
return (
<ul className="px-3">
{menuItems.map((item) => {
const href = dateParam ? `${item.href}?date=${dateParam}` : item.href;
const isActive = currentPath === item.href;
return (
<li key={item.href} className="mb-1">
<Link
className={`flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors ${
isActive
? 'bg-orange-100 text-orange-600'
: 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'
}`}
href={href}
onClick={onNavigate}
>
{item.icon}
{item.label}
</Link>
</li>
);
})}
</ul>
);
}
// Main layout component that uses Suspense
export default function AdminLayout({ children }: PropsWithChildren) {
return (
<Suspense fallback={<></>}>
<AdminLayoutClient>{children}</AdminLayoutClient>
</Suspense>
);
}