import { addDays, subDays, addWeeks, subWeeks, addMonths, subMonths, endOfWeek, format, startOfWeek, } from 'date-fns' import { ptBR } from 'date-fns/locale' import { useState } from 'react' import { AgendaDailyView } from '../components/calendar/AgendaDailyView.jsx' import { AgendaWeeklyView } from '../components/calendar/AgendaWeeklyView.jsx' import { AgendaMonthlyView } from '../components/calendar/AgendaMonthlyView.jsx' import { useAgenda } from '../hooks/useAgenda.js' import { formatLocalDateInput, parseLocalDate } from '../utils/agendaDate.js' const statusFilters = [ { label: 'Todos', value: 'Todos' }, { label: 'Confirmadas', value: 'Confirmada' }, { label: 'Em triagem', value: 'Em triagem' }, { label: 'Aguardando', value: 'Aguardando' }, ] const viewFilters = [ { label: 'Dia', value: 'Dia' }, { label: 'Semana', value: 'Semana' }, { label: 'Mês', value: 'Mes' }, ] const appointmentTypeOptions = ['Retorno', 'Primeira consulta', 'Exame', 'Avaliação pre-op'] export function AgendaPage({ navigate }) { const [modalPatientSearch, setModalPatientSearch] = useState('') const [modalDoctorSearch, setModalDoctorSearch] = useState('') const { patients, professionals, currentProfessional, viewerProfile, agendaScope, loading, error, canCreateAppointment, activeView, setActiveView, baseDate, setBaseDate, status, setStatus, setDoctorFilter, doctorSearch, setDoctorSearch, unitFilter, setUnitFilter, modalOpen, setModalOpen, form, updateForm, handleCreate, visibleAppointments, availableSlots, slotsLoading, slotsError, } = useAgenda() if (loading) { return (

Carregando agenda...

) } const weekStart = startOfWeek(baseDate, { weekStartsOn: 0 }) const weekEnd = endOfWeek(baseDate, { weekStartsOn: 0 }) const isDoctorScope = agendaScope === 'doctor' const unitOptions = [ ...new Set( professionals .map((professional) => professional.unit) .filter(Boolean), ), ].sort((a, b) => a.localeCompare(b, 'pt-BR')) const filteredPatients = (() => { const query = normalizeSearch(modalPatientSearch) if (!query) return patients return patients.filter((patient) => [patient.name, patient.full_name, patient.nome, patient.cpf, patient.email] .filter(Boolean) .join(' ') .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') .toLowerCase() .includes(query), ) })() const filteredProfessionals = (() => { const query = normalizeSearch(modalDoctorSearch) if (!query) return professionals return professionals.filter((professional) => [professional.name, professional.email, professional.unit] .filter(Boolean) .join(' ') .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') .toLowerCase() .includes(query), ) })() const selectedPatient = patients.find((patient) => String(patient.id) === String(form.patientId)) const selectedProfessional = professionals.find((professional) => String(professional.id) === String(form.professionalId)) return (

Agenda

Perfil atual: {viewerProfile?.role || (isDoctorScope ? 'Médico' : 'Usuário')}

{activeView === 'Dia' && format(baseDate, "dd 'de' MMM", { locale: ptBR })} {activeView === 'Semana' && `${format(weekStart, 'dd MMM', { locale: ptBR })} - ${format(weekEnd, 'dd MMM', { locale: ptBR })}`} {activeView === 'Mes' && format(baseDate, 'MMMM yyyy', { locale: ptBR })}
{error ? (

Não foi possível liberar a agenda

{error}

Enquanto esse vínculo não existir na API, a tela fica bloqueada para evitar exibir consultas de outro médico.

) : (

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

Visualização: {activeView.toLowerCase()} | {visibleAppointments.length} registros visíveis

{viewFilters.map((view) => ( ))}
{statusFilters.map((filter) => ( ))}
{!isDoctorScope ? (
) : null}
{!isDoctorScope && (
Perfil atual: {viewerProfile?.role || 'Administrador'}
)}
{activeView === 'Semana' && ( navigate(`/pacientes/${appointment.patientId}`)} /> )} {activeView === 'Mes' && ( { setBaseDate(day) setActiveView('Dia') }} /> )} {activeView === 'Dia' && ( navigate(`/pacientes/${appointment.patientId}`)} /> )}
)} setModalOpen(false)} open={modalOpen} title="Novo agendamento">
{ const parsedDate = parseLocalDate(event.target.value) if (parsedDate) setBaseDate(parsedDate) }} type="date" value={formatLocalDateInput(baseDate)} /> { setModalPatientSearch(event.target.value) updateForm('patientId', '') }} placeholder="Pesquisar paciente" type="search" value={modalPatientSearch || getPatientLabel(selectedPatient)} /> { updateForm('patientId', patient.id) setModalPatientSearch(getPatientLabel(patient)) }} selectedId={form.patientId} />
{availableSlots.length ? ( ) : ( updateForm('time', event.target.value)} type="time" value={form.time} /> )} {slotsLoading ? ( Calculando horários... ) : null} {slotsError ? ( {slotsError} ) : null}
{isDoctorScope ? ( ) : ( <> { setModalDoctorSearch(event.target.value) updateForm('professionalId', '') }} placeholder="Pesquisar médico" type="search" value={modalDoctorSearch || selectedProfessional?.name || ''} /> professional.unit || professional.email} getLabel={(professional) => professional.name} items={filteredProfessionals.slice(0, 6)} onSelect={(professional) => { updateForm('professionalId', professional.id) setModalDoctorSearch(professional.name) }} selectedId={form.professionalId} /> )}
) } function DarkField({ children, label }) { return ( ) } function DarkModal({ children, onClose, open, title }) { if (!open) { return null } return (

{title}

{children}
) } function SearchResults({ emptyText, getDescription, getLabel, items, onSelect, selectedId }) { return (
{items.length ? ( items.map((item) => { const isSelected = String(item.id) === String(selectedId) return ( ) }) ) : (

{emptyText}

)}
) } function getPatientLabel(patient) { return patient?.name || patient?.full_name || patient?.nome || '' } function normalizeSearch(value) { return String(value || '') .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') .trim() .toLowerCase() }