"use client"; import type React from "react"; import { useState, useEffect, useRef } from "react"; import { useRouter, useParams } from "next/navigation"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { Checkbox } from "@/components/ui/checkbox"; import { ArrowLeft, Save, Trash2, Paperclip, Upload } from "lucide-react"; import Link from "next/link"; import { useToast } from "@/hooks/use-toast"; import SecretaryLayout from "@/components/secretary-layout"; // Mock data - in a real app, this would come from an API const mockPatients = [ { id: 1, nome: "Aaron Avalos Perez", cpf: "123.456.789-00", rg: "12.345.678-9", sexo: "masculino", dataNascimento: "1990-01-15", etnia: "branca", raca: "caucasiana", naturalidade: "Aracaju", nacionalidade: "brasileira", profissao: "Engenheiro", estadoCivil: "solteiro", nomeMae: "Maria Perez", profissaoMae: "Professora", nomePai: "João Perez", profissaoPai: "Médico", nomeResponsavel: "", cpfResponsavel: "", nomeEsposo: "", email: "aaron@email.com", celular: "(79) 99943-2499", telefone1: "(79) 3214-5678", telefone2: "", cep: "49000-000", endereco: "Rua das Flores, 123", numero: "123", complemento: "Apt 101", bairro: "Centro", cidade: "Aracaju", estado: "SE", tipoSanguineo: "O+", peso: "75", altura: "1.75", alergias: "Nenhuma alergia conhecida", convenio: "Particular", plano: "Premium", numeroMatricula: "123456789", validadeCarteira: "2025-12-31", observacoes: "Paciente colaborativo", }, ]; export default function EditarPacientePage() { const router = useRouter(); const params = useParams(); const patientId = Number.parseInt(params.id as string); const { toast } = useToast(); // Photo upload state const fileInputRef = useRef(null); const [isUploadingPhoto, setIsUploadingPhoto] = useState(false); const [photoUrl, setPhotoUrl] = useState(null); // Anexos state const [anexos, setAnexos] = useState([]); const [isUploadingAnexo, setIsUploadingAnexo] = useState(false); const anexoInputRef = useRef(null); const [formData, setFormData] = useState({ nome: "", cpf: "", rg: "", sexo: "", dataNascimento: "", etnia: "", raca: "", naturalidade: "", nacionalidade: "", profissao: "", estadoCivil: "", nomeMae: "", profissaoMae: "", nomePai: "", profissaoPai: "", nomeResponsavel: "", cpfResponsavel: "", nomeEsposo: "", email: "", celular: "", telefone1: "", telefone2: "", cep: "", endereco: "", numero: "", complemento: "", bairro: "", cidade: "", estado: "", tipoSanguineo: "", peso: "", altura: "", alergias: "", convenio: "", plano: "", numeroMatricula: "", validadeCarteira: "", observacoes: "", }); const [isGuiaConvenio, setIsGuiaConvenio] = useState(false); const [validadeIndeterminada, setValidadeIndeterminada] = useState(false); useEffect(() => { async function fetchPatient() { try { const res = await fetch(`https://mock.apidog.com/m1/1053378-0-default/pacientes/${patientId}`); if (!res.ok) throw new Error(`HTTP ${res.status}`); const json = await res.json(); const p = json?.data || json; // Map API snake_case/nested to local camelCase form setFormData({ nome: p?.nome ?? "", cpf: p?.cpf ?? "", rg: p?.rg ?? "", sexo: p?.sexo ?? "", dataNascimento: p?.data_nascimento ?? p?.dataNascimento ?? "", etnia: p?.etnia ?? "", raca: p?.raca ?? "", naturalidade: p?.naturalidade ?? "", nacionalidade: p?.nacionalidade ?? "", profissao: p?.profissao ?? "", estadoCivil: p?.estado_civil ?? p?.estadoCivil ?? "", nomeMae: p?.nome_mae ?? p?.nomeMae ?? "", profissaoMae: p?.profissao_mae ?? p?.profissaoMae ?? "", nomePai: p?.nome_pai ?? p?.nomePai ?? "", profissaoPai: p?.profissao_pai ?? p?.profissaoPai ?? "", nomeResponsavel: p?.nome_responsavel ?? p?.nomeResponsavel ?? "", cpfResponsavel: p?.cpf_responsavel ?? p?.cpfResponsavel ?? "", nomeEsposo: p?.nome_esposo ?? p?.nomeEsposo ?? "", email: p?.contato?.email ?? p?.email ?? "", celular: p?.contato?.celular ?? p?.celular ?? "", telefone1: p?.contato?.telefone1 ?? p?.telefone1 ?? "", telefone2: p?.contato?.telefone2 ?? p?.telefone2 ?? "", cep: p?.endereco?.cep ?? p?.cep ?? "", endereco: p?.endereco?.logradouro ?? p?.endereco ?? "", numero: p?.endereco?.numero ?? p?.numero ?? "", complemento: p?.endereco?.complemento ?? p?.complemento ?? "", bairro: p?.endereco?.bairro ?? p?.bairro ?? "", cidade: p?.endereco?.cidade ?? p?.cidade ?? "", estado: p?.endereco?.estado ?? p?.estado ?? "", tipoSanguineo: p?.tipo_sanguineo ?? p?.tipoSanguineo ?? "", peso: p?.peso ? String(p.peso) : "", altura: p?.altura ? String(p.altura) : "", alergias: p?.alergias ?? "", convenio: p?.convenio ?? "", plano: p?.plano ?? "", numeroMatricula: p?.numero_matricula ?? p?.numeroMatricula ?? "", validadeCarteira: p?.validade_carteira ?? p?.validadeCarteira ?? "", observacoes: p?.observacoes ?? "", }); const foto = p?.foto_url || p?.fotoUrl; if (foto) setPhotoUrl(foto); } catch (e: any) { toast({ title: "Erro", description: e?.message || "Falha ao carregar paciente" }); } } async function fetchAnexos() { try { const res = await fetch(`https://mock.apidog.com/m1/1053378-0-default/pacientes/${patientId}/anexos`); if (!res.ok) return; const json = await res.json(); const items = Array.isArray(json?.data) ? json.data : json; setAnexos(Array.isArray(items) ? items : []); } catch {} } fetchPatient(); fetchAnexos(); }, [patientId, toast]); const onPickPhoto = () => fileInputRef.current?.click(); const onPhotoSelected = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; try { setIsUploadingPhoto(true); const form = new FormData(); // Common field name: 'foto'; also append 'file' for compatibility with some mocks form.append("foto", file); form.append("file", file); const res = await fetch(`https://mock.apidog.com/m1/1053378-0-default/pacientes/${patientId}/foto`, { method: "POST", body: form, }); if (!res.ok) { throw new Error(`Falha no upload (HTTP ${res.status})`); } let msg = "Foto enviada com sucesso"; try { const payload = await res.json(); if (payload?.success === false) { throw new Error(payload?.message || "A API retornou erro"); } if (payload?.message) msg = String(payload.message); if (payload?.data?.foto_url || payload?.foto_url || payload?.url) { setPhotoUrl(payload.data?.foto_url ?? payload.foto_url ?? payload.url); } } catch { // Ignore JSON parse errors } toast({ title: "Sucesso", description: msg }); } catch (err: any) { toast({ title: "Erro", description: err?.message || "Não foi possível enviar a foto" }); } finally { setIsUploadingPhoto(false); // clear the input to allow re-selecting the same file if (fileInputRef.current) fileInputRef.current.value = ""; } }; // Remove patient photo via API const onRemovePhoto = async () => { try { const res = await fetch(`https://mock.apidog.com/m1/1053378-0-default/pacientes/${patientId}/foto`, { method: "DELETE", }); if (!res.ok) throw new Error(`Falha ao remover foto (HTTP ${res.status})`); setPhotoUrl(null); toast({ title: "Sucesso", description: "Foto removida" }); } catch (err: any) { toast({ title: "Erro", description: err?.message || "Não foi possível remover a foto" }); } }; // Anexos helpers const onPickAnexo = () => anexoInputRef.current?.click(); const onAnexoSelected = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; try { setIsUploadingAnexo(true); const form = new FormData(); form.append("anexo", file); form.append("file", file); const res = await fetch(`https://mock.apidog.com/m1/1053378-0-default/pacientes/${patientId}/anexos`, { method: "POST", body: form, }); if (!res.ok) throw new Error(`Falha ao enviar anexo (HTTP ${res.status})`); // Refresh anexos list try { const refreshed = await fetch(`https://mock.apidog.com/m1/1053378-0-default/pacientes/${patientId}/anexos`); const json = await refreshed.json(); const items = Array.isArray(json?.data) ? json.data : json; setAnexos(Array.isArray(items) ? items : []); } catch {} toast({ title: "Sucesso", description: "Anexo adicionado" }); } catch (err: any) { toast({ title: "Erro", description: err?.message || "Não foi possível enviar o anexo" }); } finally { setIsUploadingAnexo(false); if (anexoInputRef.current) anexoInputRef.current.value = ""; } }; const onDeleteAnexo = async (anexoId: string | number) => { try { const res = await fetch(`https://mock.apidog.com/m1/1053378-0-default/pacientes/${patientId}/anexos/${anexoId}`, { method: "DELETE" }); if (!res.ok) throw new Error(`Falha ao remover anexo (HTTP ${res.status})`); setAnexos((prev) => prev.filter((a) => String(a.id) !== String(anexoId))); toast({ title: "Sucesso", description: "Anexo removido" }); } catch (err: any) { toast({ title: "Erro", description: err?.message || "Não foi possível remover o anexo" }); } }; const handleInputChange = (field: string, value: string) => { setFormData((prev) => ({ ...prev, [field]: value })); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); // Build API payload (snake_case) const payload = { nome: formData.nome, cpf: formData.cpf, rg: formData.rg || null, sexo: formData.sexo || null, data_nascimento: formData.dataNascimento || null, etnia: formData.etnia || null, raca: formData.raca || null, naturalidade: formData.naturalidade || null, nacionalidade: formData.nacionalidade || null, profissao: formData.profissao || null, estado_civil: formData.estadoCivil || null, nome_mae: formData.nomeMae || null, profissao_mae: formData.profissaoMae || null, nome_pai: formData.nomePai || null, profissao_pai: formData.profissaoPai || null, nome_responsavel: formData.nomeResponsavel || null, cpf_responsavel: formData.cpfResponsavel || null, contato: { email: formData.email || null, celular: formData.celular || null, telefone1: formData.telefone1 || null, telefone2: formData.telefone2 || null, }, endereco: { cep: formData.cep || null, logradouro: formData.endereco || null, numero: formData.numero || null, complemento: formData.complemento || null, bairro: formData.bairro || null, cidade: formData.cidade || null, estado: formData.estado || null, }, observacoes: formData.observacoes || null, convenio: formData.convenio || null, plano: formData.plano || null, numero_matricula: formData.numeroMatricula || null, validade_carteira: formData.validadeCarteira || null, }; try { const res = await fetch(`https://mock.apidog.com/m1/1053378-0-default/pacientes/${patientId}`, { method: "PUT", headers: { "Content-Type": "application/json", Accept: "application/json" }, body: JSON.stringify(payload), }); if (!res.ok) throw new Error(`Falha ao atualizar (HTTP ${res.status})`); toast({ title: "Sucesso", description: "Paciente atualizado com sucesso" }); router.push("/pacientes"); } catch (err: any) { toast({ title: "Erro", description: err?.message || "Não foi possível atualizar o paciente" }); } }; // Validate CPF on blur const validateCpf = async (cpf: string) => { if (!cpf) return; try { const res = await fetch("https://mock.apidog.com/m1/1053378-0-default/pacientes/validar-cpf", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ cpf }), }); const json = await res.json(); if (json?.success === false) { throw new Error(json?.message || "CPF inválido"); } if (json?.message) toast({ title: "CPF", description: String(json.message) }); } catch (err: any) { toast({ title: "CPF inválido", description: err?.message || "Falha na validação de CPF" }); } }; // CEP lookup on blur const lookupCep = async (cep: string) => { const onlyDigits = cep?.replace(/\D/g, ""); if (!onlyDigits) return; try { const res = await fetch(`https://mock.apidog.com/m1/1053378-0-default/utils/cep/${onlyDigits}`); if (!res.ok) return; const data = await res.json(); const d = data?.data || data; setFormData((prev) => ({ ...prev, endereco: d?.logradouro ?? prev.endereco, bairro: d?.bairro ?? prev.bairro, cidade: d?.localidade ?? d?.cidade ?? prev.cidade, estado: d?.uf ?? d?.estado ?? prev.estado, complemento: d?.complemento ?? prev.complemento, })); } catch {} }; return (

Editar Paciente

Atualize as informações do paciente

{/* Anexos Section */}

Anexos

{anexos.length === 0 ? (

Nenhum anexo encontrado.

) : (
    {anexos.map((a) => (
  • {a.nome || a.filename || `Anexo ${a.id}`}
  • ))}
)}

Dados Pessoais

{/* Photo upload */}
{photoUrl ? ( // eslint-disable-next-line @next/next/no-img-element Foto do paciente ) : ( Sem foto )}
{photoUrl && ( )}
handleInputChange("nome", e.target.value)} required />
handleInputChange("cpf", e.target.value)} onBlur={() => validateCpf(formData.cpf)} placeholder="000.000.000-00" required />
handleInputChange("rg", e.target.value)} placeholder="00.000.000-0" />
handleInputChange("sexo", e.target.value)} className="w-4 h-4 text-blue-600" />
handleInputChange("sexo", e.target.value)} className="w-4 h-4 text-blue-600" />
handleInputChange("dataNascimento", e.target.value)} required />
handleInputChange("naturalidade", e.target.value)} />
handleInputChange("profissao", e.target.value)} />
handleInputChange("nomeMae", e.target.value)} />
handleInputChange("profissaoMae", e.target.value)} />
handleInputChange("nomePai", e.target.value)} />
handleInputChange("profissaoPai", e.target.value)} />
handleInputChange("nomeResponsavel", e.target.value)} />
handleInputChange("cpfResponsavel", e.target.value)} placeholder="000.000.000-00" />
handleInputChange("nomeEsposo", e.target.value)} />
setIsGuiaConvenio(checked === true)} />