fix-dialog-modal

This commit is contained in:
João Gustavo 2025-11-08 00:32:00 -03:00
parent 9adf479e90
commit 5d78e9f066
3 changed files with 238 additions and 62 deletions

View File

@ -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<any>(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) {
<PopoverContent className="w-auto p-0">
<Calendar
mode="single"
selected={form.data_nascimento}
onSelect={(date) => setField("data_nascimento", date || null)}
selected={form.data_nascimento ?? undefined}
onSelect={(date) => setField("data_nascimento", date ?? null)}
initialFocus
/>
</PopoverContent>
@ -1061,28 +1093,37 @@ async function handleSubmit(ev: React.FormEvent) {
<>
<div className="space-y-6">{content}</div>
{/* Dialog de credenciais */}
{credentials && (
<CredentialsDialog
open={showCredentialsDialog}
onOpenChange={(open) => {
setShowCredentialsDialog(open);
if (!open) {
// Quando o dialog de credenciais fecha, fecha o formulário também
setCredentials(null);
if (inline) {
onClose?.();
} else {
onOpenChange?.(false);
}
<CredentialsDialog
open={showCredentialsDialog}
onOpenChange={(open) => {
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) {
</DialogContent>
</Dialog>
{/* Dialog de credenciais */}
{credentials && (
<CredentialsDialog
open={showCredentialsDialog}
onOpenChange={(open) => {
setShowCredentialsDialog(open);
if (!open) {
setCredentials(null);
onOpenChange?.(false);
<CredentialsDialog
open={showCredentialsDialog}
onOpenChange={(open) => {
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'}
/>
</>
);
}

View File

@ -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<any>(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 (<><div className="space-y-6">{content}</div>{credentials && (<CredentialsDialog open={showCredentialsDialog} onOpenChange={(open) => { 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 (
<>
<div className="space-y-6">{content}</div>
<CredentialsDialog
open={showCredentialsDialog}
onOpenChange={(open) => {
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 (<><Dialog open={open} onOpenChange={onOpenChange}><DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto"><DialogHeader><DialogTitle className="flex items-center gap-2"><User className="h-5 w-5" /> {title}</DialogTitle></DialogHeader>{content}</DialogContent></Dialog>{credentials && (<CredentialsDialog open={showCredentialsDialog} onOpenChange={(open) => { setShowCredentialsDialog(open); if (!open) { setCredentials(null); onOpenChange?.(false); } }} email={credentials.email} password={credentials.password} userName={credentials.userName} userType={credentials.userType} />)}</>);
return (
<>
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<User className="h-5 w-5" /> {title}
</DialogTitle>
</DialogHeader>
{content}
</DialogContent>
</Dialog>
<CredentialsDialog
open={showCredentialsDialog}
onOpenChange={(open) => {
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'}
/>
</>
);
}

View File

@ -2139,25 +2139,25 @@ export async function criarMedico(input: MedicoInput): Promise<Medico> {
// 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);