'use client' import { useState, useEffect } from 'react' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Badge } from '@/components/ui/badge' import { format } from 'date-fns' import { Calendar, Clock, MapPin, Users, CheckCircle, XCircle, AlertCircle } from 'lucide-react' interface Booking { id: string short_id: string status: string start_time_utc: string end_time_utc: string notes: string | null is_paid: boolean customer: { id: string email: string first_name: string | null last_name: string | null phone: string | null } service: { id: string name: string duration_minutes: number base_price: number } resource?: { id: string name: string type: string } staff: { id: string display_name: string } location: { id: string name: string } } interface Location { id: string name: string } interface Staff { staff_id: string staff_name: string role: string work_hours_start: string | null work_hours_end: string | null work_days: string | null location_id: string } export default function HQDashboard() { const [locations, setLocations] = useState([]) const [staffList, setStaffList] = useState([]) const [bookings, setBookings] = useState([]) const [selectedLocation, setSelectedLocation] = useState('') const [selectedDate, setSelectedDate] = useState(format(new Date(), 'yyyy-MM-dd')) const [loading, setLoading] = useState(false) const [activeTab, setActiveTab] = useState<'calendar' | 'bookings' | 'staff'>('calendar') useEffect(() => { fetchLocations() }, []) useEffect(() => { if (selectedLocation) { fetchBookings() fetchStaff() } }, [selectedLocation, selectedDate]) const fetchLocations = async () => { try { const response = await fetch('/api/admin/locations', { headers: { 'Authorization': `Bearer ${localStorage.getItem('admin_enrollment_key') || ''}` } }) const data = await response.json() if (data.locations) { setLocations(data.locations) if (data.locations.length > 0) { setSelectedLocation(data.locations[0].id) } } } catch (error) { console.error('Failed to fetch locations:', error) } } const fetchBookings = async () => { if (!selectedLocation) return setLoading(true) try { const startDate = new Date(selectedDate).toISOString() const endDate = new Date(selectedDate) endDate.setDate(endDate.getDate() + 1) const response = await fetch(`/api/bookings?location_id=${selectedLocation}`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('admin_enrollment_key') || ''}` } }) const data = await response.json() if (data.bookings) { const filtered = data.bookings.filter((b: Booking) => { const bookingDate = new Date(b.start_time_utc) return bookingDate >= new Date(startDate) && bookingDate < new Date(endDate) }) setBookings(filtered) } } catch (error) { console.error('Failed to fetch bookings:', error) } finally { setLoading(false) } } const fetchStaff = async () => { if (!selectedLocation) return try { const startTime = new Date(selectedDate + 'T00:00:00.000Z').toISOString() const endTime = new Date(selectedDate + 'T23:59:59.999Z').toISOString() const response = await fetch(`/api/availability/staff?location_id=${selectedLocation}&start_time_utc=${startTime}&end_time_utc=${endTime}`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('admin_enrollment_key') || ''}` } }) const data = await response.json() if (data.staff) { setStaffList(data.staff) } } catch (error) { console.error('Failed to fetch staff:', error) } } const updateBookingStatus = async (bookingId: string, newStatus: string) => { try { const response = await fetch(`/api/bookings/${bookingId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('admin_enrollment_key') || ''}` }, body: JSON.stringify({ status: newStatus }) }) if (response.ok) { setBookings(bookings.map(b => b.id === bookingId ? { ...b, status: newStatus } : b )) } } catch (error) { console.error('Failed to update booking:', error) } } const getStatusBadge = (status: string) => { const config = { pending: { icon: AlertCircle, label: 'Pending', color: 'bg-yellow-100 text-yellow-800' }, confirmed: { icon: Clock, label: 'Confirmed', color: 'bg-blue-100 text-blue-800' }, completed: { icon: CheckCircle, label: 'Completed', color: 'bg-green-100 text-green-800' }, cancelled: { icon: XCircle, label: 'Cancelled', color: 'bg-red-100 text-red-800' }, no_show: { icon: XCircle, label: 'No Show', color: 'bg-gray-100 text-gray-800' } } const { icon: Icon, label, color } = config[status as keyof typeof config] || config.pending return ( {label} ) } return (

HQ Dashboard

Operations management and scheduling

setSelectedDate(e.target.value)} />
setActiveTab(v as any)} className="space-y-6"> Calendar Bookings Staff Daily Schedule {loading ? 'Loading...' : `${bookings.length} bookings for ${format(new Date(selectedDate), 'PPP')}`}
{bookings.length === 0 ? (
No bookings for this date
) : ( bookings .sort((a, b) => new Date(a.start_time_utc).getTime() - new Date(b.start_time_utc).getTime()) .map((booking) => (
{getStatusBadge(booking.status)} {format(new Date(booking.start_time_utc), 'HH:mm')} - {format(new Date(booking.end_time_utc), 'HH:mm')}

{booking.service.name}

{booking.customer.first_name} {booking.customer.last_name} ({booking.customer.email})

{booking.staff.display_name}
{booking.resource?.name || 'Not assigned'}
{booking.notes && (

Note: {booking.notes}

)}

${booking.service.base_price.toFixed(2)}

{booking.service.duration_minutes} min

)) )}
Bookings List All bookings for selected date
{bookings.length === 0 ? (
No bookings found
) : ( bookings.map((booking) => (
{booking.short_id} {getStatusBadge(booking.status)}

{booking.service.name}

{booking.customer.first_name} {booking.customer.last_name}

{format(new Date(booking.start_time_utc), 'HH:mm')}

{booking.staff.display_name}

)) )}
Staff Availability Available staff for selected date
{staffList.length === 0 ? (
No staff available
) : ( staffList.map((staff) => (

{staff.staff_name}

{staff.role}
{staff.work_hours_start || 'N/A'} - {staff.work_hours_end || 'N/A'}
Available
)) )}
) }