From 5d78e9f066e7e7a1c5109d1cab94bf2f4ebdcc31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gustavo?= <166467972+JoaoGustavo-dev@users.noreply.github.com> Date: Sat, 8 Nov 2025 00:32:00 -0300 Subject: [PATCH] fix-dialog-modal --- .../forms/doctor-registration-form.tsx | 144 ++++++++++++------ .../forms/patient-registration-form.tsx | 142 +++++++++++++++-- susconecta/lib/api.ts | 14 +- 3 files changed, 238 insertions(+), 62 deletions(-) diff --git a/susconecta/components/features/forms/doctor-registration-form.tsx b/susconecta/components/features/forms/doctor-registration-form.tsx index 189f0b3..2183868 100644 --- a/susconecta/components/features/forms/doctor-registration-form.tsx +++ b/susconecta/components/features/forms/doctor-registration-form.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useState, useRef } from "react"; import { parse, parseISO, format } from 'date-fns'; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -167,6 +167,7 @@ export function DoctorRegistrationForm({ userName: string; userType: 'médico' | 'paciente'; } | null>(null); + const savedDoctorRef = useRef(null); const title = useMemo(() => (mode === "create" ? "Cadastro de Médico" : "Editar Médico"), [mode]); @@ -504,6 +505,11 @@ async function handleSubmit(ev: React.FormEvent) { // 1. Cria o perfil do médico na tabela doctors let savedDoctorProfile: any = await criarMedico(medicoPayload); console.log("✅ Perfil do médico criado:", savedDoctorProfile); + console.log("🔑 Senha no objeto retornado:", savedDoctorProfile?.password); + + // Salvar a senha ANTES de qualquer operação que possa sobrescrever o objeto + const senhaGerada = savedDoctorProfile?.password; + console.log("💾 Senha salva em variável:", senhaGerada); // Fallback: some create flows don't persist optional fields like birth_date/cep/sexo. // If the returned object is missing those but our payload included them, @@ -531,7 +537,9 @@ async function handleSubmit(ev: React.FormEvent) { const patched = await atualizarMedico(String(createdDoctorId), medicoPayload).catch((e) => { console.warn('[DoctorForm] fallback PATCH failed:', e); return null; }); if (patched) { console.debug('[DoctorForm] fallback PATCH result:', patched); - savedDoctorProfile = patched; + // Preservar a senha ao atualizar o objeto + savedDoctorProfile = { ...patched, password: senhaGerada }; + console.log("🔄 Senha preservada após PATCH:", savedDoctorProfile?.password); } } } catch (e) { @@ -547,6 +555,7 @@ async function handleSubmit(ev: React.FormEvent) { // { doctor, doctor_id, email, password, user_id } or similar shapes. const result = savedDoctorProfile as any; console.log('✅ Resultado de criarMedico:', result); + console.log('🔑 Senha no resultado final:', result?.password); // Determine the doctor id if available let createdDoctorId: string | null = null; @@ -559,13 +568,36 @@ async function handleSubmit(ev: React.FormEvent) { // If the function returned credentials, show them in the credentials dialog if (result && (result.password || result.email || result.user)) { - setCredentials({ + console.log('📧 Credenciais recebidas - configurando dialog...'); + console.log('📧 Email:', result.email || form.email); + console.log('🔑 Senha extraída:', result.password); + console.log('👤 Nome do usuário:', form.full_name); + + const credenciaisParaExibir = { email: result.email || form.email, - password: result.password || "", + password: result.password || senhaGerada || "", userName: form.full_name, - userType: 'médico', - }); + userType: 'médico' as const, + }; + + console.log('📋 Credenciais a serem definidas:', credenciaisParaExibir); + + // Salvar o médico no ref ANTES de abrir o dialog + savedDoctorRef.current = savedDoctorProfile; + + setCredentials(credenciaisParaExibir); setShowCredentialsDialog(true); + console.log('✅ Dialog de credenciais configurado e aberto'); + + // Verificar estados após 100ms + setTimeout(() => { + console.log('🔍 Verificando estados após 100ms:'); + console.log('- showCredentialsDialog:', showCredentialsDialog); + console.log('- credentials:', credentials); + }, 100); + + // NÃO fechar o formulário aqui - será fechado quando o usuário fechar o dialog de credenciais + return; // Sair da função para não executar o cleanup abaixo } // Upload photo if provided and we have an id @@ -800,8 +832,8 @@ async function handleSubmit(ev: React.FormEvent) { setField("data_nascimento", date || null)} + selected={form.data_nascimento ?? undefined} + onSelect={(date) => setField("data_nascimento", date ?? null)} initialFocus /> @@ -1061,28 +1093,37 @@ async function handleSubmit(ev: React.FormEvent) { <>
{content}
- {/* Dialog de credenciais */} - {credentials && ( - { - setShowCredentialsDialog(open); - if (!open) { - // Quando o dialog de credenciais fecha, fecha o formulário também - setCredentials(null); - if (inline) { - onClose?.(); - } else { - onOpenChange?.(false); - } + { + console.log('🔄 CredentialsDialog (inline) onOpenChange chamado com:', open); + setShowCredentialsDialog(open); + if (!open) { + // Dialog foi fechado - limpar estados e fechar formulário + console.log('✅ Dialog fechado - limpando formulário...'); + setCredentials(null); + + // Chamar onSaved se houver médico salvo + if (savedDoctorRef.current) { + onSaved?.(savedDoctorRef.current); + savedDoctorRef.current = null; } - }} - email={credentials.email} - password={credentials.password} - userName={credentials.userName} - userType={credentials.userType} - /> - )} + + // Limpar formulário + setForm(initial); + setPhotoPreview(null); + setServerAnexos([]); + + // Fechar formulário + if (inline) onClose?.(); + else onOpenChange?.(false); + } + }} + email={credentials?.email || ''} + password={credentials?.password || ''} + userName={credentials?.userName || ''} + userType={credentials?.userType || 'médico'} + /> ); } @@ -1100,23 +1141,36 @@ async function handleSubmit(ev: React.FormEvent) { - {/* Dialog de credenciais */} - {credentials && ( - { - setShowCredentialsDialog(open); - if (!open) { - setCredentials(null); - onOpenChange?.(false); + { + console.log('🔄 CredentialsDialog (dialog) onOpenChange chamado com:', open); + setShowCredentialsDialog(open); + if (!open) { + // Dialog foi fechado - limpar estados e fechar formulário + console.log('✅ Dialog fechado - limpando formulário...'); + setCredentials(null); + + // Chamar onSaved se houver médico salvo + if (savedDoctorRef.current) { + onSaved?.(savedDoctorRef.current); + savedDoctorRef.current = null; } - }} - email={credentials.email} - password={credentials.password} - userName={credentials.userName} - userType={credentials.userType} - /> - )} + + // Limpar formulário + setForm(initial); + setPhotoPreview(null); + setServerAnexos([]); + + // Fechar formulário principal + onOpenChange?.(false); + } + }} + email={credentials?.email || ''} + password={credentials?.password || ''} + userName={credentials?.userName || ''} + userType={credentials?.userType || 'médico'} + /> ); } diff --git a/susconecta/components/features/forms/patient-registration-form.tsx b/susconecta/components/features/forms/patient-registration-form.tsx index feafa89..aa11b20 100644 --- a/susconecta/components/features/forms/patient-registration-form.tsx +++ b/susconecta/components/features/forms/patient-registration-form.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useState, useRef } from "react"; import { format, parseISO, parse } from "date-fns"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -138,6 +138,9 @@ export function PatientRegistrationForm({ userName: string; userType: 'médico' | 'paciente'; } | null>(null); + + // Ref para guardar o paciente salvo para chamar onSaved quando o dialog fechar + const savedPatientRef = useRef(null); const title = useMemo(() => (mode === "create" ? "Cadastro de Paciente" : "Editar Paciente"), [mode]); @@ -276,7 +279,11 @@ export function PatientRegistrationForm({ setErrors((e) => ({ ...e, telefone: 'Telefone é obrigatório quando email é informado (fluxo de criação único).' })); setSubmitting(false); return; } let savedPatientProfile: any = await criarPaciente(patientPayload); - console.log('Perfil do paciente criado (via Function):', savedPatientProfile); + console.log('🎯 Paciente criado! Resposta completa:', savedPatientProfile); + console.log('🔑 Senha no objeto:', savedPatientProfile?.password); + + // Guardar a senha ANTES de qualquer operação que possa sobrescrever o objeto + const senhaGerada = savedPatientProfile?.password; // Fallback: some backend create flows (create-user-with-password) do not // persist optional patient fields like sex/cep/birth_date. The edit flow @@ -295,17 +302,56 @@ export function PatientRegistrationForm({ const patched = await atualizarPaciente(String(pacienteId), patientPayload).catch((e) => { console.warn('[PatientForm] fallback PATCH falhou:', e); return null; }); if (patched) { console.debug('[PatientForm] fallback PATCH result:', patched); - savedPatientProfile = patched; + // Preserva a senha ao fazer merge do patch + savedPatientProfile = { ...patched, password: senhaGerada }; } } } catch (e) { console.warn('[PatientForm] erro ao tentar fallback PATCH:', e); } - 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' }); + // Usar a senha que foi guardada ANTES do PATCH + const emailToDisplay = savedPatientProfile?.email || form.email; + console.log('📧 Email para exibir:', emailToDisplay); + console.log('🔐 Senha para exibir:', senhaGerada); + + if (senhaGerada && emailToDisplay) { + console.log('✅ Abrindo modal de credenciais...'); + const credentialsToShow = { + email: emailToDisplay, + password: String(senhaGerada), + userName: form.nome, + userType: 'paciente' as const + }; + console.log('📝 Credenciais a serem definidas:', credentialsToShow); + + // Guardar o paciente salvo no ref para usar quando o dialog fechar + savedPatientRef.current = savedPatientProfile; + + // Definir credenciais e abrir dialog + setCredentials(credentialsToShow); setShowCredentialsDialog(true); + + // NÃO limpar o formulário ou fechar ainda - aguardar o usuário fechar o dialog de credenciais + // O dialog de credenciais vai chamar onSaved e fechar quando o usuário clicar em "Fechar" + + // Verificar se foi setado + setTimeout(() => { + console.log('🔍 Verificando estados após 100ms:'); + console.log(' - showCredentialsDialog:', showCredentialsDialog); + console.log(' - credentials:', credentials); + }, 100); + } else { + console.error('❌ Não foi possível exibir credenciais:', { senhaGerada, emailToDisplay }); + alert(`Paciente criado!\n\nEmail: ${emailToDisplay}\n\nAVISO: A senha não pôde ser recuperada. Entre em contato com o suporte.`); + + // Se não há senha, limpar e fechar normalmente + onSaved?.(savedPatientProfile); + setForm(initial); + setPhotoPreview(null); + setServerAnexos([]); + if (inline) onClose?.(); + else onOpenChange?.(false); } if (form.photo) { @@ -313,8 +359,6 @@ export function PatientRegistrationForm({ 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); 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); } @@ -519,8 +563,86 @@ export function PatientRegistrationForm({ ); if (inline) { - return (<>
{content}
{credentials && ( { setShowCredentialsDialog(open); if (!open) { setCredentials(null); if (inline) onClose?.(); else onOpenChange?.(false); } }} email={credentials.email} password={credentials.password} userName={credentials.userName} userType={credentials.userType} />)}); + return ( + <> +
{content}
+ { + console.log('🔄 CredentialsDialog onOpenChange chamado com:', open); + setShowCredentialsDialog(open); + if (!open) { + // Dialog foi fechado - limpar estados e fechar formulário + console.log('✅ Dialog fechado - limpando formulário...'); + setCredentials(null); + + // Chamar onSaved se houver paciente salvo + if (savedPatientRef.current) { + onSaved?.(savedPatientRef.current); + savedPatientRef.current = null; + } + + // Limpar formulário + setForm(initial); + setPhotoPreview(null); + setServerAnexos([]); + + // Fechar formulário + if (inline) onClose?.(); + else onOpenChange?.(false); + } + }} + email={credentials?.email || ''} + password={credentials?.password || ''} + userName={credentials?.userName || ''} + userType={credentials?.userType || 'paciente'} + /> + + ); } - return (<> {title}{content}{credentials && ( { setShowCredentialsDialog(open); if (!open) { setCredentials(null); onOpenChange?.(false); } }} email={credentials.email} password={credentials.password} userName={credentials.userName} userType={credentials.userType} />)}); + return ( + <> + + + + + {title} + + + {content} + + + { + console.log('🔄 CredentialsDialog onOpenChange chamado com:', open); + setShowCredentialsDialog(open); + if (!open) { + // Dialog foi fechado - limpar estados e fechar formulário + console.log('✅ Dialog fechado - limpando formulário...'); + setCredentials(null); + + // Chamar onSaved se houver paciente salvo + if (savedPatientRef.current) { + onSaved?.(savedPatientRef.current); + savedPatientRef.current = null; + } + + // Limpar formulário + setForm(initial); + setPhotoPreview(null); + setServerAnexos([]); + + // Fechar formulário principal + onOpenChange?.(false); + } + }} + email={credentials?.email || ''} + password={credentials?.password || ''} + userName={credentials?.userName || ''} + userType={credentials?.userType || 'paciente'} + /> + + ); } \ No newline at end of file diff --git a/susconecta/lib/api.ts b/susconecta/lib/api.ts index fe7c217..a3b80c1 100644 --- a/susconecta/lib/api.ts +++ b/susconecta/lib/api.ts @@ -2139,25 +2139,25 @@ export async function criarMedico(input: MedicoInput): Promise { // If server returned doctor_id, fetch the doctor if (parsed && parsed.doctor_id) { const doc = await buscarMedicoPorId(String(parsed.doctor_id)).catch(() => null); - if (doc) return Object.assign(doc, { password }); - if (parsed.doctor) return Object.assign(parsed.doctor, { password }); - return Object.assign({ id: parsed.doctor_id, full_name: input.full_name, cpf: cleanCpf, email: input.email } as Medico, { password }); + if (doc) return { ...doc, password } as any; + if (parsed.doctor) return { ...parsed.doctor, password } as any; + return { id: parsed.doctor_id, full_name: input.full_name, cpf: cleanCpf, email: input.email, password } as any; } // If server returned doctor object directly if (parsed && (parsed.id || parsed.full_name || parsed.cpf)) { - return Object.assign(parsed, { password }) as Medico; + return { ...parsed, password } as any; } // If server returned an envelope with user, try to locate doctor by email if (parsed && parsed.user && parsed.user.id) { const maybe = await fetch(`${REST}/doctors?email=eq.${encodeURIComponent(String(input.email))}&select=*`, { method: 'GET', headers: baseHeaders() }).then((r) => r.ok ? r.json().catch(() => []) : []); - if (Array.isArray(maybe) && maybe.length) return Object.assign(maybe[0] as Medico, { password }); - return Object.assign({ id: parsed.user.id, full_name: input.full_name, email: input.email } as Medico, { password }); + if (Array.isArray(maybe) && maybe.length) return { ...maybe[0], password } as any; + return { id: parsed.user.id, full_name: input.full_name, email: input.email, password } as any; } // otherwise return parsed with password as best-effort - return Object.assign(parsed || {}, { password }); + return { ...(parsed || {}), password } as any; } catch (err: any) { lastErr = err; const emsg = err && typeof err === 'object' && 'message' in err ? (err as any).message : String(err);