import { format, isToday } from 'date-fns' import { ptBR } from 'date-fns/locale' import { sortAppointmentsByTime } from '../../utils/agendaDate.js' const DAY_START = '07:00' const DAY_END = '19:00' const SLOT_MINUTES = 30 export function AgendaDailyView({ baseDate, appointments, canCreateAppointment = true, onAppointmentClick, onSlotCreate }) { const dailyAppointments = sortAppointmentsByTime(appointments) const appointmentsByTime = groupAppointmentsByTime(dailyAppointments) const slots = mergeSlotsWithAppointmentTimes(generateSlots(DAY_START, DAY_END, SLOT_MINUTES), dailyAppointments) return (
Grade de horários do dia

{format(baseDate, "EEEE, dd 'de' MMMM", { locale: ptBR })}

{dailyAppointments.length} {dailyAppointments.length === 1 ? 'agendamento' : 'agendamentos'} Livre Agendado {isToday(baseDate) && ( Hoje )}
{slots.map((time) => { const slotAppointments = appointmentsByTime.get(time) || [] const primaryAppointment = slotAppointments[0] const isBooked = Boolean(primaryAppointment) return (

{time}

{isBooked ? 'Agendado' : 'Disponível'}

{isBooked ? (

{primaryAppointment.type} com {primaryAppointment.professional}

{primaryAppointment.room ? {primaryAppointment.room} : null} {primaryAppointment.mode ? {primaryAppointment.mode} : null} {slotAppointments.length > 1 ? +{slotAppointments.length - 1} : null}
) : (
Horário disponível para novo agendamento.
)}
{isBooked ? primaryAppointment.status : 'Livre'} {canCreateAppointment ? ( ) : null}
) })}
) } function getDailyToneClass(status) { switch (status) { case 'Confirmada': return 'agenda-slot-confirmed' case 'Em triagem': return 'agenda-slot-triage' case 'Cancelada': return 'agenda-slot-cancelled' case 'Bloqueado': return 'agenda-slot-blocked' case 'Aguardando': default: return 'agenda-slot-waiting' } } function generateSlots(start, end, intervalMinutes) { const [startHour, startMinute] = start.split(':').map(Number) const [endHour, endMinute] = end.split(':').map(Number) const slots = [] let cursor = startHour * 60 + startMinute const last = endHour * 60 + endMinute while (cursor < last) { slots.push(formatMinutes(cursor)) cursor += intervalMinutes } return slots } function groupAppointmentsByTime(appointments) { return appointments.reduce((map, appointment) => { const time = normalizeTime(appointment.time) if (!time) return map map.set(time, [...(map.get(time) || []), appointment]) return map }, new Map()) } function mergeSlotsWithAppointmentTimes(slots, appointments) { return [...new Set([...slots, ...appointments.map((appointment) => normalizeTime(appointment.time)).filter(Boolean)])] .sort((first, second) => minutesFromTime(first) - minutesFromTime(second)) } function normalizeTime(value) { const match = String(value || '').match(/^(\d{1,2}):(\d{2})/) if (!match) return '' return `${match[1].padStart(2, '0')}:${match[2]}` } function minutesFromTime(value) { const [hours, minutes] = normalizeTime(value).split(':').map(Number) return hours * 60 + minutes } function formatMinutes(totalMinutes) { const hours = String(Math.floor(totalMinutes / 60)).padStart(2, '0') const minutes = String(totalMinutes % 60).padStart(2, '0') return `${hours}:${minutes}` }