diff --git a/frontend/views/LancarGTO.tsx b/frontend/views/LancarGTO.tsx index 6e51d31..9da1404 100644 --- a/frontend/views/LancarGTO.tsx +++ b/frontend/views/LancarGTO.tsx @@ -62,6 +62,8 @@ const useGTOStore = create((set) => ({ clear: () => set({ paciente: null, dentista: null, items: [] }), })); +export { useGTOStore }; + // --- ODONTOGRAM DATA (4x2 Grid Layout) --- const DENTES_ADULTO = { q1: [14, 13, 12, 11, 18, 17, 16, 15], // Top: 14-11, Bottom: 18-15 diff --git a/frontend/views/PatientsView.tsx b/frontend/views/PatientsView.tsx index bb7a009..ad4dd31 100644 --- a/frontend/views/PatientsView.tsx +++ b/frontend/views/PatientsView.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect, useCallback, useRef } from 'react'; -import { Search, Plus, DollarSign, X, Printer, CreditCard, Rocket, Loader2, FolderOpen, CalendarDays, RadioTower, Pencil, Wallet, PlusCircle, Banknote, History, FileText, Calendar, Copy, CheckCircle2, Users, UserCheck, ChevronLeft, ChevronRight, Save } from 'lucide-react'; +import { Search, Plus, DollarSign, X, Printer, CreditCard, Rocket, Loader2, FolderOpen, CalendarDays, RadioTower, Pencil, Wallet, PlusCircle, Banknote, History, FileText, Calendar, Copy, CheckCircle2, Users, UserCheck, ChevronLeft, ChevronRight, Save, Stethoscope, ClipboardList, BarChart3, MapPin } from 'lucide-react'; import { HybridBackend } from '../services/backend.ts'; import { Paciente, Dentista, Agendamento, Plano } from '../types.ts'; import { useHybridBackend } from '../hooks/useHybridBackend.ts'; @@ -750,6 +750,218 @@ const EditarPacienteModal: React.FC<{ patient: Paciente; onClose: () => void; on import { PageHeader } from '../components/PageHeader.tsx'; import { ReceitaModal } from './ReceitaModal.tsx'; import { PedidoExameModal } from './PedidoExameModal.tsx'; +import { useGTOStore } from './LancarGTO.tsx'; + +// ----------- TRATAMENTOS MODAL ----------- +const TratamentosModal: React.FC<{ patient: Paciente; onClose: () => void }> = ({ patient, onClose }) => { + const { data: agendamentos, isLoading } = useHybridBackend(HybridBackend.getAgendamentos); + const meus = (agendamentos ?? []).filter(a => a.pacienteNome === patient.nome); + const concluidos = meus.filter(a => a.status === 'Concluido'); + const faltou = meus.filter(a => a.status === 'Faltou'); + + const procedureCounts = concluidos.reduce>((acc, a) => { + acc[a.procedimento] = (acc[a.procedimento] || 0) + 1; + return acc; + }, {}); + + useEffect(() => { + const h = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; + document.addEventListener('keydown', h); + return () => document.removeEventListener('keydown', h); + }, [onClose]); + + return ( +
+
+
+
+
+
+

Tratamentos

+

{patient.nome}

+
+
+ +
+ + {/* Stats */} +
+
+

{meus.length}

+

Total Consultas

+
+
+

{concluidos.length}

+

Concluídas

+
+
+

{faltou.length}

+

Faltas

+
+
+ +
+ {/* Procedimentos realizados */} + {Object.keys(procedureCounts).length > 0 && ( +
+

Procedimentos Realizados

+
+ {Object.entries(procedureCounts).sort(([,a],[,b]) => b - a).map(([proc, count]) => ( +
+

{proc}

+ {count}x +
+ ))} +
+
+ )} + + {/* Histórico cronológico */} +
+

Histórico Cronológico ({meus.length})

+ {isLoading &&

Carregando...

} + {!isLoading && meus.length === 0 &&

Nenhum atendimento registrado.

} +
+ {[...meus].sort((a, b) => new Date(b.start).getTime() - new Date(a.start).getTime()).map(a => ( +
+
+

{a.procedimento}

+

{new Date(a.start).toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit', year: 'numeric' })}

+
+ {a.status} +
+ ))} +
+
+
+ +
+ +
+
+
+ ); +}; + +// ----------- RELATORIO PACIENTE MODAL ----------- +const RelatorioPacienteModal: React.FC<{ patient: Paciente; onClose: () => void }> = ({ patient, onClose }) => { + const { data: agendamentos } = useHybridBackend(HybridBackend.getAgendamentos); + const meus = (agendamentos ?? []).filter(a => a.pacienteNome === patient.nome); + const concluidos = meus.filter(a => a.status === 'Concluido').length; + const faltou = meus.filter(a => a.status === 'Faltou').length; + const hoje = new Date().toLocaleDateString('pt-BR', { day: '2-digit', month: 'long', year: 'numeric' }); + + useEffect(() => { + const h = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; + document.addEventListener('keydown', h); + return () => document.removeEventListener('keydown', h); + }, [onClose]); + + return ( +
+
+
+
+
+
+

Relatório do Paciente

+

{patient.nome}

+
+
+
+ + +
+
+ +
+
+ + {/* Cabeçalho */} +
+

Relatório do Paciente

+

Gerado em {hoje}

+
+ + {/* Dados pessoais */} +
+

Dados Pessoais

+
+
Nome

{patient.nome}

+
CPF

{patient.cpf || '—'}

+
Telefone

{patient.telefone || '—'}

+
E-mail

{patient.email || '—'}

+
Nascimento

{patient.dataNascimento || '—'}

+
Convênio

{patient.convenio || 'Particular'}

+
+
+ + {/* Endereço */} + {(patient.logradouro || patient.cidade) && ( +
+

Endereço

+

+ {[patient.logradouro, patient.numero, patient.complemento].filter(Boolean).join(', ')} + {patient.bairro && {patient.bairro}{patient.cidade && ` — ${patient.cidade}/${patient.estado}`}} + {patient.cep && CEP {patient.cep}} +

+
+ )} + + {/* Vínculos */} + {(patient.grupoFamiliarNome || patient.indicadoPorNome) && ( +
+

Vínculos

+
+ {patient.grupoFamiliarNome &&
Familiar

{patient.grupoFamiliarNome} {patient.grupoFamiliarRelacao && `(${patient.grupoFamiliarRelacao})`}

} + {patient.indicadoPorNome &&
Indicado por

{patient.indicadoPorNome}

} +
+
+ )} + + {/* Resumo de atendimentos */} +
+

Resumo de Atendimentos

+
+

{meus.length}

Total

+

{concluidos}

Concluídos

+

{faltou}

Faltas

+
+
+ {[...meus].sort((a, b) => new Date(b.start).getTime() - new Date(a.start).getTime()).slice(0, 20).map(a => ( +
+

{a.procedimento}

{new Date(a.start).toLocaleDateString('pt-BR')}

+ {a.status} +
+ ))} +
+
+ + {/* Observações */} + {patient.observacoes && ( +
+

Observações Clínicas

+

{patient.observacoes}

+
+ )} + +
+

Assinatura / Responsável

+

{hoje}

+
+
+
+
+
+ ); +}; const CopyField: React.FC<{ label: string; value?: string | null }> = ({ label, value }) => { const [copied, setCopied] = useState(false); @@ -950,13 +1162,21 @@ export const PatientsView: React.FC = () => {
Menu Clínico
-

{modal.patient.nome}

+

{modal.patient.nome}

-
- - - - +
+ + + + + + + +
@@ -977,6 +1197,16 @@ export const PatientsView: React.FC = () => { )} + {/* TRATAMENTOS MODAL */} + {modal.type === 'tratamentos' && modal.patient && ( + + )} + + {/* RELATÓRIO PACIENTE MODAL */} + {modal.type === 'relatorio-paciente' && modal.patient && ( + + )} + {/* MODAL MENU FINANCEIRO */} {modal.type === 'financial' && modal.patient && (