From 66212930e8c5f1fa70ac075eb4793da071a13004 Mon Sep 17 00:00:00 2001 From: StsDanilo Date: Tue, 4 Nov 2025 14:26:45 -0300 Subject: [PATCH] =?UTF-8?q?Adicionado=20gest=C3=A3o=20de=20pacientes=20par?= =?UTF-8?q?a=20o=20gestor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/manager/pacientes/[id]/editar/page.tsx | 682 +++++++++++++++++++++ app/manager/pacientes/loading.tsx | 3 + app/manager/pacientes/novo/page.tsx | 676 ++++++++++++++++++++ app/manager/pacientes/page.tsx | 393 ++++++++++++ components/manager-layout.tsx | 1 + 5 files changed, 1755 insertions(+) create mode 100644 app/manager/pacientes/[id]/editar/page.tsx create mode 100644 app/manager/pacientes/loading.tsx create mode 100644 app/manager/pacientes/novo/page.tsx create mode 100644 app/manager/pacientes/page.tsx diff --git a/app/manager/pacientes/[id]/editar/page.tsx b/app/manager/pacientes/[id]/editar/page.tsx new file mode 100644 index 0000000..254be97 --- /dev/null +++ b/app/manager/pacientes/[id]/editar/page.tsx @@ -0,0 +1,682 @@ +"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"; +import { patientsService } from "@/services/patientsApi.mjs"; +import { json } from "stream/consumers"; + +export default function EditarPacientePage() { + const router = useRouter(); + const params = useParams(); + const patientId = params.id; + 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); + + type FormData = { + nome: string; // full_name + cpf: string; + dataNascimento: string; // birth_date + sexo: string; // sex + id?: string; + nomeSocial?: string; // social_name + rg?: string; + documentType?: string; // document_type + documentNumber?: string; // document_number + ethnicity?: string; + race?: string; + naturality?: string; + nationality?: string; + profession?: string; + maritalStatus?: string; // marital_status + motherName?: string; // mother_name + motherProfession?: string; // mother_profession + fatherName?: string; // father_name + fatherProfession?: string; // father_profession + guardianName?: string; // guardian_name + guardianCpf?: string; // guardian_cpf + spouseName?: string; // spouse_name + rnInInsurance?: boolean; // rn_in_insurance + legacyCode?: string; // legacy_code + notes?: string; + email?: string; + phoneMobile?: string; // phone_mobile + phone1?: string; + phone2?: string; + cep?: string; + street?: string; + number?: string; + complement?: string; + neighborhood?: string; + city?: string; + state?: string; + reference?: string; + vip?: boolean; + lastVisitAt?: string; + nextAppointmentAt?: string; + createdAt?: string; + updatedAt?: string; + createdBy?: string; + updatedBy?: string; + weightKg?: string; + heightM?: string; + bmi?: string; + bloodType?: string; + }; + + + const [formData, setFormData] = useState({ + nome: "", + cpf: "", + dataNascimento: "", + sexo: "", + id: "", + nomeSocial: "", + rg: "", + documentType: "", + documentNumber: "", + ethnicity: "", + race: "", + naturality: "", + nationality: "", + profession: "", + maritalStatus: "", + motherName: "", + motherProfession: "", + fatherName: "", + fatherProfession: "", + guardianName: "", + guardianCpf: "", + spouseName: "", + rnInInsurance: false, + legacyCode: "", + notes: "", + email: "", + phoneMobile: "", + phone1: "", + phone2: "", + cep: "", + street: "", + number: "", + complement: "", + neighborhood: "", + city: "", + state: "", + reference: "", + vip: false, + lastVisitAt: "", + nextAppointmentAt: "", + createdAt: "", + updatedAt: "", + createdBy: "", + updatedBy: "", + weightKg: "", + heightM: "", + bmi: "", + bloodType: "", + }); + + const [isGuiaConvenio, setIsGuiaConvenio] = useState(false); + const [validadeIndeterminada, setValidadeIndeterminada] = useState(false); + + useEffect(() => { + async function fetchPatient() { + try { + const res = await patientsService.getById(patientId); + // Map API snake_case/nested to local camelCase form + setFormData({ + id: res[0]?.id ?? "", + nome: res[0]?.full_name ?? "", + nomeSocial: res[0]?.social_name ?? "", + cpf: res[0]?.cpf ?? "", + rg: res[0]?.rg ?? "", + documentType: res[0]?.document_type ?? "", + documentNumber: res[0]?.document_number ?? "", + sexo: res[0]?.sex ?? "", + dataNascimento: res[0]?.birth_date ?? "", + ethnicity: res[0]?.ethnicity ?? "", + race: res[0]?.race ?? "", + naturality: res[0]?.naturality ?? "", + nationality: res[0]?.nationality ?? "", + profession: res[0]?.profession ?? "", + maritalStatus: res[0]?.marital_status ?? "", + motherName: res[0]?.mother_name ?? "", + motherProfession: res[0]?.mother_profession ?? "", + fatherName: res[0]?.father_name ?? "", + fatherProfession: res[0]?.father_profession ?? "", + guardianName: res[0]?.guardian_name ?? "", + guardianCpf: res[0]?.guardian_cpf ?? "", + spouseName: res[0]?.spouse_name ?? "", + rnInInsurance: res[0]?.rn_in_insurance ?? false, + legacyCode: res[0]?.legacy_code ?? "", + notes: res[0]?.notes ?? "", + email: res[0]?.email ?? "", + phoneMobile: res[0]?.phone_mobile ?? "", + phone1: res[0]?.phone1 ?? "", + phone2: res[0]?.phone2 ?? "", + cep: res[0]?.cep ?? "", + street: res[0]?.street ?? "", + number: res[0]?.number ?? "", + complement: res[0]?.complement ?? "", + neighborhood: res[0]?.neighborhood ?? "", + city: res[0]?.city ?? "", + state: res[0]?.state ?? "", + reference: res[0]?.reference ?? "", + vip: res[0]?.vip ?? false, + lastVisitAt: res[0]?.last_visit_at ?? "", + nextAppointmentAt: res[0]?.next_appointment_at ?? "", + createdAt: res[0]?.created_at ?? "", + updatedAt: res[0]?.updated_at ?? "", + createdBy: res[0]?.created_by ?? "", + updatedBy: res[0]?.updated_by ?? "", + weightKg: res[0]?.weight_kg ? String(res[0].weight_kg) : "", + heightM: res[0]?.height_m ? String(res[0].height_m) : "", + bmi: res[0]?.bmi ? String(res[0].bmi) : "", + bloodType: res[0]?.blood_type ?? "", + }); + + } catch (e: any) { + toast({ title: "Erro", description: e?.message || "Falha ao carregar paciente" }); + } + } + fetchPatient(); + }, [patientId, toast]); + + 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 = { + full_name: formData.nome || null, + cpf: formData.cpf || null, + email: formData.email || null, + phone_mobile: formData.phoneMobile || null, + birth_date: formData.dataNascimento || null, + social_name: formData.nomeSocial || null, + sex: formData.sexo || null, + blood_type: formData.bloodType || null, + weight_kg: formData.weightKg ? Number(formData.weightKg) : null, + height_m: formData.heightM ? Number(formData.heightM) : null, + street: formData.street || null, + number: formData.number || null, + complement: formData.complement || null, + neighborhood: formData.neighborhood || null, + city: formData.city || null, + state: formData.state || null, + cep: formData.cep || null, + }; + + try { + await patientsService.update(patientId, payload); + toast({ + title: "Sucesso", + description: "Paciente atualizado com sucesso", + variant: "default" + }); + router.push("/manager/pacientes"); + } catch (err: any) { + console.error("Erro ao atualizar paciente:", err); + toast({ + title: "Erro", + description: err?.message || "Não foi possível atualizar o paciente", + variant: "destructive" + }); + } + }; + + 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)} 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("naturality", e.target.value)} /> +
+ +
+ + +
+ +
+ + handleInputChange("profession", e.target.value)} /> +
+ +
+ + +
+ +
+ + handleInputChange("motherName", e.target.value)} /> +
+ +
+ + handleInputChange("motherProfession", e.target.value)} /> +
+ +
+ + handleInputChange("fatherName", e.target.value)} /> +
+ +
+ + handleInputChange("fatherProfession", e.target.value)} /> +
+ +
+ + handleInputChange("guardianName", e.target.value)} /> +
+ +
+ + handleInputChange("guardianCpf", e.target.value)} placeholder="000.000.000-00" /> +
+ +
+ + handleInputChange("spouseName", e.target.value)} /> +
+
+ +
+
+ setIsGuiaConvenio(checked === true)} /> + +
+
+ +
+ +