diff --git a/src/components/AgendarConsulta/CardConsulta.jsx b/src/components/AgendarConsulta/CardConsulta.jsx index a1f1eaf..8056675 100644 --- a/src/components/AgendarConsulta/CardConsulta.jsx +++ b/src/components/AgendarConsulta/CardConsulta.jsx @@ -45,6 +45,7 @@ const CardConsulta = ( {DadosConsulta, TabelaAgendamento, setShowDeleteModal} ) let nameArrayMedico = Medico?.full_name.split(' ') + console.log(DadosConsulta.status) return (
@@ -69,7 +70,7 @@ const CardConsulta = ( {DadosConsulta, TabelaAgendamento, setShowDeleteModal} ) onClick={() => {navigate(`${DadosConsulta.id}/edit`)}} > - Editar + @@ -82,7 +83,7 @@ const CardConsulta = ( {DadosConsulta, TabelaAgendamento, setShowDeleteModal} ) setShowDeleteModal(true); }} > - Excluir +
diff --git a/src/components/AgendarConsulta/FormNovaConsulta.jsx b/src/components/AgendarConsulta/FormNovaConsulta.jsx index bdae91d..4446ab5 100644 --- a/src/components/AgendarConsulta/FormNovaConsulta.jsx +++ b/src/components/AgendarConsulta/FormNovaConsulta.jsx @@ -2,8 +2,9 @@ import InputMask from "react-input-mask"; import "./style/formagendamentos.css"; import { useState, useEffect } from "react"; import { GetPatientByCPF } from "../utils/Functions-Endpoints/Patient"; -import { GetDoctorByName } from "../utils/Functions-Endpoints/Doctor"; +import { GetDoctorByName, GetAllDoctors } from "../utils/Functions-Endpoints/Doctor"; import { useAuth } from "../utils/AuthProvider"; +import API_KEY from "../utils/apiKeys"; const FormNovaConsulta = ({ onCancel, onSave, setAgendamento, agendamento }) => { const {getAuthorizationHeader} = useAuth() @@ -11,13 +12,11 @@ const FormNovaConsulta = ({ onCancel, onSave, setAgendamento, agendamento }) => const [selectedFile, setSelectedFile] = useState(null); const [anexos, setAnexos] = useState([]); const [loadingAnexos, setLoadingAnexos] = useState(false); - - const [acessibilidade, setAcessibilidade] = useState({cadeirante:false,idoso:false,gravida:false,bebe:false, autista:false }) + const [horariosDisponiveis, sethorariosDisponiveis] = useState([]) + let authHeader = getAuthorizationHeader() - - const handleclickAcessibilidade = (id) => { let resultado = acessibilidade[id] @@ -39,8 +38,9 @@ const FormNovaConsulta = ({ onCancel, onSave, setAgendamento, agendamento }) => const handleChange = (e) => { - const {value, name} = e.target; + console.log(value, name) + if(name === 'email'){ setAgendamento({...agendamento, contato:{ ...agendamento.contato, @@ -63,30 +63,119 @@ const FormNovaConsulta = ({ onCancel, onSave, setAgendamento, agendamento }) => fetchPatient() }else if(name==='convenio'){ setAgendamento({...agendamento,insurance_provider:value}) - }else if(name ==='profissional'){ - - - const fetchDoctor = async () => { - let DoctorData = await GetDoctorByName(value, authHeader) - if(DoctorData){ - setAgendamento((prev) => ({ - ...prev, - doctor_id:DoctorData.id - })) - }} - fetchDoctor() } else{ setAgendamento({...agendamento,[name]:value}) } } - const handleSubmit = (e) => { + + + +useEffect(() => { + const ChamarMedicos = async () => { + const Medicos = await GetAllDoctors(authHeader) + setTodosProfissionais(Medicos) + } + ChamarMedicos(); + + var myHeaders = new Headers(); + myHeaders.append("Content-Type", "application/json"); + myHeaders.append("apikey", API_KEY) + myHeaders.append("Authorization", `Bearer ${authHeader.split(' ')[1]}`); + +var raw = JSON.stringify({ + "doctor_id": "58ea5330-5cfe-4433-a218-2749844aee89", + "start_date": "2025-10-20", + "end_date": "2025-10-20T23:59:59.999Z", + +}); + +var requestOptions = { + method: 'POST', + headers: myHeaders, + body: raw, + redirect: 'follow' +}; + +fetch("https://yuanqfswhberkoevtmfr.supabase.co/functions/v1/get-available-slots", requestOptions) + .then(response => response.json()) + .then(result => {console.log(result); sethorariosDisponiveis(result)}) + .catch(error => console.log('error', error)); + +}, []) + +const [todosProfissionais, setTodosProfissionais] = useState([]) +const [profissionaisFiltrados, setProfissionaisFiltrados] = useState([]); +const [isDropdownOpen, setIsDropdownOpen] = useState(false); + +// FUNÇÃO DE BUSCA E FILTRAGEM +const handleSearchProfissional = (e) => { + const term = e.target.value; + handleChange(e); + + // 2. Lógica de filtragem: + if (term.trim() === '') { + setProfissionaisFiltrados([]); + setIsDropdownOpen(false); + return; + } + + // Adapte o nome da propriedade (ex: 'nome', 'full_name') + const filtered = todosProfissionais.filter(p => + p.full_name.toLowerCase().includes(term.toLowerCase()) + ); + + setProfissionaisFiltrados(filtered); + setIsDropdownOpen(filtered.length > 0); // Abre se houver resultados +}; + + +// FUNÇÃO PARA SELECIONAR UM ITEM DO DROPDOWN +const handleSelectProfissional = async (profissional) => { + + + setAgendamento(prev => ({ + ...prev, + doctor_id: profissional.id, + nome_medico: profissional.full_name + })); + + // 2. Fecha o dropdown + setProfissionaisFiltrados([]); + setIsDropdownOpen(false); + +}; + + +const formatarHora = (datetimeString) => { + // Para simplificar, vou extrair a hora e minuto do formato de string. + // Dependendo do seu ambiente, é melhor usar new Date() e toLocaleTimeString() + // como no exemplo anterior, mas aqui farei o "corte" na string. + // Ex: "2025-10-20T09:00:00.000Z" -> "09:00" + return datetimeString.substring(11, 16); + }; + + const opcoesDeHorario = horariosDisponiveis?.slots?.map(item => ({ + + value: formatarHora(item.datetime), + label: formatarHora(item.datetime), + disabled: !item.available + })); + + // Adicionando um estado para controlar as seleções, o que é comum no React + const [horarioInicio, setHorarioInicio] = useState(''); + const [horarioTermino, setHorarioTermino] = useState(''); + + +const handleSubmit = (e) => { e.preventDefault(); alert("Agendamento salvo!"); - onSave(agendamento) + onSave({...agendamento, horarioInicio:horarioInicio}) }; + + return (
@@ -95,26 +184,21 @@ const FormNovaConsulta = ({ onCancel, onSave, setAgendamento, agendamento }) =>

Informações do paciente

+
- - -
- -
- - +
- - + +
+ + +
- - -
-
+
setSelectedFile(e.target.files[0])} - /> - {selectedFile && ( - - )} -
- {loadingAnexos ? ( -

Carregando anexos...

- ) : ( - anexos.map((anexo, index) => ( -
- {anexo.nome || anexo.fileName} -
- )) - )} -

Informações do atendimento

- -
- -
handleclickAcessibilidade(e.currentTarget.id)}> - - accessible -
- -
handleclickAcessibilidade(e.currentTarget.id)}> - elderly -
- -
handleclickAcessibilidade(e.currentTarget.id)}> - pregnant_woman -
- -
handleclickAcessibilidade(e.currentTarget.id)}> - - -
- -
handleclickAcessibilidade(e.currentTarget.id)}> - -
- -
-
- - -
- +
{/* NOVO CONTAINER PAI */} +
+ + +
-
+ {/* DROPDOWN - RENDERIZAÇÃO CONDICIONAL */} + {isDropdownOpen && profissionaisFiltrados.length > 0 && ( +
+ {profissionaisFiltrados.map((profissional) => ( +
handleSelectProfissional(profissional)} + > + {profissional.full_name} +
+ ))} +
+ )} +
+ +
- +
@@ -211,30 +272,62 @@ const FormNovaConsulta = ({ onCancel, onSave, setAgendamento, agendamento }) =>
- +
-
-
- - -
-
- - -
- -
- - -
-
+
+
+ + +
+ + {/* Dropdown de Término */} +
+ + +
+
+ + +
diff --git a/src/components/AgendarConsulta/style/formagendamentos.css b/src/components/AgendarConsulta/style/formagendamentos.css index f9ca9d7..bbd606d 100644 --- a/src/components/AgendarConsulta/style/formagendamentos.css +++ b/src/components/AgendarConsulta/style/formagendamentos.css @@ -303,4 +303,41 @@ html[data-bs-theme="dark"] .icons-div:hover .icon { html[data-bs-theme="dark"] .icon, html[data-bs-theme="dark"] svg { color: #e0e0e0 !important; +} + +/* CONTAINER PAI - ESSENCIAL PARA POSICIONAMENTO */ +.campo-de-input-container { + position: relative; /* Define o contexto para o dropdown */ + /* ... outros estilos de layout (display, margin, etc.) ... */ +} + +/* ESTILO DA LISTA DROPDOWN */ +.dropdown-profissionais { + position: absolute; /* Flutua em relação ao pai (.campo-de-input-container) */ + top: 100%; /* Começa logo abaixo do input */ + left: 0; + width: 100%; /* Ocupa toda a largura do container pai */ + + /* Estilos visuais */ + background-color: white; + border: 1px solid #ccc; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + z-index: 100; /* Alto z-index para garantir que fique acima de outros elementos */ + max-height: 200px; + overflow-y: auto; +} + +/* ESTILO DE CADA ITEM DO DROPDOWN */ +.dropdown-item { + padding: 10px; + cursor: pointer; +} + +.dropdown-item:hover { + background-color: #f0f0f0; +} + +.tipo_atendimento{ + margin-left: 3rem; + } \ No newline at end of file diff --git a/src/pages/Agendamento.jsx b/src/pages/Agendamento.jsx index 9d2f0de..6b749ad 100644 --- a/src/pages/Agendamento.jsx +++ b/src/pages/Agendamento.jsx @@ -6,8 +6,8 @@ import TabelaAgendamentoDia from '../components/AgendarConsulta/TabelaAgendament 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 { GetPatientByID } from '../components/utils/Functions-Endpoints/Patient.js'; +import { GetAllDoctors, GetDoctorByID } from '../components/utils/Functions-Endpoints/Doctor.js'; import { useAuth } from '../components/utils/AuthProvider.js'; // ✨ NOVO: Caminho de importação corrigido com base na sua estrutura de pastas @@ -24,6 +24,7 @@ import { Search } from 'lucide-react'; const Agendamento = () => { const navigate = useNavigate(); + const [filaEsperaData, setfilaEsperaData] = useState([]) const [FiladeEspera, setFiladeEspera] = useState(false); const [tabela, setTabela] = useState('diario'); const [PageNovaConsulta, setPageConsulta] = useState(false); @@ -42,11 +43,37 @@ const Agendamento = () => { let authHeader = getAuthorizationHeader() - const FiltrarAgendamentos = (listaTodosAgendamentos) => { + const FiltrarAgendamentos = async (listaTodosAgendamentos) => { + + const ConfigurarFiladeEspera = async (patient_id, doctor_id, agendamento) => { + + + let medico = await GetDoctorByID(doctor_id, authHeader) + let paciente = await GetPatientByID(patient_id, authHeader) + + let dicionario = {patientInfo:paciente, doctorInfo:medico, agendamentoInfo:agendamento} + + + return dicionario + + } + let DictAgendamentosOrganizados = {}; + let ListaFilaDeEspera = [] for (let i = 0; i < listaTodosAgendamentos.length; i++) { const agendamento = listaTodosAgendamentos[i]; + if(agendamento.status === 'requested'){ + + let v = await ConfigurarFiladeEspera(agendamento.patient_id, agendamento.doctor_id, agendamento) + + ListaFilaDeEspera.push(v) + + console.log(ListaFilaDeEspera) + + } + + else{ const DiaAgendamento = agendamento.scheduled_at.split("T")[0]; //console.log(DictAgendamentosOrganizados) @@ -57,11 +84,12 @@ const Agendamento = () => { } else { // não existe → cria nova key com uma lista DictAgendamentosOrganizados[DiaAgendamento] = [agendamento]; - } + }} } setAgendamentosOrganizados(DictAgendamentosOrganizados); + setfilaEsperaData(ListaFilaDeEspera) } @@ -86,7 +114,6 @@ const Agendamento = () => { 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) @@ -96,42 +123,22 @@ const Agendamento = () => { }, []) useEffect(() => { - - console.log("mudou FiltredTodosMedicos:", FiltredTodosMedicos); - - if (FiltredTodosMedicos.length === 1) { - + console.log("mudou FiltredTodosMedicos:", FiltredTodosMedicos); + if (FiltredTodosMedicos.length === 1) { const unicoMedico = FiltredTodosMedicos[0]; console.log(unicoMedico) - const idMedicoFiltrado = unicoMedico.idMedico; - console.log(`Médico único encontrado: ${unicoMedico.nomeMedico}. ID: ${idMedicoFiltrado}`); - - const agendamentosDoMedico = filtrarAgendamentosPorMedico( 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) - - // AQUI VOCÊ PODE APLICAR SUA LÓGICA FINAL: - // Ex: setar um novo estado com os agendamentos filtrados, se for necessário: - // setAgendamentosFiltrados(agendamentosDoMedico); - - - } else { - // Opcional: Limpar a lista filtrada se a busca não for mais única - // setAgendamentosFiltrados([]); - } - + } }, [FiltredTodosMedicos]); @@ -158,28 +165,7 @@ const filtrarAgendamentosPorMedico = (dictAgendamentos, 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' }, - ]; - - // 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) - ); + // Lógica para filtrar os dados da AGENDA (AgendamentosMes) const filteredAgendamentos = useMemo(() => { @@ -248,10 +234,14 @@ const handleSearchMedicos = (term) => {

Agendar nova consulta

- + + {!PageNovaConsulta ? (
@@ -380,13 +370,13 @@ const handleSearchMedicos = (term) => { - {filteredFila.map((item, index) => ( + {filaEsperaData.map((item, index) => ( - {item.nome} - {item.email} - {item.cpf} - {item.telefone} - {item.entrada} +

{item.patientInfo[0].full_name}

+ {} + {} + {} + {} ))} diff --git a/src/pages/AgendamentoCadastroManager.jsx b/src/pages/AgendamentoCadastroManager.jsx index 7c97640..553fc0b 100644 --- a/src/pages/AgendamentoCadastroManager.jsx +++ b/src/pages/AgendamentoCadastroManager.jsx @@ -23,9 +23,9 @@ const AgendamentoCadastroManager = () => { var raw = JSON.stringify({ "patient_id": Dict.patient_id, "doctor_id": Dict.doctor_id, - "scheduled_at": DataAtual, + "scheduled_at": `${Dict.dataAtendimento}T${Dict.horarioInicio}:00.000Z`, "duration_minutes": 30, - "appointment_type": "presencial", + "appointment_type": Dict.tipo_consulta, "chief_complaint": "Dor de cabeça há 3 ", "patient_notes": "Prefiro horário pela manhã", "insurance_provider": "Unimed", diff --git a/src/pages/DoctorTable.jsx b/src/pages/DoctorTable.jsx index 3b89be5..9b88010 100644 --- a/src/pages/DoctorTable.jsx +++ b/src/pages/DoctorTable.jsx @@ -104,7 +104,7 @@ function TableDoctor() { fetch("https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors", requestOptions) .then(response => response.json()) - .then(result => setMedicos(result)) + .then(result => {setMedicos(result); console.log(result)}) .catch(error => console.log('error', error)); }, [isAuthenticated, getAuthorizationHeader]); diff --git a/src/pages/style/Agendamento.css b/src/pages/style/Agendamento.css index be2ea14..e84f292 100644 --- a/src/pages/style/Agendamento.css +++ b/src/pages/style/Agendamento.css @@ -91,7 +91,7 @@ background-color: #2c5e37; } -.legenda-item-confirmado{ +.legenda-item-confirmed{ background-color: #1e90ff; } .legenda-item-cancelado{ @@ -102,7 +102,7 @@ background-color: #f0ad4e; } -#status-card-consulta-realizado, .legenda-item-realizado { +#status-card-consulta-completed, .legenda-item-realizado { background-color: #b7ffbd; border:3px solid #91d392; padding: 5px; @@ -110,7 +110,7 @@ border-radius: 10px; } -#status-card-consulta-cancelado, .legenda-item-cancelado { +#status-card-consulta-cancelled, .legenda-item-cancelado { background-color: #ffb7cc; border:3px solid #ff6c84; padding: 5px; @@ -118,7 +118,7 @@ border-radius: 10px; } -#status-card-consulta-confirmado, .legenda-item-confirmed { +#status-card-consulta-confirmed, .legenda-item-confirmed { background-color: #eef8fb; border:3px solid #d8dfe7; padding: 5px; @@ -358,26 +358,18 @@ html[data-bs-theme="dark"] { #tabela-seletor-container i { pointer-events: none; } -/* 1. Contêiner de Limitação de Largura e Posicionamento */ -/* Este é o elemento mais importante. Ele deve envolver o input e o dropdown. */ + + .input-e-dropdown-wrapper { position: relative; - /* IMPORTANTE: Defina aqui a largura EXATA que você deseja para o input - e para o dropdown. Na sua imagem, o input parece ter cerca de 300px ou mais. - */ - width: 350px; /* Ajuste este valor conforme a largura desejada do seu input */ - - /* Se o input original estava alinhado à direita (como na imagem), - você pode precisar de um float ou margin para posicionar este wrapper. - */ - margin-left: auto; /* Exemplo para alinhar o wrapper à direita se for o caso */ + + width: 350px; + margin-left: auto; } -/* 2. Estilização da Área de Busca (Input) */ -/* Garante que o input utilize toda a largura do wrapper */ .busca-atendimento { - /* ... seus estilos de layout (flex, margin, etc.) para o busca-atendimento, se houver ... */ + } .busca-atendimento > div {