CPF vizualização e erro 404

This commit is contained in:
GilenoNeto901 2025-09-25 00:13:21 -03:00
parent 3993097c10
commit fbf15e1cbc
4 changed files with 286 additions and 240 deletions

56
et --hard 63659b6 Normal file
View File

@ -0,0 +1,56 @@
3993097 (HEAD -> main) Merge branch 'main' of https://git.popcode.com.br/RiseUP/riseup-squad23
63659b6 Verificação do cpf e colocar o erro 404
ecae83c (riseup/main, riseup/HEAD, origin/main, origin/HEAD) Merge pull request 'Conectando-o-resto-das-API' (#2) from Conectando-o-resto-das-API into main
908d545 (riseup/Conectando-o-resto-das-API, origin/Conectando-o-resto-das-API) feat: adicionar upload e delete de anexos do paciente
4b404c0 Merge branch 'main' of https://git.popcode.com.br/RiseUP/riseup-squad23
bd20c2d Merge remote-tracking branch 'origin/main'
8aeabd1 (riseup/Fix-dos-erros-do-projeto, origin/Fix-dos-erros-do-projeto) FIx: todos os erros que aparecia no console foram resolvidos
0e29e7d melhorias na organização de pastas
98f076a Mergin com TableMelhorias
589d590 Mergin com novas alterações de laudo
7b28e2a Details melhorias
9480edc (riseup/PaginaDetalhes, origin/PaginaDetalhes) Pàgina detalhes
e4515cf Adição das cores nos cards de consulta
d3dd2fd (riseup/TableMelhorias, origin/TableMelhorias) Detalhe nas tabelas
a54b119 Delete Anexos apos pacientes forem excluidos
6e93cb5 atualizar paciente
b9a35be começo do concerto do editar
82469bc Details funcional
cdfe4ea Validação de CPF
57c8f67 (riseup/DetalhesMedico, origin/DetalhesMedico) Detalhes do medico
b021444 Mudanças formularios e detalhes
d5d03b0 (riseup/mudanças-de-laudo, origin/mudanças-de-laudo) atualização do laudo
a502bbd agendamentos no incio
8e1fcd9 Merge branch 'feature/novo-cadastro-paciente'
bea9076 Merge remote-tracking branch 'origin/PaginaDetalhes'
e35f217 mergin branch inicio com main
1af8268 Atualizacão do laudo
725d60d feat: ajeitei o nome
bab85ff (riseup/AgendamentoSidebar, origin/AgendamentoSidebar) Concertar Agendamento
b2707e3 Refatora o estilo do formulário do paciente para uma aparência de cartão com tipografia maior
37e8959 Refatora o estilo do formulário do paciente para uma aparência de cartão com tipografia maior
0930385 feat: uma piquena mudança
f6a19c4 feat: Adiciona formulário de cadastro de paciente
d91b5cf form de agendar consulta melhorado
0a60dd7 Tabela semana e mes
7f07950 (riseup/feature-Melhoria-no-Dashboard, origin/feature-Melhoria-no-Dashboard) feat: Criação da página início e melhoria na navegação
39e25ad Pagina de detalhes atualizada
4f84791 pequenas mudanaças na tabela de semana e mes
6737955 form para nova consulta e tabelas de horario
26ded17 Nova pagina de detalhes
874de84 Inicio do agendamento
f3e7470 (riseup/gerenciamento-de-laudo, origin/gerenciamento-de-laudo) Laudo do Paciente
709cd4e Merge finalizado
d6b3e86 Merge detalhes-do-pacientes para main
08ffa55 Merge remote-tracking branch 'origin/CrudMedico'
70c4d5f Termino da organização
edd567d Inicio da organização
9c09113 Mudanças pos feedback de davi
aa3a5fa Criação da página dos detalhes dos pacientes
5534568 Inicio de detalhes e atualização do paciente
06ff7d5 Funcionalidade de delete e botão de opções
5b63fa2 Mascara telefones
fb9d783 adição da mascara do CPF
a489d84 metodo GET e POST
4eaabbd first commit
a244691 Initial commit

54
package-lock.json generated
View File

@ -33,6 +33,7 @@
"react-icons": "^5.5.0",
"react-input-mask": "^2.0.4",
"react-quill": "^2.0.0",
"react-router-dom": "^7.9.2",
"react-scripts": "5.0.1",
"recharts": "^3.1.2",
"sweetalert2": "^11.22.4",
@ -30711,6 +30712,53 @@
"node": ">=0.10.0"
}
},
"node_modules/react-router": {
"version": "7.9.2",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.2.tgz",
"integrity": "sha512-i2TPp4dgaqrOqiRGLZmqh2WXmbdFknUyiCRmSKs0hf6fWXkTKg5h56b+9F22NbGRAMxjYfqQnpi63egzD2SuZA==",
"license": "MIT",
"dependencies": {
"cookie": "^1.0.1",
"set-cookie-parser": "^2.6.0"
},
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
}
}
},
"node_modules/react-router-dom": {
"version": "7.9.2",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.2.tgz",
"integrity": "sha512-pagqpVJnjZOfb+vIM23eTp7Sp/AAJjOgaowhP1f1TWOdk5/W8Uk8d/M/0wfleqx7SgjitjNPPsKeCZE1hTSp3w==",
"license": "MIT",
"dependencies": {
"react-router": "7.9.2"
},
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
}
},
"node_modules/react-router/node_modules/cookie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
@ -31978,6 +32026,12 @@
"node": ">= 0.8.0"
}
},
"node_modules/set-cookie-parser": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
"license": "MIT"
},
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",

View File

@ -28,6 +28,7 @@
"react-icons": "^5.5.0",
"react-input-mask": "^2.0.4",
"react-quill": "^2.0.0",
"react-router-dom": "^7.9.2",
"react-scripts": "5.0.1",
"recharts": "^3.1.2",
"sweetalert2": "^11.22.4",

View File

@ -1,98 +1,20 @@
import React, { useState, useEffect } from 'react';
// componente de Modal para CPF duplicado
const DuplicatePatientModal = ({ show, onClose, onGoToDetails, patient }) => {
if (!show || !patient) {
return null;
}
const patientName = patient.nome || patient.nome_completo || 'Paciente sem nome';
const patientCpf = patient.cpf || 'Não informado';
const patientId = patient.id || 'Não informado';
const patientDob = patient.data_nascimento || 'Não informada';
const patientPhone = patient.contato?.telefone1 || 'Não informado';
const patientPhoto = patient.foto || null;
return (
<div className="modal show d-block" style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-header bg-danger text-white">
<h5 className="modal-title">CPF Cadastrado</h5>
<button type="button" className="btn-close" onClick={onClose} style={{ filter: 'invert(1)' }}></button>
</div>
<div className="modal-body">
<div className="d-flex align-items-center mb-3">
{patientPhoto ? (
<img src={patientPhoto} alt="Foto do Paciente" className="rounded-circle me-3" style={{ width: '80px', height: '80px', objectFit: 'cover' }} />
) : (
<div className="rounded-circle me-3 d-flex align-items-center justify-content-center" style={{ width: '80px', height: '80px', backgroundColor: '#e9ecef', fontSize: '2rem' }}>
&#x1F464;
</div>
)}
<div>
<p className="mb-1"><strong>Nome:</strong> {patientName}</p>
<p className="mb-1"><strong>CPF:</strong> {patientCpf}</p>
<p className="mb-1"><strong>ID:</strong> {patientId}</p>
</div>
</div>
<p className="mb-1"><strong>Data de Nascimento:</strong> {patientDob}</p>
<p className="mb-1"><strong>Telefone:</strong> {patientPhone}</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-primary" onClick={onClose}>
Continuar Cadastro
</button>
<button type="button" className="btn btn-primary" onClick={() => onGoToDetails(patientId)}>
Visualizar Paciente
</button>
</div>
</div>
</div>
</div>
);
};
// Modal para Erro 404
const Error404Modal = ({ show, onClose }) => {
if (!show) {
return null;
}
return (
<div className="modal show d-block" style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-header bg-danger text-white">
<h5 className="modal-title">Erro de Validação</h5>
<button type="button" className="btn-close" onClick={onClose} style={{ filter: 'invert(1)' }}></button>
</div>
<div className="modal-body">
<p className="text-danger" style={{ fontSize: '1.4rem' }}>(Erro 404). Por favor, tente novamente mais tarde.</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-primary" onClick={onClose}>
Fechar
</button>
</div>
</div>
</div>
</div>
);
};
function PatientForm({ onSave, onCancel, formData, setFormData }) {
const [showDuplicateModal, setShowDuplicateModal] = useState(false);
const [duplicatePatientData, setDuplicatePatientData] = useState(null);
const [show404Modal, setShow404Modal] = useState(false);
const [showModal, setShowModal] = useState(false);
const [showModal404, setShowModal404] = useState(false);
const [pacienteExistente, setPacienteExistente] = useState(null);
const FormatTelefones = (valor) => {
const digits = String(valor).replace(/\D/g, '').slice(0, 11);
return digits
.replace(/(\d)/, '($1')
.replace(/(\d{2})(\d)/, '$1) $2')
.replace(/(\d{2})(\d)/, '$1) $2' )
.replace(/(\d)(\d{4})/, '$1 $2')
.replace(/(\d{4})(\d{4})/, '$1-$2');
};
const ReceberRespostaAPIdoCPF = async (cpf) => {
.replace(/(\d{4})(\d{4})/, '$1-$2')
}
const ReceberRespostaAPIdoCPF = async (cpf) =>{
var myHeaders = new Headers();
myHeaders.append("Authorization", "Bearer <token>");
myHeaders.append("Content-Type", "application/json");
@ -108,19 +30,19 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
redirect: 'follow'
};
const response = await fetch("https://mock.apidog.com/m1/1053378-0-default/pacientes/validar-cpf", requestOptions);
const response = await fetch("https://mock.apidog.com/m1/1053378-0-default/pacientes/validar-cpf", requestOptions)
if (response.status === 404) {
throw new Error("404 Not Found");
if (!response.ok) {
throw new Error('Erro na API de validação de CPF. Status: ' + response.status);
}
const result = await response.json()
return result.data
}
const result = await response.json();
return result.data;
};
const fetchPatientById = async (id) => {
const BuscarPacientePorId = async (id) => {
var myHeaders = new Headers();
myHeaders.append("Authorization", "Bearer <token>");
@ -129,7 +51,7 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
headers: myHeaders,
redirect: 'follow'
};
try {
const response = await fetch(`https://mock.apidog.com/m1/1053378-0-default/pacientes/${id}`, requestOptions);
const result = await response.json();
@ -141,50 +63,57 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
};
const ValidarCPF = async (cpf) => {
let aviso = '';
let Erro = false;
let patientData = null;
let aviso
let Erro = false
try {
const resultadoAPI = await ReceberRespostaAPIdoCPF(cpf);
const { valido, existe, id } = resultadoAPI;
const resultadoAPI = await ReceberRespostaAPIdoCPF(cpf)
const valido = resultadoAPI.valido
const ExisteNoBancoDeDados = resultadoAPI.existe
const idPaciente = resultadoAPI.id_paciente
if (!valido) {
aviso = 'CPF inválido';
Erro = true;
} else if (existe) {
aviso = 'O CPF informado já está presente no sistema.';
Erro = true;
patientData = await fetchPatientById(id);
if(valido === false){
aviso = 'CPF inválido'
Erro = true
}
} catch (e) {
if (e.message === "404 Not Found") {
setShow404Modal(true);
Erro = true;
} else {
aviso = 'Erro ao validar o CPF. Tente novamente.';
Erro = true;
else if(ExisteNoBancoDeDados === true){
const paciente = await BuscarPacientePorId(idPaciente);
if (paciente) {
setPacienteExistente(paciente);
setShowModal(true);
}
Erro = true
}
} catch (error) {
console.error("Erro na validação do CPF:", error);
setShowModal404(true);
Erro = true;
}
return [Erro,aviso]
}
return { Erro, aviso, patientData };
};
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');
};
}
// Estado para armazenar a URL da foto do avatar
const [avatarUrl, setAvatarUrl] = useState(null);
// Estado para controlar quais seções estão colapsadas
const [collapsedSections, setCollapsedSections] = useState({
dadosPessoais: true,
dadosPessoais: true,
infoMedicas: false,
infoConvenio: false,
endereco: false,
contato: false,
});
// Função para alternar o estado de colapso de uma seção
const handleToggleCollapse = (section) => {
setCollapsedSections(prevState => ({
...prevState,
@ -202,20 +131,28 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
} else {
setFormData(prev => ({ ...prev, imc: '' }));
}
}, [formData.peso, formData.altura, setFormData]);
}, [formData.peso, formData.altura]);
const [enderecoData, setEnderecoData] = useState({});
useEffect(() => { setEnderecoData(formData.endereco || {}); }, [formData.endereco]);
const [contato, setContato] = useState({});
useEffect(() => { setContato(formData.contato || {}); }, [formData.contato]);
const [enderecoData, setEnderecoData] = useState({})
useEffect(() => {setEnderecoData(formData.endereco || {}); console.log(enderecoData)}, [formData.endereco])
const [contato, setContato] = useState({})
useEffect(() => {setContato(formData.contato || {})}, [formData.contato])
const handleChange = (e) => {
const { name, value, type, checked, files } = e.target;
console.log(formData, name)
if (type === 'checkbox') {
setFormData({ ...formData, [name]: checked });
} else if (type === 'file') {
setFormData({ ...formData, [name]: files[0] });
// Lógica para pré-visualizar a imagem no avatar
if (name === 'foto' && files[0]) {
const reader = new FileReader();
reader.onloadend = () => {
@ -223,22 +160,24 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
};
reader.readAsDataURL(files[0]);
} else if (name === 'foto' && !files[0]) {
setAvatarUrl(null);
}
}
setAvatarUrl(null); // Limpa o avatar se nenhum arquivo for selecionado
}}
if (name.includes('cpf')) {
setFormData({ ...formData, cpf: FormatCPF(value) });
setFormData({...formData, cpf:FormatCPF(value) });
} else if (name.includes('telefone')) {
let telefoneFormatado = FormatTelefones(value);
setContato(prev => ({ ...prev, [name]: telefoneFormatado }));
} else if (name === 'email') {
}else if (name === 'email') {
setContato(prev => ({ ...prev, email: value }));
} else if (name.includes('endereco')) {
}else if(name.includes('endereco')) {
setEnderecoData(prev => ({ ...prev, [name.split('.')[1]]: value }));
} else {
}else{
setFormData({ ...formData, [name]: value });
}
};
const handleCepBlur = async () => {
const cep = formData.cep.replace(/\D/g, '');
if (cep.length === 8) {
@ -261,35 +200,19 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
}
}
};
<<<<<<< HEAD
const handleSubmit = async () => {
if (!formData.nome || !formData.cpf || !formData.sexo || !formData.data_nascimento) {
alert('Por favor, preencha Nome, CPF, Gênero e data de nascimento.');
=======
const handleSubmit = async (e) => {
e.preventDefault();
const handleSubmit = async () => {
if (!formData.nome || !formData.cpf || !formData.sexo || !formData.data_nascimento){
alert('Por favor, preencha Nome ,CPF, Gênero e data de nascimento.');
>>>>>>> ecae83cf4cc5cac2487d7fbd9cb61a8d706b01a3
return;
}
const { Erro, aviso, patientData } = await ValidarCPF(formData.cpf);
if (Erro) {
if (patientData) {
setDuplicatePatientData(patientData);
setShowDuplicateModal(true);
} else {
if (aviso) {
alert(aviso);
}
}
const [CPFinvalido] = await ValidarCPF(formData.cpf);
if(CPFinvalido === true){
return;
}
const pacienteSalvo = await onSave({
onSave({
...formData,
endereco: {
cep: enderecoData.cep,
@ -319,59 +242,11 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
numeroMatricula: formData.numeroMatricula,
validadeCarteira: formData.validadeCarteira,
validadeIndeterminada: formData.validadeIndeterminada,
pacienteVip: formData.pacienteVip,
pacienteVip: formData.pacienteVip,
},
});
<<<<<<< HEAD
};
=======
const pacienteId = pacienteSalvo.id;
try{
if (formData.foto) await uploadFotoPaciente(pacienteId, formData.foto);
if (formData.anexos) await uploadAnexoPaciente(pacienteId, formData.anexos);
alert("Paciente salvo com sucesso!");
} catch (error) {
console.error(error);
alert("Erro ao salvar paciente ou enviar arquivos.");
}
};
const uploadFotoPaciente = async (pacienteId, foto) => {
const formDataUpload = new FormData();
formDataUpload.append('foto', foto);
try {
const res = await fetch(`https://suaapi.com/pacientes/${pacienteId}/foto`, {
method: 'POST',
headers: { 'Authorization': 'Bearer <token>' },
body: formDataUpload
});
if (!res.ok) throw new Error('Erro ao enviar foto');
alert('Foto enviada com sucesso!');
} catch (err) {
console.error(err);
alert('Falha ao enviar foto');
}
};
const uploadAnexoPaciente = async (pacienteId, anexo) => {
const formDataUpload = new FormData();
formDataUpload.append('anexo', anexo);
try {
const res = await fetch(`https://suaapi.com/pacientes/${pacienteId}/anexos`, {
method: 'POST',
headers: { 'Authorization': 'Bearer <token>' },
body: formDataUpload
});
if (!res.ok) throw new Error('Erro ao enviar anexo');
alert('Anexo enviado com sucesso!');
} catch (err) {
console.error(err);
alert('Falha ao enviar anexo');
}
};
>>>>>>> ecae83cf4cc5cac2487d7fbd9cb61a8d706b01a3
return (
<div className="card p-3">
<h3 className="mb-4 text-center" style={{ fontSize: '2.5rem' }}>MediConnect</h3>
@ -386,41 +261,41 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
</h4>
<div className={`collapse${collapsedSections.dadosPessoais ? ' show' : ''}`}>
<div className="row mt-3">
{/* AVATAR E INPUT DE FOTO */}
<div className="col-md-6 mb-3 d-flex align-items-center">
<div className="me-3">
{/* AVATAR E INPUT DE FOTO */}
{avatarUrl ? (
<img
src={avatarUrl}
alt="Avatar do Paciente"
style={{ width: '100px', height: '100px', borderRadius: '50%', objectFit: 'cover' }}
<img
src={avatarUrl}
alt="Avatar do Paciente"
style={{ width: '100px', height: '100px', borderRadius: '50%', objectFit: 'cover' }}
/>
) : (
<div
style={{
width: '100px',
height: '100px',
borderRadius: '50%',
backgroundColor: '#e0e0e0',
display: 'flex',
alignItems: 'center',
<div
style={{
width: '100px',
height: '100px',
borderRadius: '50%',
backgroundColor: '#e0e0e0',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: '3.5rem',
color: '#9e9e9e'
}}
>
&#x2624;
&#x2624;
</div>
)}
</div>
<div>
<label htmlFor="foto-input" className="btn btn-primary" style={{ fontSize: '1rem' }}>Carregar Foto</label>
<input
type="file"
className="form-control d-none"
name="foto"
id="foto-input"
onChange={handleChange}
<input
type="file"
className="form-control d-none"
name="foto"
id="foto-input"
onChange={handleChange}
accept="image/*"
/>
{formData.foto && <span className="ms-2" style={{ fontSize: '1rem' }}>{formData.foto.name}</span>}
@ -450,7 +325,7 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
</div>
<div className="col-md-6 mb-3">
<label style={{ fontSize: '1.1rem' }}>CPF: *</label>
<input type="text" className="form-control" name="cpf" value={formData.cpf} onChange={handleChange} style={{ fontSize: '1.1rem' }} />
<input type="text" className="form-control" name="cpf" value={formData.cpf} onChange={ handleChange} style={{ fontSize: '1.1rem' }} />
</div>
<div className="col-md-6 mb-3">
<label style={{ fontSize: '1.1rem' }}>RG:</label>
@ -542,6 +417,7 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
</label>
</div>
</div>
{/* CAMPOS MOVIDOS */}
<div className="col-md-12 mb-3 mt-3">
<label style={{ fontSize: '1.1rem' }}>Observações:</label>
@ -550,14 +426,16 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
<div className="col-md-12 mb-3">
<label style={{ fontSize: '1.1rem' }}>Anexos do Paciente:</label>
<div>
<label htmlFor="anexos-input" className="btn btn-secondary" style={{ fontSize: '1.1rem', background: '#9ca3af' }}>Escolher arquivo</label>
<label htmlFor="anexos-input" className="btn btn-secondary" style={{ fontSize: '1.1rem', background: '#9ca3af' }}>Escolher arquivo</label>
<input type="file" className="form-control d-none" name="anexos" id="anexos-input" onChange={handleChange} />
<span className="ms-2" style={{ fontSize: '1.1rem' }}>{formData.anexos ? formData.anexos.name : 'Nenhum arquivo escolhido'}</span>
</div>
</div>
</div>
</div>
</div>
{/* INFORMAÇÕES MÉDICAS */}
<div className="mb-5 p-4 border rounded shadow-sm">
<h4 className="mb-4 cursor-pointer d-flex justify-content-between align-items-center" onClick={() => handleToggleCollapse('infoMedicas')} style={{ fontSize: '1.8rem' }}>
@ -601,6 +479,7 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
</div>
</div>
</div>
{/* INFORMAÇÕES DE CONVÊNIO */}
<div className="mb-5 p-4 border rounded shadow-sm">
<h4 className="mb-4 cursor-pointer d-flex justify-content-between align-items-center" onClick={() => handleToggleCollapse('infoConvenio')} style={{ fontSize: '1.8rem' }}>
@ -653,6 +532,7 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
</div>
</div>
</div>
{/* ENDEREÇO */}
<div className="mb-5 p-4 border rounded shadow-sm">
<h4 className="mb-4 cursor-pointer d-flex justify-content-between align-items-center" onClick={() => handleToggleCollapse('endereco')} style={{ fontSize: '1.8rem' }}>
@ -694,6 +574,7 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
</div>
</div>
</div>
{/* CONTATO */}
<div className="mb-5 p-4 border rounded shadow-sm">
<h4 className="mb-4 cursor-pointer d-flex justify-content-between align-items-center" onClick={() => handleToggleCollapse('contato')} style={{ fontSize: '1.8rem' }}>
@ -723,24 +604,7 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
</div>
</div>
</div>
{/* Modal para CPF duplicado */}
<DuplicatePatientModal
show={showDuplicateModal}
onClose={() => setShowDuplicateModal(false)}
onGoToDetails={(id) => {
console.log(`Navegando para a página de detalhes do paciente com ID: ${id}`);
setShowDuplicateModal(false);
}}
patient={duplicatePatientData}
/>
{/*404 Error Modal */}
<Error404Modal
show={show404Modal}
onClose={() => setShow404Modal(false)}
/>
{/* Botões */}
<div className="mt-3 text-center">
<button className="btn btn-success me-3" onClick={handleSubmit} style={{ fontSize: '1.2rem', padding: '0.75rem 1.5rem' }}>
@ -750,6 +614,77 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
Cancelar
</button>
</div>
{/* Modal para paciente existente */}
{showModal && pacienteExistente && (
<div className="modal" style={{ display: 'block', backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Ops! Este CPF está cadastrado</h5>
<button type="button" className="btn-close" onClick={() => setShowModal(false)}></button>
</div>
<div className="modal-body">
<div className="text-center mb-3">
<img
src={pacienteExistente.foto || 'https://via.placeholder.com/100'}
alt="Foto do Paciente"
className="rounded-circle"
style={{ width: '100px', height: '100px', objectFit: 'cover' }}
/>
</div>
<p><strong>ID do Paciente:</strong> {pacienteExistente.id}</p>
<p><strong>Nome Completo:</strong> {pacienteExistente.nome}</p>
<p><strong>CPF:</strong> {pacienteExistente.cpf}</p>
<p><strong>Data de Nascimento:</strong> {pacienteExistente.data_nascimento}</p>
<p><strong>Telefone:</strong> {pacienteExistente.contato.telefone1}</p>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => setShowModal(false)}
>
Fechar e Continuar no Cadastro
</button>
<button
type="button"
className="btn btn-primary"
onClick={() => {
alert(`Navegando para os detalhes do paciente ID: ${pacienteExistente.id}`);
setShowModal(false);
}}
>
Visualizar Paciente Existente
</button>
</div>
</div>
</div>
</div>
)}
{/* Erro 404 */}
{showModal404 && (
<div className="modal" style={{ display: 'block', backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header bg-danger text-white">
<h5 className="modal-title">Erro de Validação</h5>
<button type="button" className="btn-close btn-close-white" onClick={() => setShowModal404(false)}></button>
</div>
<div className="modal-body">
<p style={{ fontSize: '1.4rem' }}>(Erro 404).Por favor,tente novamente mais tarde.</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-primary" onClick={() => setShowModal404(false)}>
Fechar
</button>
</div>
</div>
</div>
</div>
)}
</div>
);
}