135 lines
3.9 KiB
TypeScript
135 lines
3.9 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
|
|
import { Bell, LogOut, Settings, User, Calendar } from 'lucide-react';
|
|
import { useToast } from '@/hooks/use-toast';
|
|
import { NotificationBell, AnnouncementsModal } from '@/components/notifications/announcements';
|
|
import { UserProfile } from '@/components/user/user-profile';
|
|
|
|
interface DashboardHeaderProps {
|
|
user: {
|
|
userId: string;
|
|
email: string;
|
|
role: 'user' | 'admin';
|
|
};
|
|
}
|
|
|
|
export function DashboardHeader({ user }: DashboardHeaderProps) {
|
|
const router = useRouter();
|
|
const { toast } = useToast();
|
|
const [isLoggingOut, setIsLoggingOut] = useState(false);
|
|
const [showAnnouncements, setShowAnnouncements] = useState(false);
|
|
const [showUserProfile, setShowUserProfile] = useState(false);
|
|
const [unreadCount, setUnreadCount] = useState(0);
|
|
|
|
// Fetch unread announcements count on component mount
|
|
useEffect(() => {
|
|
fetchUnreadCount();
|
|
}, []);
|
|
|
|
const fetchUnreadCount = async () => {
|
|
try {
|
|
const response = await fetch('/api/announcements');
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
setUnreadCount(data.unreadCount || 0);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching unread count:', error);
|
|
}
|
|
};
|
|
|
|
const handleLogout = async () => {
|
|
setIsLoggingOut(true);
|
|
try {
|
|
await fetch('/api/auth/logout', {
|
|
method: 'POST',
|
|
});
|
|
|
|
toast({
|
|
title: 'Logged out successfully',
|
|
description: 'See you next time!',
|
|
});
|
|
|
|
router.push('/login');
|
|
router.refresh();
|
|
} catch (error) {
|
|
toast({
|
|
title: 'Logout failed',
|
|
description: 'Please try again',
|
|
variant: 'destructive',
|
|
});
|
|
} finally {
|
|
setIsLoggingOut(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<header className='bg-white/80 backdrop-blur-md border-b border-gray-200 sticky top-0 z-50'>
|
|
<div className='container mx-auto px-4'>
|
|
<div className='flex items-center justify-between h-16'>
|
|
<div className='flex items-center space-x-4'>
|
|
<div className='flex items-center space-x-2'>
|
|
<Calendar className='h-6 w-6 text-blue-600' />
|
|
<h1 className='text-xl font-bold text-gray-900'>TT Booking</h1>
|
|
</div>
|
|
{user.role === 'admin' && (
|
|
<Badge variant='secondary' className='bg-purple-100 text-purple-800'>
|
|
Admin
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
|
|
<div className='flex items-center space-x-4'>
|
|
<NotificationBell unreadCount={unreadCount} onClick={() => setShowAnnouncements(true)} />
|
|
|
|
{user.role === 'admin' && (
|
|
<Button variant='ghost' size='sm' onClick={() => router.push('/admin')}>
|
|
<Settings className='h-4 w-4 mr-2' />
|
|
Admin Panel
|
|
</Button>
|
|
)}
|
|
|
|
<Button
|
|
variant='ghost'
|
|
size='sm'
|
|
onClick={() => setShowUserProfile(true)}
|
|
className='flex items-center space-x-2'
|
|
>
|
|
<User className='h-4 w-4 text-gray-600' />
|
|
<span className='text-sm text-gray-700'>{user.email.split('@')[0]}</span>
|
|
</Button>
|
|
|
|
<Button variant='outline' size='sm' onClick={handleLogout} disabled={isLoggingOut}>
|
|
<LogOut className='h-4 w-4 mr-2' />
|
|
{isLoggingOut ? 'Logging out...' : 'Logout'}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Announcements Modal */}
|
|
<AnnouncementsModal
|
|
isOpen={showAnnouncements}
|
|
onClose={() => setShowAnnouncements(false)}
|
|
unreadCount={unreadCount}
|
|
onCountUpdate={setUnreadCount}
|
|
/>
|
|
|
|
{/* User Profile Modal */}
|
|
<Dialog open={showUserProfile} onOpenChange={setShowUserProfile}>
|
|
<DialogContent className='sm:max-w-4xl max-h-[90vh] overflow-y-auto'>
|
|
<DialogHeader>
|
|
<DialogTitle>User Profile</DialogTitle>
|
|
</DialogHeader>
|
|
<UserProfile />
|
|
</DialogContent>
|
|
</Dialog>
|
|
</header>
|
|
);
|
|
}
|