224 lines
6.7 KiB
TypeScript
224 lines
6.7 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';
|
|
import { ModeToggle } from '@/components/ui/mode-toggle';
|
|
import type { AppConfig } from '@/lib/app-config';
|
|
|
|
interface DashboardHeaderProps {
|
|
user: {
|
|
userId: string;
|
|
email: string;
|
|
role: 'user' | 'admin';
|
|
name?: string;
|
|
surname?: string;
|
|
};
|
|
}
|
|
|
|
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);
|
|
const [appConfig, setAppConfig] = useState<AppConfig | null>(null);
|
|
|
|
useEffect(() => {
|
|
const fetchAppConfig = async () => {
|
|
try {
|
|
const response = await fetch('/api/config');
|
|
if (response.ok) {
|
|
const config = await response.json();
|
|
setAppConfig(config);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching app config:', error);
|
|
}
|
|
};
|
|
|
|
fetchAppConfig();
|
|
}, []);
|
|
|
|
// 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-background/80 backdrop-blur-md border-b border-border sticky top-0 z-50'>
|
|
<div className='container mx-auto px-4'>
|
|
{/* Desktop Layout */}
|
|
<div className='hidden md: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-primary' />
|
|
<h1 className='text-xl font-bold text-foreground'>{appConfig?.clubName || 'TT Booking'}</h1>
|
|
</div>
|
|
{user.role === 'admin' && <Badge variant='secondary'>Admin</Badge>}
|
|
</div>
|
|
|
|
<div className='flex items-center space-x-4'>
|
|
<NotificationBell unreadCount={unreadCount} onClick={() => setShowAnnouncements(true)} />
|
|
|
|
<ModeToggle />
|
|
|
|
{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-muted-foreground' />
|
|
<span className='text-sm text-foreground'>
|
|
{user.name && user.surname ? `${user.name} ${user.surname}` : 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>
|
|
|
|
{/* Mobile Layout */}
|
|
<div className='md:hidden py-3'>
|
|
{/* Top row */}
|
|
<div className='flex items-center justify-between mb-3'>
|
|
<div className='flex items-center space-x-2 min-w-0 flex-1'>
|
|
<Calendar className='h-5 w-5 text-primary flex-shrink-0' />
|
|
<h1 className='text-lg font-bold text-foreground truncate'>
|
|
{appConfig?.clubName || 'TT Booking'}
|
|
</h1>
|
|
{user.role === 'admin' && (
|
|
<Badge variant='secondary' className='flex-shrink-0'>
|
|
Admin
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
<div className='flex items-center space-x-2 flex-shrink-0'>
|
|
<NotificationBell unreadCount={unreadCount} onClick={() => setShowAnnouncements(true)} />
|
|
<ModeToggle />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Bottom row */}
|
|
<div className='flex items-center justify-between gap-2'>
|
|
<Button
|
|
variant='ghost'
|
|
size='sm'
|
|
onClick={() => setShowUserProfile(true)}
|
|
className='flex items-center space-x-2 min-w-0 flex-1 justify-start'
|
|
>
|
|
<User className='h-4 w-4 text-muted-foreground flex-shrink-0' />
|
|
<span className='text-sm text-foreground truncate'>
|
|
{user.name && user.surname ? `${user.name} ${user.surname}` : user.email.split('@')[0]}
|
|
</span>
|
|
</Button>
|
|
|
|
<div className='flex items-center gap-2 flex-shrink-0'>
|
|
{user.role === 'admin' && (
|
|
<Button
|
|
variant='ghost'
|
|
size='sm'
|
|
onClick={() => {
|
|
console.log('Admin button clicked');
|
|
router.push('/admin');
|
|
}}
|
|
className='flex items-center gap-1 px-3 py-2 min-h-[36px] touch-manipulation'
|
|
title='Admin Panel'
|
|
>
|
|
<Settings className='h-4 w-4' />
|
|
<span className='text-xs font-medium'>Admin</span>
|
|
</Button>
|
|
)}
|
|
|
|
<Button
|
|
variant='outline'
|
|
size='sm'
|
|
onClick={handleLogout}
|
|
disabled={isLoggingOut}
|
|
className='flex items-center gap-1 px-2'
|
|
title={isLoggingOut ? 'Logging out...' : 'Logout'}
|
|
>
|
|
<LogOut className='h-4 w-4' />
|
|
<span className='text-xs'>{isLoggingOut ? 'Out' : 'Logout'}</span>
|
|
</Button>
|
|
</div>
|
|
</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>
|
|
);
|
|
}
|