Agendamentos da secretaria filtrado pelo id do médico

This commit is contained in:
jp-lima 2025-10-17 10:23:37 -03:00
parent cd38ab54ac
commit 7474639137
10 changed files with 337 additions and 37 deletions

103
package-lock.json generated
View File

@ -41,6 +41,7 @@
"react-scripts": "5.0.1",
"recharts": "^3.1.2",
"sweetalert2": "^11.22.4",
"tiptap": "^1.32.2",
"toastify-js": "^1.12.0",
"web-vitals": "^2.1.4"
},
@ -19029,6 +19030,30 @@
"integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
"license": "ISC"
},
"node_modules/@vue/compiler-sfc": {
"version": "2.7.16",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz",
"integrity": "sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==",
"peer": true,
"dependencies": {
"@babel/parser": "^7.23.5",
"postcss": "^8.4.14",
"source-map": "^0.6.1"
},
"optionalDependencies": {
"prettier": "^1.18.2 || ^2.0.0"
}
},
"node_modules/@vue/compiler-sfc/node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"license": "BSD-3-Clause",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@webassemblyjs/ast": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
@ -22153,6 +22178,13 @@
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz",
"integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA=="
},
"node_modules/de-indent": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
"integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
"license": "MIT",
"peer": true
},
"node_modules/debug": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
@ -34198,6 +34230,54 @@
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
"license": "MIT"
},
"node_modules/tiptap": {
"version": "1.32.2",
"resolved": "https://registry.npmjs.org/tiptap/-/tiptap-1.32.2.tgz",
"integrity": "sha512-5IwVj8nGo8y5V3jbdtoEd7xNUsi8Q0N6WV2Nfs70olqz3fldXkiImBrDhZJ4Anx8vhyP6PIBttrg0prFVmwIvw==",
"license": "MIT",
"dependencies": {
"prosemirror-commands": "^1.1.4",
"prosemirror-dropcursor": "^1.3.2",
"prosemirror-gapcursor": "^1.1.5",
"prosemirror-inputrules": "^1.1.3",
"prosemirror-keymap": "^1.1.4",
"prosemirror-model": "^1.13.1",
"prosemirror-state": "^1.3.3",
"prosemirror-view": "^1.16.5",
"tiptap-commands": "^1.17.1",
"tiptap-utils": "^1.13.1"
},
"peerDependencies": {
"vue": "^2.5.17",
"vue-template-compiler": "^2.5.17"
}
},
"node_modules/tiptap-commands": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/tiptap-commands/-/tiptap-commands-1.17.1.tgz",
"integrity": "sha512-CyGvMD/c6fNer5LThWGtrVMXHAqHn93ivGQpqJ58x3HNZFuoIiF9QTWXAiWbY/4QrG0ANYHKCSe9n5afickTqw==",
"license": "MIT",
"dependencies": {
"prosemirror-commands": "^1.1.4",
"prosemirror-inputrules": "^1.1.2",
"prosemirror-model": "^1.13.1",
"prosemirror-schema-list": "^1.1.4",
"prosemirror-state": "^1.3.3",
"prosemirror-tables": "^1.1.1",
"tiptap-utils": "^1.13.1"
}
},
"node_modules/tiptap-utils": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/tiptap-utils/-/tiptap-utils-1.13.1.tgz",
"integrity": "sha512-RoCvMfkdu7fp9u7nsRr1OgsYU8RFjoHKHEKpx075rJ9X0t+j5Vxah9n6QzTTr4yjvcavq22WO2flFacm36zYtA==",
"license": "MIT",
"dependencies": {
"prosemirror-model": "^1.13.1",
"prosemirror-state": "^1.3.3",
"prosemirror-tables": "^1.1.1"
}
},
"node_modules/tmpl": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@ -34973,6 +35053,29 @@
"d3-timer": "^3.0.1"
}
},
"node_modules/vue": {
"version": "2.7.16",
"resolved": "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz",
"integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==",
"deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.",
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-sfc": "2.7.16",
"csstype": "^3.1.0"
}
},
"node_modules/vue-template-compiler": {
"version": "2.7.16",
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",
"integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"de-indent": "^1.0.2",
"he": "^1.2.0"
}
},
"node_modules/w3c-hr-time": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",

View File

@ -36,6 +36,7 @@
"react-scripts": "5.0.1",
"recharts": "^3.1.2",
"sweetalert2": "^11.22.4",
"tiptap": "^1.32.2",
"toastify-js": "^1.12.0",
"web-vitals": "^2.1.4"
},

View File

@ -41,6 +41,10 @@ const CardConsulta = ( {DadosConsulta, TabelaAgendamento, setShowDeleteModal} )
BuscarMedicoEPaciente();
}, [ids, authHeader]);
let nameArrayPaciente = Paciente?.full_name.split(' ')
let nameArrayMedico = Medico?.full_name.split(' ')
return (
<div className={`container-cardconsulta-${TabelaAgendamento}`}>
@ -51,11 +55,12 @@ const CardConsulta = ( {DadosConsulta, TabelaAgendamento, setShowDeleteModal} )
<div>
<section className='cardconsulta-infosecundaria'>
<p>{DadosConsulta.horario} {Medico?.full_name}</p>
<p>{DadosConsulta.horario} {nameArrayMedico && nameArrayMedico.length > 0 ? nameArrayMedico[0] : ''} {nameArrayMedico && nameArrayMedico.length > 1 ? ` ${nameArrayMedico[1]}` : ''} </p>
</section>
<section className='cardconsulta-infoprimaria'>
<p>{Paciente?.full_name} - {DadosConsulta.exam}</p>
<p>{nameArrayPaciente && nameArrayPaciente.length > 0 ? nameArrayPaciente[0] : ''} {nameArrayPaciente && nameArrayPaciente.length > 1 ? ` ${nameArrayPaciente[1]}` : ''}- {}</p>
</section>
</div>

View File

@ -12,14 +12,13 @@ const TabelaAgendamentoDia = ({ handleClickAgendamento, agendamentos, setShowDel
console.log(Dia, "hshdhshhsdhs")
//console.log(Dia, "hshdhshhsdhs")
useEffect(() => {
setDia(ListaDiasComAgendamentos[indiceAcesso])
}, [indiceAcesso])
return (
<div>
<div>

View File

@ -138,7 +138,6 @@ const TabelaAgendamentoSemana = ({ agendamentos, ListarDiasdoMes }) => {
<button
onClick={avancarSemana}
disabled={Indice === totalSemanas - 1 || totalSemanas === 0} // Desabilita se for a última semana ou se não houver semanas
>
<i className='bi bi-chevron-compact-right'></i>
</button>

View File

@ -115,8 +115,3 @@ html[data-bs-theme="dark"] .mostrar-horario th {
color: #e0e0e0;
background-color: #232323;
}
/*
.container-botons{
margin-left: 10rem;
background-color: pink;
}*/

View File

@ -230,3 +230,4 @@ html[data-bs-theme="dark"] .cards-que-faltam {
margin-left: 5rem;
}

View File

@ -53,4 +53,4 @@ const GetDoctorByName = async (nome, authHeader) => {
}
export {GetDoctorByID, GetDoctorByName}
export {GetDoctorByID, GetDoctorByName, GetAllDoctors}

View File

@ -6,6 +6,9 @@ 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 { 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';
@ -14,6 +17,9 @@ import AgendamentosMes from '../components/AgendarConsulta/DadosConsultasMock.js
import dayjs from 'dayjs';
import "./style/Agendamento.css";
import './style/FilaEspera.css';
import { Search } from 'lucide-react';
const Agendamento = () => {
const navigate = useNavigate();
@ -29,6 +35,10 @@ const Agendamento = () => {
const [showDeleteModal, setShowDeleteModal] = useState(false)
const [AgendamentoFiltrado, setAgendamentoFiltrado] = useState()
const [ListaDeMedicos, setListaDeMedicos] = useState([])
const [FiltredTodosMedicos, setFiltredTodosMedicos] = useState([])
const [searchTermDoctor, setSearchTermDoctor] = useState('');
let authHeader = getAuthorizationHeader()
@ -39,7 +49,7 @@ const Agendamento = () => {
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
@ -50,14 +60,13 @@ const Agendamento = () => {
}
}
// faz o set de uma vez só
setAgendamentosOrganizados(DictAgendamentosOrganizados);
}
// Requisição inicial para mostrar os agendamentos do banco de dados
useEffect(() => {
var myHeaders = new Headers();
myHeaders.append("Authorization", authHeader);
myHeaders.append("apikey", API_KEY)
@ -70,10 +79,86 @@ const Agendamento = () => {
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); console.log(result, "aqui")})
.then(result => {FiltrarAgendamentos(result);})
.catch(error => console.log('error', error));
const PegarTodosOsMedicos = async () => {
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(() => {
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]);
/**
* 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
);
return agendamentosFiltrados;
};
// Dados da fila de espera (sem alteração)
@ -101,7 +186,6 @@ const Agendamento = () => {
if (!searchTerm.trim()) {
return AgendamentosMes;
}
const lowerCaseSearchTerm = searchTerm.toLowerCase();
const filteredData = {};
@ -140,8 +224,24 @@ const Agendamento = () => {
const handleClickAgendamento = (agendamento) => {
if (agendamento.status !== 'vazio') return
else setPageConsulta(true)
};
const handleSearchMedicos = (term) => {
setSearchTermDoctor(term);
if (term.trim() === '') {
setFiltredTodosMedicos([]);
return;
}
// Lógica simples de filtragem:
const filtered = ListaDeMedicos.filter(medico =>
medico.nomeMedico.toLowerCase().includes(term.toLowerCase())
);
setFiltredTodosMedicos(filtered);
};
const handleClickCancel = () => setPageConsulta(false)
return (
@ -154,26 +254,46 @@ const Agendamento = () => {
{!PageNovaConsulta ? (
<div className='atendimento-eprocura'>
<div className='busca-atendimento-container'>
<div className='input-e-dropdown-wrapper'>
<div className='busca-atendimento'>
<div>
<i className="fa-solid fa-calendar-day"></i>
<input
type="text"
placeholder="Buscar atendimento por paciente..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Filtrar atendimento por médico..."
value={searchTermDoctor}
onChange={(e) => handleSearchMedicos(e.target.value)} // Chama a nova função de filtro
/>
</div>
<div>
<select>
<option value="" disabled selected>Agendar</option>
<option value="">Atendimento</option>
<option value="">Sessões</option>
<option value="">Urgência</option>
</select>
</div>
{/* DROPDOWN (RENDERIZAÇÃO CONDICIONAL) */}
{searchTermDoctor && FiltredTodosMedicos.length > 0 && (
<div className='dropdown-medicos'>
{FiltredTodosMedicos.map((medico) => (
<div
key={medico.id}
className='dropdown-item'
onClick={() => {
// 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...
}}
>
<p>{medico.nomeMedico} </p>
</div>
))}
</div>
)}
</div>
</div>
<div className='unidade-selecionarprofissional'>
<select>
<option value="" disabled selected >Unidade</option>

View File

@ -311,7 +311,7 @@ html[data-bs-theme="dark"] {
.container-botons{
display: flex;
flex-direction: row;
flex-direction: column;
}
#tabela-seletor-container {
@ -358,3 +358,80 @@ 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 */
}
/* 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 {
/* Garante que a div interna do input ocupe toda a largura do wrapper */
width: 100%;
/* Estilos para o contêiner do ícone e input, se necessário */
}
.busca-atendimento input {
/* Garante que o input preencha a largura disponível dentro do seu contêiner */
width: calc(100% - 40px); /* Exemplo: 100% menos a largura do ícone (aprox. 40px) */
/* ... outros estilos de borda, padding, etc. do seu input ... */
}
/* 3. O Dropdown: Posicionamento e Estilização */
.dropdown-medicos {
/* POSICIONAMENTO: Faz o dropdown flutuar */
position: absolute;
/* POSICIONAMENTO: Coloca o topo do dropdown logo abaixo do input */
top: 100%;
left: 0;
/* LARGURA: Essencial. Ocupa 100% do .input-e-dropdown-wrapper, limitando-se a ele. */
width: 100%;
/* SOBREPOSIÇÃO: Garante que fique acima de outros elementos (como a Fila de Espera) */
z-index: 1000;
/* ESTILIZAÇÃO: Aparência */
background-color: #ffffff; /* Fundo branco para não vazar */
border: 1px solid #ccc; /* Borda leve */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Sombra para profundidade */
border-top: none; /* Deixa o visual mais integrado ao input */
/* COMPORTAMENTO: Limite de altura e scroll */
max-height: 250px;
overflow-y: auto;
}
/* 4. Estilização de cada item do dropdown */
.dropdown-item {
padding: 10px 15px;
cursor: pointer;
font-size: 14px;
color: #333;
/* Evita que nomes muito longos quebrem ou saiam da caixa */
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.dropdown-item:hover {
background-color: #f0f0f0; /* Cor ao passar o mouse */
color: #007bff;
}