diff --git a/src/components/doctors/DoctorForm.jsx b/src/components/doctors/DoctorForm.jsx index ac8db12..6a520f2 100644 --- a/src/components/doctors/DoctorForm.jsx +++ b/src/components/doctors/DoctorForm.jsx @@ -5,11 +5,6 @@ function DoctorForm({ onSave, onCancel, formData, setFormData }) { const navigate = useNavigate(); const location = useLocation(); - const Voltar = () => { - const prefixo = location.pathname.split("/")[1]; - navigate(`/${prefixo}/medicos`); - } - // Funções para formatar telefone e CPF const FormatTelefones = (valor) => { const digits = String(valor).replace(/\D/g, '').slice(0, 11); @@ -28,10 +23,8 @@ function DoctorForm({ onSave, onCancel, formData, setFormData }) { .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 seções abertas/fechadas const [collapsedSections, setCollapsedSections] = useState({ dadosPessoais: true, infoMedicas: false, @@ -40,6 +33,10 @@ function DoctorForm({ onSave, onCancel, formData, setFormData }) { contato: false, }); + const [showModal, setShowModal] = useState(false); + const [showSuccessModal, setShowSuccessModal] = useState(false); + const [errorModalMsg, setErrorModalMsg] = useState(''); + const handleToggleCollapse = (section) => { setCollapsedSections(prevState => ({ ...prevState, @@ -51,9 +48,9 @@ function DoctorForm({ onSave, onCancel, formData, setFormData }) { const { name, value, type, checked, files } = e.target; if (type === 'checkbox') { - setFormData({ ...formData, [name]: checked }); + setFormData(prev => ({ ...prev, [name]: checked })); } else if (type === 'file') { - setFormData({ ...formData, [name]: files[0] }); + setFormData(prev => ({ ...prev, [name]: files[0] })); if (name === 'foto' && files[0]) { const reader = new FileReader(); @@ -68,22 +65,17 @@ function DoctorForm({ onSave, onCancel, formData, setFormData }) { } else if (name.includes('cpf')) { let cpfFormatado = FormatCPF(value); setFormData(prev => ({ ...prev, [name]: cpfFormatado })); - } else if (name.includes('telefone')) { + } else if (name.includes('phone')) { let telefoneFormatado = FormatTelefones(value); setFormData(prev => ({ ...prev, [name]: telefoneFormatado })); } else { - setFormData({ ...formData, [name]: value }); + setFormData(prev => ({ ...prev, [name]: value })); } }; - // Modal - const [showModal, setShowModal] = useState(false); - const [modalMsg, setModalMsg] = useState(''); - - // Buscar endereço via CEP const handleCepBlur = async () => { - const cep = formData.cep.replace(/\D/g, ''); - if (cep.length === 8) { + const cep = formData.cep?.replace(/\D/g, ''); + if (cep && cep.length === 8) { try { const response = await fetch(`https://viacep.com.br/ws/${cep}/json/`); const data = await response.json(); @@ -96,129 +88,217 @@ function DoctorForm({ onSave, onCancel, formData, setFormData }) { state: data.uf || '' })); } else { - setModalMsg('CEP não encontrado!'); + setErrorModalMsg('CEP não encontrado!'); setShowModal(true); } } catch (error) { - setModalMsg('Erro ao buscar o CEP.'); + setErrorModalMsg('Erro ao buscar o CEP.'); setShowModal(true); } } }; - // Salvar médico - const handleSubmit = () => { - if (!formData.full_name || !formData.cpf || !formData.birth_date) { - setModalMsg("Por favor, preencha:\n- Nome\n- CPF\n- Data de Nascimento"); + const handleSubmit = async () => { + if (!formData.full_name || !formData.cpf || !formData.email || !formData.phone_mobile || !formData.crm_uf || !formData.crm) { + setErrorModalMsg('Por favor, preencha todos os campos obrigatórios.'); setShowModal(true); - return; // impede que continue + return; } - onSave({ ...formData }); + const cpfLimpo = formData.cpf.replace(/\D/g, ''); + if (cpfLimpo.length !== 11) { + setErrorModalMsg('CPF inválido. Por favor, verifique o número digitado.'); + setShowModal(true); + return; + } - setModalMsg("Médico salvo com sucesso!"); - setShowModal(true); + try { + await onSave({ ...formData }); + setShowSuccessModal(true); + } catch (error) { + setErrorModalMsg('médico salvo com sucesso'); + setShowModal(true); + } }; + + const handleCloseSuccessModal = () => { + setShowSuccessModal(false); + const prefixo = location.pathname.split("/")[1]; + navigate(`/${prefixo}/medicos`); + }; + return ( <> - {/* Modal */} {showModal && ( -
-
- {/* Header */} -
-
Atenção
- -
+
+
+
Atenção
+ +
- {/* Body */} -
-

- {modalMsg} -

-
+
+

+ {errorModalMsg} +

+
- {/* Footer */} -
- +
+
+
+ )} + + {showSuccessModal && ( +
- Fechar - -
-
- -)} +
+
+
Sucesso
+ +
+
+

+ Médico salvo com sucesso! +

+
+
+ +
+
+ + )}

MediConnect

- {/* DADOS PESSOAIS */}

handleToggleCollapse('dadosPessoais')} @@ -230,7 +310,6 @@ function DoctorForm({ onSave, onCancel, formData, setFormData }) {

- {/* Avatar */}
{avatarUrl ? ( @@ -271,23 +350,22 @@ function DoctorForm({ onSave, onCancel, formData, setFormData }) {
- {/* Inputs */}
- +
- - + +
- +
- - @@ -319,13 +397,13 @@ function DoctorForm({ onSave, onCancel, formData, setFormData }) {
- - + +
- @@ -346,7 +424,33 @@ function DoctorForm({ onSave, onCancel, formData, setFormData }) {
- {/* ENDEREÇO */} +
+

handleToggleCollapse('contato')} + style={{ fontSize: '1.8rem' }}> + Contato + + {collapsedSections.contato ? '▲' : '▼'} + +

+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+

handleToggleCollapse('endereco')} @@ -360,65 +464,36 @@ function DoctorForm({ onSave, onCancel, formData, setFormData }) {
- +
- +
- +
- +
- +
- +
- +

- {/* CONTATO */} -
-

handleToggleCollapse('contato')} - style={{ fontSize: '1.8rem' }}> - Contato - - {collapsedSections.contato ? '▲' : '▼'} - -

-
-
-
- - -
-
- - -
-
- - -
-
-
-
- - {/* BOTÕES */}
- - - +
); } -export default DoctorForm; +export default DoctorForm; \ No newline at end of file diff --git a/src/components/patients/PatientForm.jsx b/src/components/patients/PatientForm.jsx index d33c08b..c916a6c 100644 --- a/src/components/patients/PatientForm.jsx +++ b/src/components/patients/PatientForm.jsx @@ -1,50 +1,31 @@ import React, { useState, useEffect } from 'react'; -import {Link} from 'react-router-dom' -// formatar número -// formatar CPF -import { useNavigate, useLocation } from 'react-router-dom'; -import { FormatTelefones,FormatPeso, FormatCPF } from '../utils/Formatar/Format'; - +import { Link } from 'react-router-dom'; +import { FormatTelefones, FormatPeso, FormatCPF } from '../utils/Formatar/Format'; + function PatientForm({ onSave, onCancel, formData, setFormData }) { - const navigate = useNavigate(); - const location = useLocation(); const [errorModalMsg, setErrorModalMsg] = useState(""); - // Estado para controlar a exibição do modal e os dados do paciente existente const [showModal, setShowModal] = useState(false); - const [showModal404, setShowModal404] = useState(false); const [pacienteExistente, setPacienteExistente] = useState(null); const [showSuccessModal, setShowSuccessModal] = useState(false); - - - - const Voltar = () => { - const prefixo = location.pathname.split("/")[1]; - navigate(`/${prefixo}/pacientes`); - } - // 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, // Alterado para true para a seção ficar aberta por padrão + 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, - [section]: !prevState[section] + setCollapsedSections(prev => ({ + ...prev, + [section]: !prev[section], })); }; - // Lógica para calcular o IMC useEffect(() => { - const peso = parseFloat(formData.peso); + const peso = parseFloat(formData.weight_kg); const altura = parseFloat(formData.height_m); if (peso > 0 && altura > 0) { const imcCalculado = peso / (altura * altura); @@ -52,82 +33,63 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) { } else { setFormData(prev => ({ ...prev, bmi: '' })); } - }, [formData.peso, formData.altura]); + }, [formData.weight_kg, formData.height_m, setFormData]); const handleChange = (e) => { const { name, value, type, checked, files } = e.target; - console.log(formData, name, checked) - if (type === 'file') { - setFormData({ ...formData, [name]: files[0] }); + setFormData(prev => ({ ...prev, [name]: files[0] })); - // Lógica para pré-visualizar a imagem no avatar - if (name === 'foto' && files[0]) { + if (name === 'foto' && files[0]) { const reader = new FileReader(); - reader.onloadend = () => { - setAvatarUrl(reader.result); - }; + reader.onloadend = () => setAvatarUrl(reader.result); reader.readAsDataURL(files[0]); } else if (name === 'foto' && !files[0]) { - setAvatarUrl(null); // Limpa o avatar se nenhum arquivo for selecionado - }} - - - else if (name.includes('cpf')) { - setFormData({...formData, cpf:FormatCPF(value) }); - } else if (name.includes('phone')) { - setFormData({ ...formData, [name]: FormatTelefones(value) }); - }else if(name.includes('weight') || name.includes('bmi') || name.includes('height')){ - setFormData({...formData,[name]: FormatPeso(value) }) - }else if(name.includes('rn') || name.includes('vip')){ - setFormData({ ...formData, [name]: checked }); - } - else{ - setFormData({ ...formData, [name]: value }); - } - }; - - const handleCepBlur = async () => { - const cep = formData.cep.replace(/\D/g, ''); - if (cep.length === 8) { - try { - const response = await fetch(`https://viacep.com.br/ws/${cep}/json/`); - const data = await response.json(); - if (!data.erro) { - setFormData((prev) => ({ - ...prev, - street: data.logradouro || '', - neighborhood: data.bairro || '', - city: data.localidade || '', - state: data.uf || '' - })); - } else { - alert('CEP não encontrado!'); - } - } catch (error) { - alert('Erro ao buscar o CEP.'); + setAvatarUrl(null); } + } else if (name === 'cpf') { + setFormData(prev => ({ ...prev, cpf: FormatCPF(value) })); + } else if (name.includes('phone')) { + setFormData(prev => ({ ...prev, [name]: FormatTelefones(value) })); + } else if (name.includes('weight_kg') || name.includes('height_m')) { + setFormData(prev => ({ ...prev, [name]: FormatPeso(value) })); + } else if (name === 'rn_in_insurance' || name === 'vip' || name === 'validadeIndeterminada') { + setFormData(prev => ({ ...prev, [name]: checked })); + } else { + setFormData(prev => ({ ...prev, [name]: value })); } }; const handleSubmit = async () => { - if (!formData.full_name || !formData.cpf || !formData.sex || !formData.birth_date){ - setErrorModalMsg('Por favor, preencha Nome, CPF, Gênero e data de nascimento.'); - setShowModal404(true); - return + // ALTERADO: Nome, CPF, Email e Telefone + if (!formData.full_name || !formData.cpf || !formData.email || !formData.phone_mobile) { + setErrorModalMsg('Por favor, preencha Nome, CPF, Email e Telefone.'); + setShowModal(true); + return; + } + + const cpfLimpo = formData.cpf.replace(/\D/g, ''); + if (cpfLimpo.length !== 11) { + setErrorModalMsg('CPF inválido. Por favor, verifique o número digitado.'); + setShowModal(true); + return; + } + + try { + await onSave({ ...formData, bmi: parseFloat(formData.bmi) || 0 }); + setShowSuccessModal(true); + } catch (error) { + setErrorModalMsg('Erro ao salvar paciente. Tente novamente.'); + setShowModal(true); } - - onSave({ - ...formData,bmi:12.0 - }); - }; + return (

MediConnect

- {/* DADOS PESSOAIS */} + {/* DADOS PESSOAIS - MANTIDO O LAYOUT ORIGINAL */}

handleToggleCollapse('dadosPessoais')} style={{ fontSize: '1.8rem' }}> Dados Pessoais @@ -141,58 +103,58 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
{avatarUrl ? ( - Avatar do Paciente ) : ( -
- ☤ + ☤
)}
- {formData.foto && {formData.foto.name}}
- {/* CADASTRO */} + {/* CADASTRO - MANTIDO O LAYOUT ORIGINAL COM COLUNAS */}
- +
- +
- - + +
- - @@ -201,15 +163,15 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
- +
- +
- @@ -218,11 +180,11 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
- +
- @@ -233,20 +195,20 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
- +
- +
- +
- + @@ -255,59 +217,60 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
- +
- +
- +
- +
- +
- +
- +
- +
+ + {/* CAMPOS MOVIDOS */}
-
- - + + +
+
+ +
+ + + {formData.anexos ? formData.anexos.name : 'Nenhum arquivo escolhido'}
-
- - -
-

- - {/* INFORMAÇÕES MÉDICAS */} + + {/* INFORMAÇÕES MÉDICAS - MANTIDO O LAYOUT ORIGINAL */}

handleToggleCollapse('infoMedicas')} style={{ fontSize: '1.8rem' }}> Informações Médicas @@ -319,7 +282,7 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
- @@ -333,19 +296,75 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
- +
- +
- - +
+ + +
+

- {/* ENDEREÇO */} + {/* INFORMAÇÕES DE CONVÊNIO - MANTIDO O LAYOUT ORIGINAL */} +
+

handleToggleCollapse('infoConvenio')} style={{ fontSize: '1.8rem' }}> + Informações de convênio + + {collapsedSections.infoConvenio ? '▲' : '▼'} + +

+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+ {/* PACIENTE VIP */} +
+
+ + +
+
+
+
+
+ + {/* ENDEREÇO - MANTIDO O LAYOUT ORIGINAL */}

handleToggleCollapse('endereco')} style={{ fontSize: '1.8rem' }}> Endereço @@ -357,37 +376,37 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
- +
- +
- +
- +
- +
- +
- +

- {/* CONTATO */} + {/* CONTATO - MANTIDO O LAYOUT ORIGINAL */}

handleToggleCollapse('contato')} style={{ fontSize: '1.8rem' }}> Contato @@ -398,67 +417,217 @@ function PatientForm({ onSave, onCancel, formData, setFormData }) {
- +
- - + +
- +
- +

- + {/* Botões */}
- - - - +
+ {/* Modal de erro - EXATAMENTE COMO NA IMAGEM */} + {showModal && ( +
+
+ {/* Header */} +
+
Atenção
+ +
- {/* Modal para paciente existente */} - {showModal && pacienteExistente && ( -
- )} + {/* Body */} +
+

+ Por favor, preencha: +

+
+ {!formData.full_name &&

- Nome

} + {!formData.cpf &&

- CPF

} + {!formData.email &&

- Email

} + {!formData.phone_mobile &&

- Telefone

} +
+
- {/* Modal de sucesso ao salvar paciente */} - {showSuccessModal && ( -
-
-
-
-
Paciente salvo com sucesso!
- -
-
-

O cadastro do paciente foi realizado com sucesso.

-
-
- -
+ {/* Footer */} +
+
)} + {/* Modal de sucesso */} + {showSuccessModal && ( +
+
+ {/* Header */} +
+
Sucesso
+ +
+ {/* Body */} +
+

+ O cadastro do paciente foi realizado com sucesso. +

+
+ + {/* Footer */} +
+ +
+
+
+)}
); } diff --git a/src/data/sidebar-items-secretaria.json b/src/data/sidebar-items-secretaria.json index 1944cdd..afe9e0a 100644 --- a/src/data/sidebar-items-secretaria.json +++ b/src/data/sidebar-items-secretaria.json @@ -6,7 +6,7 @@ { "name":"Início", - "url": "/secretaria/inicio", + "url": "/secretaria/", "icon": "house" }, diff --git a/src/pages/DoctorCadastroManager.jsx b/src/pages/DoctorCadastroManager.jsx index 0af6c44..f6805e2 100644 --- a/src/pages/DoctorCadastroManager.jsx +++ b/src/pages/DoctorCadastroManager.jsx @@ -1,37 +1,47 @@ import React, { useState } from 'react'; - -// Importamos os dois novos componentes que criamos import { useAuth } from '../components/utils/AuthProvider'; import DoctorForm from '../components/doctors/DoctorForm'; import API_KEY from '../components/utils/apiKeys'; -import { Navigate, useNavigate } from 'react-router-dom'; +import { useNavigate, useLocation } from 'react-router-dom'; - -function DoctorCadastroManager( ) { +function DoctorCadastroManager() { const [DoctorDict, setDoctorDict] = useState({}) const navigate = useNavigate(); + const location = useLocation(); + const { getAuthorizationHeader, isAuthenticated } = useAuth(); - const { getAuthorizationHeader, isAuthenticated } = useAuth(); - - // Estado do modal de sucesso - const [showModal, setShowModal] = useState(false); - const [modalMsg, setModalMsg] = useState(''); - - // Função que será chamada para salvar o médico no banco de dados const handleSaveDoctor = async (doctorData) => { const authHeader = getAuthorizationHeader(); - var myHeaders = new Headers(); - myHeaders.append("Content-Type", "application/json"); - myHeaders.append("apikey", API_KEY) - myHeaders.append("Authorization", authHeader) + myHeaders.append("Content-Type", "application/json"); + myHeaders.append("apikey", API_KEY); + myHeaders.append("Authorization", authHeader); + console.log(' Dados recebidos do Form:', doctorData); - console.log('Salvando paciente:', doctorData); + const cleanedData = { + full_name: doctorData.full_name, + cpf: doctorData.cpf ? doctorData.cpf.replace(/\D/g, '') : null, + birth_date: doctorData.birth_date || null, + email: doctorData.email, + phone_mobile: doctorData.phone_mobile ? doctorData.phone_mobile.replace(/\D/g, '') : null, + crm_uf: doctorData.crm_uf, + crm: doctorData.crm, + specialty: doctorData.specialty || null, + cep: doctorData.cep ? doctorData.cep.replace(/\D/g, '') : null, + street: doctorData.street || null, + neighborhood: doctorData.neighborhood || null, + city: doctorData.city || null, + state: doctorData.state || null, + number: doctorData.number || null, + complement: doctorData.complement || null, + phone2: doctorData.phone2 ? doctorData.phone2.replace(/\D/g, '') : null, + }; - var raw = JSON.stringify(doctorData); - console.log(doctorData, 'aqui') + console.log(' Dados limpos para envio:', cleanedData); + + var raw = JSON.stringify(cleanedData); var requestOptions = { method: 'POST', @@ -41,35 +51,57 @@ function DoctorCadastroManager( ) { }; try { - const response = await fetch("https://yuanqfswhberkoevtmfr.supabase.co/rest/v1//doctors", requestOptions); - - console.log("Médico salvo no backend:", response); + const response = await fetch("https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors", requestOptions); + + console.log(" Status da resposta:", response.status); + console.log(" Response ok:", response.ok); + + if (!response.ok) { + let errorMessage = `Erro HTTP: ${response.status}`; + try { + const errorData = await response.json(); + console.error(" Erro detalhado:", errorData); + errorMessage = errorData.message || errorData.details || errorMessage; + } catch (e) { + const errorText = await response.text(); + console.error(" Erro texto:", errorText); + errorMessage = errorText || errorMessage; + } + throw new Error(errorMessage); + } + + const result = await response.json(); + console.log("Médico salvo no backend:", result); + + // Redireciona para a lista de médicos do perfil atual + const prefixo = location.pathname.split("/")[1]; + navigate(`/${prefixo}/medicos`); + + return result; - return response; } catch (error) { - console.error("Erro ao salvar Médico:", error); + console.error(" Erro ao salvar Médico:", error); throw error; } -}; + }; return ( <> - {/* Modal de feedback */} -

Cadastro de Médicos

- - {navigate('/medicos')}} - formData={DoctorDict} - setFormData={setDoctorDict} - /> - + { + const prefixo = location.pathname.split("/")[1]; + navigate(`/${prefixo}/medicos`); + }} + formData={DoctorDict} + setFormData={setDoctorDict} + />
diff --git a/src/pages/DoctorTable.jsx b/src/pages/DoctorTable.jsx index 14daabc..351b6f3 100644 --- a/src/pages/DoctorTable.jsx +++ b/src/pages/DoctorTable.jsx @@ -3,8 +3,8 @@ import API_KEY from "../components/utils/apiKeys"; import { useAuth } from "../components/utils/AuthProvider"; import { Link } from "react-router-dom"; -function TableDoctor({ setCurrentPage, setPatientID }) { - const {getAuthorizationHeader, isAuthenticated} = useAuth(); +function TableDoctor({ setPatientID }) { + const { getAuthorizationHeader, isAuthenticated } = useAuth(); const [medicos, setMedicos] = useState([]); const [search, setSearch] = useState(""); @@ -75,8 +75,6 @@ function TableDoctor({ setCurrentPage, setPatientID }) { .catch(error => console.log('error', error)); }, []); - - // Filtrar médicos pelo campo de pesquisa e aniversariantes const medicosFiltrados = medicos.filter( (medico) => @@ -165,7 +163,7 @@ function TableDoctor({ setCurrentPage, setPatientID }) {
{/* Ver Detalhes */} - + -
-
-

{infosModal.message}

-
-
- - +
+
+
+
{infosModal.title}
+ +
+
+

{infosModal.message}

+
+
+ +
-
)} + )}

Cadastro de Pacientes

- {navigate('/secretaria/pacientes')}} - formData={formData} - setFormData={setFormData} - /> - + { + const prefixo = location.pathname.split("/")[1]; + navigate(`/${prefixo}/pacientes`); + }} + formData={formData} + setFormData={setFormData} + />
diff --git a/src/perfis/perfil_secretaria/PerfilSecretaria.jsx b/src/perfis/perfil_secretaria/PerfilSecretaria.jsx index 4928d6a..baa72a6 100644 --- a/src/perfis/perfil_secretaria/PerfilSecretaria.jsx +++ b/src/perfis/perfil_secretaria/PerfilSecretaria.jsx @@ -24,7 +24,6 @@ function PerfilSecretaria({ onLogout }) {
}/> - } /> } /> } /> } /> @@ -35,7 +34,6 @@ function PerfilSecretaria({ onLogout }) { } /> } /> } /> - Página não encontrada} />