"use client" import type React from "react" import { useState, useEffect } 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 { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group" import { Checkbox } from "@/components/ui/checkbox" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible" import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog" import { Alert, AlertDescription } from "@/components/ui/alert" import { salvarPaciente } from "@/lib/api"; import { Upload, ChevronDown, ChevronUp, X, FileText, User, Phone, MapPin, FileImage, Save, XCircle, AlertCircle, Loader2, } from "lucide-react" interface PatientFormData { // Dados pessoais photo: File | null nome: string nomeSocial: string cpf: string rg: string outroDocumento: string numeroDocumento: string sexo: string dataNascimento: string etnia: string raca: string naturalidade: string nacionalidade: string profissao: string estadoCivil: string nomeMae: string profissaoMae: string nomePai: string profissaoPai: string nomeResponsavel: string cpfResponsavel: string nomeEsposo: string rnGuiaConvenio: boolean codigoLegado: string // Observações e anexos observacoes: string anexos: File[] // Contato email: string celular: string telefone1: string telefone2: string // Endereço cep: string logradouro: string numero: string complemento: string bairro: string cidade: string estado: string referencia: string } interface PatientRegistrationFormProps { open?: boolean onOpenChange?: (open: boolean) => void patientData?: PatientFormData | null patientId?: number | null mode?: "create" | "edit" onClose?: () => void inline?: boolean } export function PatientRegistrationForm({ open = true, onOpenChange, patientData = null, patientId = null, mode = "create", onClose, inline = false, }: PatientRegistrationFormProps) { const initialFormData: PatientFormData = { photo: null, nome: "", nomeSocial: "", cpf: "", rg: "", outroDocumento: "", numeroDocumento: "", sexo: "", dataNascimento: "", etnia: "", raca: "", naturalidade: "", nacionalidade: "Brasileira", profissao: "", estadoCivil: "", nomeMae: "", profissaoMae: "", nomePai: "", profissaoPai: "", nomeResponsavel: "", cpfResponsavel: "", nomeEsposo: "", rnGuiaConvenio: false, codigoLegado: "", observacoes: "", anexos: [], email: "", celular: "", telefone1: "", telefone2: "", cep: "", logradouro: "", numero: "", complemento: "", bairro: "", cidade: "", estado: "", referencia: "", } const [formData, setFormData] = useState(patientData || initialFormData) const [expandedSections, setExpandedSections] = useState({ dadosPessoais: true, observacoes: false, contato: false, endereco: false, }) const [photoPreview, setPhotoPreview] = useState(null) const [isLoadingCep, setIsLoadingCep] = useState(false) const [errors, setErrors] = useState>({}) const [isSubmitting, setIsSubmitting] = useState(false) useEffect(() => { if (patientId && mode === "edit") { // TODO: Fetch patient data by ID console.log("[v0] Loading patient data for ID:", patientId) // For now, use mock data or existing patientData if (patientData) { setFormData(patientData) if (patientData.photo) { const reader = new FileReader() reader.onload = (e) => setPhotoPreview(e.target?.result as string) reader.readAsDataURL(patientData.photo) } } } else if (mode === "create") { setFormData(initialFormData) setPhotoPreview(null) } }, [patientId, patientData, mode]) const toggleSection = (section: keyof typeof expandedSections) => { setExpandedSections((prev) => ({ ...prev, [section]: !prev[section], })) } const handleInputChange = (field: keyof PatientFormData, value: string | boolean | File | File[]) => { setFormData((prev) => ({ ...prev, [field]: value, })) // Clear error when user starts typing if (errors[field]) { setErrors((prev) => { const newErrors = { ...prev } delete newErrors[field] return newErrors }) } } const formatCPF = (value: string) => { const numbers = value.replace(/\D/g, "") return numbers.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, "$1.$2.$3-$4") } const handleCPFChange = (value: string) => { const formatted = formatCPF(value) handleInputChange("cpf", formatted) } const formatPhone = (value: string) => { const numbers = value.replace(/\D/g, "") if (numbers.length <= 10) { return numbers.replace(/(\d{2})(\d{4})(\d{4})/, "($1) $2-$3") } return numbers.replace(/(\d{2})(\d{5})(\d{4})/, "($1) $2-$3") } const formatCellPhone = (value: string) => { const numbers = value.replace(/\D/g, "") return numbers.replace(/(\d{2})(\d{5})(\d{4})/, "+55 ($1) $2-$3") } const formatCEP = (value: string) => { const numbers = value.replace(/\D/g, "") return numbers.replace(/(\d{5})(\d{3})/, "$1-$2") } const handlePhotoUpload = (event: React.ChangeEvent) => { const file = event.target.files?.[0] if (file) { if (file.size > 5 * 1024 * 1024) { // 5MB limit setErrors((prev) => ({ ...prev, photo: "Arquivo muito grande. Máximo 5MB." })) return } handleInputChange("photo", file) const reader = new FileReader() reader.onload = (e) => { setPhotoPreview(e.target?.result as string) } reader.readAsDataURL(file) } } const handleAnexoUpload = (event: React.ChangeEvent) => { const files = Array.from(event.target.files || []) const validFiles = files.filter((file) => { if (file.size > 10 * 1024 * 1024) { // 10MB limit per file setErrors((prev) => ({ ...prev, anexos: `Arquivo ${file.name} muito grande. Máximo 10MB por arquivo.` })) return false } return true }) handleInputChange("anexos", [...formData.anexos, ...validFiles]) } const removeAnexo = (index: number) => { const newAnexos = formData.anexos.filter((_, i) => i !== index) handleInputChange("anexos", newAnexos) } const validateCPF = (cpf: string) => { const cleanCPF = cpf.replace(/\D/g, "") if (cleanCPF.length !== 11) return false // Check for known invalid CPFs if (/^(\d)\1{10}$/.test(cleanCPF)) return false let sum = 0 for (let i = 0; i < 9; i++) { sum += Number.parseInt(cleanCPF.charAt(i)) * (10 - i) } let remainder = (sum * 10) % 11 if (remainder === 10 || remainder === 11) remainder = 0 if (remainder !== Number.parseInt(cleanCPF.charAt(9))) return false sum = 0 for (let i = 0; i < 10; i++) { sum += Number.parseInt(cleanCPF.charAt(i)) * (11 - i) } remainder = (sum * 10) % 11 if (remainder === 10 || remainder === 11) remainder = 0 return remainder === Number.parseInt(cleanCPF.charAt(10)) } const searchCEP = async (cep: string) => { const cleanCEP = cep.replace(/\D/g, "") if (cleanCEP.length !== 8) return setIsLoadingCep(true) try { const response = await fetch(`https://viacep.com.br/ws/${cleanCEP}/json/`) const data = await response.json() if (data.erro) { setErrors((prev) => ({ ...prev, cep: "CEP não encontrado" })) } else { handleInputChange("logradouro", data.logradouro || "") handleInputChange("bairro", data.bairro || "") handleInputChange("cidade", data.localidade || "") handleInputChange("estado", data.uf || "") // Clear CEP error if successful if (errors.cep) { setErrors((prev) => { const newErrors = { ...prev } delete newErrors.cep return newErrors }) } } } catch (error) { console.error("Erro ao buscar CEP:", error) setErrors((prev) => ({ ...prev, cep: "Erro ao buscar CEP. Tente novamente." })) } finally { setIsLoadingCep(false) } } const validateForm = () => { const newErrors: Record = {} // Required fields if (!formData.nome.trim()) { newErrors.nome = "Nome é obrigatório" } // CPF validation if (formData.cpf && !validateCPF(formData.cpf)) { newErrors.cpf = "CPF inválido" } // Email validation if (formData.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) { newErrors.email = "E-mail inválido" } // Responsible CPF validation if (formData.cpfResponsavel && !validateCPF(formData.cpfResponsavel)) { newErrors.cpfResponsavel = "CPF do responsável inválido" } // Date validation if (formData.dataNascimento) { const birthDate = new Date(formData.dataNascimento) const today = new Date() if (birthDate > today) { newErrors.dataNascimento = "Data de nascimento não pode ser futura" } } setErrors(newErrors) return Object.keys(newErrors).length === 0 } const handleSubmit = async (event: React.FormEvent) => { event.preventDefault() if (!validateForm()) { // Expand sections with errors const errorFields = Object.keys(errors) if (errorFields.some((field) => ["nome", "cpf", "rg", "sexo", "dataNascimento"].includes(field))) { setExpandedSections((prev) => ({ ...prev, dadosPessoais: true })) } if (errorFields.some((field) => ["email", "celular"].includes(field))) { setExpandedSections((prev) => ({ ...prev, contato: true })) } if (errorFields.some((field) => ["cep", "logradouro"].includes(field))) { setExpandedSections((prev) => ({ ...prev, endereco: true })) } return } setIsSubmitting(true) try { console.log("[v0] Saving patient data:", formData) console.log("[v0] Mode:", mode) console.log("[v0] Patient ID:", patientId) // Simulate network delay await salvarPaciente(formData) // TODO: Implement actual API call // const response = await fetch('/api/patients', { // method: mode === 'create' ? 'POST' : 'PUT', // headers: { 'Content-Type': 'application/json' }, // body: JSON.stringify(formData) // }) // Reset form if creating new patient if (mode === "create") { setFormData(initialFormData) setPhotoPreview(null) } if (inline && onClose) { onClose() } else if (onOpenChange) { onOpenChange(false) } // Show success message (you might want to use a toast notification) alert(mode === "create" ? "Paciente cadastrado com sucesso!" : "Paciente atualizado com sucesso!") } catch (error) { console.error("Erro ao salvar paciente:", error) setErrors({ submit: "Erro ao salvar paciente. Tente novamente." }) } finally { setIsSubmitting(false) } } const handleCancel = () => { if (inline && onClose) { onClose() } else if (onOpenChange) { onOpenChange(false) } } if (inline) { return (
{errors.submit && ( {errors.submit} )}
{/* Dados Pessoais */} toggleSection("dadosPessoais")}> Dados Pessoais {expandedSections.dadosPessoais ? ( ) : ( )} {/* Foto */}
{photoPreview ? ( Preview ) : ( )}
{errors.photo &&

{errors.photo}

}

Máximo 5MB

{/* Nome e Nome Social */}
handleInputChange("nome", e.target.value)} className={errors.nome ? "border-destructive" : ""} /> {errors.nome &&

{errors.nome}

}
handleInputChange("nomeSocial", e.target.value)} />
{/* CPF e RG */}
handleCPFChange(e.target.value)} placeholder="000.000.000-00" maxLength={14} className={errors.cpf ? "border-destructive" : ""} /> {errors.cpf &&

{errors.cpf}

}
handleInputChange("rg", e.target.value)} />
{/* Outros Documentos */}
handleInputChange("numeroDocumento", e.target.value)} disabled={!formData.outroDocumento} />
{/* Sexo e Data de Nascimento */}
handleInputChange("sexo", value)}>
handleInputChange("dataNascimento", e.target.value)} className={errors.dataNascimento ? "border-destructive" : ""} /> {errors.dataNascimento &&

{errors.dataNascimento}

}
{/* Etnia e Raça */}
handleInputChange("raca", e.target.value)} placeholder="Opcional" />
{/* Naturalidade e Nacionalidade */}
handleInputChange("naturalidade", e.target.value)} placeholder="Cidade de nascimento" />
handleInputChange("nacionalidade", e.target.value)} />
{/* Profissão e Estado Civil */}
handleInputChange("profissao", e.target.value)} />
{/* Dados dos Pais */}
handleInputChange("nomeMae", e.target.value)} />
handleInputChange("profissaoMae", e.target.value)} />
handleInputChange("nomePai", e.target.value)} />
handleInputChange("profissaoPai", e.target.value)} />
{/* Responsável */}
handleInputChange("nomeResponsavel", e.target.value)} placeholder="Para menores ou dependentes" />
handleCPFChange(e.target.value)} placeholder="000.000.000-00" maxLength={14} className={errors.cpfResponsavel ? "border-destructive" : ""} /> {errors.cpfResponsavel &&

{errors.cpfResponsavel}

}
{/* Esposo e Configurações */}
handleInputChange("nomeEsposo", e.target.value)} />
handleInputChange("codigoLegado", e.target.value)} placeholder="ID de outro sistema" />
{/* RN na Guia do Convênio */}
handleInputChange("rnGuiaConvenio", checked as boolean)} />
{/* Observações e Anexos */} toggleSection("observacoes")}> Observações e Anexos {expandedSections.observacoes ? ( ) : ( )}