import React, { useState, useMemo, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import API_KEY from "../components/utils/apiKeys.js"; import AgendamentoCadastroManager from "./AgendamentoCadastroManager.jsx"; import { GetPatientByID } from "../components/utils/Functions-Endpoints/Patient.js"; import TabelaAgendamentoDia from "../components/AgendarConsulta/TabelaAgendamentoDia"; import TabelaAgendamentoSemana from "../components/AgendarConsulta/TabelaAgendamentoSemana"; import TabelaAgendamentoMes from "../components/AgendarConsulta/TabelaAgendamentoMes"; import FormNovaConsulta from "../components/AgendarConsulta/FormNovaConsulta"; import { GetAllDoctors, GetDoctorByID, } from "../components/utils/Functions-Endpoints/Doctor.js"; 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 CalendarComponent from "../components/AgendarConsulta/CalendarComponent.jsx"; import "./style/Agendamento.css"; import "./style/FilaEspera.css"; import Spinner from "../components/Spinner.jsx"; dayjs.locale("pt-br"); dayjs.extend(isBetween); dayjs.extend(localeData); // Offset de horário para bater com o que o paciente marca (ajuste se precisar) const HORARIO_OFFSET = 3; // se a diferença for 2h, troca para 2 const Agendamento = ({ setDictInfo }) => { const navigate = useNavigate(); const [listaTodosAgendamentos, setListaTodosAgendamentos] = useState([]); const [selectedID, setSelectedId] = useState("0"); const [filaEsperaData, setFilaEsperaData] = useState([]); const [FiladeEspera, setFiladeEspera] = useState(false); const [PageNovaConsulta, setPageConsulta] = useState(false); const [searchTerm, setSearchTerm] = useState(""); const { getAuthorizationHeader } = useAuth(); const [DictAgendamentosOrganizados, setAgendamentosOrganizados] = useState( {} ); const [showDeleteModal, setShowDeleteModal] = useState(false); const [ListaDeMedicos, setListaDeMedicos] = useState([]); const [FiltredTodosMedicos, setFiltredTodosMedicos] = useState([]); const [searchTermDoctor, setSearchTermDoctor] = useState(""); const [doctorDropdownOpen, setDoctorDropdownOpen] = useState(false); const [MedicoFiltrado, setMedicoFiltrado] = useState({ id: "vazio" }); const [cacheAgendamentos, setCacheAgendamentos] = useState([]); const [appointmentToEdit, setAppointmentToEdit] = useState(null); const [showConfirmModal, setShowConfirmModal] = useState(false); const [motivoCancelamento, setMotivoCancelamento] = useState(""); const [showSpinner, setShowSpinner] = useState(true); 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 = getAuthorizationHeader(); const cacheMedicos = useMemo(() => ({}), []); const cachePacientes = useMemo(() => ({}), []); const [currentDate, setCurrentDate] = useState(dayjs()); const [selectedDay, setSelectedDay] = useState(dayjs()); const [editingAppointmentId, setEditingAppointmentId] = useState(null); const [quickJump, setQuickJump] = useState({ month: currentDate.month(), year: currentDate.year(), }); const fetchAppointments = async () => { const myHeaders = new Headers(); myHeaders.append("Authorization", authHeader); myHeaders.append("apikey", API_KEY); const requestOptions = { method: "GET", headers: myHeaders, redirect: "follow", }; try { const res = await fetch( "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments?select=*", requestOptions ); const data = await res.json(); setListaTodosAgendamentos(data); } catch (err) { console.error("Erro ao buscar agendamentos", err); } }; const updateAppointmentStatus = async (id, updates) => { const myHeaders = new Headers(); myHeaders.append("Authorization", authHeader); myHeaders.append("apikey", API_KEY); myHeaders.append("Content-Type", "application/json"); myHeaders.append("Prefer", "return=representation"); 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) { await fetchAppointments(); return true; } else { console.error("Erro ao atualizar agendamento:", await response.text()); return false; } } catch (error) { console.error("Erro de rede/servidor:", error); return false; } }; const deleteConsulta = async (id) => { setShowSpinner(true); const success = await updateAppointmentStatus(id, { status: "cancelled", cancellation_reason: motivoCancelamento, updated_at: new Date().toISOString(), }); setShowSpinner(false); if (success) { setShowDeleteModal(false); setMotivoCancelamento(""); setSelectedId("0"); } else { alert("Falha ao cancelar a consulta."); } }; const confirmConsulta = async (id) => { setShowSpinner(true); const success = await updateAppointmentStatus(id, { status: "agendado", cancellation_reason: null, updated_at: new Date().toISOString(), }); setShowSpinner(false); if (success) { setShowConfirmModal(false); setSelectedId("0"); } else { alert("Falha ao reverter o cancelamento."); } }; const handleQuickJumpChange = (type, value) => { setQuickJump((prev) => ({ ...prev, [type]: Number(value) })); }; useEffect(() => { setQuickJump({ month: currentDate.month(), year: currentDate.year(), }); }, [currentDate]); const applyQuickJump = () => { let newDate = dayjs().year(quickJump.year).month(quickJump.month).date(1); setCurrentDate(newDate); setSelectedDay(newDate); }; useEffect(() => { if (!listaTodosAgendamentos.length) { setShowSpinner(false); return; } setShowSpinner(true); const fetchDados = async () => { const newDict = {}; const newFila = []; for (const agendamento of listaTodosAgendamentos) { if (!agendamento.doctor_id || !agendamento.patient_id) continue; if (!cacheMedicos[agendamento.doctor_id]) { cacheMedicos[agendamento.doctor_id] = ( await GetDoctorByID(agendamento.doctor_id, authHeader) )[0]; } if (!cachePacientes[agendamento.patient_id]) { cachePacientes[agendamento.patient_id] = ( await GetPatientByID(agendamento.patient_id, authHeader) )[0]; } const medico = cacheMedicos[agendamento.doctor_id]; const paciente = cachePacientes[agendamento.patient_id]; const agendamentoMelhorado = { ...agendamento, medico_nome: medico?.full_name, paciente_nome: paciente?.full_name, paciente_cpf: paciente?.cpf, }; 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) ); } setAgendamentosOrganizados(newDict); setFilaEsperaData(newFila); setShowSpinner(false); }; fetchDados(); }, [listaTodosAgendamentos, authHeader, cacheMedicos, cachePacientes]); useEffect(() => { fetchAppointments(); GetAllDoctors(authHeader).then((docs) => setListaDeMedicos( docs.map((d) => ({ nomeMedico: d.full_name, idMedico: d.id })) ) ); }, [authHeader]); const handleSearchMedicos = (term) => {}; const filaEsperaFiltrada = useMemo(() => { if (!waitlistSearch.trim()) return filaEsperaData; const term = waitlistSearch.toLowerCase(); return filaEsperaData.filter( (item) => (item?.Infos?.paciente_nome?.toLowerCase() || "").includes(term) || (item?.Infos?.paciente_cpf?.toLowerCase() || "").includes(term) || (item?.Infos?.nome_medico?.toLowerCase() || "").includes(term) ); }, [waitlistSearch, filaEsperaData]); const applySortingWaitlist = (arr) => { if (!Array.isArray(arr) || !waitSortKey) return arr; const copy = [...arr]; if (waitSortKey === "paciente") { copy.sort((a, b) => (a?.Infos?.paciente_nome || "").localeCompare( b?.Infos?.paciente_nome || "" ) ); } else if (waitSortKey === "medico") { copy.sort((a, b) => (a?.Infos?.nome_medico || "").localeCompare(b?.Infos?.nome_medico || "") ); } else if (waitSortKey === "data") { copy.sort( (a, b) => new Date(a?.agendamento?.scheduled_at || 0) - new Date(b?.agendamento?.scheduled_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]); const generateDateGrid = () => { 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; }; const dateGrid = useMemo(() => generateDateGrid(), [currentDate]); const weekDays = ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"]; const handleDateClick = (day) => setSelectedDay(day); const DeleteModal = () => (
Qual o motivo do cancelamento?
Tem certeza que deseja retirar o cancelamento?
Isso reverterá o status do agendamento para Agendado.{selectedDay.format("D [de] MMMM [de] YYYY")}
Nenhuma consulta agendada.
| Nome do Paciente | CPF | Médico Solicitado | Data da Solicitação | Ações |
|---|---|---|---|---|
| {item?.Infos?.paciente_nome} | {item?.Infos?.paciente_cpf} | {item?.Infos?.medico_nome} | {dayjs(item.agendamento.scheduled_at).format("DD/MM/YYYY")} | |
|
{showSpinner ? (
Nenhuma solicitação encontrada. > )} |
||||