diff --git a/src/components/doctors/DoctorForm.jsx b/src/components/doctors/DoctorForm.jsx index e89df68e..f6773273 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 eac2c93b..c2419126 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 8be99eef..8146e7b0 100644 --- a/src/pages/Agendamento.jsx +++ b/src/pages/Agendamento.jsx @@ -1,184 +1,230 @@ -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 TabelaAgendamentoDia from '../components/AgendarConsulta/TabelaAgendamentoDia'; -import TabelaAgendamentoSemana from '../components/AgendarConsulta/TabelaAgendamentoSemana'; -import TabelaAgendamentoMes from '../components/AgendarConsulta/TabelaAgendamentoMes'; -import FormNovaConsulta from '../components/AgendarConsulta/FormNovaConsulta'; +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 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 } from '../components/utils/Functions-Endpoints/Doctor.js'; +import { GetAllDoctors } from "../components/utils/Functions-Endpoints/Doctor.js"; -import { useAuth } from '../components/utils/AuthProvider.js'; +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 AgendamentosMes from "../components/AgendarConsulta/DadosConsultasMock.js"; - -import dayjs from 'dayjs'; +import dayjs from "dayjs"; import "./style/Agendamento.css"; -import './style/FilaEspera.css'; -import { Search } from 'lucide-react'; - - +import "./style/FilaEspera.css"; +import { Search } from "lucide-react"; const Agendamento = () => { const navigate = useNavigate(); - const [FiladeEspera, setFiladeEspera] = useState(false); - const [tabela, setTabela] = useState('diario'); + const [FiladeEspera, setFiladeEspera] = useState(false); + const [tabela, setTabela] = useState("diario"); const [PageNovaConsulta, setPageConsulta] = useState(false); - const [searchTerm, setSearchTerm] = useState(''); - const [agendamentos, setAgendamentos] = useState() - const {getAuthorizationHeader} = useAuth() - const [DictAgendamentosOrganizados, setAgendamentosOrganizados ] = useState({}) + const [searchTerm, setSearchTerm] = useState(""); + const [agendamentos, setAgendamentos] = useState(); + const { getAuthorizationHeader } = useAuth(); + const [DictAgendamentosOrganizados, setAgendamentosOrganizados] = useState( + {} + ); - const [showDeleteModal, setShowDeleteModal] = useState(false) - const [AgendamentoFiltrado, setAgendamentoFiltrado] = useState() - - const [ListaDeMedicos, setListaDeMedicos] = useState([]) - const [FiltredTodosMedicos, setFiltredTodosMedicos] = useState([]) - const [searchTermDoctor, setSearchTermDoctor] = useState(''); + const [showDeleteModal, setShowDeleteModal] = useState(false); + const [AgendamentoFiltrado, setAgendamentoFiltrado] = useState(); + const [ListaDeMedicos, setListaDeMedicos] = useState([]); + const [FiltredTodosMedicos, setFiltredTodosMedicos] = useState([]); + const [searchTermDoctor, setSearchTermDoctor] = useState(""); - let authHeader = getAuthorizationHeader() + let authHeader = getAuthorizationHeader(); const FiltrarAgendamentos = (listaTodosAgendamentos) => { - let DictAgendamentosOrganizados = {}; + let DictAgendamentosOrganizados = {}; - for (let i = 0; i < listaTodosAgendamentos.length; i++) { - const agendamento = listaTodosAgendamentos[i]; - const DiaAgendamento = agendamento.scheduled_at.split("T")[0]; + for (let i = 0; i < listaTodosAgendamentos.length; i++) { + const agendamento = listaTodosAgendamentos[i]; + const DiaAgendamento = agendamento.scheduled_at.split("T")[0]; - //console.log(DictAgendamentosOrganizados) + //console.log(DictAgendamentosOrganizados) - if (DiaAgendamento in DictAgendamentosOrganizados) { - // já existe a data → adiciona na lista - DictAgendamentosOrganizados[DiaAgendamento].push(agendamento); - } else { - // não existe → cria nova key com uma lista - DictAgendamentosOrganizados[DiaAgendamento] = [agendamento]; + if (DiaAgendamento in DictAgendamentosOrganizados) { + // já existe a data → adiciona na lista + DictAgendamentosOrganizados[DiaAgendamento].push(agendamento); + } else { + // não existe → cria nova key com uma lista + DictAgendamentosOrganizados[DiaAgendamento] = [agendamento]; + } } - } - - setAgendamentosOrganizados(DictAgendamentosOrganizados); - - } + setAgendamentosOrganizados(DictAgendamentosOrganizados); + }; // Requisição inicial para mostrar os agendamentos do banco de dados useEffect(() => { - var myHeaders = new Headers(); + var myHeaders = new Headers(); myHeaders.append("Authorization", authHeader); - myHeaders.append("apikey", API_KEY) + myHeaders.append("apikey", API_KEY); var requestOptions = { - method: 'GET', + method: "GET", headers: myHeaders, - redirect: 'follow' + redirect: "follow", }; - fetch("https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments?select&doctor_id&patient_id&status&scheduled_at&order&limit&offset", requestOptions) - .then(response => response.json()) - .then(result => {FiltrarAgendamentos(result);}) - .catch(error => console.log('error', error)); + fetch( + "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments?select&doctor_id&patient_id&status&scheduled_at&order&limit&offset", + requestOptions + ) + .then((response) => response.json()) + .then((result) => { + FiltrarAgendamentos(result); + }) + .catch((error) => console.log("error", error)); const PegarTodosOsMedicos = async () => { - let lista = [] - const TodosOsMedicos = await GetAllDoctors(authHeader) + let lista = []; + const TodosOsMedicos = await GetAllDoctors(authHeader); //console.log(TodosOsMedicos, "tentativa") - for(let d = 0; TodosOsMedicos.length > d; d++){ - lista.push({nomeMedico: TodosOsMedicos[d].full_name, idMedico: TodosOsMedicos[d].id })} - setListaDeMedicos(lista) - } - PegarTodosOsMedicos() - - }, []) - - useEffect(() => { + for (let d = 0; TodosOsMedicos.length > d; d++) { + lista.push({ + nomeMedico: TodosOsMedicos[d].full_name, + idMedico: TodosOsMedicos[d].id, + }); + } + setListaDeMedicos(lista); + }; + PegarTodosOsMedicos(); + }, []); + useEffect(() => { console.log("mudou FiltredTodosMedicos:", FiltredTodosMedicos); if (FiltredTodosMedicos.length === 1) { - - const unicoMedico = FiltredTodosMedicos[0]; - console.log(unicoMedico) - - const idMedicoFiltrado = unicoMedico.idMedico; + const unicoMedico = FiltredTodosMedicos[0]; + console.log(unicoMedico); + + const idMedicoFiltrado = unicoMedico.idMedico; + + console.log( + `Médico único encontrado: ${unicoMedico.nomeMedico}. ID: ${idMedicoFiltrado}` + ); - console.log(`Médico único encontrado: ${unicoMedico.nomeMedico}. ID: ${idMedicoFiltrado}`); - - - const agendamentosDoMedico = filtrarAgendamentosPorMedico( - DictAgendamentosOrganizados, - idMedicoFiltrado + DictAgendamentosOrganizados, + idMedicoFiltrado ); // ========================================================================= - - console.log(`Total de agendamentos filtrados para este médico: ${agendamentosDoMedico.length}`); - console.log("Lista completa de Agendamentos do Médico:", agendamentosDoMedico); - FiltrarAgendamentos(agendamentosDoMedico) - - + + console.log( + `Total de agendamentos filtrados para este médico: ${agendamentosDoMedico.length}` + ); + console.log( + "Lista completa de Agendamentos do Médico:", + agendamentosDoMedico + ); + FiltrarAgendamentos(agendamentosDoMedico); + // AQUI VOCÊ PODE APLICAR SUA LÓGICA FINAL: // Ex: setar um novo estado com os agendamentos filtrados, se for necessário: - // setAgendamentosFiltrados(agendamentosDoMedico); - - + // setAgendamentosFiltrados(agendamentosDoMedico); } else { - // Opcional: Limpar a lista filtrada se a busca não for mais única - // setAgendamentosFiltrados([]); + // Opcional: Limpar a lista filtrada se a busca não for mais única + // setAgendamentosFiltrados([]); } + }, [FiltredTodosMedicos]); - }, [FiltredTodosMedicos]); - - - -/** - * 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. - */ -const filtrarAgendamentosPorMedico = (dictAgendamentos, idMedicoFiltrado) => { - + /** + * 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. + */ + 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 => - agendamento.doctor_id === idMedicoFiltrado + const agendamentosFiltrados = todosOsAgendamentos.filter( + (agendamento) => agendamento.doctor_id === idMedicoFiltrado ); return agendamentosFiltrados; -}; - - - + }; // Dados da fila de espera (sem alteração) const filaEsperaData = [ - { nome: 'Ricardo Pereira', email: 'ricardo.pereira@gmail.com', cpf: '444.777.666-55', telefone: '(79) 99123-4567', entrada: '25/09/2025 às 08:00' }, - { nome: 'Ana Costa', email: 'ana.costa@gmail.com', cpf: '321.654.987-00', telefone: '(79) 97777-3333', entrada: '25/09/2025 às 08:30' }, - { nome: 'Lucas Martins', email: 'lucas.martins@gmail.com', cpf: '777.666.555-33', telefone: '(79) 99654-3210', entrada: '25/09/2025 às 09:00' }, - { nome: 'João Souza', email: 'joao.souza@gmail.com', cpf: '987.654.321-00', telefone: '(79) 98888-2222', entrada: '25/09/2025 às 14:00' }, - { nome: 'Maria Silva', email: 'maria.silva@gmail.com', cpf: '123.456.789-00', telefone: '(79) 99999-1111', entrada: '25/09/2025 às 14:30' }, - { nome: 'Fernanda Lima', email: 'fernanda.lima@gmail.com', cpf: '888.999.000-22', telefone: '(79) 98877-6655', entrada: '26/09/2025 às 09:30' }, - { nome: 'Carlos Andrade', email: 'carlos.andrade@gmail.com', cpf: '222.555.888-11', telefone: '(79) 99876-5432', entrada: '26/09/2025 às 10:00' }, - { nome: 'Juliana Oliveira', email: 'juliana.o@gmail.com', cpf: '111.222.333-44', telefone: '(79) 98765-1234', entrada: '26/09/2025 às 11:30' }, + { + nome: "Ricardo Pereira", + email: "ricardo.pereira@gmail.com", + cpf: "444.777.666-55", + telefone: "(79) 99123-4567", + entrada: "25/09/2025 às 08:00", + }, + { + nome: "Ana Costa", + email: "ana.costa@gmail.com", + cpf: "321.654.987-00", + telefone: "(79) 97777-3333", + entrada: "25/09/2025 às 08:30", + }, + { + nome: "Lucas Martins", + email: "lucas.martins@gmail.com", + cpf: "777.666.555-33", + telefone: "(79) 99654-3210", + entrada: "25/09/2025 às 09:00", + }, + { + nome: "João Souza", + email: "joao.souza@gmail.com", + cpf: "987.654.321-00", + telefone: "(79) 98888-2222", + entrada: "25/09/2025 às 14:00", + }, + { + nome: "Maria Silva", + email: "maria.silva@gmail.com", + cpf: "123.456.789-00", + telefone: "(79) 99999-1111", + entrada: "25/09/2025 às 14:30", + }, + { + nome: "Fernanda Lima", + email: "fernanda.lima@gmail.com", + cpf: "888.999.000-22", + telefone: "(79) 98877-6655", + entrada: "26/09/2025 às 09:30", + }, + { + nome: "Carlos Andrade", + email: "carlos.andrade@gmail.com", + cpf: "222.555.888-11", + telefone: "(79) 99876-5432", + entrada: "26/09/2025 às 10:00", + }, + { + nome: "Juliana Oliveira", + email: "juliana.o@gmail.com", + cpf: "111.222.333-44", + telefone: "(79) 98765-1234", + entrada: "26/09/2025 às 11:30", + }, ]; // Filtro da fila de espera (sem alteração) - const filteredFila = filaEsperaData.filter(item => - item.nome.toLowerCase().includes(searchTerm.toLowerCase()) || - item.email.toLowerCase().includes(searchTerm.toLowerCase()) || - item.cpf.includes(searchTerm) || - item.telefone.includes(searchTerm) + const filteredFila = filaEsperaData.filter( + (item) => + item.nome.toLowerCase().includes(searchTerm.toLowerCase()) || + item.email.toLowerCase().includes(searchTerm.toLowerCase()) || + item.cpf.includes(searchTerm) || + item.telefone.includes(searchTerm) ); // Lógica para filtrar os dados da AGENDA (AgendamentosMes) @@ -192,9 +238,11 @@ const filtrarAgendamentosPorMedico = (dictAgendamentos, idMedicoFiltrado) => { for (const semana in AgendamentosMes) { filteredData[semana] = {}; for (const dia in AgendamentosMes[semana]) { - filteredData[semana][dia] = AgendamentosMes[semana][dia].filter(agendamento => - agendamento.status === 'vazio' || - (agendamento.paciente && agendamento.paciente.toLowerCase().includes(lowerCaseSearchTerm)) + filteredData[semana][dia] = AgendamentosMes[semana][dia].filter( + (agendamento) => + agendamento.status === "vazio" || + (agendamento.paciente && + agendamento.paciente.toLowerCase().includes(lowerCaseSearchTerm)) ); } } @@ -202,206 +250,280 @@ const filtrarAgendamentosPorMedico = (dictAgendamentos, idMedicoFiltrado) => { }, [searchTerm]); const ListarDiasdoMes = (ano, mes) => { - let segundas = []; let tercas = []; let quartas = []; let quintas = []; let sextas = [] - const base = dayjs(`${ano}-${mes}-01`) - const DiasnoMes = base.daysInMonth() + let segundas = []; + let tercas = []; + let quartas = []; + let quintas = []; + let sextas = []; + const base = dayjs(`${ano}-${mes}-01`); + const DiasnoMes = base.daysInMonth(); for (let d = 1; d <= DiasnoMes; d++) { - const data = dayjs(`${ano}-${mes}-${d}`) - const dia = data.format('dddd') + const data = dayjs(`${ano}-${mes}-${d}`); + const dia = data.format("dddd"); switch (dia) { - case 'Monday': segundas.push(d); break - case 'Tuesday': tercas.push(d); break - case 'Wednesday': quartas.push(d); break - case 'Thursday': quintas.push(d); break - case 'Friday': sextas.push(d); break - default: break + case "Monday": + segundas.push(d); + break; + case "Tuesday": + tercas.push(d); + break; + case "Wednesday": + quartas.push(d); + break; + case "Thursday": + quintas.push(d); + break; + case "Friday": + sextas.push(d); + break; + default: + break; } } - let ListaDiasDatas = {segundas:segundas,tercas:tercas,quartas: quartas,quintas: quintas,sextas: sextas} - return ListaDiasDatas - } + let ListaDiasDatas = { + segundas: segundas, + tercas: tercas, + quartas: quartas, + quintas: quintas, + sextas: sextas, + }; + return ListaDiasDatas; + }; const handleClickAgendamento = (agendamento) => { - if (agendamento.status !== 'vazio') return - else setPageConsulta(true) -}; + if (agendamento.status !== "vazio") return; + else setPageConsulta(true); + }; - -const handleSearchMedicos = (term) => { + const handleSearchMedicos = (term) => { setSearchTermDoctor(term); - if (term.trim() === '') { - setFiltredTodosMedicos([]); - return; + if (term.trim() === "") { + setFiltredTodosMedicos([]); + return; } - + // Lógica simples de filtragem: - const filtered = ListaDeMedicos.filter(medico => - medico.nomeMedico.toLowerCase().includes(term.toLowerCase()) + const filtered = ListaDeMedicos.filter((medico) => + medico.nomeMedico.toLowerCase().includes(term.toLowerCase()) ); setFiltredTodosMedicos(filtered); -}; - + }; - const handleClickCancel = () => setPageConsulta(false) + const handleClickCancel = () => setPageConsulta(false); return (

Agendar nova consulta

- +
+
+ +
+ +
+ +
+
{!PageNovaConsulta ? ( -
- -
- -
- -
-
+
+
+
+
+
handleSearchMedicos(e.target.value)} // Chama a nova função de filtro + type="text" + placeholder="Filtrar atendimento por médico..." + value={searchTermDoctor} + onChange={(e) => handleSearchMedicos(e.target.value)} // Chama a nova função de filtro /> +
-
- - {/* DROPDOWN (RENDERIZAÇÃO CONDICIONAL) */} - {searchTermDoctor && FiltredTodosMedicos.length > 0 && ( -
+ + {/* 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}

-
+
{ + // 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}

+
))} -
- )} -
-
+
+ )} +
+
- -
+
- +
-
+
-
- {FiladeEspera === false ? - ( -
-
-
-
- - - +
+ {FiladeEspera === false ? ( +
+
+
+
+ + + +
+
+
+ Realizado
-
-
Realizado
-
Confirmado
-
Agendado
-
Cancelado
+
+ Confirmado
-
- - {tabela === "diario" && } - {tabela === 'semanal' && } - {tabela === 'mensal' && } -
-
- ) - : - ( -
-
- setSearchTerm(e.target.value)} +
+ Agendado +
+
+ Cancelado +
+
+
+ + {tabela === "diario" && ( + -

Fila de Espera

-
- - - - - - - - - - - - {filteredFila.map((item, index) => ( - - - - - - - - ))} - -
NomeEmailCPFTelefoneEntrou na fila de espera
{item.nome}{item.email}{item.cpf}{item.telefone}{item.entrada}
+ )} + {tabela === "semanal" && ( + + )} + {tabela === "mensal" && ( + + )}
- ) - } +
+ ) : ( +
+
+ setSearchTerm(e.target.value)} + /> +

Fila de Espera

+
+ + + + + + + + + + + + {filteredFila.map((item, index) => ( + + + + + + + + ))} + +
NomeEmailCPFTelefoneEntrou na fila de espera
{item.nome}{item.email}{item.cpf}{item.telefone}{item.entrada}
+
+ )}
) : ( )} - {showDeleteModal && ( + {showDeleteModal && (
{ >
-
Confirmação de Exclusão @@ -429,12 +550,11 @@ const handleSearchMedicos = (term) => {

- Tem certeza que deseja excluir este paciente? + Tem certeza que deseja excluir este paciente?

- -
-
)} - - +
+ )}
- ) -} + ); +}; -export default Agendamento; \ No newline at end of file +export default Agendamento; diff --git a/src/pages/DisponibilidadesDoctorPage.jsx b/src/pages/DisponibilidadesDoctorPage.jsx new file mode 100644 index 00000000..65284b69 --- /dev/null +++ b/src/pages/DisponibilidadesDoctorPage.jsx @@ -0,0 +1,145 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { Link } from "react-router-dom"; + +const ENDPOINT_LISTAR = "https://mock.apidog.com/m1/1053378-0-default/rest/v1/doctor_availability"; + +const DisponibilidadesDoctorPage = () => { + 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 eecfb147..4115823e 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 de6d35d0..45521bf3 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 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 }) { @@ -36,9 +37,11 @@ function PerfilSecretaria({ onLogout }) { } /> } /> } /> - } /> - Página não encontrada} /> + } /> + } /> + }/> } /> + Página não encontrada} />