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, Edit, Trash2 } from 'lucide-react'; import "../pages/style/Agendamento.css"; import '../pages/style/FilaEspera.css'; import '../pages/style/TableDoctor.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(); const [isLoading, setIsLoading] = useState(true); 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(''); // Estados para filtro, ordenação e paginação da fila de espera const [waitlistSearch, setWaitlistSearch] = useState(''); const [waitSortKey, setWaitSortKey] = useState(null); const [waitSortDir, setWaitSortDir] = useState('asc'); const [waitPage, setWaitPage] = useState(1); const [waitPerPage, setWaitPerPage] = useState(10); const authHeader = useMemo(() => getAuthorizationHeader(), [getAuthorizationHeader]); useEffect(() => { const carregarDados = async () => { const patientId = user?.patient_id || "6e7f8829-0574-42df-9290-8dbb70f75ada"; if (!authHeader) { console.warn("Header de autorização não disponível."); setIsLoading(false); 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() || []; 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); } }; carregarDados(); }, [authHeader, user]); 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); // Filtro e ordenação da fila de espera const filaEsperaFiltrada = useMemo(() => { if (!waitlistSearch.trim()) return filaEsperaData; const term = waitlistSearch.toLowerCase(); return filaEsperaData.filter( (item) => (item?.Infos?.medico_nome?.toLowerCase() || '').includes(term) ); }, [waitlistSearch, filaEsperaData]); const applySortingWaitlist = (arr) => { if (!Array.isArray(arr) || !waitSortKey) return arr; const copy = [...arr]; if (waitSortKey === 'medico') { copy.sort((a, b) => (a?.Infos?.medico_nome || '').localeCompare(b?.Infos?.medico_nome || '')); } else if (waitSortKey === 'data') { copy.sort((a, b) => new Date(a?.agendamento?.created_at || 0) - new Date(b?.agendamento?.created_at || 0) ); } if (waitSortDir === 'desc') copy.reverse(); return copy; }; const filaEsperaOrdenada = applySortingWaitlist(filaEsperaFiltrada); const waitTotalPages = Math.ceil(filaEsperaOrdenada.length / waitPerPage) || 1; const waitIndiceInicial = (waitPage - 1) * waitPerPage; const waitIndiceFinal = waitIndiceInicial + waitPerPage; const filaEsperaPaginada = filaEsperaOrdenada.slice(waitIndiceInicial, waitIndiceFinal); const gerarNumerosWaitPages = () => { const paginas = []; const paginasParaMostrar = 5; let inicio = Math.max(1, waitPage - Math.floor(paginasParaMostrar / 2)); let fim = Math.min(waitTotalPages, inicio + paginasParaMostrar - 1); inicio = Math.max(1, fim - paginasParaMostrar + 1); for (let i = inicio; i <= fim; i++) paginas.push(i); return paginas; }; useEffect(() => { setWaitPage(1); }, [waitlistSearch, waitSortKey, waitSortDir]); if (isLoading) { return (
{selectedDay.format('D [de] MMMM [de] YYYY')}
Nenhuma consulta agendada para esta data.
| 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. |
||
Deseja realmente cancelar esta consulta?
Esta ação não pode ser desfeita.