Files
tt-booking/components/dashboard/dashboard-header.tsx
T

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>
);
}