From ea48af41619347d73d1b510335e1b2b902c32af3 Mon Sep 17 00:00:00 2001 From: GagoDuBroca Date: Wed, 5 Nov 2025 11:11:16 -0300 Subject: [PATCH] =?UTF-8?q?Pagina=C3=A7=C3=B5es=20e=20aba=20de=20detalhes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/doctor/medicos/page.tsx | 258 ++++++++++++----- app/manager/home/page.tsx | 84 +++++- app/manager/usuario/page.tsx | 90 ++++-- app/secretary/pacientes/page.tsx | 475 +++++++++++++++++-------------- 4 files changed, 593 insertions(+), 314 deletions(-) diff --git a/app/doctor/medicos/page.tsx b/app/doctor/medicos/page.tsx index 9b2ec3f..50db228 100644 --- a/app/doctor/medicos/page.tsx +++ b/app/doctor/medicos/page.tsx @@ -1,6 +1,7 @@ +// app/doctor/pacientes/page.tsx (assumindo a localização) "use client"; -import { useEffect, useState } from "react"; +import { useEffect, useState, useCallback } from "react"; import DoctorLayout from "@/components/doctor-layout"; import Link from "next/link"; import { @@ -9,9 +10,17 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { Eye, Edit, Calendar, Trash2 } from "lucide-react"; +import { Eye, Edit, Calendar, Trash2, Loader2 } from "lucide-react"; import { api } from "@/services/api.mjs"; import { PatientDetailsModal } from "@/components/ui/patient-details-modal"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Button } from "@/components/ui/button"; interface Paciente { id: string; @@ -41,6 +50,60 @@ export default function PacientesPage() { const [selectedPatient, setSelectedPatient] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); + // --- Lógica de Paginação INÍCIO --- + const [itemsPerPage, setItemsPerPage] = useState(5); + const [currentPage, setCurrentPage] = useState(1); + + const totalPages = Math.ceil(pacientes.length / itemsPerPage); + + const indexOfLastItem = currentPage * itemsPerPage; + const indexOfFirstItem = indexOfLastItem - itemsPerPage; + const currentItems = pacientes.slice(indexOfFirstItem, indexOfLastItem); + + const paginate = (pageNumber: number) => setCurrentPage(pageNumber); + + // Funções de Navegação + const goToPrevPage = () => { + setCurrentPage((prev) => Math.max(1, prev - 1)); + }; + + const goToNextPage = () => { + setCurrentPage((prev) => Math.min(totalPages, prev + 1)); + }; + + // Lógica para gerar os números das páginas visíveis (máximo de 5) + const getVisiblePageNumbers = (totalPages: number, currentPage: number) => { + const pages: number[] = []; + const maxVisiblePages = 5; + const halfRange = Math.floor(maxVisiblePages / 2); + let startPage = Math.max(1, currentPage - halfRange); + let endPage = Math.min(totalPages, currentPage + halfRange); + + if (endPage - startPage + 1 < maxVisiblePages) { + if (endPage === totalPages) { + startPage = Math.max(1, totalPages - maxVisiblePages + 1); + } + if (startPage === 1) { + endPage = Math.min(totalPages, maxVisiblePages); + } + } + + for (let i = startPage; i <= endPage; i++) { + pages.push(i); + } + return pages; + }; + + const visiblePageNumbers = getVisiblePageNumbers(totalPages, currentPage); + + // Lógica para mudar itens por página, resetando para a página 1 + const handleItemsPerPageChange = (value: string) => { + setItemsPerPage(Number(value)); + setCurrentPage(1); + }; + // --- Lógica de Paginação FIM --- + + const handleOpenModal = (patient: Paciente) => { setSelectedPatient(patient); setIsModalOpen(true); @@ -51,71 +114,98 @@ export default function PacientesPage() { setIsModalOpen(false); }; - const formatDate = (dateString: string) => { - if (!dateString) return ""; - const date = new Date(dateString); - return new Intl.DateTimeFormat("pt-BR").format(date); + const formatDate = (dateString: string | null | undefined) => { + if (!dateString) return "N/A"; + try { + const date = new Date(dateString); + return new Intl.DateTimeFormat("pt-BR").format(date); + } catch (e) { + return dateString; // Retorna o string original se o formato for inválido + } }; - const [itemsPerPage, setItemsPerPage] = useState(5); - const [currentPage, setCurrentPage] = useState(1); + const fetchPacientes = useCallback(async () => { + try { + setLoading(true); + setError(null); + const json = await api.get("/rest/v1/patients"); + const items = Array.isArray(json) + ? json + : Array.isArray(json?.data) + ? json.data + : []; - const indexOfLastItem = currentPage * itemsPerPage; - const indexOfFirstItem = indexOfLastItem - itemsPerPage; - const currentItems = pacientes.slice(indexOfFirstItem, indexOfLastItem); + const mapped: Paciente[] = items.map((p: any) => ({ + id: String(p.id ?? ""), + nome: p.full_name ?? "—", + telefone: p.phone_mobile ?? "N/A", + cidade: p.city ?? "N/A", + estado: p.state ?? "N/A", + ultimoAtendimento: formatDate(p.created_at), + proximoAtendimento: "N/A", // Necessita de lógica de agendamento real + email: p.email ?? "N/A", + birth_date: p.birth_date ?? "N/A", + cpf: p.cpf ?? "N/A", + blood_type: p.blood_type ?? "N/A", + weight_kg: p.weight_kg ?? 0, + height_m: p.height_m ?? 0, + street: p.street ?? "N/A", + number: p.number ?? "N/A", + complement: p.complement ?? "N/A", + neighborhood: p.neighborhood ?? "N/A", + cep: p.cep ?? "N/A", + })); - const paginate = (pageNumber: number) => setCurrentPage(pageNumber); + setPacientes(mapped); + setCurrentPage(1); // Resetar a página ao carregar novos dados + } catch (e: any) { + console.error("Erro ao carregar pacientes:", e); + setError(e?.message || "Erro ao carregar pacientes"); + } finally { + setLoading(false); + } + }, []); useEffect(() => { - async function fetchPacientes() { - try { - setLoading(true); - setError(null); - const json = await api.get("/rest/v1/patients"); - const items = Array.isArray(json) ? json : Array.isArray(json?.data) ? json.data : []; - - const mapped = items.map((p: any) => ({ - id: String(p.id ?? ""), - nome: p.full_name ?? "", - telefone: p.phone_mobile ?? "", - cidade: p.city ?? "", - estado: p.state ?? "", - ultimoAtendimento: formatDate(p.created_at) ?? "", - proximoAtendimento: "", - email: p.email ?? "", - birth_date: p.birth_date ?? "", - cpf: p.cpf ?? "", - blood_type: p.blood_type ?? "", - weight_kg: p.weight_kg ?? 0, - height_m: p.height_m ?? 0, - street: p.street ?? "", - number: p.number ?? "", - complement: p.complement ?? "", - neighborhood: p.neighborhood ?? "", - cep: p.cep ?? "", - })); - - setPacientes(mapped); - } catch (e: any) { - setError(e?.message || "Erro ao carregar pacientes"); - } finally { - setLoading(false); - } - } fetchPacientes(); - }, []); + }, [fetchPacientes]); return (
-
-

Pacientes

-

- Lista de pacientes vinculados -

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

Pacientes

+

+ Lista de pacientes vinculados +

+
+ {/* Adicione um seletor de itens por página ao lado de um botão de 'Novo Paciente' se aplicável */} +
+ + + + +
-
+ +
@@ -143,6 +233,7 @@ export default function PacientesPage() { {loading ? ( @@ -191,7 +282,7 @@ export default function PacientesPage() { Ver detalhes - + Laudos @@ -202,11 +293,13 @@ export default function PacientesPage() { { + // Simulação de exclusão (A exclusão real deve ser feita via API) const newPacientes = pacientes.filter((pac) => pac.id !== p.id); setPacientes(newPacientes); alert(`Paciente ID: ${p.id} excluído`); + // Necessário chamar a API de exclusão aqui }} - className="text-red-600" + className="text-red-600 focus:bg-red-50 focus:text-red-600" > Excluir @@ -221,22 +314,47 @@ export default function PacientesPage() {
+ Carregando pacientes...
- {/* Paginação Responsiva */} -
- {Array.from({ length: Math.ceil(pacientes.length / itemsPerPage) }, (_, i) => ( + {/* Paginação ATUALIZADA */} + {totalPages > 1 && ( +
+ + {/* Botão Anterior */} - ))} -
+ + {/* Números das Páginas */} + {visiblePageNumbers.map((number) => ( + + ))} + + {/* Botão Próximo */} + + +
+ )} + {/* Fim da Paginação ATUALIZADA */} +
@@ -247,4 +365,4 @@ export default function PacientesPage() { /> ); -} +} \ No newline at end of file diff --git a/app/manager/home/page.tsx b/app/manager/home/page.tsx index 86e4750..cb5e260 100644 --- a/app/manager/home/page.tsx +++ b/app/manager/home/page.tsx @@ -1,3 +1,4 @@ +// app/manager/home/page.tsx (ou doctors/page.tsx, dependendo da sua rota) "use client"; import React, { useEffect, useState, useCallback } from "react"; @@ -81,14 +82,52 @@ export default function DoctorsPage() { const [itemsPerPage, setItemsPerPage] = useState(10); const [currentPage, setCurrentPage] = useState(1); - // Cálculo dos itens a serem exibidos na página atual + // 1. Definição do total de páginas + const totalPages = Math.ceil(doctors.length / itemsPerPage); + + // 2. Cálculo dos itens a serem exibidos na página atual const indexOfLastItem = currentPage * itemsPerPage; const indexOfFirstItem = indexOfLastItem - itemsPerPage; const currentItems = doctors.slice(indexOfFirstItem, indexOfLastItem); - // Função para mudar de página + // 3. Função para mudar de página const paginate = (pageNumber: number) => setCurrentPage(pageNumber); + // 4. Funções para Navegação ADICIONADAS + const goToPrevPage = () => { + setCurrentPage((prev) => Math.max(1, prev - 1)); + }; + + const goToNextPage = () => { + setCurrentPage((prev) => Math.min(totalPages, prev + 1)); + }; + + // 5. Lógica para gerar os números das páginas visíveis (máximo de 5) + const getVisiblePageNumbers = (totalPages: number, currentPage: number) => { + const pages: number[] = []; + const maxVisiblePages = 5; + const halfRange = Math.floor(maxVisiblePages / 2); + let startPage = Math.max(1, currentPage - halfRange); + let endPage = Math.min(totalPages, currentPage + halfRange); + + if (endPage - startPage + 1 < maxVisiblePages) { + if (endPage === totalPages) { + startPage = Math.max(1, totalPages - maxVisiblePages + 1); + } + if (startPage === 1) { + endPage = Math.min(totalPages, maxVisiblePages); + } + } + + for (let i = startPage; i <= endPage; i++) { + pages.push(i); + } + return pages; + }; + + const visiblePageNumbers = getVisiblePageNumbers(totalPages, currentPage); + // Fim da lógica de números de página visíveis + // Lógica para mudar itens por página, resetando para a página 1 const handleItemsPerPageChange = (value: string) => { setItemsPerPage(Number(value)); @@ -206,7 +245,7 @@ export default function DoctorsPage() { Inativo - {/* Select de Itens por Página Adicionado */} + {/* Select de Itens por Página */} - {/* Select de Itens por Página ADICIONADO */} + {/* Select de Itens por Página */}
- {/* Fim do Filtro e Itens por Página ADICIONADO */} + {/* Fim do Filtro e Itens por Página */} {/* Tabela */}
@@ -284,25 +315,46 @@ export default function UsersPage() { - {/* Paginação ADICIONADA */} - {pageNumbers.length > 1 && ( + {/* Paginação ATUALIZADA */} + {totalPages > 1 && (
- {pageNumbers.map((number) => ( + + {/* Botão Anterior */} + + + {/* Números das Páginas */} + {visiblePageNumbers.map((number) => ( ))} + + {/* Botão Próximo */} + +
)} - {/* Fim da Paginação ADICIONADA */} + {/* Fim da Paginação ATUALIZADA */} )}
diff --git a/app/secretary/pacientes/page.tsx b/app/secretary/pacientes/page.tsx index e7f73af..8501cd7 100644 --- a/app/secretary/pacientes/page.tsx +++ b/app/secretary/pacientes/page.tsx @@ -1,108 +1,139 @@ +// app/secretary/pacientes/page.tsx "use client"; -import { useState, useEffect, useRef, useCallback } from "react"; +import { useState, useEffect, useCallback } from "react"; import Link from "next/link"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Plus, Edit, Trash2, Eye, Calendar, Filter } from "lucide-react"; +import { Plus, Edit, Trash2, Eye, Calendar, Filter, Loader2 } from "lucide-react"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; import SecretaryLayout from "@/components/secretary-layout"; import { patientsService } from "@/services/patientsApi.mjs"; +// Defina o tamanho da página. +const PAGE_SIZE = 5; + export default function PacientesPage() { + // --- ESTADOS DE DADOS E GERAL --- const [searchTerm, setSearchTerm] = useState(""); const [convenioFilter, setConvenioFilter] = useState("all"); const [vipFilter, setVipFilter] = useState("all"); - const [patients, setPatients] = useState([]); - const [loading, setLoading] = useState(false); + + // Lista completa, carregada da API uma única vez + const [allPatients, setAllPatients] = useState([]); + // Lista após a aplicação dos filtros (base para a paginação) + const [filteredPatients, setFilteredPatients] = useState([]); + + const [loading, setLoading] = useState(true); const [error, setError] = useState(null); + + // --- ESTADOS DE PAGINAÇÃO --- const [page, setPage] = useState(1); - const [hasNext, setHasNext] = useState(true); - const [isFetching, setIsFetching] = useState(false); - const observerRef = useRef(null); + + // CÁLCULO DA PAGINAÇÃO + const totalPages = Math.ceil(filteredPatients.length / PAGE_SIZE); + const startIndex = (page - 1) * PAGE_SIZE; + const endIndex = startIndex + PAGE_SIZE; + // Pacientes a serem exibidos na tabela (aplicando a paginação) + const currentPatients = filteredPatients.slice(startIndex, endIndex); + + // --- ESTADOS DE DIALOGS --- const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [patientToDelete, setPatientToDelete] = useState(null); const [detailsDialogOpen, setDetailsDialogOpen] = useState(false); const [patientDetails, setPatientDetails] = useState(null); + + // --- FUNÇÕES DE LÓGICA --- + + // 1. Função para carregar TODOS os pacientes da API + const fetchAllPacientes = useCallback( + async () => { + setLoading(true); + setError(null); + try { + // Como o backend retorna um array, chamamos sem paginação + const res = await patientsService.list(); + + const mapped = res.map((p: any) => ({ + id: String(p.id ?? ""), + nome: p.full_name ?? "—", + telefone: p.phone_mobile ?? p.phone1 ?? "—", + cidade: p.city ?? "—", + estado: p.state ?? "—", + // Formate as datas se necessário, aqui usamos como string + ultimoAtendimento: p.last_visit_at?.split('T')[0] ?? "—", + proximoAtendimento: p.next_appointment_at?.split('T')[0] ?? "—", + vip: Boolean(p.vip ?? false), + convenio: p.convenio ?? "Particular", // Define um valor padrão + status: p.status ?? undefined, + })); + + setAllPatients(mapped); + } catch (e: any) { + console.error(e); + setError(e?.message || "Erro ao buscar pacientes"); + } finally { + setLoading(false); + } + }, + [] + ); + + // 2. Efeito para aplicar filtros e calcular a lista filtrada (chama-se quando allPatients ou filtros mudam) + useEffect(() => { + const filtered = allPatients.filter((patient) => { + // Filtro por termo de busca (Nome ou Telefone) + const matchesSearch = + patient.nome?.toLowerCase().includes(searchTerm.toLowerCase()) || + patient.telefone?.includes(searchTerm); + + // Filtro por Convênio + const matchesConvenio = + convenioFilter === "all" || + patient.convenio === convenioFilter; + + // Filtro por VIP + const matchesVip = + vipFilter === "all" || + (vipFilter === "vip" && patient.vip) || + (vipFilter === "regular" && !patient.vip); + + return matchesSearch && matchesConvenio && matchesVip; + }); + + setFilteredPatients(filtered); + // Garante que a página atual seja válida após a filtragem + setPage(1); + }, [allPatients, searchTerm, convenioFilter, vipFilter]); + + // 3. Efeito inicial para buscar os pacientes + useEffect(() => { + fetchAllPacientes(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + + // --- LÓGICA DE AÇÕES (DELETAR / VER DETALHES) --- + const openDetailsDialog = async (patientId: string) => { setDetailsDialogOpen(true); setPatientDetails(null); try { const res = await patientsService.getById(patientId); - setPatientDetails(res[0]); + setPatientDetails(Array.isArray(res) ? res[0] : res); // Supondo que retorne um array com um item } catch (e: any) { setPatientDetails({ error: e?.message || "Erro ao buscar detalhes" }); } }; - const fetchPacientes = useCallback( - async (pageToFetch: number) => { - if (isFetching || !hasNext) return; - setIsFetching(true); - setError(null); - try { - const res = await patientsService.list(); - const mapped = res.map((p: any) => ({ - id: String(p.id ?? ""), - nome: p.full_name ?? "", - telefone: p.phone_mobile ?? p.phone1 ?? "", - cidade: p.city ?? "", - estado: p.state ?? "", - ultimoAtendimento: p.last_visit_at ?? "", - proximoAtendimento: p.next_appointment_at ?? "", - vip: Boolean(p.vip ?? false), - convenio: p.convenio ?? "", // se não existir, fica vazio - status: p.status ?? undefined, - })); - - setPatients((prev) => { - const all = [...prev, ...mapped]; - const unique = Array.from(new Map(all.map((p) => [p.id, p])).values()); - return unique; - }); - - if (!mapped.id) setHasNext(false); // parar carregamento - else setPage((prev) => prev + 1); - } catch (e: any) { - setError(e?.message || "Erro ao buscar pacientes"); - } finally { - setIsFetching(false); - } - }, - [isFetching, hasNext] - ); - - useEffect(() => { - fetchPacientes(page); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - if (!observerRef.current || !hasNext) return; - const observer = new window.IntersectionObserver((entries) => { - if (entries[0].isIntersecting && !isFetching && hasNext) { - fetchPacientes(page); - } - }); - observer.observe(observerRef.current); - return () => { - if (observerRef.current) observer.unobserve(observerRef.current); - }; - }, [fetchPacientes, page, hasNext, isFetching]); - const handleDeletePatient = async (patientId: string) => { - // Remove from current list (client-side deletion) try { - const res = await patientsService.delete(patientId); - - if (res) { - alert(`${res.error} ${res.message}`); - } - - setPatients((prev) => prev.filter((p) => String(p.id) !== String(patientId))); + await patientsService.delete(patientId); + // Atualiza a lista completa para refletir a exclusão + setAllPatients((prev) => prev.filter((p) => String(p.id) !== String(patientId))); } catch (e: any) { - setError(e?.message || "Erro ao deletar paciente"); + alert(`Erro ao deletar paciente: ${e?.message || 'Erro desconhecido'}`); } setDeleteDialogOpen(false); setPatientToDelete(null); @@ -113,25 +144,18 @@ export default function PacientesPage() { setDeleteDialogOpen(true); }; - const filteredPatients = patients.filter((patient) => { - const matchesSearch = patient.nome?.toLowerCase().includes(searchTerm.toLowerCase()) || patient.telefone?.includes(searchTerm); - const matchesConvenio = convenioFilter === "all" || (patient.convenio ?? "") === convenioFilter; - const matchesVip = vipFilter === "all" || (vipFilter === "vip" && patient.vip) || (vipFilter === "regular" && !patient.vip); - - return matchesSearch && matchesConvenio && matchesVip; - }); - return ( -
+
+ {/* Header */}

Pacientes

Gerencie as informações de seus pacientes

- - @@ -139,30 +163,41 @@ export default function PacientesPage() {
- {/* Bloco de Filtros: Corrigido o uso de classes para responsividade e removida a duplicação dos filtros VIP e Aniversariantes */} + {/* Bloco de Filtros */}
+ + {/* Busca */} + setSearchTerm(e.target.value)} + className="flex-grow min-w-[150px] p-2 border rounded-md text-sm" + /> + {/* Convênio */} -
- Convênio +
+ Convênio
{/* VIP */} -
- VIP +
+ VIP
- - {/* Aniversariantes */} -
- Aniversariantes - -
- + + {/* Aniversariantes (mantido como placeholder) */}
- {/* Tabela com rolagem horizontal (overflow-x-auto) para responsividade */} -
+ {/* Tabela */} +
{error ? (
{`Erro ao carregar pacientes: ${error}`}
+ ) : loading ? ( +
+ Carregando pacientes... +
) : ( - {/* Aumentei um pouco o min-width para garantir espaço */} +
- - - - - - - + + + + + + + - {filteredPatients.length === 0 ? ( + {currentPatients.length === 0 ? ( ) : ( - filteredPatients.map((patient) => ( + currentPatients.map((patient) => ( - - + + + + {/* --- COLUNA AÇÕES CORRIGIDA --- */} + {/* --- FIM DA COLUNA AÇÕES CORRIGIDA --- */} + )) )}
NomeTelefoneCidadeEstadoÚltimo atendimentoPróximo atendimentoAçõesNomeTelefoneCidade / EstadoConvênioÚltimo atendimentoPróximo atendimentoAções
- {patients.length === 0 ? "Nenhum paciente cadastrado" : "Nenhum paciente encontrado com os filtros aplicados"} + {allPatients.length === 0 ? "Nenhum paciente cadastrado" : "Nenhum paciente encontrado com os filtros aplicados"}
-
- {patient.nome?.charAt(0) || "?"} +
+ {patient.nome?.charAt(0) || "?"}
- {patient.nome} + + {patient.nome} + {patient.vip && ( + VIP + )} +
{patient.telefone}{patient.cidade}{patient.estado}{`${patient.cidade} / ${patient.estado}`}{patient.convenio} {patient.ultimoAtendimento} {patient.proximoAtendimento} - - -
Ações
-
- - openDetailsDialog(String(patient.id))}> - - Ver detalhes - - - - - Editar - - - - - Marcar consulta - - openDeleteDialog(String(patient.id))}> - - Excluir - - -
+ + +
Ações
+
+ + openDetailsDialog(String(patient.id))}> + + Ver detalhes + + + {/* O Trecho CORRIGIDO ABAIXO */} + + {/* O Link deve ter o estilo de um DropdownMenuItem, e englobar todo o conteúdo (ícone + texto) */} + + + Editar + + + + + + Marcar consulta + + openDeleteDialog(String(patient.id))}> + + Excluir + + +
)} -
- {isFetching &&
Carregando mais pacientes...
}
-
+ + {/* --- PAGINAÇÃO --- */} + {totalPages > 1 && !loading && ( +
+ + {/* Botões de Navegação */} +
+ {/* Botão Anterior */} + + {/* Renderização dos botões de número de página (Limitando a 5) */} + {Array.from({ length: totalPages }, (_, index) => index + 1) + // Limita a exibição dos botões para 5 (janela de visualização) + .slice(Math.max(0, page - 3), Math.min(totalPages, page + 2)) + .map((pageNumber) => ( + + ))} + + {/* Botão Próximo */} + +
+
+ )} + {/* --- FIM DA PAGINAÇÃO --- */} +
+ + {/* AlertDialogs (Mantidos) */} @@ -287,74 +370,40 @@ export default function PacientesPage() { - {/* Modal de detalhes do paciente */} Detalhes do Paciente {patientDetails === null ? ( -
Carregando...
+
+ + Carregando... +
) : patientDetails?.error ? ( -
{patientDetails.error}
+
{patientDetails.error}
) : ( -
-

- Nome: {patientDetails.full_name} -

-

- CPF: {patientDetails.cpf} -

-

- Email: {patientDetails.email} -

-

- Telefone: {patientDetails.phone_mobile ?? patientDetails.phone1 ?? patientDetails.phone2 ?? "-"} -

-

- Nome social: {patientDetails.social_name ?? "-"} -

-

- Sexo: {patientDetails.sex ?? "-"} -

-

- Tipo sanguíneo: {patientDetails.blood_type ?? "-"} -

-

- Peso: {patientDetails.weight_kg ?? "-"} - {patientDetails.weight_kg ? "kg" : ""} -

-

- Altura: {patientDetails.height_m ?? "-"} - {patientDetails.height_m ? "m" : ""} -

-

- IMC: {patientDetails.bmi ?? "-"} -

-

- Endereço: {patientDetails.street ?? "-"} -

-

- Bairro: {patientDetails.neighborhood ?? "-"} -

-

- Cidade: {patientDetails.city ?? "-"} -

-

- Estado: {patientDetails.state ?? "-"} -

-

- CEP: {patientDetails.cep ?? "-"} -

-

- Criado em: {patientDetails.created_at ?? "-"} -

-

- Atualizado em: {patientDetails.updated_at ?? "-"} -

-

- Id: {patientDetails.id ?? "-"} +

+

Nome: {patientDetails.full_name}

+

CPF: {patientDetails.cpf}

+

Email: {patientDetails.email}

+

Telefone: {patientDetails.phone_mobile ?? patientDetails.phone1 ?? patientDetails.phone2 ?? "-"}

+

Convênio: {patientDetails.convenio ?? "Particular"}

+

VIP: {patientDetails.vip ? "Sim" : "Não"}

+

Nome social: {patientDetails.social_name ?? "-"}

+

Sexo: {patientDetails.sex ?? "-"}

+

Tipo sanguíneo: {patientDetails.blood_type ?? "-"}

+

Peso: {patientDetails.weight_kg ? `${patientDetails.weight_kg} kg` : "-"}

+

Altura: {patientDetails.height_m ? `${patientDetails.height_m} m` : "-"}

+

IMC: {patientDetails.bmi ?? "-"}

+

Endereço: {patientDetails.street ?? "-"}

+

Bairro: {patientDetails.neighborhood ?? "-"}

+

Cidade/Estado: {patientDetails.city ?? "-"} / {patientDetails.state ?? "-"}

+

CEP: {patientDetails.cep ?? "-"}

+

+ Criado em: {patientDetails.created_at ?? "-"} | Atualizado em: {patientDetails.updated_at ?? "-"}

+

Id: {patientDetails.id ?? "-"}

)}