merge com melhoriasAgendamentos
This commit is contained in:
commit
aa399d2d99
70
src/PagesPaciente/CardConsultaPaciente.jsx
Normal file
70
src/PagesPaciente/CardConsultaPaciente.jsx
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { useEffect, useMemo,useState } from 'react'
|
||||||
|
import { GetDoctorByID } from '../components/utils/Functions-Endpoints/Doctor'
|
||||||
|
import { GetPatientByID } from '../components/utils/Functions-Endpoints/Patient'
|
||||||
|
import { useAuth } from '../components/utils/AuthProvider'
|
||||||
|
|
||||||
|
const CardConsultaPaciente = ({consulta}) => {
|
||||||
|
|
||||||
|
const [Paciente, setPaciente] = useState({})
|
||||||
|
const [Medico, setMedico] = useState({})
|
||||||
|
const {getAuthorizationHeader} = useAuth()
|
||||||
|
|
||||||
|
const authHeader = getAuthorizationHeader()
|
||||||
|
|
||||||
|
const ids = useMemo(() => {
|
||||||
|
return {
|
||||||
|
doctor_id: consulta?.doctor_id,
|
||||||
|
patient_id: consulta?.patient_id,
|
||||||
|
status: consulta?.status
|
||||||
|
};
|
||||||
|
}, [consulta]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const BuscarMedicoEPaciente = async () => {
|
||||||
|
if (!ids.doctor_id || !ids.patient_id || ids.status === 'nada') return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [Doctor, Patient] = await Promise.all([
|
||||||
|
GetDoctorByID(ids.doctor_id, authHeader),
|
||||||
|
GetPatientByID(ids.patient_id, authHeader)
|
||||||
|
]);
|
||||||
|
|
||||||
|
setMedico(Doctor?.[0] || null);
|
||||||
|
setPaciente(Patient?.[0] || null);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao buscar médico/paciente:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BuscarMedicoEPaciente();
|
||||||
|
}, [ids, authHeader]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
console.log(consulta, "dento do card")
|
||||||
|
|
||||||
|
let horario = consulta.scheduled_at.split("T")[1]
|
||||||
|
let Data = consulta.scheduled_at.split("T")[0]
|
||||||
|
|
||||||
|
console.log(horario)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="card-consulta">
|
||||||
|
<div class="horario-container">
|
||||||
|
|
||||||
|
<span class="horario">
|
||||||
|
{`${Data?.split("-")[2]}/${Data?.split("-")[1]}`}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-container">
|
||||||
|
<span class="informacao">
|
||||||
|
Dr {Medico?.full_name} - {Medico?.specialty}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CardConsultaPaciente
|
||||||
81
src/PagesPaciente/ConsultaCadastroManager.jsx
Normal file
81
src/PagesPaciente/ConsultaCadastroManager.jsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import FormConsultaPaciente from './FormConsultaPaciente'
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { useAuth } from '../components/utils/AuthProvider'
|
||||||
|
import API_KEY from '../components/utils/apiKeys'
|
||||||
|
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import { UserInfos } from '../components/utils/Functions-Endpoints/General'
|
||||||
|
const ConsultaCadastroManager = () => {
|
||||||
|
|
||||||
|
const {getAuthorizationHeader} = useAuth()
|
||||||
|
const [Dict, setDict] = useState({})
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const [idUsuario, setIDusuario] = useState("")
|
||||||
|
|
||||||
|
let authHeader = getAuthorizationHeader()
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const ColherInfoUsuario =async () => {
|
||||||
|
const result = await UserInfos(authHeader)
|
||||||
|
|
||||||
|
setIDusuario(result?.profile?.id)
|
||||||
|
|
||||||
|
}
|
||||||
|
ColherInfoUsuario()
|
||||||
|
|
||||||
|
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleSave = (Dict) => {
|
||||||
|
let DataAtual = dayjs()
|
||||||
|
var myHeaders = new Headers();
|
||||||
|
myHeaders.append("apikey", API_KEY);
|
||||||
|
myHeaders.append("Authorization", authHeader);
|
||||||
|
myHeaders.append("Content-Type", "application/json");
|
||||||
|
|
||||||
|
var raw = JSON.stringify({
|
||||||
|
"patient_id": Dict.patient_id,
|
||||||
|
"doctor_id": Dict.doctor_id,
|
||||||
|
"scheduled_at": `${Dict.dataAtendimento}T${Dict.horarioInicio}:00.000Z`,
|
||||||
|
"duration_minutes": 30,
|
||||||
|
"appointment_type": Dict.tipo_consulta,
|
||||||
|
|
||||||
|
"patient_notes": "Prefiro horário pela manhã",
|
||||||
|
"insurance_provider": Dict.convenio,
|
||||||
|
"status": Dict.status,
|
||||||
|
"created_by": idUsuario
|
||||||
|
});
|
||||||
|
|
||||||
|
var requestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: myHeaders,
|
||||||
|
body: raw,
|
||||||
|
redirect: 'follow'
|
||||||
|
};
|
||||||
|
|
||||||
|
fetch("https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments", requestOptions)
|
||||||
|
.then(response => response.text())
|
||||||
|
.then(result => console.log(result))
|
||||||
|
.catch(error => console.log('error', error));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<FormConsultaPaciente agendamento={Dict} setAgendamento={setDict} onSave={handleSave} onCancel={() => navigate("/paciente/agendamento/")}/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConsultaCadastroManager
|
||||||
96
src/PagesPaciente/ConsultasPaciente.jsx
Normal file
96
src/PagesPaciente/ConsultasPaciente.jsx
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import "./style.css"
|
||||||
|
import CardConsultaPaciente from './CardConsultaPaciente'
|
||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import API_KEY from '../components/utils/apiKeys'
|
||||||
|
import { useAuth } from '../components/utils/AuthProvider'
|
||||||
|
|
||||||
|
const ConsultasPaciente = () => {
|
||||||
|
const {getAuthorizationHeader} = useAuth()
|
||||||
|
|
||||||
|
let authHeader = getAuthorizationHeader()
|
||||||
|
|
||||||
|
const [consultas, setConsultas] = useState([])
|
||||||
|
|
||||||
|
const FiltrarAgendamentos = (agendamentos, id) => {
|
||||||
|
// Verifica se a lista de agendamentos é válida antes de tentar filtrar
|
||||||
|
if (!agendamentos || !Array.isArray(agendamentos)) {
|
||||||
|
console.error("A lista de agendamentos é inválida.");
|
||||||
|
setConsultas([]); // Garante que setConsultas receba uma lista vazia
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Filtragem
|
||||||
|
// O método .filter() cria uma nova lista contendo apenas os itens que retornarem 'true'
|
||||||
|
const consultasFiltradas = agendamentos.filter(agendamento => {
|
||||||
|
// A condição: o patient_id do agendamento deve ser estritamente igual ao id fornecido
|
||||||
|
// Usamos toString() para garantir a comparação, pois um pode ser number e o outro string
|
||||||
|
return agendamento.patient_id && agendamento.patient_id.toString() === id.toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. Adicionar a lista no setConsultas
|
||||||
|
console.log(consultasFiltradas)
|
||||||
|
setConsultas(consultasFiltradas);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exemplo de como você chamaria (assumindo que DadosAgendamento é sua lista original):
|
||||||
|
// FiltrarAgendamentos(DadosAgendamento, Paciente.id);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
var myHeaders = new Headers();
|
||||||
|
myHeaders.append("Authorization", authHeader);
|
||||||
|
myHeaders.append("apikey", API_KEY)
|
||||||
|
|
||||||
|
var requestOptions = {
|
||||||
|
method: 'GET',
|
||||||
|
headers: myHeaders,
|
||||||
|
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, "6e7f8829-0574-42df-9290-8dbb70f75ada" )})
|
||||||
|
.catch(error => console.log('error', error));
|
||||||
|
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const navigate = useNavigate()
|
||||||
|
/*
|
||||||
|
const consultas = [
|
||||||
|
{
|
||||||
|
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||||
|
"doctor_id": "eaca4372-17bc-4905-9eff-7aeda46157b4",
|
||||||
|
"patient_id": "3854866a-5476-48be-8313-77029ccdd7a7",
|
||||||
|
"scheduled_at": "2019-08-24T14:15:22Z",
|
||||||
|
"status": "string"
|
||||||
|
}
|
||||||
|
]*/
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1> Gerencie suas consultas</h1>
|
||||||
|
|
||||||
|
<div className='form-container'>
|
||||||
|
|
||||||
|
<button className="btn btn-primary" onClick={() => {navigate("criar")}}>
|
||||||
|
<i className="bi bi-plus-circle"></i> Adicionar Consulta
|
||||||
|
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<h2>Seus proximos atendimentos</h2>
|
||||||
|
|
||||||
|
{consultas.map((consulta) => (
|
||||||
|
<CardConsultaPaciente consulta={consulta}/>
|
||||||
|
|
||||||
|
))}
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Historico de consultas:</h2>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConsultasPaciente
|
||||||
318
src/PagesPaciente/FormConsultaPaciente.jsx
Normal file
318
src/PagesPaciente/FormConsultaPaciente.jsx
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
import InputMask from "react-input-mask";
|
||||||
|
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { GetPatientByCPF } from "../components/utils/Functions-Endpoints/Patient";
|
||||||
|
import { GetDoctorByName, GetAllDoctors } from "../components/utils/Functions-Endpoints/Doctor";
|
||||||
|
import { useAuth } from "../components/utils/AuthProvider";
|
||||||
|
import API_KEY from "../components/utils/apiKeys";
|
||||||
|
|
||||||
|
const FormConsultaPaciente = ({ onCancel, onSave, setAgendamento, agendamento }) => {
|
||||||
|
const {getAuthorizationHeader} = useAuth()
|
||||||
|
|
||||||
|
console.log(agendamento, 'aqui2')
|
||||||
|
|
||||||
|
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 [todosProfissionais, setTodosProfissionais] = useState([])
|
||||||
|
const [profissionaisFiltrados, setProfissionaisFiltrados] = useState([]);
|
||||||
|
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
|
const [horarioInicio, setHorarioInicio] = useState('');
|
||||||
|
const [horarioTermino, setHorarioTermino] = useState('');
|
||||||
|
|
||||||
|
const [horariosDisponiveis, sethorariosDisponiveis] = useState([])
|
||||||
|
|
||||||
|
let authHeader = getAuthorizationHeader()
|
||||||
|
|
||||||
|
const FormatCPF = (valor) => {
|
||||||
|
const digits = String(valor).replace(/\D/g, '').slice(0, 11);
|
||||||
|
return digits
|
||||||
|
.replace(/(\d{3})(\d)/, '$1.$2')
|
||||||
|
.replace(/(\d{3})(\d)/, '$1.$2')
|
||||||
|
.replace(/(\d{3})(\d{1,2})$/, '$1-$2');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const handleChange = (e) => {
|
||||||
|
const {value, name} = e.target;
|
||||||
|
console.log(value, name, agendamento)
|
||||||
|
|
||||||
|
if(name === 'email'){
|
||||||
|
setAgendamento({...agendamento, contato:{
|
||||||
|
...agendamento.contato,
|
||||||
|
email:value
|
||||||
|
}})}
|
||||||
|
else if(name === 'status'){
|
||||||
|
if(agendamento.status==='requested'){
|
||||||
|
setAgendamento((prev) => ({
|
||||||
|
...prev,
|
||||||
|
status:'confirmed',
|
||||||
|
}));
|
||||||
|
}else if(agendamento.status === 'confirmed'){
|
||||||
|
console.log(value)
|
||||||
|
setAgendamento((prev) => ({
|
||||||
|
...prev,
|
||||||
|
status:'requested',
|
||||||
|
}));
|
||||||
|
}}
|
||||||
|
|
||||||
|
else if(name === 'paciente_cpf'){
|
||||||
|
|
||||||
|
let cpfFormatted = FormatCPF(value)
|
||||||
|
const fetchPatient = async () => {
|
||||||
|
let patientData = await GetPatientByCPF(cpfFormatted, authHeader);
|
||||||
|
if (patientData) {
|
||||||
|
setAgendamento((prev) => ({
|
||||||
|
...prev,
|
||||||
|
paciente_nome: patientData.full_name,
|
||||||
|
patient_id: patientData.id
|
||||||
|
}));
|
||||||
|
}}
|
||||||
|
setAgendamento(prev => ({ ...prev, cpf: cpfFormatted }))
|
||||||
|
fetchPatient()
|
||||||
|
}else if(name==='convenio'){
|
||||||
|
setAgendamento({...agendamento,insurance_provider:value})
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
setAgendamento({...agendamento,[name]:value})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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": agendamento.doctor_id,
|
||||||
|
"start_date": agendamento.dataAtendimento,
|
||||||
|
"end_date": `${agendamento.dataAtendimento}T23: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));
|
||||||
|
|
||||||
|
}, [agendamento.dataAtendimento, agendamento.doctor_id])
|
||||||
|
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
medico_nome: profissional.full_name
|
||||||
|
}));
|
||||||
|
// 2. Fecha o dropdown
|
||||||
|
setProfissionaisFiltrados([]);
|
||||||
|
setIsDropdownOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const formatarHora = (datetimeString) => {
|
||||||
|
return datetimeString.substring(11, 16);
|
||||||
|
};
|
||||||
|
|
||||||
|
const opcoesDeHorario = horariosDisponiveis?.slots?.map(item => ({
|
||||||
|
|
||||||
|
value: formatarHora(item.datetime),
|
||||||
|
label: formatarHora(item.datetime),
|
||||||
|
disabled: !item.available
|
||||||
|
}));
|
||||||
|
|
||||||
|
const handleSubmit = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
alert("Agendamento salvo!");
|
||||||
|
onSave({...agendamento, horarioInicio:horarioInicio})
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="form-container">
|
||||||
|
|
||||||
|
|
||||||
|
<form className="form-agendamento" onSubmit={handleSubmit}>
|
||||||
|
1
|
||||||
|
|
||||||
|
<h2 className="section-title">Informações do atendimento</h2>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="campo-informacoes-atendimento">
|
||||||
|
|
||||||
|
<div className="campo-de-input-container"> {/* NOVO CONTAINER PAI */}
|
||||||
|
<div className="campo-de-input">
|
||||||
|
<label>Nome do profissional *</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="medico_nome" // Use o nome correto da propriedade no estado `agendamento`
|
||||||
|
onChange={handleSearchProfissional}
|
||||||
|
value={agendamento.medico_nome}
|
||||||
|
autoComplete="off" // Ajuda a evitar o autocomplete nativo do navegador
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* DROPDOWN - RENDERIZAÇÃO CONDICIONAL */}
|
||||||
|
{isDropdownOpen && profissionaisFiltrados.length > 0 && (
|
||||||
|
<div className='dropdown-profissionais'>
|
||||||
|
{profissionaisFiltrados.map((profissional) => (
|
||||||
|
<div
|
||||||
|
key={profissional.id} // Use o ID do profissional
|
||||||
|
className='dropdown-item'
|
||||||
|
onClick={() => handleSelectProfissional(profissional)}
|
||||||
|
>
|
||||||
|
{profissional.full_name}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tipo_atendimento">
|
||||||
|
<label>Tipo de atendimento *</label>
|
||||||
|
<select onChange={handleChange} name="tipo_atendimento" >
|
||||||
|
<option value="presencial" selected>Presencial</option>
|
||||||
|
<option value="teleconsulta">Teleconsulta</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section id="informacoes-atendimento-segunda-linha">
|
||||||
|
<section id="informacoes-atendimento-segunda-linha-esquerda">
|
||||||
|
|
||||||
|
<div className="campo-informacoes-atendimento">
|
||||||
|
|
||||||
|
|
||||||
|
<div className="campo-de-input">
|
||||||
|
<label>Data *</label>
|
||||||
|
<input type="date" name="dataAtendimento" value={agendamento.dataAtendimento} onChange={handleChange} required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
<div className="campo-de-input">
|
||||||
|
<label htmlFor="inicio">Início *</label>
|
||||||
|
<select
|
||||||
|
id="inicio"
|
||||||
|
name="inicio"
|
||||||
|
required
|
||||||
|
value={horarioInicio}
|
||||||
|
onChange={(e) => setHorarioInicio(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="" disabled>Selecione a hora de início</option>
|
||||||
|
{opcoesDeHorario?.map((opcao, index) => (
|
||||||
|
<option
|
||||||
|
key={index}
|
||||||
|
value={opcao.value}
|
||||||
|
disabled={opcao.disabled}
|
||||||
|
>
|
||||||
|
{opcao.label}
|
||||||
|
{opcao.disabled && " (Indisponível)"}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{/* Dropdown de Término */}
|
||||||
|
<div className="campo-de-input">
|
||||||
|
<label htmlFor="termino">Término *</label>
|
||||||
|
<select
|
||||||
|
id="termino"
|
||||||
|
name="termino"
|
||||||
|
required
|
||||||
|
value={horarioTermino}
|
||||||
|
onChange={(e) => setHorarioTermino(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="" disabled>Selecione a hora de término</option>
|
||||||
|
{opcoesDeHorario?.map((opcao, index) => (
|
||||||
|
<option
|
||||||
|
key={index}
|
||||||
|
value={opcao.value}
|
||||||
|
disabled={opcao.disabled}
|
||||||
|
>
|
||||||
|
{opcao.label}
|
||||||
|
{opcao.disabled && " (Indisponível)"}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="informacoes-atendimento-segunda-linha-direita">
|
||||||
|
|
||||||
|
|
||||||
|
<div className="campo-de-input">
|
||||||
|
<label>Observações</label>
|
||||||
|
<textarea name="observacoes" rows="4" cols="1"></textarea>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div className="form-actions">
|
||||||
|
<button type="submit" className="btn-primary">Salvar agendamento</button>
|
||||||
|
<button type="button" className="btn-cancel" onClick={onCancel}>Cancelar</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FormConsultaPaciente;
|
||||||
44
src/PagesPaciente/style.css
Normal file
44
src/PagesPaciente/style.css
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
/* Estilo geral do card para agrupar e dar um formato */
|
||||||
|
.card-consulta {
|
||||||
|
background-color: #007bff; /* Um tom de azul padrão */
|
||||||
|
display: flex; /* Para colocar horário e info lado a lado */
|
||||||
|
border-radius: 10px; /* Cantos arredondados */
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Sombra suave */
|
||||||
|
overflow: hidden; /* Garante que o fundo azul não 'vaze' */
|
||||||
|
width: 280px; /* Largura de exemplo */
|
||||||
|
margin: 20px;
|
||||||
|
font-family: Arial, sans-serif; /* Fonte legível */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 1. Estilo para o Horário (Fundo Azul e Texto Branco/Grande) */
|
||||||
|
.horario-container {
|
||||||
|
background-color: #007bff; /* Um tom de azul padrão */
|
||||||
|
color: white; /* Texto branco */
|
||||||
|
padding: 15px 20px; /* Espaçamento interno */
|
||||||
|
display: flex;
|
||||||
|
align-items: center; /* Centraliza verticalmente */
|
||||||
|
justify-content: center; /* Centraliza horizontalmente */
|
||||||
|
flex-shrink: 0; /* Impede que o container do horário encolha */
|
||||||
|
border-right: 1px solid #0056b3; /* Uma linha sutil de separação */
|
||||||
|
}
|
||||||
|
|
||||||
|
.horario {
|
||||||
|
font-size: 2.2em; /* Torna o horário grande */
|
||||||
|
font-weight: bold; /* Deixa em negrito */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Estilo para as Informações (Fundo Branco) */
|
||||||
|
.info-container {
|
||||||
|
border-radius: 20px 0px 0px 20px;
|
||||||
|
background-color: white; /* Fundo branco, como solicitado */
|
||||||
|
color: #333; /* Cor escura para o texto para bom contraste */
|
||||||
|
padding: 15px; /* Espaçamento interno */
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-grow: 1; /* Faz com que a div de informações preencha o espaço restante */
|
||||||
|
}
|
||||||
|
|
||||||
|
.informacao {
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
@ -3,10 +3,12 @@ import { GetPatientByID } from '../utils/Functions-Endpoints/Patient';
|
|||||||
import { useAuth } from '../utils/AuthProvider';
|
import { useAuth } from '../utils/AuthProvider';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import "./style/card-consulta.css"
|
||||||
const CardConsulta = ( {DadosConsulta, TabelaAgendamento, setShowDeleteModal, setDictInfo, setSelectedId} ) => {
|
const CardConsulta = ( {DadosConsulta, TabelaAgendamento, setShowDeleteModal, setDictInfo, setSelectedId} ) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
console.log(DadosConsulta, "AQUIIII")
|
||||||
|
|
||||||
const {getAuthorizationHeader} = useAuth()
|
const {getAuthorizationHeader} = useAuth()
|
||||||
const authHeader = getAuthorizationHeader()
|
const authHeader = getAuthorizationHeader()
|
||||||
const [Paciente, setPaciente] = useState()
|
const [Paciente, setPaciente] = useState()
|
||||||
@ -48,7 +50,7 @@ const CardConsulta = ( {DadosConsulta, TabelaAgendamento, setShowDeleteModal, se
|
|||||||
console.log(DadosConsulta.status)
|
console.log(DadosConsulta.status)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`container-cardconsulta-${TabelaAgendamento}`}>
|
<div className={`container-cardconsulta container-cardconsulta-${TabelaAgendamento}`}>
|
||||||
|
|
||||||
{DadosConsulta.id?
|
{DadosConsulta.id?
|
||||||
|
|
||||||
@ -65,23 +67,18 @@ const CardConsulta = ( {DadosConsulta, TabelaAgendamento, setShowDeleteModal, se
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='container-botons'>
|
<div className='actions-container'>
|
||||||
<button className="btn btn-sm btn-edit-custom"
|
<button className="btn btn-sm btn-edit-custom"
|
||||||
|
|
||||||
onClick={() => {navigate(`2/edit`)
|
onClick={() => {navigate(`2/edit`)
|
||||||
setDictInfo({agendamento:DadosConsulta, Infos:{paciente_cpf:Paciente.cpf, paciente_nome:Paciente.full_name}})
|
setDictInfo({...DadosConsulta,paciente_cpf:Paciente.cpf, paciente_nome:Paciente.full_name, nome_medico:Medico.full_name})
|
||||||
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
>
|
>
|
||||||
<i className="bi bi-pencil me-1"></i>
|
<i className="bi bi-pencil me-1"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
className="btn btn-sm btn-delete-custom"
|
className="btn btn-sm btn-delete-custom-style "
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
console.log(DadosConsulta.id)
|
console.log(DadosConsulta.id)
|
||||||
setSelectedId(DadosConsulta.id);
|
setSelectedId(DadosConsulta.id);
|
||||||
|
|||||||
@ -70,7 +70,7 @@ const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
|||||||
if (patientData) {
|
if (patientData) {
|
||||||
setAgendamento((prev) => ({
|
setAgendamento((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
pacinte_nome: patientData.full_name,
|
paciente_nome: patientData.full_name,
|
||||||
patient_id: patientData.id
|
patient_id: patientData.id
|
||||||
}));
|
}));
|
||||||
}}
|
}}
|
||||||
@ -146,7 +146,7 @@ const handleSelectProfissional = async (profissional) => {
|
|||||||
setAgendamento(prev => ({
|
setAgendamento(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
doctor_id: profissional.id,
|
doctor_id: profissional.id,
|
||||||
medico_nome: profissional.full_name
|
nome_medico: profissional.full_name
|
||||||
}));
|
}));
|
||||||
// 2. Fecha o dropdown
|
// 2. Fecha o dropdown
|
||||||
setProfissionaisFiltrados([]);
|
setProfissionaisFiltrados([]);
|
||||||
@ -215,9 +215,9 @@ const handleSubmit = (e) => {
|
|||||||
<label>Nome do profissional *</label>
|
<label>Nome do profissional *</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="medico_nome" // Use o nome correto da propriedade no estado `agendamento`
|
name="nome_medico" // Use o nome correto da propriedade no estado `agendamento`
|
||||||
onChange={handleSearchProfissional}
|
onChange={handleSearchProfissional}
|
||||||
value={agendamento.medico_nome}
|
value={agendamento?.nome_medico}
|
||||||
autoComplete="off" // Ajuda a evitar o autocomplete nativo do navegador
|
autoComplete="off" // Ajuda a evitar o autocomplete nativo do navegador
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -10,6 +10,7 @@ const TabelaAgendamentoDia = ({ handleClickAgendamento, agendamentos, setShowDel
|
|||||||
|
|
||||||
let ListaDiasComAgendamentos = Object.keys(agendamentos)
|
let ListaDiasComAgendamentos = Object.keys(agendamentos)
|
||||||
|
|
||||||
|
console.log(agendamentos)
|
||||||
|
|
||||||
|
|
||||||
//console.log(Dia, "hshdhshhsdhs")
|
//console.log(Dia, "hshdhshhsdhs")
|
||||||
|
|||||||
61
src/components/AgendarConsulta/style/card-consulta.css
Normal file
61
src/components/AgendarConsulta/style/card-consulta.css
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
.actions-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-left: 2rem;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
|
||||||
|
/* 🎨 Glassmorphism */
|
||||||
|
background: rgba(255, 255, 255, 0.25);
|
||||||
|
backdrop-filter: blur(80px);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mostra no hover do card */
|
||||||
|
.container-cardconsulta:hover .actions-container {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Estilos base para o botão de edição (amarelo) */
|
||||||
|
.btn-edit-custom-style {
|
||||||
|
background-color: #ffc107; /* Amarelo da sua imagem */
|
||||||
|
color: #343a40; /* Cor do ícone (cinza escuro para contraste) */
|
||||||
|
border: none;
|
||||||
|
padding: 8px 12px; /* Ajuste o padding para o tamanho do botão */
|
||||||
|
border-radius: 0.25rem; /* Leve arredondamento de borda */
|
||||||
|
transition: background-color 0.2s ease-in-out; /* Suaviza a transição de cor */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 5. Estilos base para o botão de exclusão (vermelho) */
|
||||||
|
.btn-delete-custom-style {
|
||||||
|
background-color: #dc3545; /* Vermelho da sua imagem */
|
||||||
|
color: #ffffff; /* Cor do ícone (branco para contraste) */
|
||||||
|
border: none;
|
||||||
|
padding: 8px 12px; /* Ajuste o padding para o tamanho do botão */
|
||||||
|
border-radius: 0.25rem; /* Leve arredondamento de borda */
|
||||||
|
transition: background-color 0.2s ease-in-out; /* Suaviza a transição de cor */
|
||||||
|
|
||||||
|
font-weight:bold ;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 6. Estilo de hover para o botão de exclusão */
|
||||||
|
.btn-delete-custom-style:hover {
|
||||||
|
background-color: #c82333; /* Um vermelho um pouco mais escuro para o hover */
|
||||||
|
filter: brightness(90%); /* Alternativa: escurecer um pouco mais */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 7. Estilos para os ícones dentro dos botões (já está no JSX com fs-4) */
|
||||||
|
/* .fs-4 do Bootstrap já cuida do tamanho do ícone. Se precisar de mais controle, adicione aqui. */
|
||||||
|
.action-button .bi {
|
||||||
|
/* Exemplo: se precisar de um ajuste fino além do fs-4 */
|
||||||
|
/* font-size: 1.5rem; */
|
||||||
|
}
|
||||||
@ -92,7 +92,6 @@ font-weight: 600;
|
|||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ajuste para a classe calendario, se for usada */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -52,11 +52,13 @@ const Agendamento = ({setDictInfo}) => { // Mantido setDictInfo (versão main)
|
|||||||
let medico = await GetDoctorByID(doctor_id, authHeader);
|
let medico = await GetDoctorByID(doctor_id, authHeader);
|
||||||
let paciente = await GetPatientByID(patient_id, authHeader);
|
let paciente = await GetPatientByID(patient_id, authHeader);
|
||||||
|
|
||||||
|
console.log(medico)
|
||||||
|
|
||||||
let dicionario = {
|
let dicionario = {
|
||||||
agendamento: agendamento,
|
agendamento: agendamento,
|
||||||
Infos: {
|
Infos: {
|
||||||
nome_nedico: medico.full_name,
|
nome_medico: medico[0]?.full_name,
|
||||||
doctor_id: medico.id,
|
doctor_id: medico[0]?.id,
|
||||||
patient_id: paciente[0].id,
|
patient_id: paciente[0].id,
|
||||||
paciente_nome: paciente[0].full_name,
|
paciente_nome: paciente[0].full_name,
|
||||||
paciente_cpf: paciente[0].cpf
|
paciente_cpf: paciente[0].cpf
|
||||||
@ -119,7 +121,7 @@ const Agendamento = ({setDictInfo}) => { // Mantido setDictInfo (versão main)
|
|||||||
|
|
||||||
fetch("https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments?select&doctor_id&patient_id&status&scheduled_at&order&limit&offset", requestOptions)
|
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(response => response.json())
|
||||||
.then(result => {FiltrarAgendamentos(result);})
|
.then(result => {FiltrarAgendamentos(result);console.log(result)})
|
||||||
.catch(error => console.log('error', error));
|
.catch(error => console.log('error', error));
|
||||||
|
|
||||||
const PegarTodosOsMedicos = async () => {
|
const PegarTodosOsMedicos = async () => {
|
||||||
@ -392,7 +394,7 @@ const handleSearchMedicos = (term) => {
|
|||||||
<tr key={index}>
|
<tr key={index}>
|
||||||
<td> <p>{item.Infos?.paciente_nome} </p> </td>
|
<td> <p>{item.Infos?.paciente_nome} </p> </td>
|
||||||
<td><p>{item.Infos?.paciente_cpf} </p></td>
|
<td><p>{item.Infos?.paciente_cpf} </p></td>
|
||||||
<td><p>{item.Infos?.nome_nedico} </p></td>
|
<td><p>{item.Infos?.nome_medico} </p></td>
|
||||||
<td>{dayjs(item.agendamento.created_at).format('DD/MM/YYYY HH:mm')}</td>
|
<td>{dayjs(item.agendamento.created_at).format('DD/MM/YYYY HH:mm')}</td>
|
||||||
<td> <div className="d-flex gap-2">
|
<td> <div className="d-flex gap-2">
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,8 @@ const AgendamentoEditPage = ({setDictInfo, DictInfo}) => {
|
|||||||
|
|
||||||
let id = params.id
|
let id = params.id
|
||||||
|
|
||||||
|
console.log(DictInfo, "DENTRO DO EDITAR")
|
||||||
|
|
||||||
//console.log(DictInfo, 'aqui')
|
//console.log(DictInfo, 'aqui')
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -21,10 +21,11 @@ function DoctorCadastroManager() {
|
|||||||
const authHeader = getAuthorizationHeader();
|
const authHeader = getAuthorizationHeader();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
console.log(authHeader)
|
||||||
var myHeaders = new Headers();
|
var myHeaders = new Headers();
|
||||||
myHeaders.append("Content-Type", "application/json");
|
myHeaders.append("Content-Type", "application/json");
|
||||||
myHeaders.append("apikey", API_KEY);
|
myHeaders.append("apikey", API_KEY);
|
||||||
myHeaders.append("Authorization", authHeader);
|
myHeaders.append("Authorization",`Bearer ${authHeader.split(` `)[1]}` );
|
||||||
|
|
||||||
console.log('Dados recebidos do Form:', doctorData);
|
console.log('Dados recebidos do Form:', doctorData);
|
||||||
|
|
||||||
@ -58,7 +59,7 @@ function DoctorCadastroManager() {
|
|||||||
redirect: 'follow'
|
redirect: 'follow'
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch("https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors", requestOptions);
|
const response = await fetch("https://yuanqfswhberkoevtmfr.supabase.co/functions/v1/create-doctor", requestOptions);
|
||||||
|
|
||||||
console.log("Status da resposta:", response.status);
|
console.log("Status da resposta:", response.status);
|
||||||
console.log("Response ok:", response.ok);
|
console.log("Response ok:", response.ok);
|
||||||
|
|||||||
@ -72,7 +72,7 @@ function PatientCadastroManager({ setCurrentPage }) {
|
|||||||
|
|
||||||
const cleanedData = {
|
const cleanedData = {
|
||||||
full_name: patientData.full_name,
|
full_name: patientData.full_name,
|
||||||
cpf: cpfLimpo,
|
cpf: patientData.cpf,
|
||||||
email: patientData.email,
|
email: patientData.email,
|
||||||
phone_mobile: patientData.phone_mobile,
|
phone_mobile: patientData.phone_mobile,
|
||||||
birth_date: patientData.birth_date || null,
|
birth_date: patientData.birth_date || null,
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import { Routes, Route } from "react-router-dom";
|
import { Routes, Route } from "react-router-dom";
|
||||||
import Sidebar from "../../components/Sidebar";
|
import Sidebar from "../../components/Sidebar";
|
||||||
import PacienteItems from "../../data/sidebar-items-paciente.json";
|
import PacienteItems from "../../data/sidebar-items-paciente.json";
|
||||||
import Agendamento from "../../pages/Agendamento";
|
|
||||||
import LaudoManager from "../../pages/LaudoManager";
|
import LaudoManager from "../../pages/LaudoManager";
|
||||||
|
import ConsultaCadastroManager from "../../PagesPaciente/ConsultaCadastroManager";
|
||||||
|
import ConsultasPaciente from "../../PagesPaciente/ConsultasPaciente";
|
||||||
|
|
||||||
function PerfilPaciente({ onLogout }) {
|
function PerfilPaciente({ onLogout }) {
|
||||||
return (
|
return (
|
||||||
<div id="app" className="active">
|
<div id="app" className="active">
|
||||||
@ -11,7 +14,8 @@ function PerfilPaciente({ onLogout }) {
|
|||||||
<div id="main">
|
<div id="main">
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<LaudoManager />} />
|
<Route path="/" element={<LaudoManager />} />
|
||||||
<Route path="agendamento" element={<Agendamento />} />
|
<Route path="agendamento" element={<ConsultasPaciente />} />
|
||||||
|
<Route path="agendamento/criar" element={<ConsultaCadastroManager />} />
|
||||||
<Route path="laudo" element={<LaudoManager />} />
|
<Route path="laudo" element={<LaudoManager />} />
|
||||||
<Route path="*" element={<h2>Página não encontrada</h2>} />
|
<Route path="*" element={<h2>Página não encontrada</h2>} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user