"use client"; import { useEffect, useMemo, useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { AlertCircle, ChevronDown, ChevronUp, FileImage, Loader2, Save, Upload, User, X, XCircle, Trash2 } from "lucide-react"; import { Checkbox } from "@/components/ui/checkbox"; import { Popover, PopoverTrigger, PopoverContent } from "@/components/ui/popover"; import { criarMedico, atualizarMedico, buscarMedicoPorId, uploadFotoMedico, listarAnexosMedico, adicionarAnexoMedico, removerAnexoMedico, MedicoInput, } from "@/lib/api"; import { buscarCepAPI } from "@/lib/api"; type FormacaoAcademica = { instituicao: string; curso: string; ano_conclusao: string; }; type DadosBancarios = { banco: string; agencia: string; conta: string; tipo_conta: string; }; export type Medico = { id: string; nome?: string; nome_social?: string | null; cpf?: string; rg?: string | null; sexo?: string | null; data_nascimento?: string | null; telefone?: string; celular?: string; contato_emergencia?: string; email?: string; crm?: string; estado_crm?: string; rqe?: string; formacao_academica?: FormacaoAcademica[]; curriculo_url?: string | null; especialidade?: string; observacoes?: string | null; foto_url?: string | null; tipo_vinculo?: string; dados_bancarios?: DadosBancarios; agenda_horario?: string; valor_consulta?: number | string; }; type Mode = "create" | "edit"; export interface DoctorRegistrationFormProps { open?: boolean; onOpenChange?: (open: boolean) => void; doctorId?: number | null; inline?: boolean; mode?: Mode; onSaved?: (medico: Medico) => void; onClose?: () => void; } type FormData = { photo: File | null; nome: string; nome_social: string; crm: string; estado_crm: string; rqe: string; formacao_academica: FormacaoAcademica[]; curriculo: File | null; especialidade: string; cpf: string; rg: string; sexo: string; data_nascimento: string; email: string; telefone: string; celular: string; contato_emergencia: string; cep: string; logradouro: string; numero: string; complemento: string; bairro: string; cidade: string; estado: string; observacoes: string; anexos: File[]; tipo_vinculo: string; dados_bancarios: DadosBancarios; agenda_horario: string; valor_consulta: string; }; const initial: FormData = { photo: null, nome: "", nome_social: "", crm: "", estado_crm: "", rqe: "", formacao_academica: [], curriculo: null, especialidade: "", cpf: "", rg: "", sexo: "", data_nascimento: "", email: "", telefone: "", celular: "", contato_emergencia: "", cep: "", logradouro: "", numero: "", complemento: "", bairro: "", cidade: "", estado: "", observacoes: "", anexos: [], tipo_vinculo: "", dados_bancarios: { banco: "", agencia: "", conta: "", tipo_conta: "", }, agenda_horario: "", valor_consulta: "", }; export function DoctorRegistrationForm({ open = true, onOpenChange, doctorId = null, inline = false, mode = "create", onSaved, onClose, }: DoctorRegistrationFormProps) { const [form, setForm] = useState(initial); const [errors, setErrors] = useState>({}); const [expanded, setExpanded] = useState({ dados: true, contato: false, endereco: false, obs: false, formacao: false, admin: false }); const [isSubmitting, setSubmitting] = useState(false); const [isSearchingCEP, setSearchingCEP] = useState(false); const [photoPreview, setPhotoPreview] = useState(null); const [serverAnexos, setServerAnexos] = useState([]); const title = useMemo(() => (mode === "create" ? "Cadastro de Médico" : "Editar Médico"), [mode]); useEffect(() => { let alive = true; async function load() { if (mode === "edit" && doctorId) { const medico = await buscarMedicoPorId(doctorId); if (!alive) return; setForm({ photo: null, nome: medico.nome ?? "", nome_social: medico.nome_social ?? "", crm: medico.crm ?? "", estado_crm: medico.estado_crm ?? "", rqe: medico.rqe ?? "", formacao_academica: medico.formacao_academica ?? [], curriculo: null, especialidade: medico.especialidade ?? "", cpf: medico.cpf ?? "", rg: medico.rg ?? "", sexo: medico.sexo ?? "", data_nascimento: medico.data_nascimento ?? "", email: medico.email ?? "", telefone: medico.telefone ?? "", celular: medico.celular ?? "", contato_emergencia: medico.contato_emergencia ?? "", cep: "", logradouro: "", numero: "", complemento: "", bairro: "", cidade: "", estado: "", observacoes: medico.observacoes ?? "", anexos: [], tipo_vinculo: medico.tipo_vinculo ?? "", dados_bancarios: medico.dados_bancarios ?? { banco: "", agencia: "", conta: "", tipo_conta: "" }, agenda_horario: medico.agenda_horario ?? "", valor_consulta: medico.valor_consulta ? String(medico.valor_consulta) : "", }); try { const list = await listarAnexosMedico(doctorId); setServerAnexos(list ?? []); } catch {} } } load(); return () => { alive = false; }; }, [mode, doctorId]); function setField(k: T, v: FormData[T]) { setForm((s) => ({ ...s, [k]: v })); if (errors[k as string]) setErrors((e) => ({ ...e, [k]: "" })); } function addFormacao() { setField("formacao_academica", [ ...form.formacao_academica, { instituicao: "", curso: "", ano_conclusao: "" }, ]); } function removeFormacao(index: number) { const newFormacao = [...form.formacao_academica]; newFormacao.splice(index, 1); setField("formacao_academica", newFormacao); } function handleFormacaoChange(index: number, field: keyof FormacaoAcademica, value: string) { const newFormacao = [...form.formacao_academica]; newFormacao[index][field] = value; setField("formacao_academica", newFormacao); } function formatPhone(v: string) { const n = v.replace(/\D/g, "").slice(0, 11); if (n.length > 6) { return n.replace(/(\d{2})(\d{5})(\d{0,4})/, "($1) $2-$3"); } else if (n.length > 2) { return n.replace(/(\d{2})(\d{0,5})/, "($1) $2"); } return n; } function formatRG(v: string) { v = v.replace(/\D/g, "").slice(0, 9); v = v.replace(/(\d{2})(\d)/, "$1.$2"); v = v.replace(/(\d{3})(\d)/, "$1.$2"); v = v.replace(/(\d{3})(\d{1,2})$/, "$1-$2"); return v; } function formatCPF(v: string) { 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 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 && !res.erro) { setField("logradouro", res.logradouro ?? ""); setField("bairro", res.bairro ?? ""); setField("cidade", res.localidade ?? ""); setField("estado", res.uf ?? ""); } else { setErrors((e) => ({ ...e, cep: "CEP não encontrado" })); } } catch { setErrors((e) => ({ ...e, cep: "Erro ao buscar CEP" })); } finally { setSearchingCEP(false); } } function validateLocal(): boolean { const e: Record = {}; if (!form.nome.trim()) e.nome = "Nome é obrigatório"; if (!form.cpf.trim()) e.cpf = "CPF é obrigatório"; if (!form.crm.trim()) e.crm = "CRM é obrigatório"; if (!form.especialidade.trim()) e.especialidade = "Especialidade é obrigatória"; setErrors(e); return Object.keys(e).length === 0; } async function handleSubmit(ev: React.FormEvent) { ev.preventDefault(); if (!validateLocal()) return; setSubmitting(true); setErrors((e) => ({ ...e, submit: "" })); try { const payload: MedicoInput = { nome: form.nome, nome_social: form.nome_social || null, cpf: form.cpf || null, rg: form.rg || null, sexo: form.sexo || null, data_nascimento: form.data_nascimento || null, telefone: form.telefone || null, celular: form.celular || null, contato_emergencia: form.contato_emergencia || null, email: form.email || null, crm: form.crm, estado_crm: form.estado_crm || null, rqe: form.rqe || null, formacao_academica: form.formacao_academica ?? [], curriculo_url: null, especialidade: form.especialidade, observacoes: form.observacoes || null, tipo_vinculo: form.tipo_vinculo || null, dados_bancarios: form.dados_bancarios ?? null, agenda_horario: form.agenda_horario || null, valor_consulta: form.valor_consulta || null, }; const saved = mode === "create" ? await criarMedico(payload) : await atualizarMedico(doctorId as number, payload); const medicoId = saved.id; if (form.photo) { try { await uploadFotoMedico(medicoId, form.photo); } catch (e) { console.warn("Falha ao enviar foto:", e); } } if (form.anexos?.length) { for (const f of form.anexos) { try { await adicionarAnexoMedico(medicoId, f); } catch (e) { console.warn("Falha ao enviar anexo:", f.name, e); } } } onSaved?.(saved); if (inline) onClose?.(); else onOpenChange?.(false); } catch (err: any) { setErrors((e) => ({ ...e, submit: err?.message || "Erro ao salvar médico" })); } 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 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); } const content = ( <> {errors.submit && ( {errors.submit} )}
setExpanded((s) => ({ ...s, dados: !s.dados }))}> Dados Pessoais e Profissionais {expanded.dados ? : }
{photoPreview ? ( Preview ) : ( )}
{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("crm", e.target.value)} className={errors.crm ? "border-destructive" : ""} /> {errors.crm &&

{errors.crm}

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

{errors.especialidade}

}
setField("rqe", e.target.value)} />
setField("curriculo", e.target.files?.[0] || null)} accept=".pdf,.doc,.docx" /> {form.curriculo && {form.curriculo.name}}
handleCPFChange(e.target.value)} placeholder="000.000.000-00" maxLength={14} className={errors.cpf ? "border-destructive" : ""} /> {errors.cpf &&

{errors.cpf}

}
setField("rg", formatRG(e.target.value))} maxLength={12} />
setField("data_nascimento", e.target.value)} />
setExpanded((s) => ({ ...s, formacao: !s.formacao }))}> Formação Acadêmica {expanded.formacao ? : } {form.formacao_academica.map((formacao, index) => (
handleFormacaoChange(index, "instituicao", e.target.value) } />
handleFormacaoChange(index, "curso", e.target.value) } />
handleFormacaoChange(index, "ano_conclusao", e.target.value) } />
))}
setExpanded((s) => ({ ...s, contato: !s.contato }))}> Contato {expanded.contato ? : }
setField("email", e.target.value)} />
setField("telefone", formatPhone(e.target.value))} placeholder="(XX) XXXXX-XXXX" />
setField("celular", formatPhone(e.target.value))} placeholder="(XX) XXXXX-XXXX" />
setField("contato_emergencia", formatPhone(e.target.value))} placeholder="(XX) XXXXX-XXXX" />
setExpanded((s) => ({ ...s, admin: !s.admin }))}> Dados Administrativos e Financeiros {expanded.admin ? : }
setField("valor_consulta", e.target.value)} placeholder="R$ 0,00" />