'use client';
import { useState } from 'react';
import { ChevronLeft, ChevronRight, Plus, Clock, User, Calendar as CalendarIcon } from 'lucide-react';
interface Appointment {
id: string;
patient: string;
time: string;
duration: number;
type: 'consulta' | 'exame' | 'retorno';
status: 'confirmed' | 'pending' | 'absent';
professional: string;
notes: string;
}
interface Professional {
id: string;
name: string;
specialty: string;
}
interface AgendaCalendarProps {
professionals: Professional[];
appointments: Appointment[];
onAddAppointment: () => void;
onEditAppointment: (appointment: Appointment) => void;
}
export default function AgendaCalendar({
professionals,
appointments,
onAddAppointment,
onEditAppointment
}: AgendaCalendarProps) {
const [view, setView] = useState<'day' | 'week' | 'month'>('week');
const [selectedProfessional, setSelectedProfessional] = useState('all');
const [currentDate, setCurrentDate] = useState(new Date());
const timeSlots = Array.from({ length: 11 }, (_, i) => {
const hour = i + 8; // Das 8h às 18h
return [`${hour.toString().padStart(2, '0')}:00`, `${hour.toString().padStart(2, '0')}:30`];
}).flat();
const getStatusColor = (status: string) => {
switch (status) {
case 'confirmed': return 'bg-green-100 border-green-500 text-green-800';
case 'pending': return 'bg-yellow-100 border-yellow-500 text-yellow-800';
case 'absent': return 'bg-red-100 border-red-500 text-red-800';
default: return 'bg-gray-100 border-gray-500 text-gray-800';
}
};
const getTypeIcon = (type: string) => {
switch (type) {
case 'consulta': return '🩺';
case 'exame': return '📋';
case 'retorno': return '↩️';
default: return '📅';
}
};
const formatDate = (date: Date) => {
return date.toLocaleDateString('pt-BR', {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric',
timeZone: 'America/Sao_Paulo'
});
};
const navigateDate = (direction: 'prev' | 'next') => {
const newDate = new Date(currentDate);
if (view === 'day') {
newDate.setDate(newDate.getDate() + (direction === 'next' ? 1 : -1));
} else if (view === 'week') {
newDate.setDate(newDate.getDate() + (direction === 'next' ? 7 : -7));
} else {
newDate.setMonth(newDate.getMonth() + (direction === 'next' ? 1 : -1));
}
setCurrentDate(newDate);
};
const goToToday = () => {
setCurrentDate(new Date());
};
const filteredAppointments = selectedProfessional === 'all'
? appointments
: appointments.filter(app => app.professional === selectedProfessional);
return (
Agenda
{formatDate(currentDate)}
Atalhos: 'C' para calendário, 'F' para fila de espera
{}
{view !== 'month' && (
Hora
{timeSlots.map(time => (
{time}
))}
{currentDate.toLocaleDateString('pt-BR', { weekday: 'long', timeZone: 'America/Sao_Paulo' })}
{timeSlots.map(time => (
))}
{filteredAppointments.map(app => {
// parse appointment time in Brazil timezone
const d = new Date(app.time);
// extract hour/minute in America/Sao_Paulo using Intl.DateTimeFormat
const parts = new Intl.DateTimeFormat('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', timeZone: 'America/Sao_Paulo' }).formatToParts(d);
const hourPart = parts.find(p => p.type === 'hour')?.value ?? '00';
const minutePart = parts.find(p => p.type === 'minute')?.value ?? '00';
const hour = parseInt(hourPart, 10);
const minute = parseInt(minutePart, 10);
return (
onEditAppointment(app)}
>
{app.patient}
{String(hour).padStart(2,'0')}:{String(minute).padStart(2,'0')} - {app.type} {getTypeIcon(app.type)}
{professionals.find(p => p.id === app.professional)?.name}
{app.status === 'confirmed' ? 'confirmado' : app.status === 'pending' ? 'pendente' : 'ausente'}
);
})}
)}
{}
{view === 'month' && (
{filteredAppointments.map(app => {
const d = new Date(app.time);
const parts = new Intl.DateTimeFormat('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', timeZone: 'America/Sao_Paulo' }).formatToParts(d);
const hourPart = parts.find(p => p.type === 'hour')?.value ?? '00';
const minutePart = parts.find(p => p.type === 'minute')?.value ?? '00';
const hours = String(hourPart).padStart(2,'0');
const minutes = String(minutePart).padStart(2,'0');
return (
{app.patient}
{hours}:{minutes} - {app.type} {getTypeIcon(app.type)}
{professionals.find(p => p.id === app.professional)?.name}
{app.notes && (
{app.notes}
)}
);
})}
)}
);
}