diff --git a/src/PagesMedico/DoctorAgendamentoManager.jsx b/src/PagesMedico/DoctorAgendamentoManager.jsx
index 7f0d77ed..34eb2946 100644
--- a/src/PagesMedico/DoctorAgendamentoManager.jsx
+++ b/src/PagesMedico/DoctorAgendamentoManager.jsx
@@ -1,654 +1,1018 @@
-import React, { useState, useMemo, useEffect, useCallback } from 'react';
-import { useNavigate } from 'react-router-dom';
-import API_KEY from '../components/utils/apiKeys.js';
-import AgendamentoCadastroManager from '../pages/AgendamentoCadastroManager.jsx';
+import React, { useState, useMemo, useEffect, useCallback } from "react";
+import { useNavigate } from "react-router-dom";
+import API_KEY from "../components/utils/apiKeys.js";
+import AgendamentoCadastroManager from "../pages/AgendamentoCadastroManager.jsx";
// Removidos imports não utilizados no novo fluxo
-import { GetAllDoctors } 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 { Search, ChevronLeft, ChevronRight, Edit, Trash2, CheckCircle } from 'lucide-react';
+import { GetAllDoctors } 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 {
+ Search,
+ ChevronLeft,
+ ChevronRight,
+ Edit,
+ Trash2,
+ CheckCircle,
+} from "lucide-react";
import "../pages/style/Agendamento.css";
-import '../pages/style/FilaEspera.css';
-import Spinner from '../components/Spinner.jsx';
+import "../pages/style/FilaEspera.css";
+import Spinner from "../components/Spinner.jsx";
-
-dayjs.locale('pt-br');
+dayjs.locale("pt-br");
dayjs.extend(isBetween);
dayjs.extend(localeData);
-
const Agendamento = () => {
- const navigate = useNavigate();
- const { getAuthorizationHeader, user } = useAuth();
- const authHeader = getAuthorizationHeader();
+ const navigate = useNavigate();
+ const { getAuthorizationHeader, user } = useAuth();
+ const authHeader = getAuthorizationHeader();
- // ID do médico que você quer visualizar
- const ID_MEDICO_ESPECIFICO = "078d2a67-b4c1-43c8-ae32-c1e75bb5b3df";
+ // ID do médico que você quer visualizar
+ const ID_MEDICO_ESPECIFICO = "078d2a67-b4c1-43c8-ae32-c1e75bb5b3df";
- const [listaTodosAgendamentos, setListaTodosAgendamentos] = useState([]);
- const [selectedID, setSelectedId] = useState('0');
- const [filaEsperaData, setFilaEsperaData] = useState([]);
- const [FiladeEspera, setFiladeEspera] = useState(false);
- const [PageNovaConsulta, setPageConsulta] = useState(false);
- const [DictAgendamentosOrganizados, setAgendamentosOrganizados] = useState({});
- const [showDeleteModal, setShowDeleteModal] = useState(false);
- const [ListaDeMedicos, setListaDeMedicos] = useState([]);
- const [FiltredTodosMedicos, setFiltredTodosMedicos] = useState([]);
- const [searchTermDoctor, setSearchTermDoctor] = useState('');
- const [MedicoFiltrado, setMedicoFiltrado] = useState({ id: "vazio" });
- 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 [cacheMedicos, setCacheMedicos] = useState({});
- const [cachePacientes, setCachePacientes] = useState({});
- const [currentDate, setCurrentDate] = useState(dayjs());
- const [selectedDay, setSelectedDay] = useState(dayjs());
- const [agendamentoParaEdicao, setAgendamentoParaEdicao] = useState(null);
- const [quickJump, setQuickJump] = useState({
- month: currentDate.month(),
- year: currentDate.year()
- });
+ const [listaTodosAgendamentos, setListaTodosAgendamentos] = useState([]);
+ const [selectedID, setSelectedId] = useState("0");
+ const [filaEsperaData, setFilaEsperaData] = useState([]);
+ const [FiladeEspera, setFiladeEspera] = useState(false);
+ const [PageNovaConsulta, setPageConsulta] = useState(false);
+ const [DictAgendamentosOrganizados, setAgendamentosOrganizados] = useState(
+ {}
+ );
+ const [showDeleteModal, setShowDeleteModal] = useState(false);
+ const [ListaDeMedicos, setListaDeMedicos] = useState([]);
+ const [FiltredTodosMedicos, setFiltredTodosMedicos] = useState([]);
+ const [searchTermDoctor, setSearchTermDoctor] = useState("");
+ const [MedicoFiltrado, setMedicoFiltrado] = useState({ id: "vazio" });
+ 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 [cacheMedicos, setCacheMedicos] = useState({});
+ const [cachePacientes, setCachePacientes] = useState({});
+ const [currentDate, setCurrentDate] = useState(dayjs());
+ const [selectedDay, setSelectedDay] = useState(dayjs());
+ const [agendamentoParaEdicao, setAgendamentoParaEdicao] = useState(null);
+ const [quickJump, setQuickJump] = useState({
+ month: currentDate.month(),
+ year: currentDate.year(),
+ });
- // ✨ ALTERAÇÃO PRINCIPAL: A busca agora filtra pelo ID do médico direto na API
- const fetchAppointments = useCallback(async () => {
- if (!authHeader) return;
- setShowSpinner(true);
- const myHeaders = new Headers();
- myHeaders.append("Authorization", authHeader);
- myHeaders.append("apikey", API_KEY);
- const requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' };
+ // ✨ ALTERAÇÃO PRINCIPAL: A busca agora filtra pelo ID do médico direto na API
+ const fetchAppointments = useCallback(async () => {
+ if (!authHeader) return;
+ setShowSpinner(true);
+ const myHeaders = new Headers();
+ myHeaders.append("Authorization", authHeader);
+ myHeaders.append("apikey", API_KEY);
+ const requestOptions = {
+ method: "GET",
+ headers: myHeaders,
+ redirect: "follow",
+ };
- // A URL agora contém o filtro para o ID do médico específico
- const apiUrl = `https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments?doctor_id=eq.${ID_MEDICO_ESPECIFICO}&select=*`;
+ // A URL agora contém o filtro para o ID do médico específico
+ const apiUrl = `https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments?doctor_id=eq.${ID_MEDICO_ESPECIFICO}&select=*`;
- try {
- const res = await fetch(apiUrl, requestOptions);
- const data = await res.json();
- setListaTodosAgendamentos(data || []);
- } catch (err) {
- console.error('Erro ao buscar agendamentos', err);
- setListaTodosAgendamentos([]);
- } finally {
- setShowSpinner(false);
- }
- }, [authHeader, ID_MEDICO_ESPECIFICO]);
+ try {
+ const res = await fetch(apiUrl, requestOptions);
+ const data = await res.json();
+ setListaTodosAgendamentos(data || []);
+ } catch (err) {
+ console.error("Erro ao buscar agendamentos", err);
+ setListaTodosAgendamentos([]);
+ } finally {
+ setShowSpinner(false);
+ }
+ }, [authHeader, ID_MEDICO_ESPECIFICO]);
-
- const updateAppointmentStatus = useCallback(async (id, updates) => {
- setShowSpinner(true);
- 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;
- } finally {
- setShowSpinner(false);
- }
- }, [authHeader, fetchAppointments]);
-
-
- const deleteConsulta = useCallback(async (id) => {
- const success = await updateAppointmentStatus(id, { status: "cancelled", cancellation_reason: motivoCancelamento, updated_at: new Date().toISOString() });
- if (success) {
- setShowDeleteModal(false);
- setMotivoCancelamento("");
- setSelectedId('0');
+ const updateAppointmentStatus = useCallback(
+ async (id, updates) => {
+ setShowSpinner(true);
+ 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 {
- alert("Falha ao cancelar a consulta.");
+ console.error(
+ "Erro ao atualizar agendamento:",
+ await response.text()
+ );
+ return false;
}
- }, [motivoCancelamento, updateAppointmentStatus]);
+ } catch (error) {
+ console.error("Erro de rede/servidor:", error);
+ return false;
+ } finally {
+ setShowSpinner(false);
+ }
+ },
+ [authHeader, fetchAppointments]
+ );
+ const deleteConsulta = useCallback(
+ async (id) => {
+ const success = await updateAppointmentStatus(id, {
+ status: "cancelled",
+ cancellation_reason: motivoCancelamento,
+ updated_at: new Date().toISOString(),
+ });
+ if (success) {
+ setShowDeleteModal(false);
+ setMotivoCancelamento("");
+ setSelectedId("0");
+ } else {
+ alert("Falha ao cancelar a consulta.");
+ }
+ },
+ [motivoCancelamento, updateAppointmentStatus]
+ );
- const confirmConsulta = useCallback(async (id) => {
- const success = await updateAppointmentStatus(id, { status: "agendado", cancellation_reason: null, updated_at: new Date().toISOString() });
- if (success) {
- setSelectedId('0');
- } else {
- alert("Falha ao reverter o cancelamento.");
+ const confirmConsulta = useCallback(
+ async (id) => {
+ const success = await updateAppointmentStatus(id, {
+ status: "agendado",
+ cancellation_reason: null,
+ updated_at: new Date().toISOString(),
+ });
+ if (success) {
+ setSelectedId("0");
+ } else {
+ alert("Falha ao reverter o cancelamento.");
+ }
+ },
+ [updateAppointmentStatus]
+ );
+
+ useEffect(() => {
+ if (authHeader) {
+ fetchAppointments();
+ // A busca de todos os médicos pode continuar caso a secretária precise ver a lista
+ if (user?.role !== "doctor") {
+ GetAllDoctors(authHeader).then((docs) => {
+ if (docs) {
+ setListaDeMedicos(
+ docs.map((d) => ({ nomeMedico: d.full_name, idMedico: d.id }))
+ );
+ }
+ });
+ }
+ }
+ }, [authHeader, fetchAppointments, user?.role]);
+
+ useEffect(() => {
+ const processData = async () => {
+ // Como os dados já vêm filtrados da API, não precisamos mais da verificação de 'user' aqui
+ if (!listaTodosAgendamentos.length) {
+ setAgendamentosOrganizados({});
+ setFilaEsperaData([]);
+ return;
+ }
+
+ setShowSpinner(true);
+
+ // ✨ SIMPLIFICAÇÃO: Não é mais necessário filtrar por `user.role`,
+ // pois a API já retornou apenas os agendamentos do médico desejado.
+ const appointmentsToShow = listaTodosAgendamentos;
+
+ const patientIdsToFetch = new Set();
+ const doctorIdsToFetch = new Set();
+
+ appointmentsToShow.forEach((ag) => {
+ if (ag.patient_id && !cachePacientes[ag.patient_id]) {
+ patientIdsToFetch.add(ag.patient_id);
}
- }, [updateAppointmentStatus]);
-
- useEffect(() => {
- if(authHeader) {
- fetchAppointments();
- // A busca de todos os médicos pode continuar caso a secretária precise ver a lista
- if (user?.role !== 'doctor') {
- GetAllDoctors(authHeader).then(docs => {
- if (docs) {
- setListaDeMedicos(docs.map(d => ({ nomeMedico: d.full_name, idMedico: d.id })));
- }
- });
- }
+ if (ag.doctor_id && !cacheMedicos[ag.doctor_id]) {
+ doctorIdsToFetch.add(ag.doctor_id);
}
- }, [authHeader, fetchAppointments, user?.role]);
+ });
- useEffect(() => {
- const processData = async () => {
- // Como os dados já vêm filtrados da API, não precisamos mais da verificação de 'user' aqui
- if (!listaTodosAgendamentos.length) {
- setAgendamentosOrganizados({});
- setFilaEsperaData([]);
- return;
+ const fetchPromises = [];
+
+ if (patientIdsToFetch.size > 0) {
+ const query = `id=in.(${Array.from(patientIdsToFetch).join(",")})`;
+ fetchPromises.push(
+ fetch(
+ `https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/patients?${query}&select=*`,
+ {
+ headers: { apikey: API_KEY, Authorization: authHeader },
}
+ ).then((res) => res.json())
+ );
+ } else {
+ fetchPromises.push(Promise.resolve(null)); // Mantém a ordem do Promise.all
+ }
- setShowSpinner(true);
-
- // ✨ SIMPLIFICAÇÃO: Não é mais necessário filtrar por `user.role`,
- // pois a API já retornou apenas os agendamentos do médico desejado.
- const appointmentsToShow = listaTodosAgendamentos;
-
- const patientIdsToFetch = new Set();
- const doctorIdsToFetch = new Set();
-
- appointmentsToShow.forEach(ag => {
- if (ag.patient_id && !cachePacientes[ag.patient_id]) {
- patientIdsToFetch.add(ag.patient_id);
- }
- if (ag.doctor_id && !cacheMedicos[ag.doctor_id]) {
- doctorIdsToFetch.add(ag.doctor_id);
- }
- });
-
- const fetchPromises = [];
-
- if (patientIdsToFetch.size > 0) {
- const query = `id=in.(${Array.from(patientIdsToFetch).join(',')})`;
- fetchPromises.push(
- fetch(`https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/patients?${query}&select=*`, {
- headers: { apikey: API_KEY, Authorization: authHeader }
- }).then(res => res.json())
- );
- } else {
- fetchPromises.push(Promise.resolve(null)); // Mantém a ordem do Promise.all
+ if (doctorIdsToFetch.size > 0) {
+ const query = `id=in.(${Array.from(doctorIdsToFetch).join(",")})`;
+ fetchPromises.push(
+ fetch(
+ `https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors?${query}&select=id,full_name`,
+ {
+ headers: { apikey: API_KEY, Authorization: authHeader },
}
+ ).then((res) => res.json())
+ );
+ } else {
+ fetchPromises.push(Promise.resolve(null));
+ }
- if (doctorIdsToFetch.size > 0) {
- const query = `id=in.(${Array.from(doctorIdsToFetch).join(',')})`;
- fetchPromises.push(
- fetch(`https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors?${query}&select=id,full_name`, {
- headers: { apikey: API_KEY, Authorization: authHeader }
- }).then(res => res.json())
- );
- } else {
- fetchPromises.push(Promise.resolve(null));
- }
-
- const [newPatients, newDoctors] = await Promise.all(fetchPromises);
+ const [newPatients, newDoctors] = await Promise.all(fetchPromises);
- const updatedPatientCache = { ...cachePacientes };
- if (newPatients) newPatients.forEach(p => updatedPatientCache[p.id] = p);
+ const updatedPatientCache = { ...cachePacientes };
+ if (newPatients)
+ newPatients.forEach((p) => (updatedPatientCache[p.id] = p));
- const updatedDoctorCache = { ...cacheMedicos };
- if (newDoctors) newDoctors.forEach(d => updatedDoctorCache[d.id] = d);
-
- setCachePacientes(updatedPatientCache);
- setCacheMedicos(updatedDoctorCache);
+ const updatedDoctorCache = { ...cacheMedicos };
+ if (newDoctors) newDoctors.forEach((d) => (updatedDoctorCache[d.id] = d));
- const newDict = {};
- const newFila = [];
+ setCachePacientes(updatedPatientCache);
+ setCacheMedicos(updatedDoctorCache);
- for (const agendamento of appointmentsToShow) {
- const medico = updatedDoctorCache[agendamento.doctor_id];
- const paciente = updatedPatientCache[agendamento.patient_id];
+ const newDict = {};
+ const newFila = [];
- if (!medico || !paciente) continue;
+ for (const agendamento of appointmentsToShow) {
+ const medico = updatedDoctorCache[agendamento.doctor_id];
+ const paciente = updatedPatientCache[agendamento.patient_id];
- const agendamentoMelhorado = {
- ...agendamento,
- medico_nome: medico.full_name || 'N/A',
- paciente_nome: paciente.full_name || 'N/A',
- paciente_cpf: paciente.cpf || 'N/A'
- };
+ if (!medico || !paciente) continue;
- 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] = [];
- newDict[DiaAgendamento].push(agendamentoMelhorado);
- }
- }
-
- for (const key in newDict) {
- newDict[key].sort((a, b) => new Date(a.scheduled_at) - new Date(b.scheduled_at));
- }
-
- setAgendamentosOrganizados(newDict);
- setFilaEsperaData(newFila);
- setShowSpinner(false);
+ const agendamentoMelhorado = {
+ ...agendamento,
+ medico_nome: medico.full_name || "N/A",
+ paciente_nome: paciente.full_name || "N/A",
+ paciente_cpf: paciente.cpf || "N/A",
};
- processData();
- }, [listaTodosAgendamentos, authHeader]); // Removido 'user' das dependências pois não é mais usado aqui
-
- // O restante do código permanece o mesmo...
-
- const handleEditConsulta = (agendamento) => {
- setAgendamentoParaEdicao(agendamento);
- setPageConsulta(true);
- };
-
- const handleSearchMedicos = (term) => {
- setSearchTermDoctor(term);
- if (term.trim()) {
- const filtered = ListaDeMedicos.filter(medico =>
- medico.nomeMedico.toLowerCase().includes(term.toLowerCase())
- );
- setFiltredTodosMedicos(filtered);
+ if (agendamento.status === "requested") {
+ newFila.push({
+ agendamento: agendamentoMelhorado,
+ Infos: agendamentoMelhorado,
+ });
} else {
- setFiltredTodosMedicos([]);
- setMedicoFiltrado({ id: "vazio" });
+ const DiaAgendamento = dayjs(agendamento.scheduled_at).format(
+ "YYYY-MM-DD"
+ );
+ if (!newDict[DiaAgendamento]) newDict[DiaAgendamento] = [];
+ newDict[DiaAgendamento].push(agendamentoMelhorado);
}
- };
-
- 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 = () => (
-
-
-
-
-
Confirmação de Cancelamento
-
-
-
-
Qual o motivo do cancelamento? (Opcional)
-
-
-
-
- {/* ✨ Botão sempre ativo ✨ */}
-
-
-
-
-
-);
-
-
- useEffect(() => {
- setQuickJump({
- month: currentDate.month(),
- year: currentDate.year()
- });
- }, [currentDate]);
-
- 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?.medico_nome?.toLowerCase() || '').includes(term)
+ for (const key in newDict) {
+ newDict[key].sort(
+ (a, b) => new Date(a.scheduled_at) - new Date(b.scheduled_at)
);
- }, [waitlistSearch, filaEsperaData]);
+ }
- const applySortingWaitlist = useCallback((arr) => {
- if (!Array.isArray(arr) || !waitSortKey) return arr;
- const copy = [...arr];
- const key = waitSortKey;
- const dir = waitSortDir === 'asc' ? 1 : -1;
- copy.sort((a, b) => {
- const valA = key === 'data' ? new Date(a.agendamento.scheduled_at) : (a.Infos?.[`${key}_nome`] || '');
- const valB = key === 'data' ? new Date(b.agendamento.scheduled_at) : (b.Infos?.[`${key}_nome`] || '');
- if (valA < valB) return -1 * dir;
- if (valA > valB) return 1 * dir;
- return 0;
- });
- return copy;
- }, [waitSortKey, waitSortDir]);
-
- const filaEsperaOrdenada = useMemo(() => applySortingWaitlist(filaEsperaFiltrada), [filaEsperaFiltrada, applySortingWaitlist]);
- 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;
+ setAgendamentosOrganizados(newDict);
+ setFilaEsperaData(newFila);
+ setShowSpinner(false);
};
- useEffect(() => { setWaitPage(1); }, [waitlistSearch, waitSortKey, waitSortDir]);
+ processData();
+ }, [listaTodosAgendamentos, authHeader]); // Removido 'user' das dependências pois não é mais usado aqui
- const handleQuickJumpChange = (type, value) => {
- setQuickJump(prev => ({ ...prev, [type]: Number(value) }));
- };
+ // O restante do código permanece o mesmo...
- const applyQuickJump = () => {
- let newDate = dayjs().year(quickJump.year).month(quickJump.month).date(1);
- setCurrentDate(newDate);
- setSelectedDay(newDate);
- };
+ const handleEditConsulta = (agendamento) => {
+ setAgendamentoParaEdicao(agendamento);
+ setPageConsulta(true);
+ };
- return (
-
-
Agendar nova consulta
-
-
-
-
-
- {!PageNovaConsulta ? (
-
- {user?.role !== 'doctor' && (
-
-
-
-
-
- handleSearchMedicos(e.target.value)} />
-
-
- {searchTermDoctor && FiltredTodosMedicos.length > 0 && (
-
- {FiltredTodosMedicos.map((medico) => (
-
{
- setSearchTermDoctor(medico.nomeMedico);
- setFiltredTodosMedicos([]);
- setMedicoFiltrado({ id: medico.idMedico });
- }}
- >
-
{medico.nomeMedico}
-
- ))}
-
- )}
-
-
-
- )}
-
-
-
-
-
- {!FiladeEspera ? (
-
-
-
{selectedDay.format('MMM')}{selectedDay.format('DD')}
-
{selectedDay.format('dddd')}
{selectedDay.format('D [de] MMMM [de] YYYY')}
-
-
Consultas para {selectedDay.format('DD/MM')}
- {showSpinner ?
: (DictAgendamentosOrganizados[selectedDay.format('YYYY-MM-DD')]?.filter(app => MedicoFiltrado.id === "vazio" || app.doctor_id === MedicoFiltrado.id).length > 0) ? (
- DictAgendamentosOrganizados[selectedDay.format('YYYY-MM-DD')]
- .filter(app => MedicoFiltrado.id === "vazio" || app.doctor_id === MedicoFiltrado.id)
- .map(app => (
-
-
{dayjs(app.scheduled_at).format('HH:mm')}
-
{app.paciente_nome}Dr(a). {app.medico_nome}
-
- {app.status === 'cancelled' ? (
-
- ) : (
-
- )}
- {app.status !== 'cancelled' && (
-
- )}
-
-
- ))
- ) : (
Nenhuma consulta agendada.
)}
-
-
-
-
-
Realizado
-
Confirmado
-
Agendado
-
Cancelado
-
-
-
-
{currentDate.format('MMMM [de] YYYY')}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {weekDays.map(day =>
{day}
)}
- {dateGrid.map((day, index) => {
- const dayString = day.format('YYYY-MM-DD');
- const appointmentsOnDay = DictAgendamentosOrganizados[dayString] || [];
- const filteredAppointments = appointmentsOnDay.filter(app => MedicoFiltrado.id === "vazio" || app.doctor_id === MedicoFiltrado.id);
- 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')}
- {filteredAppointments.length > 0 &&
{filteredAppointments.length}
}
-
- );
- })}
-
-
-
- ) : (
-
-
-
-
-
Fila de Espera
-
-
-
Filtros
-
setWaitlistSearch(e.target.value)} />Digite o nome do paciente, CPF ou nome do médico
-
-
- Ordenar por:
-
-
-
-
-
{filaEsperaFiltrada.length} DE {filaEsperaData.length} SOLICITAÇÕES ENCONTRADAS
-
-
-
-
-
-
- | Nome do Paciente |
- CPF |
- Médico Solicitado |
- Data da Solicitação |
- Ações |
-
-
-
- {filaEsperaPaginada.length > 0 ? (
- filaEsperaPaginada.map((item, index) => (
-
- | {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. >)}
-
- |
-
- )}
-
-
- {filaEsperaFiltrada.length > 0 && (
-
-
- Itens por página:
-
-
-
-
Página {waitPage} de {waitTotalPages} • Mostrando {waitIndiceInicial + 1}-{Math.min(waitIndiceFinal, filaEsperaFiltrada.length)} de {filaEsperaFiltrada.length}
-
-
-
- )}
-
-
-
-
-
-
- )}
-
-
- ) : (
-
{
- setPageConsulta(false);
- fetchAppointments();
- }}
- />
- )}
- {showDeleteModal && }
+ const handleSearchMedicos = (term) => {
+ setSearchTermDoctor(term);
+ if (term.trim()) {
+ const filtered = ListaDeMedicos.filter((medico) =>
+ medico.nomeMedico.toLowerCase().includes(term.toLowerCase())
+ );
+ setFiltredTodosMedicos(filtered);
+ } else {
+ setFiltredTodosMedicos([]);
+ setMedicoFiltrado({ id: "vazio" });
+ }
+ };
+
+ 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 = () => (
+
+
+
+
+
Confirmação de Cancelamento
+
+
+
+
Qual o motivo do cancelamento? (Opcional)
+
+
+
+
+ {/* ✨ Botão sempre ativo ✨ */}
+
+
+
+
+ );
+
+ useEffect(() => {
+ setQuickJump({
+ month: currentDate.month(),
+ year: currentDate.year(),
+ });
+ }, [currentDate]);
+
+ 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?.medico_nome?.toLowerCase() || "").includes(term)
);
-}
+ }, [waitlistSearch, filaEsperaData]);
+
+ const applySortingWaitlist = useCallback(
+ (arr) => {
+ if (!Array.isArray(arr) || !waitSortKey) return arr;
+ const copy = [...arr];
+ const key = waitSortKey;
+ const dir = waitSortDir === "asc" ? 1 : -1;
+ copy.sort((a, b) => {
+ const valA =
+ key === "data"
+ ? new Date(a.agendamento.scheduled_at)
+ : a.Infos?.[`${key}_nome`] || "";
+ const valB =
+ key === "data"
+ ? new Date(b.agendamento.scheduled_at)
+ : b.Infos?.[`${key}_nome`] || "";
+ if (valA < valB) return -1 * dir;
+ if (valA > valB) return 1 * dir;
+ return 0;
+ });
+ return copy;
+ },
+ [waitSortKey, waitSortDir]
+ );
+
+ const filaEsperaOrdenada = useMemo(
+ () => applySortingWaitlist(filaEsperaFiltrada),
+ [filaEsperaFiltrada, applySortingWaitlist]
+ );
+ 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 handleQuickJumpChange = (type, value) => {
+ setQuickJump((prev) => ({ ...prev, [type]: Number(value) }));
+ };
+
+ const applyQuickJump = () => {
+ let newDate = dayjs().year(quickJump.year).month(quickJump.month).date(1);
+ setCurrentDate(newDate);
+ setSelectedDay(newDate);
+ };
+
+ return (
+
+
Agendar nova consulta
+ {!PageNovaConsulta ? (
+
+ {user?.role !== "doctor" && (
+
+
+
+
+
+ handleSearchMedicos(e.target.value)}
+ />
+
+
+ {searchTermDoctor && FiltredTodosMedicos.length > 0 && (
+
+ {FiltredTodosMedicos.map((medico) => (
+
{
+ setSearchTermDoctor(medico.nomeMedico);
+ setFiltredTodosMedicos([]);
+ setMedicoFiltrado({ id: medico.idMedico });
+ }}
+ >
+
{medico.nomeMedico}
+
+ ))}
+
+ )}
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+ {!FiladeEspera ? (
+
+
+
+ {selectedDay.format("MMM")}
+ {selectedDay.format("DD")}
+
+
+
{selectedDay.format("dddd")}
+
{selectedDay.format("D [de] MMMM [de] YYYY")}
+
+
+
Consultas para {selectedDay.format("DD/MM")}
+ {showSpinner ? (
+
+ ) : DictAgendamentosOrganizados[
+ selectedDay.format("YYYY-MM-DD")
+ ]?.filter(
+ (app) =>
+ MedicoFiltrado.id === "vazio" ||
+ app.doctor_id === MedicoFiltrado.id
+ ).length > 0 ? (
+ DictAgendamentosOrganizados[
+ selectedDay.format("YYYY-MM-DD")
+ ]
+ .filter(
+ (app) =>
+ MedicoFiltrado.id === "vazio" ||
+ app.doctor_id === MedicoFiltrado.id
+ )
+ .map((app) => (
+
+
+ {dayjs(app.scheduled_at).format("HH:mm")}
+
+
+ {app.paciente_nome}
+ Dr(a). {app.medico_nome}
+
+
+ {app.status === "cancelled" ? (
+
+ ) : (
+
+ )}
+ {app.status !== "cancelled" && (
+
+ )}
+
+
+ ))
+ ) : (
+
+
Nenhuma consulta agendada.
+
+ )}
+
+
+
+
+
+ Realizado
+
+
+ Confirmado
+
+
+ Agendado
+
+
+ Cancelado
+
+
+
+
+
{currentDate.format("MMMM [de] YYYY")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {weekDays.map((day) => (
+
+ {day}
+
+ ))}
+ {dateGrid.map((day, index) => {
+ const dayString = day.format("YYYY-MM-DD");
+ const appointmentsOnDay =
+ DictAgendamentosOrganizados[dayString] || [];
+ const filteredAppointments = appointmentsOnDay.filter(
+ (app) =>
+ MedicoFiltrado.id === "vazio" ||
+ app.doctor_id === MedicoFiltrado.id
+ );
+ 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")}
+ {filteredAppointments.length > 0 && (
+
+ {filteredAppointments.length}
+
+ )}
+
+ );
+ })}
+
+
+
+ ) : (
+
+
+
+
+
+
Fila de Espera
+
+
+
+
+ {" "}
+ Filtros
+
+
+
+ setWaitlistSearch(e.target.value)
+ }
+ />
+
+ Digite o nome do paciente, CPF ou nome do médico
+
+
+
+
+
+ Ordenar por:
+
+
+
+
+
+
+ {filaEsperaFiltrada.length} DE{" "}
+ {filaEsperaData.length} SOLICITAÇÕES ENCONTRADAS
+
+
+
+
+
+
+
+ | Nome do Paciente |
+ CPF |
+ Médico Solicitado |
+ Data da Solicitação |
+ Ações |
+
+
+
+ {filaEsperaPaginada.length > 0 ? (
+ filaEsperaPaginada.map((item, index) => (
+
+ | {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.
+
+ >
+ )}
+
+ |
+
+ )}
+
+
+ {filaEsperaFiltrada.length > 0 && (
+
+
+
+ Itens por página:
+
+
+
+
+
+ Página {waitPage} de {waitTotalPages} •
+ Mostrando {waitIndiceInicial + 1}-
+ {Math.min(
+ waitIndiceFinal,
+ filaEsperaFiltrada.length
+ )}{" "}
+ de {filaEsperaFiltrada.length}
+
+
+
+
+ )}
+
+
+
+
+
+
+ )}
+
+
+ ) : (
+
{
+ setPageConsulta(false);
+ fetchAppointments();
+ }}
+ />
+ )}
+ {showDeleteModal && }
+
+ );
+};
export default Agendamento;
diff --git a/src/pages/FinanceiroDashboard.jsx b/src/pages/FinanceiroDashboard.jsx
index b3768ce8..d2bf7727 100644
--- a/src/pages/FinanceiroDashboard.jsx
+++ b/src/pages/FinanceiroDashboard.jsx
@@ -86,7 +86,7 @@ function mockFetchPagamentos() {
{
id: "PAY-001",
paciente: { nome: "Sarah Oliveira", convenio: "Unimed" },
- valor: 20000,
+ valor: 20000,
forma_pagamento: "Cartão",
data_vencimento: "2025-09-30",
status: "pendente",
@@ -96,7 +96,7 @@ function mockFetchPagamentos() {
{
id: "PAY-002",
paciente: { nome: "Laissa Marquetti", convenio: "Bradesco Saúde" },
- valor: 15000,
+ valor: 15000,
forma_pagamento: "Dinheiro",
data_vencimento: "2025-09-15",
status: "pago",
@@ -106,14 +106,14 @@ function mockFetchPagamentos() {
{
id: "PAY-003",
paciente: { nome: "Vera Santos", convenio: "Particular" },
- valor: 30000,
+ valor: 30000,
forma_pagamento: "Pix",
data_vencimento: "2025-09-20",
- status: "vencido",
+ status: "vencido",
desconto: 0,
observacoes: "Não respondeu ao contato"
},
- {
+ {
id: "PAY-004",
paciente: { nome: "Carlos Almeida", convenio: "Particular" },
valor: 10000,
@@ -169,7 +169,7 @@ export default function FinanceiroDashboard() {
recebido += valorLiquido;
descontos += p.desconto;
} else {
- aReceber += p.valor;
+ aReceber += valorLiquido;
}
});
@@ -244,8 +244,7 @@ export default function FinanceiroDashboard() {