import React, { useState, useMemo, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import API_KEY from '../components/utils/apiKeys.js'; import AgendamentoCadastroManager from '../pages/AgendamentoCadastroManager.jsx'; import { useAuth } from '../components/utils/AuthProvider.js'; import dayjs from 'dayjs'; import 'dayjs/locale/pt-br'; import isBetween from 'dayjs/plugin/isBetween'; import localeData from 'dayjs/plugin/localeData'; import { ChevronLeft, ChevronRight, Trash2 } from 'lucide-react'; import '../pages/style/Agendamento.css'; import '../pages/style/FilaEspera.css'; import Spinner from '../components/Spinner.jsx'; dayjs.locale('pt-br'); dayjs.extend(isBetween); dayjs.extend(localeData); const Agendamento = ({ setDictInfo }) => { const navigate = useNavigate(); const { getAuthorizationHeader, user } = useAuth(); console.log('USER NO AGENDAMENTO:', user); const [patientId, setPatientId] = useState('bf7d8323-05e1-437a-817c-f08eb5f174ef'); const [isLoading, setIsLoading] = useState(false); // começa false const [DictAgendamentosOrganizados, setDictAgendamentosOrganizados] = useState({}); const [filaEsperaData, setFilaDeEsperaData] = useState([]); const [FiladeEspera, setFiladeEspera] = useState(false); const [PageNovaConsulta, setPageConsulta] = useState(false); const [currentDate, setCurrentDate] = useState(dayjs()); const [selectedDay, setSelectedDay] = useState(dayjs()); const [quickJump, setQuickJump] = useState({ month: currentDate.month(), year: currentDate.year(), }); const [isCancelModalOpen, setIsCancelModalOpen] = useState(false); const [appointmentToCancel, setAppointmentToCancel] = useState(null); const [cancellationReason, setCancellationReason] = useState(''); const authHeader = useMemo( () => getAuthorizationHeader(), [getAuthorizationHeader] ); // Buscar consultas desse paciente const carregarDados = async () => { // só tenta buscar quando tiver header e patientId if (!authHeader) { console.warn('Header de autorização não disponível.'); return; } if (!patientId) { console.warn('patientId ainda não carregado, aguardando contexto.'); return; } setIsLoading(true); try { const myHeaders = new Headers({ Authorization: authHeader, apikey: API_KEY, }); const requestOptions = { method: 'GET', headers: myHeaders }; const response = await fetch( `https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments?select=*,doctors(full_name)&patient_id=eq.${patientId}`, requestOptions ); if (!response.ok) throw new Error(`Erro na requisição: ${response.statusText}`); const consultasBrutas = (await response.json()) || []; console.log('CONSULTAS BRUTAS PACIENTE:', consultasBrutas); const newDict = {}; const newFila = []; for (const agendamento of consultasBrutas) { const agendamentoMelhorado = { ...agendamento, medico_nome: agendamento.doctors?.full_name || 'Médico não informado', }; if (agendamento.status === 'requested') { newFila.push({ agendamento: agendamentoMelhorado, Infos: agendamentoMelhorado, }); } else { const diaAgendamento = dayjs( agendamento.scheduled_at ).format('YYYY-MM-DD'); if (newDict[diaAgendamento]) { newDict[diaAgendamento].push(agendamentoMelhorado); } else { newDict[diaAgendamento] = [agendamentoMelhorado]; } } } for (const key in newDict) { newDict[key].sort((a, b) => a.scheduled_at.localeCompare(b.scheduled_at) ); } setDictAgendamentosOrganizados(newDict); setFilaDeEsperaData(newFila); } catch (err) { console.error('Falha ao buscar ou processar agendamentos:', err); setDictAgendamentosOrganizados({}); setFilaDeEsperaData([]); } finally { setIsLoading(false); } }; // roda quando authHeader ou patientId mudarem useEffect(() => { carregarDados(); }, [authHeader, patientId]); // padrão recomendado para fetch com useEffect [web:46][web:82] const updateAppointmentStatus = async (id, updates) => { const myHeaders = new Headers({ Authorization: authHeader, apikey: API_KEY, 'Content-Type': 'application/json', }); const requestOptions = { method: 'PATCH', headers: myHeaders, body: JSON.stringify(updates), }; try { const response = await fetch( `https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments?id=eq.${id}`, requestOptions ); if (!response.ok) throw new Error('Falha ao atualizar o status.'); return true; } catch (error) { console.error('Erro de rede/servidor:', error); return false; } }; const handleCancelClick = (appointmentId) => { setAppointmentToCancel(appointmentId); setCancellationReason(''); setIsCancelModalOpen(true); }; const executeCancellation = async () => { if (!appointmentToCancel) return; setIsLoading(true); const motivo = cancellationReason.trim() || 'Cancelado pelo paciente (motivo não especificado)'; const success = await updateAppointmentStatus(appointmentToCancel, { status: 'cancelled', cancellation_reason: motivo, updated_at: new Date().toISOString(), }); setIsCancelModalOpen(false); setAppointmentToCancel(null); setCancellationReason(''); if (success) { alert('Solicitação cancelada com sucesso!'); setDictAgendamentosOrganizados((prev) => { const newDict = { ...prev }; for (const date in newDict) { newDict[date] = newDict[date].filter( (app) => app.id !== appointmentToCancel ); } return newDict; }); setFilaDeEsperaData((prev) => prev.filter((item) => item.agendamento.id !== appointmentToCancel) ); } else { alert('Falha ao cancelar a solicitação.'); } setIsLoading(false); }; const handleQuickJumpChange = (type, value) => setQuickJump((prev) => ({ ...prev, [type]: Number(value) })); const applyQuickJump = () => { const newDate = dayjs() .year(quickJump.year) .month(quickJump.month) .date(1); setCurrentDate(newDate); setSelectedDay(newDate); }; const dateGrid = useMemo(() => { const grid = []; const startOfMonth = currentDate.startOf('month'); let currentDay = startOfMonth.subtract(startOfMonth.day(), 'day'); for (let i = 0; i < 42; i++) { grid.push(currentDay); currentDay = currentDay.add(1, 'day'); } return grid; }, [currentDate]); const weekDays = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb']; const handleDateClick = (day) => setSelectedDay(day); if (isLoading) { return (
); } return (

Minhas consultas

{!PageNovaConsulta ? (
{!FiladeEspera ? (
{selectedDay.format('MMM')} {selectedDay.format('DD')}

{selectedDay.format('dddd')}

{selectedDay.format('D [de] MMMM [de] YYYY')}

Realizado
Confirmado
Agendado
Cancelado

Consultas para {selectedDay.format('DD/MM')}

{DictAgendamentosOrganizados[ selectedDay.format('YYYY-MM-DD') ]?.length > 0 ? ( DictAgendamentosOrganizados[ selectedDay.format('YYYY-MM-DD') ].map((app) => (
{dayjs(app.scheduled_at).add(3, 'hour').format('HH:mm')}
Consulta com Dr(a). {app.medico_nome}
{app.status !== 'cancelled' && dayjs(app.scheduled_at).isAfter(dayjs()) && ( )}
)) ) : (

Nenhuma consulta agendada para esta data.

)}

{currentDate.format('MMMM [de] YYYY')}

{weekDays.map((day) => (
{day}
))} {dateGrid.map((day, index) => { const appointmentsOnDay = DictAgendamentosOrganizados[ day.format('YYYY-MM-DD') ] || []; const cellClasses = `day-cell ${ day.isSame(currentDate, 'month') ? 'current-month' : 'other-month' } ${day.isSame(dayjs(), 'day') ? 'today' : ''} ${ day.isSame(selectedDay, 'day') ? 'selected' : '' }`; return (
handleDateClick(day)} > {day.format('D')} {appointmentsOnDay.length > 0 && (
{appointmentsOnDay.length}
)}
); })}
) : (

Minhas Solicitações em Fila de Espera

{filaEsperaData.length > 0 ? ( filaEsperaData.map((item) => ( )) ) : ( )}
Médico Solicitado Data da Solicitação Ações
Dr(a). {item.Infos?.medico_nome} {dayjs( item.agendamento.created_at ).format('DD/MM/YYYY HH:mm')}
Nenhuma solicitação na fila de espera.
)}
) : ( { carregarDados(); // recarrega consultas do paciente setPageConsulta(false); }} /> )} {isCancelModalOpen && (

Confirmação de Cancelamento

Qual o motivo do cancelamento?

)}
); }; export default Agendamento;