forked from RiseUP/riseup-squad23
359 lines
13 KiB
JavaScript
359 lines
13 KiB
JavaScript
import InputMask from "react-input-mask";
|
||
import "./style/formagendamentos.css";
|
||
import { useState, useEffect, useCallback } from "react";
|
||
import { GetPatientByCPF } from "../utils/Functions-Endpoints/Patient";
|
||
import { 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();
|
||
|
||
const [sessoes, setSessoes] = useState(1);
|
||
const [tempoBaseConsulta] = useState(30);
|
||
const [showSuccessModal, setShowSuccessModal] = useState(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([]);
|
||
|
||
const 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;
|
||
|
||
if (name === 'email') {
|
||
setAgendamento(prev => ({
|
||
...prev,
|
||
contato: { ...prev.contato, email: value }
|
||
}));
|
||
} else if (name === 'status') {
|
||
setAgendamento(prev => ({
|
||
...prev,
|
||
status: prev.status === 'requested' ? 'confirmed' : 'requested'
|
||
}));
|
||
} else if (name === 'paciente_cpf') {
|
||
const cpfFormatted = FormatCPF(value);
|
||
const fetchPatient = async () => {
|
||
const patientData = await GetPatientByCPF(cpfFormatted, authHeader);
|
||
if (patientData) {
|
||
setAgendamento(prev => ({
|
||
...prev,
|
||
paciente_nome: patientData.full_name,
|
||
patient_id: patientData.id
|
||
}));
|
||
}
|
||
};
|
||
setAgendamento(prev => ({ ...prev, paciente_cpf: cpfFormatted }));
|
||
fetchPatient();
|
||
} else if (name === 'convenio') {
|
||
setAgendamento(prev => ({ ...prev, insurance_provider: value }));
|
||
} else {
|
||
setAgendamento(prev => ({ ...prev, [name]: value }));
|
||
}
|
||
};
|
||
|
||
const ChamarMedicos = useCallback(async () => {
|
||
const Medicos = await GetAllDoctors(authHeader);
|
||
setTodosProfissionais(Medicos);
|
||
}, [authHeader]);
|
||
|
||
useEffect(() => {
|
||
ChamarMedicos();
|
||
}, [ChamarMedicos]);
|
||
|
||
useEffect(() => {
|
||
if (!agendamento.dataAtendimento || !agendamento.doctor_id) return;
|
||
|
||
const myHeaders = new Headers();
|
||
myHeaders.append("Content-Type", "application/json");
|
||
myHeaders.append("apikey", API_KEY);
|
||
myHeaders.append("Authorization", `Bearer ${authHeader.split(' ')[1]}`);
|
||
|
||
const raw = JSON.stringify({
|
||
doctor_id: agendamento.doctor_id,
|
||
start_date: agendamento.dataAtendimento,
|
||
end_date: `${agendamento.dataAtendimento}T23:59:59.999Z`,
|
||
});
|
||
|
||
const requestOptions = {
|
||
method: 'POST',
|
||
headers: myHeaders,
|
||
body: raw,
|
||
};
|
||
|
||
fetch("https://yuanqfswhberkoevtmfr.supabase.co/functions/v1/get-available-slots", requestOptions)
|
||
.then(response => response.json())
|
||
.then(result => sethorariosDisponiveis(result))
|
||
.catch(error => console.log('error', error));
|
||
}, [agendamento.dataAtendimento, agendamento.doctor_id, authHeader]);
|
||
|
||
const handleSearchProfissional = (e) => {
|
||
const term = e.target.value;
|
||
handleChange(e);
|
||
|
||
if (term.trim() === '') {
|
||
setProfissionaisFiltrados([]);
|
||
setIsDropdownOpen(false);
|
||
return;
|
||
}
|
||
|
||
const filtered = todosProfissionais.filter(p =>
|
||
p.full_name.toLowerCase().includes(term.toLowerCase())
|
||
);
|
||
|
||
setProfissionaisFiltrados(filtered);
|
||
setIsDropdownOpen(filtered.length > 0);
|
||
};
|
||
|
||
const handleSelectProfissional = (profissional) => {
|
||
setAgendamento(prev => ({
|
||
...prev,
|
||
doctor_id: profissional.id,
|
||
nome_medico: profissional.full_name
|
||
}));
|
||
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 calcularHorarioTermino = useCallback((inicio, sessoes, tempoBase) => {
|
||
if (!inicio || inicio.length !== 5 || !inicio.includes(':')) return '';
|
||
|
||
const [horas, minutos] = inicio.split(':').map(Number);
|
||
const minutosInicio = (horas * 60) + minutos;
|
||
const duracaoTotalMinutos = sessoes * tempoBase;
|
||
const minutosTermino = minutosInicio + duracaoTotalMinutos;
|
||
|
||
const horaTermino = Math.floor(minutosTermino / 60) % 24;
|
||
const minutoTermino = minutosTermino % 60;
|
||
|
||
const formatar = (num) => String(num).padStart(2, '0');
|
||
return `${formatar(horaTermino)}:${formatar(minutoTermino)}`;
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
const novoTermino = calcularHorarioTermino(horarioInicio, sessoes, tempoBaseConsulta);
|
||
setHorarioTermino(novoTermino);
|
||
setAgendamento(prev => ({
|
||
...prev,
|
||
horarioTermino: novoTermino
|
||
}));
|
||
}, [horarioInicio, sessoes, tempoBaseConsulta, setAgendamento, calcularHorarioTermino]);
|
||
|
||
const handleSubmit = (e) => {
|
||
e.preventDefault();
|
||
setShowSuccessModal(true);
|
||
};
|
||
|
||
const handleCloseModal = () => {
|
||
setShowSuccessModal(false);
|
||
onSave({ ...agendamento, horarioInicio: horarioInicio });
|
||
};
|
||
|
||
return (
|
||
<div className="form-container">
|
||
{showSuccessModal && (
|
||
<div className="modal-overlay">
|
||
<div className="modal-content">
|
||
<div className="modal-header">
|
||
<h5 className="modal-title">Sucesso</h5>
|
||
<button onClick={handleCloseModal} className="modal-close-btn">×</button>
|
||
</div>
|
||
<div className="modal-body">
|
||
<p className="modal-message">Agendamento salvo com sucesso!</p>
|
||
</div>
|
||
<div className="modal-footer">
|
||
<button onClick={handleCloseModal} className="modal-confirm-btn">Fechar</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
<form className="form-agendamento" onSubmit={handleSubmit}>
|
||
<h2 className="section-title">Informações do paciente</h2>
|
||
|
||
<div className="campos-informacoes-paciente" id="informacoes-paciente-linha-um">
|
||
<div className="campo-de-input">
|
||
<label>CPF do paciente</label>
|
||
<input type="text" name="paciente_cpf" placeholder="000.000.000-00" onChange={handleChange} value={agendamento.paciente_cpf}/>
|
||
</div>
|
||
|
||
<div className="campo-de-input">
|
||
<label>Nome *</label>
|
||
<input type="text" name="paciente_nome" value={agendamento.paciente_nome} placeholder="Insira o nome do paciente" required onChange={handleChange} />
|
||
</div>
|
||
</div>
|
||
|
||
<div className="campos-informacoes-paciente" id="informacoes-paciente-linha-tres">
|
||
<div>
|
||
<label>Convênio</label>
|
||
<select name="convenio" onChange={handleChange} value={agendamento.insurance_provider}>
|
||
<option value="publico">Público</option>
|
||
<option value="unimed">Unimed</option>
|
||
<option value="bradesco_saude">Bradesco Saúde</option>
|
||
<option value="hapvida">Hapvida</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<h2 className="section-title">Informações do atendimento</h2>
|
||
|
||
<div className="campo-informacoes-atendimento">
|
||
<div className="campo-de-input-container">
|
||
<div className="campo-de-input">
|
||
<label>Nome do profissional *</label>
|
||
<input
|
||
type="text"
|
||
name="nome_medico"
|
||
onChange={handleSearchProfissional}
|
||
value={agendamento?.nome_medico || ''}
|
||
autoComplete="off"
|
||
required
|
||
/>
|
||
</div>
|
||
|
||
{isDropdownOpen && profissionaisFiltrados.length > 0 && (
|
||
<div className='dropdown-profissionais'>
|
||
{profissionaisFiltrados.map((profissional) => (
|
||
<div
|
||
key={profissional.id}
|
||
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" value={agendamento.tipo_atendimento}>
|
||
<option value="presencial">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" onChange={handleChange} value={agendamento.dataAtendimento} required />
|
||
</div>
|
||
|
||
<div className="linha">
|
||
<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 className='seletor-wrapper'>
|
||
<label>Número de Sessões *</label>
|
||
<div className='sessao-contador'>
|
||
<button
|
||
type="button"
|
||
onClick={() => setSessoes(prev => Math.max(0, prev - 1))}
|
||
disabled={sessoes === 0}
|
||
>
|
||
<i className="bi bi-chevron-compact-left"></i>
|
||
</button>
|
||
|
||
<p className='sessao-valor'>{sessoes}</p>
|
||
|
||
<button
|
||
type="button"
|
||
onClick={() => setSessoes(prev => Math.min(3, prev + 1))}
|
||
disabled={sessoes === 3}
|
||
>
|
||
<i className="bi bi-chevron-compact-right"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="campo-de-input">
|
||
<label htmlFor="termino">Término *</label>
|
||
<input
|
||
type="text"
|
||
id="termino"
|
||
name="termino"
|
||
value={horarioTermino || '— —'}
|
||
readOnly
|
||
className="horario-termino-readonly"
|
||
/>
|
||
</div>
|
||
</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" onChange={handleChange} value={agendamento.observacoes || ''}></textarea>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
|
||
<div className="campo-de-input-check">
|
||
<input
|
||
className="form-check-input form-custom-check"
|
||
type="checkbox"
|
||
name="status"
|
||
onChange={handleChange}
|
||
checked={agendamento.status === 'requested'}
|
||
/>
|
||
<label className="form-check-label checkbox-label" htmlFor="status">
|
||
Adicionar a fila de espera
|
||
</label>
|
||
</div>
|
||
|
||
<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 FormNovaConsulta; |