283 lines
16 KiB
JavaScript
283 lines
16 KiB
JavaScript
import React from 'react';
|
|
import { Link, usePage } from '@inertiajs/react';
|
|
import {
|
|
LayoutDashboard,
|
|
Search,
|
|
Bookmark,
|
|
MessageSquare,
|
|
CreditCard,
|
|
User,
|
|
LogOut,
|
|
Bell,
|
|
CheckCircle,
|
|
AlertCircle,
|
|
ArrowRight,
|
|
UserCheck,
|
|
Megaphone,
|
|
Briefcase
|
|
} from 'lucide-react';
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuTrigger,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator
|
|
} from '@/components/ui/dropdown-menu';
|
|
|
|
export default function EmployerLayout({ children, title, fullPage = false }) {
|
|
const { url, props } = usePage();
|
|
const { auth, unread_messages_count } = props;
|
|
|
|
const user = auth?.user || {
|
|
name: 'John Doe',
|
|
company_name: 'Al Mansoor Household',
|
|
email: 'employer@example.com',
|
|
subscription_status: 'active',
|
|
subscription_expires_at: '2026-12-31',
|
|
};
|
|
|
|
const isSubActive = user.subscription_status === 'active';
|
|
|
|
const navItems = [
|
|
{ name: 'Dashboard', href: '/employer/dashboard', icon: LayoutDashboard },
|
|
{ name: 'Find Workers', href: '/employer/workers', icon: Search },
|
|
{ name: 'My Jobs', href: '/employer/jobs', icon: Briefcase },
|
|
{ name: 'Shortlist', href: '/employer/shortlist', icon: Bookmark },
|
|
{ name: 'Candidates', href: '/employer/candidates', icon: UserCheck },
|
|
{ name: 'Messages', href: '/employer/messages', icon: MessageSquare, badge: unread_messages_count },
|
|
{ name: 'Announcements', href: '/employer/announcements', icon: Megaphone },
|
|
{ name: 'Subscription', href: '/employer/subscription', icon: CreditCard },
|
|
{ name: 'My Profile', href: '/employer/profile', icon: User },
|
|
];
|
|
|
|
const mobileTabs = [
|
|
{ name: 'Search', href: '/employer/workers', icon: Search },
|
|
{ name: 'Shortlist', href: '/employer/shortlist', icon: Bookmark },
|
|
{ name: 'Candidates', href: '/employer/candidates', icon: UserCheck },
|
|
{ name: 'Messages', href: '/employer/messages', icon: MessageSquare, badge: unread_messages_count },
|
|
{ name: 'Profile', href: '/employer/profile', icon: User },
|
|
];
|
|
|
|
return (
|
|
<div className="min-h-screen flex flex-col bg-slate-50 font-sans select-none">
|
|
{/* Top Subscription Gate Banner */}
|
|
{!isSubActive && !fullPage && (
|
|
<div className="bg-[#185FA5] text-white px-4 py-2.5 text-xs sm:text-sm font-medium flex items-center justify-between shadow-sm z-50">
|
|
<div className="flex items-center space-x-2 truncate">
|
|
<AlertCircle className="w-4 h-4 text-amber-300 flex-shrink-0 animate-bounce" />
|
|
<span className="truncate">You need an active subscription to contact workers.</span>
|
|
</div>
|
|
<Link
|
|
href="/employer/subscription"
|
|
className="bg-white text-[#185FA5] hover:bg-slate-100 px-3 py-1 rounded-lg text-xs font-bold transition-colors inline-flex items-center space-x-1 flex-shrink-0 shadow-sm"
|
|
>
|
|
<span>Subscribe now</span>
|
|
<ArrowRight className="w-3 h-3" />
|
|
</Link>
|
|
</div>
|
|
)}
|
|
|
|
{/* Mobile Header Navbar */}
|
|
{!fullPage && (
|
|
<header className="lg:hidden sticky top-0 z-40 bg-white border-b border-slate-200 px-4 h-14 flex items-center justify-between">
|
|
<div className="flex items-center space-x-2.5">
|
|
<div className="w-8 h-8 bg-[#185FA5] text-white rounded-lg flex items-center justify-center font-bold text-base shadow-sm">
|
|
M
|
|
</div>
|
|
<span className="font-bold text-lg text-slate-800 tracking-tight truncate">Employer Portal</span>
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-3">
|
|
<Link href="/employer/messages" className="relative p-2 text-slate-600 hover:bg-slate-100 rounded-lg">
|
|
<Bell className="w-5 h-5" />
|
|
{unread_messages_count > 0 && (
|
|
<span className="absolute top-1.5 right-1.5 w-2 h-2 bg-red-500 rounded-full animate-ping" />
|
|
)}
|
|
</Link>
|
|
|
|
<div className="w-8 h-8 rounded-full bg-slate-100 border border-slate-200 flex items-center justify-center font-bold text-xs text-[#185FA5]">
|
|
{user.name.charAt(0)}
|
|
</div>
|
|
</div>
|
|
</header>
|
|
)}
|
|
|
|
<div className="flex flex-1 flex-col lg:flex-row h-screen overflow-hidden">
|
|
{/* Desktop Sidebar (lg+) */}
|
|
<aside className="hidden lg:flex w-64 bg-white border-r border-slate-200 flex-col justify-between flex-shrink-0 sticky top-0 h-screen">
|
|
<div>
|
|
{/* Top Section */}
|
|
<div className="p-6 border-b border-slate-100 space-y-4">
|
|
<div className="flex items-center space-x-3">
|
|
<div className="w-10 h-10 bg-[#185FA5] text-white rounded-xl flex items-center justify-center font-bold text-xl shadow-md">
|
|
M
|
|
</div>
|
|
<span className="font-bold text-xl text-slate-800 tracking-tight">Employer Portal</span>
|
|
</div>
|
|
|
|
{/* Subscription Status Pill */}
|
|
<Link href="/employer/subscription" className="block">
|
|
{isSubActive ? (
|
|
<div className="flex items-center justify-between px-3 py-1.5 bg-emerald-50 border border-emerald-200 rounded-lg text-xs font-semibold text-emerald-700 hover:bg-emerald-100 transition-colors">
|
|
<div className="flex items-center space-x-1.5 truncate">
|
|
<CheckCircle className="w-3.5 h-3.5 text-emerald-600 flex-shrink-0" />
|
|
<span className="truncate">Active until {user.subscription_expires_at || 'Dec 31'}</span>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div className="flex items-center justify-between px-3 py-1.5 bg-red-50 border border-red-200 rounded-lg text-xs font-semibold text-red-700 hover:bg-red-100 transition-colors">
|
|
<div className="flex items-center space-x-1.5 truncate">
|
|
<AlertCircle className="w-3.5 h-3.5 text-red-600 flex-shrink-0" />
|
|
<span className="truncate">Expired — Renew now</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</Link>
|
|
</div>
|
|
|
|
{/* Navigation Items */}
|
|
<nav className="p-4 space-y-1">
|
|
{navItems.map((item) => {
|
|
const Icon = item.icon;
|
|
const isActive = url.startsWith(item.href);
|
|
|
|
return (
|
|
<Link
|
|
key={item.name}
|
|
href={item.href}
|
|
className={`flex items-center justify-between px-4 py-3 rounded-xl text-sm transition-all duration-200 group ${
|
|
isActive
|
|
? 'bg-[#185FA5] text-white font-bold shadow-lg shadow-blue-900/20 scale-[1.02]'
|
|
: 'text-slate-600 hover:bg-slate-50 hover:text-slate-900'
|
|
}`}
|
|
>
|
|
<div className="flex items-center space-x-3">
|
|
<Icon className={`w-5 h-5 transition-colors ${isActive ? 'text-white' : 'text-slate-400 group-hover:text-slate-900'}`} />
|
|
<span className="tracking-tight">{item.name}</span>
|
|
</div>
|
|
|
|
{item.badge > 0 && (
|
|
<span className={`text-[10px] font-black px-2 py-0.5 rounded-full ${isActive ? 'bg-white text-[#185FA5]' : 'bg-[#185FA5] text-white'}`}>
|
|
{item.badge}
|
|
</span>
|
|
)}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
</div>
|
|
</aside>
|
|
|
|
{/* Main Content Area */}
|
|
<main className="flex-1 flex flex-col min-w-0 h-screen relative overflow-hidden bg-[#FAFBFF]">
|
|
{/* Top Desktop Header */}
|
|
{!fullPage && (
|
|
<header className="hidden lg:flex h-16 bg-white border-b border-slate-200 items-center justify-between px-8 shrink-0 sticky top-0 z-30 shadow-sm">
|
|
<div className="flex items-center space-x-4">
|
|
<div className="text-xs font-bold text-slate-400 uppercase tracking-widest">
|
|
{title || 'Overview'}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-6">
|
|
{/* Language Switcher */}
|
|
<div className="flex items-center bg-slate-50 border border-slate-200 rounded-xl p-1">
|
|
<button className="px-3 py-1 text-[10px] font-black bg-white text-[#185FA5] rounded-lg shadow-sm border border-slate-100">EN</button>
|
|
<button className="px-3 py-1 text-[10px] font-black text-slate-400 hover:text-slate-600">AR</button>
|
|
</div>
|
|
|
|
{/* Chat/Notifications */}
|
|
<Link href="/employer/messages" className="relative p-2.5 text-slate-500 hover:text-[#185FA5] hover:bg-blue-50 rounded-xl transition-all group">
|
|
<MessageSquare className="w-5 h-5" />
|
|
<span className="absolute top-2 right-2 w-2 h-2 bg-red-500 rounded-full border-2 border-white group-hover:scale-110 transition-transform" />
|
|
</Link>
|
|
|
|
{/* Profile Section with Dropdown */}
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<button className="flex items-center space-x-3 pl-6 border-l border-slate-200 group outline-none">
|
|
<div className="text-right hidden sm:block">
|
|
<div className="text-xs font-black text-slate-900 group-hover:text-[#185FA5] transition-colors">{user.name}</div>
|
|
<div className="text-[10px] font-bold text-slate-400 uppercase tracking-tighter">Employer Account</div>
|
|
</div>
|
|
<div className="w-10 h-10 rounded-xl bg-blue-100 text-[#185FA5] flex items-center justify-center font-black text-xs border border-blue-200 shadow-sm transition-transform group-hover:scale-105">
|
|
{user.name.charAt(0)}
|
|
</div>
|
|
</button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" className="w-56 mt-2">
|
|
<DropdownMenuLabel className="text-[10px] font-black text-slate-400 uppercase tracking-widest px-2 py-1.5">My Account</DropdownMenuLabel>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem asChild>
|
|
<Link href="/employer/profile" className="flex items-center space-x-2 text-xs font-bold text-slate-600 cursor-pointer">
|
|
<User className="w-4 h-4" />
|
|
<span>Profile Settings</span>
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem asChild>
|
|
<Link href="/employer/subscription" className="flex items-center space-x-2 text-xs font-bold text-slate-600 cursor-pointer">
|
|
<CreditCard className="w-4 h-4" />
|
|
<span>Subscription</span>
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem asChild>
|
|
<Link
|
|
href={route('employer.logout')}
|
|
method="post"
|
|
as="button"
|
|
className="w-full flex items-center space-x-2 text-xs font-bold text-rose-600 cursor-pointer"
|
|
>
|
|
<LogOut className="w-4 h-4" />
|
|
<span>Sign Out</span>
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</div>
|
|
</header>
|
|
)}
|
|
|
|
<div className={`flex-1 overflow-y-auto ${fullPage ? 'p-0' : 'p-4 sm:p-8 pb-24 lg:pb-8'}`}>
|
|
{title && !fullPage && (
|
|
<h1 className="text-2xl font-black text-slate-900 mb-6 tracking-tight lg:hidden">{title}</h1>
|
|
)}
|
|
{children}
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
{/* Mobile Bottom Tab Bar */}
|
|
{!fullPage && (
|
|
<nav className="lg:hidden fixed bottom-0 left-0 right-0 bg-white border-t border-slate-200 h-16 px-4 flex items-center justify-around z-40">
|
|
{mobileTabs.map((tab) => {
|
|
const Icon = tab.icon;
|
|
const isActive = url.startsWith(tab.href);
|
|
|
|
return (
|
|
<Link
|
|
key={tab.name}
|
|
href={tab.href}
|
|
className={`flex flex-col items-center justify-center space-y-1 w-16 h-full ${
|
|
isActive ? 'text-[#185FA5]' : 'text-slate-400 hover:text-slate-600'
|
|
}`}
|
|
>
|
|
<div className="relative">
|
|
<Icon className="w-5 h-5" />
|
|
{tab.badge > 0 && (
|
|
<span className="absolute -top-1 -right-2 w-3.5 h-3.5 bg-red-500 text-white rounded-full flex items-center justify-center text-[8px] font-bold">
|
|
{tab.badge}
|
|
</span>
|
|
)}
|
|
</div>
|
|
<span className="text-[10px] font-bold">{tab.name}</span>
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|