diff --git a/src/components/doctors/DoctorForm.jsx b/src/components/doctors/DoctorForm.jsx index e89df68..f677327 100644 --- a/src/components/doctors/DoctorForm.jsx +++ b/src/components/doctors/DoctorForm.jsx @@ -7,6 +7,7 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { const navigate = useNavigate(); const location = useLocation(); + const FormatTelefones = (valor) => { const digits = String(valor).replace(/\D/g, "").slice(0, 11); return digits @@ -28,7 +29,6 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { const cpfLimpo = cpf.replace(/\D/g, ""); if (cpfLimpo.length !== 11) return false; - if (/^(\d)\1+$/.test(cpfLimpo)) return false; let soma = 0; @@ -51,6 +51,7 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { ); }; + const [avatarUrl, setAvatarUrl] = useState(null); const [showRequiredModal, setShowRequiredModal] = useState(false); const [emptyFields, setEmptyFields] = useState([]); @@ -122,6 +123,10 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { } }; + const handleAvailabilityUpdate = (newAvailability) => { + setFormData((prev) => ({ ...prev, availability: newAvailability })); + }; + const handleCepBlur = async () => { const cep = formData.cep?.replace(/\D/g, ""); if (cep && cep.length === 8) { @@ -250,8 +255,10 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { setShowRequiredModal(false); }; + return ( <> + {/* Modal de Alerta */} {showRequiredModal && (
@@ -299,6 +306,7 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) {
)} + {/* Formulário Principal */}

MediConnect

@@ -319,6 +327,7 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { }`} >
+ {/* Foto / Avatar */}
{avatarUrl ? ( @@ -354,6 +363,7 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) {
+ {/* Nome Completo */}
+ {/* Data de Nascimento */}
+ {/* CPF */}
+ {/* Estado do CRM */}
+ {/* Especialização */}
+ {/* Telefone 1 (Principal) */}
+ {/* Telefone 2 (Opcional) */}
+ {/* CEP */}
+ {/* Rua */}
+ {/* Bairro */}
+ {/* Cidade */}
+ {/* Estado */}
+ {/* Número */}
+ {/* Complemento */}
{/* HORÁRIOS */} -
-

handleToggleCollapse("horarios")} - > - Horários - - {collapsedSections.horarios ? "▲" : "▼"} - -

- -
- { - console.log("Disponibilidades atualizadas:", dados); - // Se quiser salvar no formData: - // setFormData(prev => ({ ...prev, disponibilidades: dados })); - }} - /> -
+
+

handleToggleCollapse("horarios")} + > + Horários de Atendimento + + {collapsedSections.horarios ? "▲" : "▼"} + +

+
+
+
+

+ Defina seus horários de atendimento para cada dia da semana. + Marque um dia para começar a adicionar blocos de tempo. +

+
+
+
+
-
- - {/* BOTÕES DE AÇÃO */} + {/* BOTÕES DE AÇÃO */}
+
); } diff --git a/src/components/doctors/HorariosDisponibilidade.jsx b/src/components/doctors/HorariosDisponibilidade.jsx index eac2c93..c241912 100644 --- a/src/components/doctors/HorariosDisponibilidade.jsx +++ b/src/components/doctors/HorariosDisponibilidade.jsx @@ -1,106 +1,401 @@ -import React, { useState } from "react"; +import React, { useState, useEffect, useCallback } from "react"; +import { Clock } from "lucide-react"; -const diasDaSemana = [ - "segunda", - "terca", - "quarta", - "quinta", - "sexta", - "sabado", - "domingo" +const initialBlockTemplate = { + id: null, + inicio: "09:00", + termino: "17:00", + isNew: true, +}; + +const emptyAvailabilityTemplate = [ + { dia: "Segunda-feira", isChecked: false, blocos: [] }, + { dia: "Terça-feira", isChecked: false, blocos: [] }, + { dia: "Quarta-feira", isChecked: false, blocos: [] }, + { dia: "Quinta-feira", isChecked: false, blocos: [] }, + { dia: "Sexta-feira", isChecked: false, blocos: [] }, + { dia: "Sábado", isChecked: false, blocos: [] }, + { dia: "Domingo", isChecked: false, blocos: [] }, ]; -export default function HorariosDisponibilidade({ onChange }) { - const [disponibilidades, setDisponibilidades] = useState( - diasDaSemana.map(dia => ({ - weekday: dia, - slots: [{ start_time: "09:00", end_time: "17:00" }], - ativo: false, - })) - ); +const HorariosDisponibilidade = ({ + initialAvailability = emptyAvailabilityTemplate, + onUpdate, +}) => { + const [availability, setAvailability] = useState(initialAvailability); - function handleToggleDia(index) { - const updated = [...disponibilidades]; - updated[index].ativo = !updated[index].ativo; - setDisponibilidades(updated); - onChange?.(updated); - } + useEffect(() => { + if (initialAvailability !== emptyAvailabilityTemplate) { + setAvailability(initialAvailability); + } + }, [initialAvailability]); - function handleSlotChange(indexDia, indexSlot, campo, valor) { - const updated = [...disponibilidades]; - updated[indexDia].slots[indexSlot][campo] = valor; - setDisponibilidades(updated); - onChange?.(updated); - } + useEffect(() => { + if (onUpdate) { + onUpdate(availability); + } + }, [availability, onUpdate]); - function handleAddSlot(indexDia) { - const updated = [...disponibilidades]; - updated[indexDia].slots.push({ start_time: "", end_time: "" }); - setDisponibilidades(updated); - onChange?.(updated); - } + const handleDayCheck = useCallback((dayIndex, currentIsChecked) => { + const isChecked = !currentIsChecked; - function handleRemoveSlot(indexDia, indexSlot) { - const updated = [...disponibilidades]; - updated[indexDia].slots.splice(indexSlot, 1); - setDisponibilidades(updated); - onChange?.(updated); - } + setAvailability((prev) => + prev.map((day, i) => + i === dayIndex + ? { + ...day, + isChecked, + blocos: isChecked + ? day.blocos.length === 0 + ? [ + { + ...initialBlockTemplate, + id: Date.now() + Math.random(), + isNew: true, + }, + ] + : day.blocos + : [], + } + : day + ) + ); + }, []); - return ( -
- {disponibilidades.map((dia, i) => ( -
-
- + const handleAddBlock = useCallback((dayIndex) => { + const tempId = Date.now() + Math.random(); + const newBlock = { ...initialBlockTemplate, id: tempId, isNew: true }; + + setAvailability((prev) => + prev.map((day, i) => + i === dayIndex + ? { + ...day, + blocos: [...day.blocos, newBlock], + isChecked: true, + } + : day + ) + ); + }, []); + + const handleRemoveBlock = useCallback((dayIndex, blockId) => { + setAvailability((prev) => + prev.map((day, i) => { + if (i === dayIndex) { + const newBlocos = day.blocos.filter((bloco) => bloco.id !== blockId); + return { + ...day, + blocos: newBlocos, + isChecked: newBlocos.length > 0, + }; + } + return day; + }) + ); + }, []); + + const handleTimeChange = useCallback((dayIndex, blockId, field, value) => { + setAvailability((prev) => + prev.map((day, i) => + i === dayIndex + ? { + ...day, + blocos: day.blocos.map((bloco) => + bloco.id === blockId ? { ...bloco, [field]: value } : bloco + ), + } + : day + ) + ); + }, []); + + const renderTimeBlock = (dayIndex, bloco) => ( +
+
+
+ +
handleToggleDia(i)} + id={`inicio-${dayIndex}-${bloco.id}`} + type="time" + value={bloco.inicio} + onChange={(e) => + handleTimeChange(dayIndex, bloco.id, "inicio", e.target.value) + } + style={{ + padding: "8px", + border: "1px solid #d1d5db", + borderRadius: "8px", + width: "100%", + boxSizing: "border-box", + outline: "none", + }} + step="300" + /> +
- - {dia.ativo && ( -
- {dia.slots.map((slot, j) => ( -
- handleSlotChange(i, j, "start_time", e.target.value)} - className="border rounded p-1" - /> - até - handleSlotChange(i, j, "end_time", e.target.value)} - className="border rounded p-1" - /> - {dia.slots.length > 1 && ( - - )} -
- ))} - -
- )}
- ))} + +
+ +
+ + handleTimeChange(dayIndex, bloco.id, "termino", e.target.value) + } + style={{ + padding: "8px", + border: "1px solid #d1d5db", + borderRadius: "8px", + width: "100%", + boxSizing: "border-box", + outline: "none", + }} + step="300" + /> + +
+
+
+ + + {bloco.isNew && ( + + (Novo) + + )}
); -} + + return ( +
+
+ {availability.map((day, dayIndex) => { + const isChecked = day.isChecked; + + const dayHeaderStyle = { + display: "flex", + alignItems: "center", + justifyContent: "space-between", + padding: "12px 0", + borderBottom: "1px solid #e5e7eb", + marginBottom: "16px", + backgroundColor: isChecked ? "#1f2937" : "#f9fafb", + borderRadius: "8px", + paddingLeft: "16px", + paddingRight: "16px", + cursor: "pointer", + transition: "background-color 0.2s", + }; + + return ( +
+
handleDayCheck(dayIndex, isChecked)} + > + +
+ + {isChecked && ( +
+ {day.blocos.length === 0 && ( +

+ Nenhum bloco de horário definido. +

+ )} + +
+ {day.blocos.map((bloco) => + renderTimeBlock(dayIndex, bloco) + )} +
+ + +
+ )} +
+ ); + })} +
+
+ ); +}; + +export default HorariosDisponibilidade; diff --git a/src/pages/Agendamento.jsx b/src/pages/Agendamento.jsx index 4a226d3..7f7b831 100644 --- a/src/pages/Agendamento.jsx +++ b/src/pages/Agendamento.jsx @@ -6,6 +6,7 @@ import TabelaAgendamentoDia from '../components/AgendarConsulta/TabelaAgendament import TabelaAgendamentoSemana from '../components/AgendarConsulta/TabelaAgendamentoSemana'; import TabelaAgendamentoMes from '../components/AgendarConsulta/TabelaAgendamentoMes'; import FormNovaConsulta from '../components/AgendarConsulta/FormNovaConsulta'; +// Importação de endpoints para lógica da Fila de Espera e Médicos (versão main) import { GetPatientByID } from '../components/utils/Functions-Endpoints/Patient.js'; import { GetAllDoctors, GetDoctorByID } from '../components/utils/Functions-Endpoints/Doctor.js'; @@ -13,7 +14,6 @@ import { useAuth } from '../components/utils/AuthProvider.js'; // ✨ NOVO: Caminho de importação corrigido com base na sua estrutura de pastas import AgendamentosMes from '../components/AgendarConsulta/DadosConsultasMock.js'; - import dayjs from 'dayjs'; import "./style/Agendamento.css"; import './style/FilaEspera.css'; @@ -21,21 +21,22 @@ import { Search } from 'lucide-react'; -const Agendamento = ({setDictInfo}) => { +const Agendamento = ({setDictInfo}) => { // Mantido setDictInfo (versão main) const navigate = useNavigate(); - const [selectedID, setSelectedId] = useState('0') - const [filaEsperaData, setfilaEsperaData] = useState([]) - const [FiladeEspera, setFiladeEspera] = useState(false); + // Estados mesclados + const [selectedID, setSelectedId] = useState('0') // (main) + const [filaEsperaData, setfilaEsperaData] = useState([]) // (main) + const [FiladeEspera, setFiladeEspera] = useState(false); const [tabela, setTabela] = useState('diario'); const [PageNovaConsulta, setPageConsulta] = useState(false); const [searchTerm, setSearchTerm] = useState(''); - const [agendamentos, setAgendamentos] = useState() + const [agendamentos, setAgendamentos] = useState() // (main) const {getAuthorizationHeader} = useAuth() - const [DictAgendamentosOrganizados, setAgendamentosOrganizados ] = useState({}) + const [DictAgendamentosOrganizados, setAgendamentosOrganizados ] = useState({}) const [showDeleteModal, setShowDeleteModal] = useState(false) - const [AgendamentoFiltrado, setAgendamentoFiltrado] = useState() + const [AgendamentoFiltrado, setAgendamentoFiltrado] = useState() // (main) const [ListaDeMedicos, setListaDeMedicos] = useState([]) const [FiltredTodosMedicos, setFiltredTodosMedicos] = useState([]) @@ -44,6 +45,7 @@ const Agendamento = ({setDictInfo}) => { let authHeader = getAuthorizationHeader() + // Função FiltrarAgendamentos (Mesclado: Mantido o da MAIN, mais completo e com ordenação/fila de espera real) const FiltrarAgendamentos = async (listaTodosAgendamentos) => { const ConfigurarFiladeEspera = async (patient_id, doctor_id, agendamento) => { // Assumindo que GetDoctorByID e GetPatientByID estão definidos no seu escopo @@ -66,11 +68,9 @@ const Agendamento = ({setDictInfo}) => { let DictAgendamentosOrganizados = {}; let ListaFilaDeEspera = []; - // 1. Agrupamento (igual ao seu código original) + // 1. Agrupamento for (const agendamento of listaTodosAgendamentos) { if (agendamento.status === 'requested') { - // Recomenda-se usar Promise.all para melhorar a performance - // mas, para manter a estrutura, mantemos o await no loop. let v = await ConfigurarFiladeEspera(agendamento.patient_id, agendamento.doctor_id, agendamento); ListaFilaDeEspera.push(v); } else { @@ -84,42 +84,33 @@ const Agendamento = ({setDictInfo}) => { } } -// ---------------------------------------------------------------------- // 2. Ordenação Interna: Ordenar os agendamentos por HORÁRIO (do menor para o maior) for (const DiaAgendamento in DictAgendamentosOrganizados) { DictAgendamentosOrganizados[DiaAgendamento].sort((a, b) => { - // Compara as strings de data/hora (ISO 8601) diretamente, - // que funcionam para ordenação cronológica. if (a.scheduled_at < b.scheduled_at) return -1; if (a.scheduled_at > b.scheduled_at) return 1; return 0; }); } -// ---------------------------------------------------------------------- - // 3. Ordenação Externa: Ordenar os DIAS (as chaves do objeto) - // Para garantir que as chaves fiquem na sequência cronológica correta. - - // Pega as chaves (datas) + // 3. Ordenação Externa: Ordenar os DIAS const chavesOrdenadas = Object.keys(DictAgendamentosOrganizados).sort((a, b) => { - // Compara as chaves de data (strings 'YYYY-MM-DD') if (a < b) return -1; if (a > b) return 1; return 0; }); - // Cria um novo objeto no formato desejado, garantindo a ordem das chaves let DictAgendamentosFinal = {}; for (const data of chavesOrdenadas) { DictAgendamentosFinal[data] = DictAgendamentosOrganizados[data]; } - setAgendamentosOrganizados(DictAgendamentosFinal); // Use o objeto final ordenado + setAgendamentosOrganizados(DictAgendamentosFinal); setfilaEsperaData(ListaFilaDeEspera); }; - // Requisição inicial para mostrar os agendamentos do banco de dados + // Requisição inicial (Mesclado: Mantido o da MAIN, pois o da disponibilidade2 não tem a ordenação/fila de espera no .then) useEffect(() => { - var myHeaders = new Headers(); + var myHeaders = new Headers(); myHeaders.append("Authorization", authHeader); myHeaders.append("apikey", API_KEY) @@ -146,6 +137,7 @@ const Agendamento = ({setDictInfo}) => { }, []) + // Efeito de filtro de médico (Presente em ambas, mantida a lógica da MAIN/disponibilidade2 que se complementam) useEffect(() => { console.log("mudou FiltredTodosMedicos:", FiltredTodosMedicos); if (FiltredTodosMedicos.length === 1) { @@ -165,6 +157,7 @@ const Agendamento = ({setDictInfo}) => { } }, [FiltredTodosMedicos]); +// Função de Delete (Presente apenas na MAIN) const deleteConsulta = (selectedPatientId) => { console.log("tentando apagar") var myHeaders = new Headers(); @@ -184,20 +177,10 @@ fetch(`https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments?id=eq.${sel } - -/** - * Filtra todos os agendamentos em um objeto aninhado (data -> [agendamentos]) - * com base no ID do médico. - * - * @param {Object} dictAgendamentos - O dicionário de agendamentos. - * @param {string} idMedicoFiltrado - O ID do médico (doctor_id) para ser usado como filtro. - * @returns {Array} Um array contendo todos os agendamentos que correspondem ao idMedicoFiltrado. - */ +// Função auxiliar de filtro de médico (Presente em ambas, mantida a versão mais limpa) const filtrarAgendamentosPorMedico = (dictAgendamentos, idMedicoFiltrado) => { - // O corpo da função deve usar esses nomes de variáveis: const todasAsListasDeAgendamentos = Object.values(dictAgendamentos); - const todosOsAgendamentos = todasAsListasDeAgendamentos.flat(); const agendamentosFiltrados = todosOsAgendamentos.filter(agendamento => @@ -209,7 +192,7 @@ const filtrarAgendamentosPorMedico = (dictAgendamentos, idMedicoFiltrado) => { - // Lógica para filtrar os dados da AGENDA (AgendamentosMes) + // Lógica para filtrar os dados da AGENDA (useMemo) - (Presente em ambas, mantida a da MAIN, que está melhor formatada) const filteredAgendamentos = useMemo(() => { if (!searchTerm.trim()) { return AgendamentosMes; @@ -229,6 +212,7 @@ const filtrarAgendamentosPorMedico = (dictAgendamentos, idMedicoFiltrado) => { return filteredData; }, [searchTerm]); + // ListarDiasdoMes (Presente em ambas) const ListarDiasdoMes = (ano, mes) => { let segundas = []; let tercas = []; let quartas = []; let quintas = []; let sextas = [] const base = dayjs(`${ano}-${mes}-01`) @@ -249,12 +233,14 @@ const filtrarAgendamentosPorMedico = (dictAgendamentos, idMedicoFiltrado) => { return ListaDiasDatas } + // handleClickAgendamento (Presente em ambas) const handleClickAgendamento = (agendamento) => { if (agendamento.status !== 'vazio') return else setPageConsulta(true) }; +// handleSearchMedicos (Presente em ambas) const handleSearchMedicos = (term) => { setSearchTermDoctor(term); if (term.trim() === '') { @@ -275,56 +261,79 @@ const handleSearchMedicos = (term) => { return (

Agendar nova consulta

+ + {/* Mesclagem dos botões de navegação: Adicionar Consulta da main + Gerenciamento da disponibilidade2 */} +
+ + + + + +
- - - {!PageNovaConsulta ? (
+ {/* Bloco de busca por médico */}
- -
- -
-
- - handleSearchMedicos(e.target.value)} // Chama a nova função de filtro - /> +
+
+
+ + handleSearchMedicos(e.target.value)} // Chama a nova função de filtro + /> +
+ + {/* DROPDOWN (RENDERIZAÇÃO CONDICIONAL) */} + {searchTermDoctor && FiltredTodosMedicos.length > 0 && ( +
+ {FiltredTodosMedicos.map((medico) => ( +
{ + setSearchTermDoctor(medico.nomeMedico); // Preenche o input + // setFiltredTodosMedicos([]); // Opcional: fechar o dropdown + }} + > +

{medico.nomeMedico}

+
+ ))} +
+ )} +
- {/* DROPDOWN (RENDERIZAÇÃO CONDICIONAL) */} - {searchTermDoctor && FiltredTodosMedicos.length > 0 && ( -
- {FiltredTodosMedicos.map((medico) => ( -
{ - // Ação ao selecionar o médico - setSearchTermDoctor(medico.nomeMedico); // Preenche o input - //setFiltredTodosMedicos([]); // Fecha o dropdown - // Lógica adicional, como selecionar o ID do médico... - }} - > -

{medico.nomeMedico}

-
- ))} -
- )} -
-
+ {/* Div da disponibilidade2 - Unidade/Selecionar Profissional (manter) */} +
+ + +
+
@@ -374,6 +383,7 @@ const handleSearchMedicos = (term) => {
+ {/* Componentes de Tabela - Adicionado props de delete da main */} {tabela === "diario" && } {tabela === 'semanal' && } {tabela === 'mensal' && } @@ -382,6 +392,7 @@ const handleSearchMedicos = (term) => { ) : ( + // Fila de Espera - Restaurada a versão da MAIN com dados reais
{ - - - - - + {/* Ajustado o cabeçalho */} + {/* Ajustado o cabeçalho */} + {/* Ajustado o cabeçalho */} + {/* Ajustado o cabeçalho */} @@ -408,15 +418,15 @@ const handleSearchMedicos = (term) => { {filaEsperaData.map((item, index) => ( - - - + + + {/* Formatando a data de criação */}
NomeTelefoneTelefoneEntrou na fila de esperaNome do PacienteCPFMédico SolicitadoData da SolicitaçãoAções

{item.Infos?.paciente_nome}

{}

{}{}

{item.Infos?.paciente_cpf}

{item.Infos?.nome_nedico}

{dayjs(item.agendamento.created_at).format('DD/MM/YYYY HH:mm')}
) : ( + // AgendamentoCadastroManager - (Mesclado: Mantido o setPageConsulta da main) )} + {/* Modal de Confirmação de Exclusão (Da MAIN) */} {showDeleteModal && (
{ + const [disponibilidades, setDisponibilidades] = useState([]); + const [loading, setLoading] = useState(false); + const [filtroMedicoId, setFiltroMedicoId] = useState(""); + const [filtroActive, setFiltroActive] = useState("true"); + const [medicoValido, setMedicoValido] = useState(false); + + const fetchDisponibilidades = useCallback(async (doctorId, activeStatus) => { + setLoading(true); + let url = `${ENDPOINT_LISTAR}?select=*`; + if (doctorId) url += `&doctor_id=eq.${doctorId}`; + if (activeStatus === "true" || activeStatus === "false") url += `&active=eq.${activeStatus}`; + + try { + const response = await fetch(url); + const result = await response.json(); + setDisponibilidades(Array.isArray(result) ? result : []); + setMedicoValido(Array.isArray(result) && result.length > 0); + } catch (error) { + setDisponibilidades([]); + setMedicoValido(false); + } finally { + setLoading(false); + } + }, []); + + useEffect(() => { + if (filtroMedicoId) { + fetchDisponibilidades(filtroMedicoId, filtroActive); + } else { + setDisponibilidades([]); + setMedicoValido(false); + } + }, [filtroMedicoId, filtroActive, fetchDisponibilidades]); + + return ( +
+
+

+ Disponibilidades por Médico +

+ + + Gerenciar Disponibilidades + +
+ +
+
+
+ + setFiltroMedicoId(e.target.value)} + style={{ border: "1px solid #ccc", borderRadius: "4px", padding: "5px" }} + /> +
+
+ + +
+
+ +
+
+

+ Disponibilidades Encontradas ({disponibilidades.length}) +

+ + {loading ? ( +

Carregando disponibilidades...

+ ) : disponibilidades.length === 0 ? ( +

+ Nenhuma disponibilidade encontrada para os filtros aplicados. +

+ ) : ( + + + + {["ID", "ID Médico", "Dia da Semana", "Início", "Término", "Intervalo (min)", "Tipo Consulta", "Status"].map( + (header) => ( + + ) + )} + + + + {disponibilidades.map((disp, index) => ( + + + + + + + + + + + ))} + +
+ {header} +
{disp.id || "N/A"}{disp.doctor_id}{disp.weekday}{disp.start_time || "N/A"}{disp.end_time || "N/A"}{disp.slot_minutes}{disp.appointment_type} + + {disp.active ? "Ativa" : "Inativa"} + +
+ )} +
+
+
+
+ ); +}; + +export default DisponibilidadesDoctorPage; diff --git a/src/pages/DoctorEditPage.jsx b/src/pages/DoctorEditPage.jsx index eecfb14..4115823 100644 --- a/src/pages/DoctorEditPage.jsx +++ b/src/pages/DoctorEditPage.jsx @@ -1,77 +1,146 @@ -import React from 'react' -import { GetDoctorByID } from '../components/utils/Functions-Endpoints/Doctor' -import DoctorForm from '../components/doctors/DoctorForm' -import { useAuth } from '../components/utils/AuthProvider' -import {useEffect, useState} from 'react' -import { useParams } from 'react-router-dom' -import API_KEY from '../components/utils/apiKeys' +import React, { useEffect, useState, useCallback } from "react"; +import { useParams, useSearchParams } from "react-router-dom"; +import { GetDoctorByID } from "../components/utils/Functions-Endpoints/Doctor"; +import DoctorForm from "../components/doctors/DoctorForm"; +import { useAuth } from "../components/utils/AuthProvider"; +import API_KEY from "../components/utils/apiKeys"; + +const ENDPOINT_AVAILABILITY = + "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctor_availability"; + const DoctorEditPage = () => { - const {getAuthorizationHeader, isAuthenticated} = useAuth(); - const [DoctorToPUT, setDoctorPUT] = useState({}) - - const Parametros = useParams() + const { getAuthorizationHeader } = useAuth(); + const [DoctorToPUT, setDoctorPUT] = useState({}); - const DoctorID = Parametros.id + const Parametros = useParams(); + const [searchParams] = useSearchParams(); + const DoctorID = Parametros.id; + const availabilityId = searchParams.get("availabilityId"); -useEffect(() => { - - const authHeader = getAuthorizationHeader() + const [availabilityToPATCH, setAvailabilityToPATCH] = useState(null); + const [mode, setMode] = useState("doctor"); - GetDoctorByID(DoctorID, authHeader) - .then((data) => { - console.log(data, "médico vindo da API"); - setDoctorPUT(data[0]) - ; // supabase retorna array + useEffect(() => { + const authHeader = getAuthorizationHeader(); + + if (availabilityId) { + setMode("availability"); + + fetch(`${ENDPOINT_AVAILABILITY}?id=eq.${availabilityId}&select=*`, { + method: "GET", + headers: { + apikey: API_KEY, + Authorization: authHeader, + }, }) - .catch((err) => console.error("Erro ao buscar paciente:", err)); + .then((res) => res.json()) + .then((data) => { + if (data && data.length > 0) { + setAvailabilityToPATCH(data[0]); + console.log("Disponibilidade vinda da API:", data[0]); + } + }) + .catch((err) => console.error("Erro ao buscar disponibilidade:", err)); + } else { + setMode("doctor"); + GetDoctorByID(DoctorID, authHeader) + .then((data) => { + console.log(data, "médico vindo da API"); + setDoctorPUT(data[0]); + }) + .catch((err) => console.error("Erro ao buscar paciente:", err)); + } + }, [DoctorID, availabilityId, getAuthorizationHeader]); - -}, []) const HandlePutDoctor = async () => { -const authHeader = getAuthorizationHeader() - + const authHeader = getAuthorizationHeader(); - var myHeaders = new Headers(); - myHeaders.append('apikey', API_KEY) - myHeaders.append("Authorization", authHeader); - myHeaders.append("Content-Type", "application/json"); + var myHeaders = new Headers(); + myHeaders.append("apikey", API_KEY); + myHeaders.append("Authorization", authHeader); + myHeaders.append("Content-Type", "application/json"); - var raw = JSON.stringify(DoctorToPUT); + var raw = JSON.stringify(DoctorToPUT); - console.log("Enviando médico para atualização:", DoctorToPUT); + console.log("Enviando médico para atualização (PUT):", DoctorToPUT); - var requestOptions = { - method: 'PUT', - headers: myHeaders, - body: raw, - redirect: 'follow' + var requestOptions = { + method: "PUT", + headers: myHeaders, + body: raw, + redirect: "follow", + }; + + try { + const response = await fetch( + `https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors?id=eq.${DoctorID}`, + requestOptions + ); + console.log("Resposta PUT Doutor:", response); + alert("Dados do médico atualizados com sucesso!"); + } catch (error) { + console.error("Erro ao atualizar médico:", error); + alert("Erro ao atualizar dados do médico."); + throw error; + } }; - try { - const response = await fetch(`https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors?id=eq.${DoctorID}`,requestOptions); - console.log(response) - - } catch (error) { - console.error("Erro ao atualizar paciente:", error); - throw error; - } + // 2. Função para Atualizar DISPONIBILIDADE (PATCH) + const HandlePatchAvailability = async (data) => { + const authHeader = getAuthorizationHeader(); - } + var myHeaders = new Headers(); + myHeaders.append("apikey", API_KEY); + myHeaders.append("Authorization", authHeader); + myHeaders.append("Content-Type", "application/json"); + var raw = JSON.stringify(data); + + console.log("Enviando disponibilidade para atualização (PATCH):", data); + + var requestOptions = { + method: "PATCH", + headers: myHeaders, + body: raw, + redirect: "follow", + }; + + try { + const response = await fetch( + `${ENDPOINT_AVAILABILITY}?id=eq.${availabilityId}`, + requestOptions + ); + console.log("Resposta PATCH Disponibilidade:", response); + alert("Disponibilidade atualizada com sucesso!"); + // Opcional: Redirecionar de volta para a lista de disponibilidades + // navigate('/disponibilidades'); + } catch (error) { + console.error("Erro ao atualizar disponibilidade:", error); + alert("Erro ao atualizar disponibilidade."); + throw error; + } + }; return (
+

+ {mode === "availability" + ? `Editar Horário Disponível (ID: ${availabilityId.substring(0, 8)})` + : `Editar Médico (ID: ${DoctorID})`} +

- - +
- ) -} + ); +}; -export default DoctorEditPage \ No newline at end of file +export default DoctorEditPage; diff --git a/src/perfis/perfil_secretaria/PerfilSecretaria.jsx b/src/perfis/perfil_secretaria/PerfilSecretaria.jsx index 041ab95..c3b090c 100644 --- a/src/perfis/perfil_secretaria/PerfilSecretaria.jsx +++ b/src/perfis/perfil_secretaria/PerfilSecretaria.jsx @@ -2,7 +2,7 @@ import { Routes, Route } from "react-router-dom"; import { useState } from "react"; import Sidebar from "../../components/Sidebar"; -import FinanceiroDashboard from "../../pages/FinanceiroDashboard"; +import HorariosDisponibilidade from "../../components/doctors/HorariosDisponibilidade"; import SecretariaItems from "../../data/sidebar-items-secretaria.json"; import Inicio from "../../pages/Inicio"; import TablePaciente from "../../pages/TablePaciente"; @@ -16,6 +16,7 @@ import EditPage from "../../pages/EditPage"; import DoctorDetails from "../../pages/DoctorDetails"; import DoctorEditPage from "../../pages/DoctorEditPage"; import ExcecoesDisponibilidade from "../../pages/ExcecoesDisponibilidade"; +import DisponibilidadesDoctorPage from "../../pages/DisponibilidadesDoctorPage" import AgendamentoEditPage from "../../pages/AgendamentoEditPage"; function PerfilSecretaria({ onLogout }) { @@ -37,9 +38,11 @@ function PerfilSecretaria({ onLogout }) { } /> } /> } /> - } /> - Página não encontrada} /> + } /> + } /> + }/> } /> + Página não encontrada} />