diff --git a/susconecta/app/(main-routes)/doutores/page.tsx b/susconecta/app/(main-routes)/doutores/page.tsx index be0b8a8..96e0557 100644 --- a/susconecta/app/(main-routes)/doutores/page.tsx +++ b/susconecta/app/(main-routes)/doutores/page.tsx @@ -10,14 +10,14 @@ import { Label } from "@/components/ui/label"; import { MoreHorizontal, Plus, Search, Edit, Trash2, ArrowLeft, Eye } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { DoctorRegistrationForm } from "@/components/forms/doctor-registration-form"; -import ProtectedRoute from "@/components/ProtectedRoute"; // <-- IMPORTADO -import { listarMedicos, excluirMedico, Medico } from "@/lib/api"; + +import { listarMedicos, excluirMedico, buscarMedicos, buscarMedicoPorId, Medico } from "@/lib/api"; function normalizeMedico(m: any): Medico { return { id: String(m.id ?? m.uuid ?? ""), - nome: m.nome ?? m.full_name ?? "", // 👈 Supabase usa full_name + full_name: m.full_name ?? m.nome ?? "", // 👈 Correção: usar full_name como padrão nome_social: m.nome_social ?? m.social_name ?? null, cpf: m.cpf ?? "", rg: m.rg ?? m.document_number ?? null, @@ -39,6 +39,20 @@ function normalizeMedico(m: any): Medico { dados_bancarios: m.dados_bancarios ?? null, agenda_horario: m.agenda_horario ?? null, valor_consulta: m.valor_consulta ?? null, + active: m.active ?? true, + cep: m.cep ?? "", + city: m.city ?? "", + complement: m.complement ?? null, + neighborhood: m.neighborhood ?? "", + number: m.number ?? "", + phone2: m.phone2 ?? null, + state: m.state ?? "", + street: m.street ?? "", + created_at: m.created_at ?? null, + created_by: m.created_by ?? null, + updated_at: m.updated_at ?? null, + updated_by: m.updated_by ?? null, + user_id: m.user_id ?? null, }; } @@ -50,33 +64,178 @@ export default function DoutoresPage() { const [showForm, setShowForm] = useState(false); const [editingId, setEditingId] = useState(null); const [viewingDoctor, setViewingDoctor] = useState(null); + const [searchResults, setSearchResults] = useState([]); + const [searchMode, setSearchMode] = useState(false); + const [searchTimeout, setSearchTimeout] = useState(null); async function load() { setLoading(true); try { const list = await listarMedicos({ limit: 50 }); -setDoctors((list ?? []).map(normalizeMedico)); + const normalized = (list ?? []).map(normalizeMedico); + console.log('🏥 Médicos carregados:', normalized); + setDoctors(normalized); } finally { setLoading(false); } } + // Função para detectar se é um UUID válido + function isValidUUID(str: string): boolean { + const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; + return uuidRegex.test(str); + } + + // Função para buscar médicos no servidor + async function handleBuscarServidor(termoBusca?: string) { + const termo = (termoBusca || search).trim(); + + if (!termo) { + setSearchMode(false); + setSearchResults([]); + return; + } + console.log('🔍 Buscando médico por:', termo); + + setLoading(true); + try { + // Se parece com UUID, tenta busca direta por ID + if (isValidUUID(termo)) { + console.log('📋 Detectado UUID, buscando por ID...'); + try { + const medico = await buscarMedicoPorId(termo); + const normalizado = normalizeMedico(medico); + console.log('✅ Médico encontrado por ID:', normalizado); + setSearchResults([normalizado]); + setSearchMode(true); + return; + } catch (error) { + console.log('❌ Não encontrado por ID, tentando busca geral...'); + } + } + + // Busca geral + const resultados = await buscarMedicos(termo); + const normalizados = resultados.map(normalizeMedico); + console.log('📋 Resultados da busca geral:', normalizados); + + setSearchResults(normalizados); + setSearchMode(true); + } catch (error) { + console.error('❌ Erro na busca:', error); + setSearchResults([]); + setSearchMode(true); + } finally { + setLoading(false); + } + } + + // Handler para mudança no campo de busca com busca automática + function handleSearchChange(e: React.ChangeEvent) { + const valor = e.target.value; + setSearch(valor); + + // Limpa o timeout anterior se existir + if (searchTimeout) { + clearTimeout(searchTimeout); + } + + // Se limpar a busca, volta ao modo normal + if (!valor.trim()) { + setSearchMode(false); + setSearchResults([]); + return; + } + + // Busca automática com debounce ajustável + // Para IDs (UUID) longos, faz busca no servidor + // Para busca parcial, usa apenas filtro local + const isLikeUUID = valor.includes('-') && valor.length > 10; + const shouldSearchServer = isLikeUUID || valor.length >= 3; + + if (shouldSearchServer) { + const debounceTime = isLikeUUID ? 300 : 500; + const newTimeout = setTimeout(() => { + handleBuscarServidor(valor); + }, debounceTime); + + setSearchTimeout(newTimeout); + } else { + // Para termos curtos, apenas usa filtro local + setSearchMode(false); + setSearchResults([]); + } + } + + // Handler para Enter no campo de busca + function handleSearchKeyDown(e: React.KeyboardEvent) { + if (e.key === 'Enter') { + e.preventDefault(); + handleBuscarServidor(); + } + } + + // Handler para o botão de busca + function handleClickBuscar() { + handleBuscarServidor(); + } + useEffect(() => { load(); }, []); - const filtered = useMemo(() => { + // Limpa o timeout quando o componente é desmontado + useEffect(() => { + return () => { + if (searchTimeout) { + clearTimeout(searchTimeout); + } + }; + }, [searchTimeout]); + + // Lista de médicos a exibir (busca ou filtro local) + const displayedDoctors = useMemo(() => { + console.log('🔍 Filtro - search:', search, 'searchMode:', searchMode, 'doctors:', doctors.length, 'searchResults:', searchResults.length); + + // Se não tem busca, mostra todos os médicos if (!search.trim()) return doctors; - const q = search.toLowerCase(); - return doctors.filter((d) => { - const byName = (d.nome || "").toLowerCase().includes(q); - const byCrm = (d.crm || "").toLowerCase().includes(q); + + const q = search.toLowerCase().trim(); + const qDigits = q.replace(/\D/g, ""); + + // Se estamos em modo de busca (servidor), filtra os resultados da busca + const sourceList = searchMode ? searchResults : doctors; + console.log('🔍 Usando sourceList:', searchMode ? 'searchResults' : 'doctors', '- tamanho:', sourceList.length); + + const filtered = sourceList.filter((d) => { + // Busca por nome + const byName = (d.full_name || "").toLowerCase().includes(q); + + // Busca por CRM (remove formatação se necessário) + const byCrm = qDigits.length >= 3 && (d.crm || "").replace(/\D/g, "").includes(qDigits); + + // Busca por ID (UUID completo ou parcial) + const byId = (d.id || "").toLowerCase().includes(q); + + // Busca por email + const byEmail = (d.email || "").toLowerCase().includes(q); + + // Busca por especialidade const byEspecialidade = (d.especialidade || "").toLowerCase().includes(q); - return byName || byCrm || byEspecialidade; + + const match = byName || byCrm || byId || byEmail || byEspecialidade; + if (match) { + console.log('✅ Match encontrado:', d.full_name, d.id, 'por:', { byName, byCrm, byId, byEmail, byEspecialidade }); + } + + return match; }); - }, [doctors, search]); + + console.log('🔍 Resultados filtrados:', filtered.length); + return filtered; + }, [doctors, search, searchMode, searchResults]); function handleAdd() { setEditingId(null); @@ -137,153 +296,176 @@ setDoctors((list ?? []).map(normalizeMedico));

{editingId ? "Editar Médico" : "Novo Médico"}

- setShowForm(false)} - /> - - ) : ( -
-
-
-

Médicos

-

Gerencie os médicos da sua clínica

-
+ setShowForm(false)} + /> +
+ ); + } -
-
- - setSearch(e.target.value)} - /> -
- + {searchMode && ( + -
-
- -
- - - - Nome - Especialidade - CRM - Contato - Ações - - - - {loading ? ( - - - Carregando… - - - ) : filtered.length > 0 ? ( - filtered.map((doctor) => ( - - {doctor.nome} - - {doctor.especialidade} - - {doctor.crm} - -
- {doctor.email} - {doctor.telefone} -
-
- - - - - - - handleView(doctor)}> - - Ver - - handleEdit(String(doctor.id))}> - - Editar - - handleDelete(String(doctor.id))} className="text-destructive"> - - Excluir - - - - -
- )) - ) : ( - - - Nenhum médico encontrado - - - )} -
-
-
- - {viewingDoctor && ( - setViewingDoctor(null)}> - - - Detalhes do Médico - - Informações detalhadas de {viewingDoctor?.nome}. - - -
-
- - {viewingDoctor?.nome} -
-
- - - {viewingDoctor?.especialidade} - -
-
- - {viewingDoctor?.crm} -
-
- - {viewingDoctor?.email} -
-
- - {viewingDoctor?.telefone} -
-
- - - -
-
- )} - -
- Mostrando {filtered.length} de {doctors.length} + )}
+ + + +
+ + + + Nome + Especialidade + CRM + Contato + Ações + + + + {loading ? ( + + + Carregando… + + + ) : displayedDoctors.length > 0 ? ( + displayedDoctors.map((doctor) => ( + + {doctor.full_name} + + {doctor.especialidade} + + {doctor.crm} + +
+ {doctor.email} + {doctor.telefone} +
+
+ + + + + + + handleView(doctor)}> + + Ver + + handleEdit(String(doctor.id))}> + + Editar + + handleDelete(String(doctor.id))} className="text-destructive"> + + Excluir + + + + +
+ )) + ) : ( + + + Nenhum médico encontrado + + + )} +
+
+
+ + {viewingDoctor && ( + setViewingDoctor(null)}> + + + Detalhes do Médico + + Informações detalhadas de {viewingDoctor?.full_name}. + + +
+
+ + {viewingDoctor?.full_name} +
+
+ + + {viewingDoctor?.especialidade} + +
+
+ + {viewingDoctor?.crm} +
+
+ + {viewingDoctor?.email} +
+
+ + {viewingDoctor?.telefone} +
+
+ + + +
+
)} - + +
+ Mostrando {displayedDoctors.length} {searchMode ? 'resultado(s) da busca' : `de ${doctors.length}`} +
+ ); } diff --git a/susconecta/app/(main-routes)/pacientes/page.tsx b/susconecta/app/(main-routes)/pacientes/page.tsx index bacb207..c9bffb7 100644 --- a/susconecta/app/(main-routes)/pacientes/page.tsx +++ b/susconecta/app/(main-routes)/pacientes/page.tsx @@ -10,34 +10,29 @@ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, Di import { Label } from "@/components/ui/label"; import { MoreHorizontal, Plus, Search, Eye, Edit, Trash2, ArrowLeft } from "lucide-react"; -import { Paciente, Endereco, listarPacientes, buscarPacientePorId, excluirPaciente } from "@/lib/api"; +import { Paciente, Endereco, listarPacientes, buscarPacientes, buscarPacientePorId, excluirPaciente } from "@/lib/api"; import { PatientRegistrationForm } from "@/components/forms/patient-registration-form"; function normalizePaciente(p: any): Paciente { - const endereco: Endereco = { - cep: p.endereco?.cep ?? p.cep ?? "", - logradouro: p.endereco?.logradouro ?? p.street ?? "", - numero: p.endereco?.numero ?? p.number ?? "", - complemento: p.endereco?.complemento ?? p.complement ?? "", - bairro: p.endereco?.bairro ?? p.neighborhood ?? "", - cidade: p.endereco?.cidade ?? p.city ?? "", - estado: p.endereco?.estado ?? p.state ?? "", - }; - return { id: String(p.id ?? p.uuid ?? p.paciente_id ?? ""), - nome: p.full_name ?? "", // 👈 troca nome → full_name - nome_social: p.social_name ?? null, // 👈 Supabase usa social_name + full_name: p.full_name ?? p.name ?? p.nome ?? "", + social_name: p.social_name ?? p.nome_social ?? null, cpf: p.cpf ?? "", - rg: p.rg ?? p.document_number ?? null, // 👈 às vezes vem como document_number - sexo: p.sexo ?? p.sex ?? null, // 👈 Supabase usa sex - data_nascimento: p.data_nascimento ?? p.birth_date ?? null, - telefone: p.telefone ?? p.phone_mobile ?? "", + rg: p.rg ?? p.document_number ?? null, + sex: p.sex ?? p.sexo ?? null, + birth_date: p.birth_date ?? p.data_nascimento ?? null, + phone_mobile: p.phone_mobile ?? p.telefone ?? "", email: p.email ?? "", - endereco, - observacoes: p.observacoes ?? p.notes ?? null, - foto_url: p.foto_url ?? null, + cep: p.cep ?? "", + street: p.street ?? p.logradouro ?? "", + number: p.number ?? p.numero ?? "", + complement: p.complement ?? p.complemento ?? "", + neighborhood: p.neighborhood ?? p.bairro ?? "", + city: p.city ?? p.cidade ?? "", + state: p.state ?? p.estado ?? "", + notes: p.notes ?? p.observacoes ?? null, }; } @@ -56,7 +51,12 @@ export default function PacientesPage() { try { setLoading(true); const data = await listarPacientes({ page: 1, limit: 20 }); - setPatients((data ?? []).map(normalizePaciente)); + + if (Array.isArray(data)) { + setPatients(data.map(normalizePaciente)); + } else { + setPatients([]); + } setError(null); } catch (e: any) { setPatients([]); @@ -72,13 +72,23 @@ export default function PacientesPage() { const filtered = useMemo(() => { if (!search.trim()) return patients; - const q = search.toLowerCase(); + const q = search.toLowerCase().trim(); const qDigits = q.replace(/\D/g, ""); + return patients.filter((p) => { - const byName = (p.nome || "").toLowerCase().includes(q); - const byCPF = (p.cpf || "").replace(/\D/g, "").includes(qDigits); - const byId = String(p.id || "").includes(qDigits); - return byName || byCPF || byId; + // Busca por nome + const byName = (p.full_name || "").toLowerCase().includes(q); + + // Busca por CPF (remove formatação) + const byCPF = qDigits.length >= 3 && (p.cpf || "").replace(/\D/g, "").includes(qDigits); + + // Busca por ID (UUID completo ou parcial) + const byId = (p.id || "").toLowerCase().includes(q); + + // Busca por email + const byEmail = (p.email || "").toLowerCase().includes(q); + + return byName || byCPF || byId || byEmail; }); }, [patients, search]); @@ -122,25 +132,33 @@ export default function PacientesPage() { const q = search.trim(); if (!q) return loadAll(); - - if (/^\d+$/.test(q)) { - try { - setLoading(true); + try { + setLoading(true); + setError(null); + + // Se parece com ID (UUID), busca diretamente + if (q.includes('-') && q.length > 10) { const one = await buscarPacientePorId(q); setPatients(one ? [normalizePaciente(one)] : []); setError(one ? null : "Paciente não encontrado."); - } catch (e: any) { - setPatients([]); - setError(e?.message || "Paciente não encontrado."); - } finally { - setLoading(false); + // Limpa o campo de busca para que o filtro não interfira + setSearch(""); + return; } - return; - } - - await loadAll(); - setTimeout(() => setSearch(q), 0); + // Para outros termos, usa busca avançada + const results = await buscarPacientes(q); + setPatients(results.map(normalizePaciente)); + setError(results.length === 0 ? "Nenhum paciente encontrado." : null); + // Limpa o campo de busca para que o filtro não interfira + setSearch(""); + + } catch (e: any) { + setPatients([]); + setError(e?.message || "Erro na busca."); + } finally { + setLoading(false); + } } if (loading) return

Carregando pacientes...

; @@ -159,7 +177,7 @@ export default function PacientesPage() { setShowForm(false)} /> @@ -210,11 +228,11 @@ export default function PacientesPage() { {filtered.length > 0 ? ( filtered.map((p) => ( - {p.nome || "(sem nome)"} + {p.full_name || "(sem nome)"} {p.cpf || "-"} - {p.telefone || "-"} - {p.endereco?.cidade || "-"} - {p.endereco?.estado || "-"} + {p.phone_mobile || "-"} + {p.city || "-"} + {p.state || "-"} @@ -258,13 +276,13 @@ export default function PacientesPage() { Detalhes do Paciente - Informações detalhadas de {viewingPatient.nome}. + Informações detalhadas de {viewingPatient.full_name}.
- {viewingPatient.nome} + {viewingPatient.full_name}
@@ -272,17 +290,17 @@ export default function PacientesPage() {
- {viewingPatient.telefone} + {viewingPatient.phone_mobile}
- {`${viewingPatient.endereco?.logradouro || ''}, ${viewingPatient.endereco?.numero || ''} - ${viewingPatient.endereco?.bairro || ''}, ${viewingPatient.endereco?.cidade || ''} - ${viewingPatient.endereco?.estado || ''}`} + {`${viewingPatient.street || ''}, ${viewingPatient.number || ''} - ${viewingPatient.neighborhood || ''}, ${viewingPatient.city || ''} - ${viewingPatient.state || ''}`}
- {viewingPatient.observacoes || "Nenhuma"} + {viewingPatient.notes || "Nenhuma"}
diff --git a/susconecta/app/profissional/page.tsx b/susconecta/app/profissional/page.tsx index 9452bb5..d2c6ab0 100644 --- a/susconecta/app/profissional/page.tsx +++ b/susconecta/app/profissional/page.tsx @@ -7,6 +7,7 @@ import "react-quill/dist/quill.snow.css"; import Link from "next/link"; import ProtectedRoute from "@/components/ProtectedRoute"; import { useAuth } from "@/hooks/useAuth"; +import { buscarPacientes } from "@/lib/api"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -566,53 +567,190 @@ const ProfissionalPage = () => { }; - const renderPacientesSection = () => ( -
-

Gerenciamento de Pacientes

- - - - Paciente - CPF - Idade - Status do laudo - Ações - - - - {pacientes.map((paciente) => ( - - {paciente.nome} - {paciente.cpf} - {paciente.idade} - {paciente.statusLaudo} - -
-
- + {(buscaPaciente || pacientesBusca.length > 0 || erroBusca) && ( + + )} +
+ + {/* Resultados da busca */} + {erroBusca && ( +
+

{erroBusca}

+
+ )} + + {pacientesBusca.length > 0 && ( +
+

Resultados da busca ({pacientesBusca.length}):

+
+ {pacientesBusca.map((paciente, index) => ( +
+
+

{paciente.nome}

+

CPF: {paciente.cpf} • Idade: {paciente.idade} anos

+
+ -
- Ver informações do paciente -
-
-
- - - ))} - -
-
- ); + ))} + + + )} + + + {/* Tabela de pacientes padrão */} +
+

Pacientes Recentes

+ + + + Paciente + CPF + Idade + Status do laudo + Ações + + + + {pacientes.map((paciente) => ( + + {paciente.nome} + {paciente.cpf} + {paciente.idade} + {paciente.statusLaudo} + +
+
+ +
+ Ver informações do paciente +
+
+
+
+
+
+ ))} +
+
+
+ + ); + }; const renderProntuarioSection = () => ( @@ -2291,7 +2429,7 @@ function LaudoEditor() { case 'calendario': return renderCalendarioSection(); case 'pacientes': - return renderPacientesSection(); + return ; case 'prontuario': return renderProntuarioSection(); case 'laudos': diff --git a/susconecta/components/dashboard/header.tsx b/susconecta/components/dashboard/header.tsx index 9bf263a..9942a60 100644 --- a/susconecta/components/dashboard/header.tsx +++ b/susconecta/components/dashboard/header.tsx @@ -1,6 +1,6 @@ "use client" -import { Bell, Search, ChevronDown } from "lucide-react" +import { Bell, ChevronDown } from "lucide-react" import { useAuth } from "@/hooks/useAuth" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" @@ -40,11 +40,6 @@ export function PagesHeader({ title = "", subtitle = "" }: { title?: string, sub
-
- - -
- diff --git a/susconecta/components/forms/doctor-registration-form.tsx b/susconecta/components/forms/doctor-registration-form.tsx index caeef2e..b50ef60 100644 --- a/susconecta/components/forms/doctor-registration-form.tsx +++ b/susconecta/components/forms/doctor-registration-form.tsx @@ -1,6 +1,7 @@ "use client"; import { useEffect, useMemo, useState } from "react"; +import { buscarPacientePorId } from "@/lib/api"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -21,8 +22,10 @@ import { listarAnexosMedico, adicionarAnexoMedico, removerAnexoMedico, - MedicoInput, + MedicoInput, // 👈 importado do lib/api + Medico, // 👈 adicionado import do tipo Medico } from "@/lib/api"; +; import { buscarCepAPI } from "@/lib/api"; @@ -39,39 +42,16 @@ type DadosBancarios = { 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; + doctorId?: string | number | null; inline?: boolean; mode?: Mode; onSaved?: (medico: Medico) => void; @@ -80,7 +60,7 @@ export interface DoctorRegistrationFormProps { type FormData = { photo: File | null; - nome: string; + full_name: string; // Substitua 'nome' por 'full_name' nome_social: string; crm: string; estado_crm: string; @@ -107,14 +87,13 @@ type FormData = { anexos: File[]; tipo_vinculo: string; dados_bancarios: DadosBancarios; - agenda_horario: string; valor_consulta: string; }; const initial: FormData = { photo: null, - nome: "", + full_name: "", nome_social: "", crm: "", estado_crm: "", @@ -128,7 +107,7 @@ const initial: FormData = { data_nascimento: "", email: "", telefone: "", - celular: "", + celular: "", // Aqui, 'celular' pode ser 'phone_mobile' contato_emergencia: "", cep: "", logradouro: "", @@ -152,6 +131,7 @@ const initial: FormData = { + export function DoctorRegistrationForm({ open = true, onOpenChange, @@ -175,46 +155,78 @@ export function DoctorRegistrationForm({ 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 {} + console.log("[DoctorForm] Carregando médico ID:", doctorId); + const medico = await buscarMedicoPorId(String(doctorId)); + console.log("[DoctorForm] Dados recebidos do API:", medico); + console.log("[DoctorForm] Campos principais:", { + full_name: medico.full_name, + crm: medico.crm, + especialidade: medico.especialidade, + specialty: (medico as any).specialty, + cpf: medico.cpf, + email: medico.email + }); + console.log("[DoctorForm] Verificando especialidade:", { + 'medico.especialidade': medico.especialidade, + 'medico.specialty': (medico as any).specialty, + 'typeof especialidade': typeof medico.especialidade, + 'especialidade length': medico.especialidade?.length + }); + if (!alive) return; + + // Busca a especialidade em diferentes campos possíveis + const especialidade = medico.especialidade || + (medico as any).specialty || + (medico as any).speciality || + ""; + console.log('🎯 Especialidade encontrada:', especialidade); + + const formData = { + photo: null, + full_name: String(medico.full_name || ""), + nome_social: String(medico.nome_social || ""), + crm: String(medico.crm || ""), + estado_crm: String(medico.estado_crm || ""), + rqe: String(medico.rqe || ""), + formacao_academica: Array.isArray(medico.formacao_academica) ? medico.formacao_academica : [], + curriculo: null, + especialidade: String(especialidade), + cpf: String(medico.cpf || ""), + rg: String(medico.rg || ""), + sexo: String(medico.sexo || ""), + data_nascimento: String(medico.data_nascimento || ""), + email: String(medico.email || ""), + telefone: String(medico.telefone || ""), + celular: String(medico.celular || ""), + contato_emergencia: String(medico.contato_emergencia || ""), + cep: String(medico.cep || ""), + logradouro: String(medico.street || ""), + numero: String(medico.number || ""), + complemento: String(medico.complement || ""), + bairro: String(medico.neighborhood || ""), + cidade: String(medico.city || ""), + estado: String(medico.state || ""), + observacoes: String(medico.observacoes || ""), + anexos: [], + tipo_vinculo: String(medico.tipo_vinculo || ""), + dados_bancarios: medico.dados_bancarios || { banco: "", agencia: "", conta: "", tipo_conta: "" }, + agenda_horario: String(medico.agenda_horario || ""), + valor_consulta: medico.valor_consulta ? String(medico.valor_consulta) : "", + }; + + console.log("[DoctorForm] Dados do formulário preparados:", formData); + setForm(formData); + + try { + const list = await listarAnexosMedico(String(doctorId)); + setServerAnexos(list ?? []); + } catch (err) { + console.error("[DoctorForm] Erro ao carregar anexos:", err); + } + } catch (err) { + console.error("[DoctorForm] Erro ao carregar médico:", err); + } } } load(); @@ -222,10 +234,11 @@ export function DoctorRegistrationForm({ }, [mode, doctorId]); - function setField(k: T, v: FormData[T]) { - setForm((s) => ({ ...s, [k]: v })); - if (errors[k as string]) setErrors((e) => ({ ...e, [k]: "" })); - } +function setField(k: T, v: FormData[T]) { + setForm((s) => ({ ...s, [k]: v })); + if (errors[k as string]) setErrors((e) => ({ ...e, [k]: "" })); +} + function addFormacao() { @@ -299,76 +312,92 @@ export function DoctorRegistrationForm({ } - 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; - } + function validateLocal(): boolean { + const e: Record = {}; - async function handleSubmit(ev: React.FormEvent) { + if (!form.full_name.trim()) e.full_name = "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"; + if (!form.cep.trim()) e.cep = "CEP é obrigatório"; // Verifique se o CEP está preenchido + if (!form.bairro.trim()) e.bairro = "Bairro é obrigatório"; // Verifique se o bairro está preenchido + if (!form.cidade.trim()) e.cidade = "Cidade é obrigatória"; // Verifique se a cidade está preenchida + + setErrors(e); + return Object.keys(e).length === 0; +} + + + +async function handleSubmit(ev: React.FormEvent) { ev.preventDefault(); - if (!validateLocal()) return; + console.log("Submitting the form..."); // Verifique se a função está sendo chamada + + if (!validateLocal()) { + console.log("Validation failed"); + return; // Se a validação falhar, saia da função. + } 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 payload: MedicoInput = { + user_id: null, + crm: form.crm || "", + crm_uf: form.estado_crm || "", + specialty: form.especialidade || "", + full_name: form.full_name || "", + cpf: form.cpf || "", + email: form.email || "", + phone_mobile: form.celular || "", + phone2: form.telefone || null, + cep: form.cep || "", + street: form.logradouro || "", + number: form.numero || "", + complement: form.complemento || undefined, + neighborhood: form.bairro || undefined, + city: form.cidade || "", + state: form.estado || "", + birth_date: form.data_nascimento || null, + rg: form.rg || null, + active: true, + created_by: null, + updated_by: null, +}; +// Validação dos campos obrigatórios +const requiredFields = ['crm', 'crm_uf', 'specialty', 'full_name', 'cpf', 'email', 'phone_mobile', 'cep', 'street', 'number', 'city', 'state']; +const missingFields = requiredFields.filter(field => !payload[field as keyof MedicoInput]); + +if (missingFields.length > 0) { + console.warn('⚠️ Campos obrigatórios vazios:', missingFields); +} + + + + console.log("📤 Payload being sent:", payload); + console.log("🔧 Mode:", mode, "DoctorId:", doctorId); + + try { + if (mode === "edit" && !doctorId) { + throw new Error("ID do médico não fornecido para edição"); + } + const saved = mode === "create" ? await criarMedico(payload) - : await atualizarMedico(doctorId as number, payload); + : await atualizarMedico(String(doctorId), 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); - } - } - } + console.log("✅ Médico salvo com sucesso:", saved); onSaved?.(saved); - if (inline) onClose?.(); - else onOpenChange?.(false); + setSubmitting(false); } catch (err: any) { + console.error("❌ Erro ao salvar médico:", err); + console.error("❌ Detalhes do erro:", { + message: err?.message, + status: err?.status, + stack: err?.stack + }); setErrors((e) => ({ ...e, submit: err?.message || "Erro ao salvar médico" })); } finally { setSubmitting(false); @@ -376,6 +405,10 @@ export function DoctorRegistrationForm({ } + + + + function handlePhoto(e: React.ChangeEvent) { const f = e.target.files?.[0]; if (!f) return; @@ -449,8 +482,10 @@ export function DoctorRegistrationForm({
- setField("nome", e.target.value)} className={errors.nome ? "border-destructive" : ""} /> - {errors.nome &&

{errors.nome}

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

{errors.full_name}

}
@@ -471,16 +506,21 @@ export function DoctorRegistrationForm({
-
- - setField("especialidade", e.target.value)} className={errors.especialidade ? "border-destructive" : ""} /> - {errors.especialidade &&

{errors.especialidade}

} -
-
- - setField("rqe", e.target.value)} /> -
-
+
+ + setField("especialidade", e.target.value)} // Envia o valor correto + className={errors.especialidade ? "border-destructive" : ""} + /> + {errors.especialidade &&

{errors.especialidade}

} +
+
+ + setField("rqe", e.target.value)} /> +
+
+
@@ -629,14 +669,25 @@ export function DoctorRegistrationForm({ setField("email", e.target.value)} />
-
- - setField("telefone", formatPhone(e.target.value))} - placeholder="(XX) XXXXX-XXXX" - /> -
+
+
+ + setField("telefone", formatPhone(e.target.value))} + placeholder="(XX) XXXXX-XXXX" + /> +
+
+ + setField("celular", formatPhone(e.target.value))} + placeholder="(XX) XXXXX-XXXX" + /> +
+
+
@@ -703,11 +754,14 @@ export function DoctorRegistrationForm({
-