From 0fd8cc631ea9209c0c5e3346f33dca706b5ec8f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gustavo?= <166467972+JoaoGustavo-dev@users.noreply.github.com> Date: Tue, 21 Oct 2025 21:57:21 -0300 Subject: [PATCH] add-patients-endpoint --- .../forms/patient-registration-form.tsx | 624 +++--------------- susconecta/lib/api.ts | 151 ++++- 2 files changed, 221 insertions(+), 554 deletions(-) diff --git a/susconecta/components/forms/patient-registration-form.tsx b/susconecta/components/forms/patient-registration-form.tsx index 61a7d7b..31cd412 100644 --- a/susconecta/components/forms/patient-registration-form.tsx +++ b/susconecta/components/forms/patient-registration-form.tsx @@ -1,7 +1,7 @@ "use client"; import { useEffect, useMemo, useState } from "react"; -import { format, parse, isValid, parseISO } from "date-fns"; +import { format, parseISO } from "date-fns"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -24,7 +24,6 @@ import { listarAnexos, removerAnexo, buscarPacientePorId, - criarUsuarioPaciente, criarPaciente, } from "@/lib/api"; import { getAvatarPublicUrl } from '@/lib/api'; @@ -104,8 +103,7 @@ export function PatientRegistrationForm({ const [isSearchingCEP, setSearchingCEP] = useState(false); const [photoPreview, setPhotoPreview] = useState(null); const [serverAnexos, setServerAnexos] = useState([]); - - // Estados para o dialog de credenciais + const [showCredentialsDialog, setShowCredentialsDialog] = useState(false); const [credentials, setCredentials] = useState<{ email: string; @@ -120,9 +118,7 @@ export function PatientRegistrationForm({ async function load() { if (mode !== "edit" || patientId == null) return; try { - console.log("[PatientForm] Carregando paciente ID:", patientId); const p = await buscarPacientePorId(String(patientId)); - console.log("[PatientForm] Dados recebidos:", p); setForm((s) => ({ ...s, nome: p.full_name || "", @@ -130,9 +126,7 @@ export function PatientRegistrationForm({ cpf: p.cpf || "", rg: p.rg || "", sexo: p.sex || "", - birth_date: p.birth_date ? (() => { - try { return format(parseISO(String(p.birth_date)), 'dd/MM/yyyy'); } catch { return String(p.birth_date); } - })() : "", + birth_date: p.birth_date ? (() => { try { return format(parseISO(String(p.birth_date)), 'dd/MM/yyyy'); } catch { return String(p.birth_date); } })() : "", telefone: p.phone_mobile || "", email: p.email || "", cep: p.cep || "", @@ -147,7 +141,7 @@ export function PatientRegistrationForm({ const ax = await listarAnexos(String(patientId)).catch(() => []); setServerAnexos(Array.isArray(ax) ? ax : []); - // Try to detect existing public avatar (no file extension) and set preview + try { const url = getAvatarPublicUrl(String(patientId)); try { @@ -157,14 +151,10 @@ export function PatientRegistrationForm({ const get = await fetch(url, { method: 'GET' }); if (get.ok) { setPhotoPreview(url); } } - } catch (inner) { - // ignore network/CORS errors while detecting - } - } catch (detectErr) { - // ignore detection errors - } + } catch (inner) { /* ignore */ } + } catch (detectErr) { /* ignore */ } } catch (err) { - console.error("[PatientForm] Erro ao carregar paciente:", err); + console.error('[PatientForm] Erro ao carregar paciente:', err); } } load(); @@ -179,33 +169,13 @@ export function PatientRegistrationForm({ const n = v.replace(/\D/g, "").slice(0, 11); return n.replace(/(\d{3})(\d{3})(\d{3})(\d{0,2})/, (_, a, b, c, d) => `${a}.${b}.${c}${d ? "-" + d : ""}`); } - function handleCPFChange(v: string) { - setField("cpf", formatCPF(v)); - } + function handleCPFChange(v: string) { setField("cpf", formatCPF(v)); } - function formatCEP(v: string) { - const n = v.replace(/\D/g, "").slice(0, 8); - return n.replace(/(\d{5})(\d{0,3})/, (_, a, b) => `${a}${b ? "-" + b : ""}`); - } + function formatCEP(v: string) { const n = v.replace(/\D/g, "").slice(0, 8); return n.replace(/(\d{5})(\d{0,3})/, (_, a, b) => `${a}${b ? "-" + b : ""}`); } async function fillFromCEP(cep: string) { - const clean = cep.replace(/\D/g, ""); - if (clean.length !== 8) return; - setSearchingCEP(true); - try { - const res = await buscarCepAPI(clean); - if (res?.erro) { - setErrors((e) => ({ ...e, cep: "CEP não encontrado" })); - } else { - setField("logradouro", res.logradouro ?? ""); - setField("bairro", res.bairro ?? ""); - setField("cidade", res.localidade ?? ""); - setField("estado", res.uf ?? ""); - } - } catch { - setErrors((e) => ({ ...e, cep: "Erro ao buscar CEP" })); - } finally { - setSearchingCEP(false); - } + const clean = cep.replace(/\D/g, ""); if (clean.length !== 8) return; setSearchingCEP(true); + try { const res = await buscarCepAPI(clean); if (res?.erro) setErrors((e) => ({ ...e, cep: "CEP não encontrado" })); else { setField("logradouro", res.logradouro ?? ""); setField("bairro", res.bairro ?? ""); setField("cidade", res.localidade ?? ""); setField("estado", res.uf ?? ""); } } + catch { setErrors((e) => ({ ...e, cep: "Erro ao buscar CEP" })); } finally { setSearchingCEP(false); } } function validateLocal(): boolean { @@ -222,14 +192,9 @@ export function PatientRegistrationForm({ try { const parts = String(form.birth_date).split(/\D+/).filter(Boolean); if (parts.length === 3) { - const [d, m, y] = parts; - const date = new Date(Number(y), Number(m) - 1, Number(d)); - if (!isNaN(date.getTime())) { - isoDate = date.toISOString().slice(0, 10); - } + const [d, m, y] = parts; const date = new Date(Number(y), Number(m) - 1, Number(d)); if (!isNaN(date.getTime())) isoDate = date.toISOString().slice(0, 10); } } catch {} - return { full_name: form.nome, social_name: form.nome_social || null, @@ -251,375 +216,110 @@ export function PatientRegistrationForm({ } async function handleSubmit(ev: React.FormEvent) { - ev.preventDefault(); - if (!validateLocal()) return; - + ev.preventDefault(); if (!validateLocal()) return; try { - if (!validarCPFLocal(form.cpf)) { - setErrors((e) => ({ ...e, cpf: "CPF inválido" })); - return; - } - if (mode === "create") { - const existe = await verificarCpfDuplicado(form.cpf); - if (existe) { - setErrors((e) => ({ ...e, cpf: "CPF já cadastrado no sistema" })); - return; - } - } - } catch (err) { - console.error("Erro ao validar CPF", err); - setErrors({ submit: "Erro ao validar CPF." }); - return; - } + if (!validarCPFLocal(form.cpf)) { setErrors((e) => ({ ...e, cpf: "CPF inválido" })); return; } + if (mode === "create") { const existe = await verificarCpfDuplicado(form.cpf); if (existe) { setErrors((e) => ({ ...e, cpf: "CPF já cadastrado no sistema" })); return; } } + } catch (err) { console.error("Erro ao validar CPF", err); setErrors({ submit: "Erro ao validar CPF." }); return; } setSubmitting(true); try { if (mode === "edit") { if (patientId == null) throw new Error("Paciente inexistente para edição"); - const payload = toPayload(); - const saved = await atualizarPaciente(String(patientId), payload); - // If a new photo was selected locally, remove existing public avatar (if any) then upload the new one + const payload = toPayload(); const saved = await atualizarPaciente(String(patientId), payload); if (form.photo) { - try { - setUploadingPhoto(true); - // Attempt to remove existing avatar first (no-op if none) - try { - await removerFotoPaciente(String(patientId)); - // clear any cached preview so upload result will repopulate it - setPhotoPreview(null); - } catch (remErr) { - // If removal fails (permissions/CORS), continue to attempt upload — we don't want to block the user - console.warn('[PatientForm] aviso: falha ao remover avatar antes do upload:', remErr); - } - await uploadFotoPaciente(String(patientId), form.photo); - } catch (upErr) { - console.warn('[PatientForm] Falha ao enviar foto do paciente:', upErr); - // don't block the main update — show a warning - alert('Paciente atualizado, mas falha ao enviar a foto. Tente novamente.'); - } finally { - setUploadingPhoto(false); - } + try { setUploadingPhoto(true); try { await removerFotoPaciente(String(patientId)); setPhotoPreview(null); } catch (remErr) { console.warn('[PatientForm] aviso: falha ao remover avatar antes do upload:', remErr); } await uploadFotoPaciente(String(patientId), form.photo); } + catch (upErr) { console.warn('[PatientForm] Falha ao enviar foto do paciente:', upErr); alert('Paciente atualizado, mas falha ao enviar a foto. Tente novamente.'); } + finally { setUploadingPhoto(false); } } - onSaved?.(saved); - alert("Paciente atualizado com sucesso!"); - - setForm(initial); - setPhotoPreview(null); - setServerAnexos([]); - if (inline) onClose?.(); - else onOpenChange?.(false); - + onSaved?.(saved); alert("Paciente atualizado com sucesso!"); setForm(initial); setPhotoPreview(null); setServerAnexos([]); if (inline) onClose?.(); else onOpenChange?.(false); } else { - // --- NOVA LÓGICA DE CRIAÇÃO --- + // create const patientPayload = toPayload(); - const savedPatientProfile = await criarPaciente(patientPayload); - console.log(" Perfil do paciente criado:", savedPatientProfile); - - if (form.email && form.email.includes('@')) { - console.log(" Criando usuário de autenticação (paciente)..."); - try { - const userResponse = await criarUsuarioPaciente({ - email: form.email, - full_name: form.nome, - phone_mobile: form.telefone, - }); - - if (userResponse.success && userResponse.user) { - console.log(" Usuário de autenticação criado:", userResponse.user); - - // Mostra credenciais no dialog usando as credenciais retornadas - setCredentials({ - email: userResponse.email ?? form.email, - password: userResponse.password ?? '', - userName: form.nome, - userType: 'paciente', - }); - setShowCredentialsDialog(true); - - // Tenta vincular o user_id ao perfil do paciente recém-criado - try { - const apiMod = await import('@/lib/api'); - const pacienteId = savedPatientProfile?.id || (savedPatientProfile && (savedPatientProfile as any).id); - const userId = (userResponse.user as any)?.id || (userResponse.user as any)?.user_id || (userResponse.user as any)?.id; - - // Guard: verify userId is present and looks plausible before attempting to PATCH - const isPlausibleUserId = (id: any) => { - if (!id) return false; - const s = String(id).trim(); - if (!s) return false; - // quick UUID v4-ish check (xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx) or numeric id fallback - const uuidV4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; - const numeric = /^\d+$/; - return uuidV4.test(s) || numeric.test(s) || s.length >= 8; - }; - - if (!pacienteId) { - console.warn('[PatientForm] pacienteId ausente; pulando vinculação de user_id'); - } else if (!isPlausibleUserId(userId)) { - // Do not attempt to PATCH when userId is missing/invalid to avoid 400s - console.warn('[PatientForm] userId inválido ou ausente; não será feita a vinculação. userResponse:', userResponse); - } else if (typeof apiMod.vincularUserIdPaciente === 'function') { - console.log('[PatientForm] Vinculando user_id ao paciente:', pacienteId, userId); - try { - await apiMod.vincularUserIdPaciente(pacienteId, String(userId)); - console.log('[PatientForm] user_id vinculado com sucesso ao paciente'); - } catch (linkErr) { - console.warn('[PatientForm] Falha ao vincular user_id ao paciente:', linkErr); - } - } - } catch (dynErr) { - console.warn('[PatientForm] Não foi possível importar helper para vincular user_id:', dynErr); - } - - // Limpa formulário mas NÃO fecha ainda - fechará quando o dialog de credenciais fechar - setForm(initial); - setPhotoPreview(null); - setServerAnexos([]); - // If a photo was selected during creation, upload it now using the created patient id - if (form.photo) { - try { - setUploadingPhoto(true); - const pacienteId = savedPatientProfile?.id || (savedPatientProfile && (savedPatientProfile as any).id); - if (pacienteId) { - await uploadFotoPaciente(String(pacienteId), form.photo); - } - } catch (upErr) { - console.warn('[PatientForm] Falha ao enviar foto do paciente após criação:', upErr); - // Non-blocking: inform user - alert('Paciente criado, mas falha ao enviar a foto. Você pode tentar novamente no perfil.'); - } finally { - setUploadingPhoto(false); - } - } - onSaved?.(savedPatientProfile); - return; - } else { - throw new Error((userResponse as any).message || "Falhou ao criar o usuário de acesso."); - } - } catch (userError: any) { - console.error(" Erro ao criar usuário via signup:", userError); - - // Mensagem de erro específica para email duplicado - const errorMsg = userError?.message || String(userError); - - if (errorMsg.toLowerCase().includes('already registered') || - errorMsg.toLowerCase().includes('já está cadastrado') || - errorMsg.toLowerCase().includes('já existe')) { - alert( - ` Este email já está cadastrado no sistema.\n\n` + - ` O perfil do paciente foi salvo com sucesso.\n\n` + - `Para criar acesso ao sistema, use um email diferente ou recupere a senha do email existente.` - ); - } else { - alert( - ` Paciente cadastrado com sucesso!\n\n` + - ` Porém houve um problema ao criar o acesso:\n${errorMsg}\n\n` + - `O cadastro do paciente foi salvo, mas será necessário criar o acesso manualmente.` - ); - } - - // Limpa formulário e fecha - setForm(initial); - setPhotoPreview(null); - setServerAnexos([]); - onSaved?.(savedPatientProfile); - if (inline) onClose?.(); - else onOpenChange?.(false); - return; - } - } else { - alert("Paciente cadastrado com sucesso (sem usuário de acesso - email não fornecido)."); - onSaved?.(savedPatientProfile); - setForm(initial); - setPhotoPreview(null); - setServerAnexos([]); - if (inline) onClose?.(); - else onOpenChange?.(false); + // require phone when email present for single-call function + if (form.email && form.email.includes('@') && (!form.telefone || !String(form.telefone).trim())) { + setErrors((e) => ({ ...e, telefone: 'Telefone é obrigatório quando email é informado (fluxo de criação único).' })); setSubmitting(false); return; } + const savedPatientProfile = await criarPaciente(patientPayload); + console.log('Perfil do paciente criado (via Function):', savedPatientProfile); + + const maybePassword = (savedPatientProfile as any)?.password || (savedPatientProfile as any)?.generated_password; + if (maybePassword) { + setCredentials({ email: (savedPatientProfile as any).email || form.email, password: String(maybePassword), userName: form.nome, userType: 'paciente' }); + setShowCredentialsDialog(true); + } + + if (form.photo) { + try { setUploadingPhoto(true); const pacienteId = savedPatientProfile?.id || (savedPatientProfile && (savedPatientProfile as any).id); if (pacienteId) await uploadFotoPaciente(String(pacienteId), form.photo); } + catch (upErr) { console.warn('[PatientForm] Falha ao enviar foto do paciente após criação:', upErr); alert('Paciente criado, mas falha ao enviar a foto. Você pode tentar novamente no perfil.'); } + finally { setUploadingPhoto(false); } + } + + onSaved?.(savedPatientProfile); setForm(initial); setPhotoPreview(null); setServerAnexos([]); if (inline) onClose?.(); else onOpenChange?.(false); } - } catch (err: any) { - console.error("❌ Erro no handleSubmit:", err); - // Exibe mensagem amigável ao usuário - const userMessage = err?.message?.includes("toPayload") || err?.message?.includes("is not defined") - ? "Erro ao processar os dados do formulário. Por favor, verifique os campos e tente novamente." - : err?.message || "Erro ao salvar paciente. Por favor, tente novamente."; - setErrors({ submit: userMessage }); - } finally { - setSubmitting(false); - } + } catch (err: any) { console.error("❌ Erro no handleSubmit:", err); const userMessage = err?.message?.includes("toPayload") || err?.message?.includes("is not defined") ? "Erro ao processar os dados do formulário. Por favor, verifique os campos e tente novamente." : err?.message || "Erro ao salvar paciente. Por favor, tente novamente."; setErrors({ submit: userMessage }); } + finally { setSubmitting(false); } } - function handlePhoto(e: React.ChangeEvent) { - const f = e.target.files?.[0]; - if (!f) return; - if (f.size > 5 * 1024 * 1024) { - setErrors((e) => ({ ...e, photo: "Arquivo muito grande. Máx 5MB." })); - return; - } - setField("photo", f); - const fr = new FileReader(); - fr.onload = (ev) => setPhotoPreview(String(ev.target?.result || "")); - fr.readAsDataURL(f); - } + function handlePhoto(e: React.ChangeEvent) { const f = e.target.files?.[0]; if (!f) return; if (f.size > 5 * 1024 * 1024) { setErrors((e) => ({ ...e, photo: "Arquivo muito grande. Máx 5MB." })); return; } setField("photo", f); const fr = new FileReader(); fr.onload = (ev) => setPhotoPreview(String(ev.target?.result || "")); fr.readAsDataURL(f); } - function addLocalAnexos(e: React.ChangeEvent) { - const fs = Array.from(e.target.files || []); - setField("anexos", [...form.anexos, ...fs]); - } - function removeLocalAnexo(idx: number) { - const clone = [...form.anexos]; - clone.splice(idx, 1); - setField("anexos", clone); - } + function addLocalAnexos(e: React.ChangeEvent) { const fs = Array.from(e.target.files || []); setField("anexos", [...form.anexos, ...fs]); } + function removeLocalAnexo(idx: number) { const clone = [...form.anexos]; clone.splice(idx, 1); setField("anexos", clone); } - async function handleRemoverFotoServidor() { - if (mode !== "edit" || !patientId) return; - try { - setUploadingPhoto(true); - await removerFotoPaciente(String(patientId)); - // clear preview and inform user - setPhotoPreview(null); - alert('Foto removida com sucesso.'); - } catch (e: any) { - console.warn('[PatientForm] erro ao remover foto do servidor', e); - // Show detailed guidance for common cases - if (String(e?.message || '').includes('401')) { - alert('Falha ao remover a foto: não autenticado. Faça login novamente e tente novamente.\nDetalhe: ' + (e?.message || '')); - } else if (String(e?.message || '').includes('403')) { - alert('Falha ao remover a foto: sem permissão. Verifique as permissões do token e se o storage aceita esse usuário.\nDetalhe: ' + (e?.message || '')); - } else { - alert(e?.message || 'Não foi possível remover a foto do storage. Veja console para detalhes.'); - } - } finally { - setUploadingPhoto(false); - } - } + async function handleRemoverFotoServidor() { if (mode !== "edit" || !patientId) return; try { setUploadingPhoto(true); await removerFotoPaciente(String(patientId)); setPhotoPreview(null); alert('Foto removida com sucesso.'); } catch (e: any) { console.warn('[PatientForm] erro ao remover foto do servidor', e); if (String(e?.message || '').includes('401')) { alert('Falha ao remover a foto: não autenticado. Faça login novamente e tente novamente.\nDetalhe: ' + (e?.message || '')); } else if (String(e?.message || '').includes('403')) { alert('Falha ao remover a foto: sem permissão. Verifique as permissões do token e se o storage aceita esse usuário.\nDetalhe: ' + (e?.message || '')); } else { alert(e?.message || 'Não foi possível remover a foto do storage. Veja console para detalhes.'); } } finally { setUploadingPhoto(false); } } - async function handleRemoverAnexoServidor(anexoId: string | number) { - if (mode !== "edit" || !patientId) return; - try { - await removerAnexo(String(patientId), anexoId); - setServerAnexos((prev) => prev.filter((a) => String(a.id ?? a.anexo_id) !== String(anexoId))); - } catch (e: any) { - alert(e?.message || "Não foi possível remover o anexo."); - } - } + async function handleRemoverAnexoServidor(anexoId: string | number) { if (mode !== "edit" || !patientId) return; try { await removerAnexo(String(patientId), anexoId); setServerAnexos((prev) => prev.filter((a) => String(a.id ?? a.anexo_id) !== String(anexoId))); } catch (e: any) { alert(e?.message || "Não foi possível remover o anexo."); } } const content = ( <> {errors.submit && ( - - - {errors.submit} - + {errors.submit} )}
+ {/* Personal data, contact, address, attachments... keep markup concise */} setExpanded((s) => ({ ...s, dados: !s.dados }))}> - - - - Dados Pessoais - - {expanded.dados ? : } - + Dados Pessoais{expanded.dados ? : }
- {photoPreview ? ( - Preview - ) : ( - - )} + {photoPreview ? Preview : }
- {mode === "edit" && ( - - )} + {mode === "edit" && ()} {errors.photo &&

{errors.photo}

}

Máximo 5MB

-
- - setField("nome", e.target.value)} className={errors.nome ? "border-destructive" : ""} /> - {errors.nome &&

{errors.nome}

} -
-
- - setField("nome_social", e.target.value)} /> -
+
setField("nome", e.target.value)} className={errors.nome ? "border-destructive" : ""} />{errors.nome &&

{errors.nome}

}
+
setField("nome_social", e.target.value)} />
-
- - handleCPFChange(e.target.value)} - placeholder="000.000.000-00" - maxLength={14} - className={errors.cpf ? "border-destructive" : ""} - /> - {errors.cpf &&

{errors.cpf}

} -
-
- - setField("rg", e.target.value)} /> -
+
handleCPFChange(e.target.value)} placeholder="000.000.000-00" maxLength={14} className={errors.cpf ? "border-destructive" : ""} />{errors.cpf &&

{errors.cpf}

}
+
setField("rg", e.target.value)} />
-
- +
-
- - { - const v = e.target.value.replace(/[^0-9\/]/g, "").slice(0, 10); - setField("birth_date", v); - }} - onBlur={() => { - const raw = form.birth_date; - const parts = raw.split(/\D+/).filter(Boolean); - if (parts.length === 3) { - const d = `${parts[0].padStart(2,'0')}/${parts[1].padStart(2,'0')}/${parts[2].padStart(4,'0')}`; - setField("birth_date", d); - } - }} - /> -
+
{ const v = e.target.value.replace(/[^0-9\/]*/g, "").slice(0, 10); setField("birth_date", v); }} onBlur={() => { const raw = form.birth_date; const parts = raw.split(/\D+/).filter(Boolean); if (parts.length === 3) { const d = `${parts[0].padStart(2,'0')}/${parts[1].padStart(2,'0')}/${parts[2].padStart(4,'0')}`; setField("birth_date", d); } }} />
@@ -629,25 +329,13 @@ export function PatientRegistrationForm({ setExpanded((s) => ({ ...s, contato: !s.contato }))}> - - - Contato - {expanded.contato ? : } - - + Contato{expanded.contato ? : }
-
- - setField("email", e.target.value)} /> - {errors.email &&

{errors.email}

} -
-
- - setField("telefone", e.target.value)} /> -
+
setField("email", e.target.value)} />{errors.email &&

{errors.email}

}
+
setField("telefone", e.target.value)} />{errors.telefone &&

{errors.telefone}

}
@@ -657,66 +345,19 @@ export function PatientRegistrationForm({ setExpanded((s) => ({ ...s, endereco: !s.endereco }))}> - - - Endereço - {expanded.endereco ? : } - - + Endereço{expanded.endereco ? : }
-
- -
- { - const v = formatCEP(e.target.value); - setField("cep", v); - if (v.replace(/\D/g, "").length === 8) fillFromCEP(v); - }} - placeholder="00000-000" - maxLength={9} - disabled={isSearchingCEP} - className={errors.cep ? "border-destructive" : ""} - /> - {isSearchingCEP && } -
- {errors.cep &&

{errors.cep}

} -
-
- - setField("logradouro", e.target.value)} /> -
-
- - setField("numero", e.target.value)} /> -
+
{ const v = formatCEP(e.target.value); setField("cep", v); if (v.replace(/\D/g, "").length === 8) fillFromCEP(v); }} placeholder="00000-000" maxLength={9} disabled={isSearchingCEP} className={errors.cep ? "border-destructive" : ""} />{isSearchingCEP && }
{errors.cep &&

{errors.cep}

}
+
setField("logradouro", e.target.value)} />
+
setField("numero", e.target.value)} />
-
-
- - setField("complemento", e.target.value)} /> -
-
- - setField("bairro", e.target.value)} /> -
-
+
setField("complemento", e.target.value)} />
setField("bairro", e.target.value)} />
-
-
- - setField("cidade", e.target.value)} /> -
-
- - setField("estado", e.target.value)} placeholder="UF" /> -
-
+
setField("cidade", e.target.value)} />
setField("estado", e.target.value)} placeholder="UF" />
@@ -725,19 +366,11 @@ export function PatientRegistrationForm({ setExpanded((s) => ({ ...s, obs: !s.obs }))}> - - - Observações e Anexos - {expanded.obs ? : } - - + Observações e Anexos{expanded.obs ? : } -
- -