From a045b3ca720027de58e7ab8e855d4c1cf830ae7b Mon Sep 17 00:00:00 2001 From: keven Date: Fri, 26 Sep 2025 09:04:44 -0300 Subject: [PATCH] [MVPTN-88] commit de backup --- package-lock.json | 7 + package.json | 1 + src/actions/text/GetNameInitials.ts | 2 +- .../(t_pessoa)/pessoa/fisica/page copy 3.tsx | 463 ++++++++++++++++++ .../(t_pessoa)/pessoa/fisica/page.tsx | 292 +---------- .../t_pessoa/TPessoaTable copy.tsx | 217 ++++++++ .../_components/t_pessoa/TPessoaTable.tsx | 354 ++++++------- .../cadastros/_interfaces/TPessoaInterface.ts | 1 + src/app/_components/dataTable/dataTable.tsx | 134 +++++ 9 files changed, 1007 insertions(+), 464 deletions(-) create mode 100644 src/app/(protected)/(cadastros)/cadastros/(t_pessoa)/pessoa/fisica/page copy 3.tsx create mode 100644 src/app/(protected)/(cadastros)/cadastros/_components/t_pessoa/TPessoaTable copy.tsx create mode 100644 src/app/_components/dataTable/dataTable.tsx diff --git a/package-lock.json b/package-lock.json index 918aa7e..97ea25c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,6 +38,7 @@ "react": "19.1.0", "react-dom": "19.1.0", "react-hook-form": "^7.62.0", + "react-masked-text": "^1.0.5", "sonner": "^2.0.7", "tailwind-merge": "^3.3.1", "tinymce": "^8.1.2", @@ -2950,6 +2951,12 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/react-masked-text": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/react-masked-text/-/react-masked-text-1.0.5.tgz", + "integrity": "sha512-WichrlCXehL0apIfIgOdi2mjBE03tdMi8wXF+DhHe2ySWYxXCkP88aqDBaJZWUMa3Jp8p2h71u7TpC7EzEjXYw==", + "license": "ISC" + }, "node_modules/react-remove-scroll": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", diff --git a/package.json b/package.json index 1ffb165..0d3d8da 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "react": "19.1.0", "react-dom": "19.1.0", "react-hook-form": "^7.62.0", + "react-masked-text": "^1.0.5", "sonner": "^2.0.7", "tailwind-merge": "^3.3.1", "tinymce": "^8.1.2", diff --git a/src/actions/text/GetNameInitials.ts b/src/actions/text/GetNameInitials.ts index 621409e..a9518e8 100644 --- a/src/actions/text/GetNameInitials.ts +++ b/src/actions/text/GetNameInitials.ts @@ -1,4 +1,4 @@ -export default function GetNameInitials(data: string): string { +export default function GetNameInitials(data?: string): string { if (!data) return ""; // Remove espaços extras no início e no fim e divide em palavras diff --git a/src/app/(protected)/(cadastros)/cadastros/(t_pessoa)/pessoa/fisica/page copy 3.tsx b/src/app/(protected)/(cadastros)/cadastros/(t_pessoa)/pessoa/fisica/page copy 3.tsx new file mode 100644 index 0000000..1a13229 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/(t_pessoa)/pessoa/fisica/page copy 3.tsx @@ -0,0 +1,463 @@ +'use client'; + +import MaskedText from 'react-masked-text'; + +import React, { useEffect, useState, useCallback } from "react"; +import { Card, CardContent } from "@/components/ui/card"; + +import Loading from "@/app/_components/loading/loading"; +import TPessoaTable from "../../../_components/t_pessoa/TPessoaTable"; +import TPessoaForm from "../../../_components/t_pessoa/TPessoaForm"; + +import { useTPessoaIndexHook } from "../../../_hooks/t_pessoa/useTPessoaIndexHook"; +import { useTPessoaSaveHook } from "../../../_hooks/t_pessoa/useTPessoaSaveHook"; +import { useTPessoaDeleteHook } from "../../../_hooks/t_pessoa/useTPessoaDeleteHook"; + +import ConfirmDialog from "@/app/_components/confirm_dialog/ConfirmDialog"; +import { useConfirmDialog } from "@/app/_components/confirm_dialog/useConfirmDialog"; + +import TPessoaInterface from "../../../_interfaces/TPessoaInterface"; +import Header from "@/app/_components/structure/Header"; +import { ColumnDef, ColumnFiltersState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, RowSelectionState, SortingState, useReactTable, VisibilityState } from "@tanstack/react-table"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Button } from "@/components/ui/button"; +import { ArrowUpDownIcon, EllipsisIcon, MoreHorizontalIcon, PencilIcon, Trash2Icon } from "lucide-react"; +import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; +import { TPessoaIndexData } from "../../../_data/TPessoa/TPessoaIndexData"; +import { Input } from "@/components/ui/input"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; +import GetNameInitials from "@/actions/text/GetNameInitials"; + +const pessoas = await TPessoaIndexData(); + +const columns: ColumnDef[] = [ + + // ID + { + accessorKey: "pessoa_id", + header: ({ column }) => ( + + ), + cell: ({ row }) => ( + Number(row.getValue("pessoa_id")) + ), + }, + + // Nome / Email / Foto + { + id: "nome_completo", + header: ({ column }) => ( + + ), + accessorFn: (row) => row, + cell: ({ row }) => { + const pessoa = row.original; + return ( +
+
+ {pessoa.foto ? ( + {pessoa.nome + ) : ( + + {GetNameInitials(pessoa.nome)} + + )} +
+
+
+ {pessoa.nome || "-"} +
+
{pessoa.email || "-"}
+
+
+ ); + }, + sortingFn: (a, b) => { + const nameA = a.original.nome?.toLowerCase() || ""; + const nameB = b.original.nome?.toLowerCase() || ""; + return nameA.localeCompare(nameB); + }, + }, + + // CPF + { + accessorKey: "cpf_cnpj", + header: ({ column }) => ( + + ), + cell: ({ row }) => ( + row.getValue("cpf_cnpj") + ), + }, + + // Telefone + { + accessorKey: "telefone", + header: ({ column }) => ( + + ), + cell: ({ row }) => ( + {row.getValue("telefone") || "-"} + ), + }, + + // Cidade / UF + { + id: "cidade_uf", + header: ({ column }) => ( + + + ), + accessorFn: (row) => `${row.cidade}/${row.uf}`, + cell: ({ row }) => {row.getValue("cidade_uf") || "-"}, + sortingFn: (a, b) => { + const cityA = `${a.original.cidade}/${a.original.uf}`.toLowerCase(); + const cityB = `${b.original.cidade}/${b.original.uf}`.toLowerCase(); + return cityA.localeCompare(cityB); + }, + }, + + // Data de cadastro + { + accessorKey: "data_cadastro", + header: ({ column }) => ( + + ), + cell: ({ row }) => {row.getValue("data_cadastro") || "-"}, + sortingFn: "datetime", // você pode usar função própria se precisar + }, + + // Ações (não ordenável) + { + id: "actions", + header: "Actions", + cell: ({ row }) => { + const pessoa = row.original; + return ( + + + + + + + + { }}> + + Editar + + + + + { }} + > + + Remover + + + + + ); + }, + enableSorting: false, + enableHiding: false, + }, +]; + + +export default function TPessoaFisica() { + + // Controle de estado do botão + const [buttonIsLoading, setButtonIsLoading] = useState(false); + + // Hooks para leitura e salvamento + const { tPessoa, fetchTPessoa } = useTPessoaIndexHook(); + const { saveTCensec } = useTPessoaSaveHook(); + const { deleteTCensec } = useTPessoaDeleteHook(); + + // Estados + const [selectedAndamento, setSelectedAndamento] = useState(null); + const [isFormOpen, setIsFormOpen] = useState(false); + + // Estado para saber qual item será deletado + const [itemToDelete, setItemToDelete] = useState(null); + + /** + * Hook do modal de confirmação + */ + const { + isOpen: isConfirmOpen, + openDialog: openConfirmDialog, + handleConfirm, + handleCancel, + } = useConfirmDialog(); + + /** + * Abre o formulário no modo de edição ou criação + */ + const handleOpenForm = useCallback((data: TPessoaInterface | null) => { + setSelectedAndamento(data); + setIsFormOpen(true); + }, []); + + /** + * Fecha o formulário e limpa o andamento selecionado + */ + const handleCloseForm = useCallback(() => { + setSelectedAndamento(null); + setIsFormOpen(false); + }, []); + + /** + * Salva os dados do formulário + */ + const handleSave = useCallback(async (formData: TPessoaInterface) => { + + // Coloca o botão em estado de loading + setButtonIsLoading(true); + + // Aguarda salvar o registro + await saveTCensec(formData); + + // Remove o botão em estado de loading + setButtonIsLoading(false); + + // Atualiza a lista de dados + fetchTPessoa(); + + }, [saveTCensec, fetchTPessoa, handleCloseForm]); + + /** + * Quando o usuário clica em "remover" na tabela + */ + const handleConfirmDelete = useCallback((item: TPessoaInterface) => { + + // Define o item atual para remoção + setItemToDelete(item); + + // Abre o modal de confirmação + openConfirmDialog(); + + }, [openConfirmDialog]); + + /** + * Executa a exclusão de fato quando o usuário confirma + */ + const handleDelete = useCallback(async () => { + + // Protege contra null + if (!itemToDelete) return; + + // Executa o Hook de remoção + await deleteTCensec(itemToDelete); + + // Atualiza a lista + await fetchTPessoa(); + + // Limpa o item selecionado + setItemToDelete(null); + + // Fecha o modal + handleCancel(); + + }, [itemToDelete, fetchTPessoa, handleCancel]); + + /** + * Busca inicial dos dados + */ + useEffect(() => { + fetchTPessoa(); + }, []); + + const [sorting, setSorting] = React.useState([]); + const [columnFilters, setColumnFilters] = React.useState([]); + const [columnVisibility, setColumnVisibility] = React.useState({}); + const [rowSelection, setRowSelection] = React.useState({}); + + const table = useReactTable({ + data: pessoas.data, + columns, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + onSortingChange: setSorting, + onColumnFiltersChange: setColumnFilters, + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + getCoreRowModel: getCoreRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getPaginationRowModel: getPaginationRowModel(), + }); + + + /** + * Tela de loading enquanto carrega os dados + */ + if (tPessoa.length == 0) { + return ; + } + + return ( +
+ {/* Cabeçalho */} +
{ handleOpenForm(null) }} + /> + + {/* Filtro */} +
+ table.getColumn("nome_completo")?.setFilterValue(e.target.value)} + className="w-full" + /> + + + + + + {table + .getAllColumns() + .filter((col) => col.getCanHide()) + .map((col) => ( + col.toggleVisibility(!!v)} + > + {col.id} + + ))} + + +
+ + {/* Tabela */} +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + {header.isPlaceholder + ? null + : flexRender(header.column.columnDef.header, header.getContext())} + + ))} + + ))} + + + {table.getRowModel().rows.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + Nenhum resultado encontrado. + + + )} + +
+
+ + {/* Paginação */} +
+ + +
+ + {/* Modal de confirmação */} + + + {/* Formulário de criação/edição */} + +
+ ); +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/(t_pessoa)/pessoa/fisica/page.tsx b/src/app/(protected)/(cadastros)/cadastros/(t_pessoa)/pessoa/fisica/page.tsx index ad8259d..d1fbbaa 100644 --- a/src/app/(protected)/(cadastros)/cadastros/(t_pessoa)/pessoa/fisica/page.tsx +++ b/src/app/(protected)/(cadastros)/cadastros/(t_pessoa)/pessoa/fisica/page.tsx @@ -1,7 +1,6 @@ 'use client'; import React, { useEffect, useState, useCallback } from "react"; -import { Card, CardContent } from "@/components/ui/card"; import Loading from "@/app/_components/loading/loading"; import TPessoaTable from "../../../_components/t_pessoa/TPessoaTable"; @@ -16,159 +15,6 @@ import { useConfirmDialog } from "@/app/_components/confirm_dialog/useConfirmDia import TPessoaInterface from "../../../_interfaces/TPessoaInterface"; import Header from "@/app/_components/structure/Header"; -import { ColumnDef, ColumnFiltersState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, RowSelectionState, SortingState, useReactTable, VisibilityState } from "@tanstack/react-table"; -import { Checkbox } from "@/components/ui/checkbox"; -import { Button } from "@/components/ui/button"; -import { ArrowUpDownIcon, EllipsisIcon, MoreHorizontalIcon, PencilIcon, Trash2Icon } from "lucide-react"; -import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; -import { TPessoaIndexData } from "../../../_data/TPessoa/TPessoaIndexData"; -import { Input } from "@/components/ui/input"; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; -import GetNameInitials from "@/actions/text/GetNameInitials"; - -const pessoas = await TPessoaIndexData(); - -// Definição de colunas -const columns: ColumnDef[] = [ - { - id: "select", - header: ({ table }) => ( - table.toggleAllPageRowsSelected(!!value)} - aria-label="Select all rows" - /> - ), - cell: ({ row }) => ( - row.toggleSelected(!!value)} - aria-label={`Select row ${row.index}`} - /> - ), - enableSorting: false, - enableHiding: false, - }, - { - accessorKey: "#", - header: ({ column }) => ( - - ), - cell: ({ row }) => {row.getValue("pessoa_id") || ''}, - }, - { - accessorKey: "foto_nome_email", - header: ({ column }) => ( - - ), - cell: ({ row }) => ( -
- {/* Avatar */} -
- {row.getValue("foto") ? ( - {row.getValue("nome") - ) : ( - - {GetNameInitials(row.getValue("nome"))} - - )} -
- {/* Nome e Email */} -
-
- {row.getValue("nome") || "-"} -
-
- {row.getValue("email") || "-"} -
-
-
- ), - }, - { - accessorKey: "cpf", - header: ({ column }) => ( - - ), - cell: ({ row }) => ( - row.getValue("cpf_cnpj") - ), - }, - { - accessorKey: "telefone", - header: "Telefone", - cell: ({ row }) => ( - {row.getValue("telefone")} - ), - }, - { - accessorKey: "cidade_uf", - header: "Cidade/UF", - cell: ({ row }) => ( - row.getValue("cidade") + "/" + row.getValue("uf") - ), - }, - { - accessorKey: "data_cadastro", - header: "Cadastro", - cell: ({ row }) => ( - row.getValue("data_cadastro") - ), - }, - { - id: "actions", - header: "Actions", - cell: ({ row }) => { - const pessoa = row.original; - return ( - - - - - - - - { }} - > - - Editar - - - - - { }} - > - - Remover - - - - - ); - }, - enableHiding: false, - }, -]; export default function TPessoaFisica() { @@ -274,31 +120,6 @@ export default function TPessoaFisica() { fetchTPessoa(); }, []); - const [sorting, setSorting] = React.useState([]); - const [columnFilters, setColumnFilters] = React.useState([]); - const [columnVisibility, setColumnVisibility] = React.useState({}); - const [rowSelection, setRowSelection] = React.useState({}); - - const table = useReactTable({ - data: pessoas.data, - columns, - state: { - sorting, - columnFilters, - columnVisibility, - rowSelection, - }, - onSortingChange: setSorting, - onColumnFiltersChange: setColumnFilters, - onColumnVisibilityChange: setColumnVisibility, - onRowSelectionChange: setRowSelection, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - getFilteredRowModel: getFilteredRowModel(), - getPaginationRowModel: getPaginationRowModel(), - }); - - /** * Tela de loading enquanto carrega os dados */ @@ -316,113 +137,12 @@ export default function TPessoaFisica() { buttonAction={() => { handleOpenForm(null) }} /> - {/* Tabela de andamentos */} - - - - - - -
- {/* Filtro */} -
- table.getColumn("foto_nome_email")?.setFilterValue(e.target.value)} - className="max-w-sm" - /> - - - - - - {table - .getAllColumns() - .filter((col) => col.getCanHide()) - .map((col) => ( - col.toggleVisibility(!!v)} - > - {col.id} - - ))} - - -
- - {/* Tabela */} -
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - - {header.isPlaceholder - ? null - : flexRender(header.column.columnDef.header, header.getContext())} - - ))} - - ))} - - - {table.getRowModel().rows.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender(cell.column.columnDef.cell, cell.getContext())} - - ))} - - )) - ) : ( - - - Nenhum resultado encontrado. - - - )} - -
- -
- - {/* Paginação */} -
- - -
- - {/* Quantidade de linhas selecionadas */} -
- {Object.keys(rowSelection).length} de {table.getFilteredRowModel().rows.length} selecionadas -
-
+ {/* Tabela de Registros */} + { }} + onEdit={() => { }} + /> {/* Modal de confirmação */} void; + onDelete: (item: TPessoaInterface, isEditingFormStatus: boolean) => void; +} + +/** + * Renderiza o badge de situação + */ +function StatusBadge({ situacao }: { situacao: string }) { + const isActive = situacao === "A"; + + const baseClasses = + "text-xs font-medium px-2.5 py-0.5 rounded-sm me-2"; + + const activeClasses = + "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300"; + + const inactiveClasses = + "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300"; + + return ( + + {isActive ? "Ativo" : "Inativo"} + + ); +} + +export default function TCensecTable({ + data, + onEdit, + onDelete +}: TPessoaTableProps) { + return ( + + + + # + Tipo + + Nome / Email + + CPF / CNPJ + Telefone + Cidade / UF + Data Cadastro + Status + Ações + + + + + {data.map((item) => ( + + {/* ID */} + + {Number(item.pessoa_id)} + + + {/* Tipo de pessoa */} + + + {item.pessoa_tipo === "F" ? "Física" : "Jurídica"} + + + + {/* Nome e Email*/} + +
+ {/* Avatar */} +
+ {item?.foto ? ( + {item.nome + ) : ( + + {item.nome + ? item.nome + .split(" ") + .slice(0, 2) // Pega no máximo 2 palavras + .map((n) => n[0]) + .join("") + .toUpperCase() + : "?"} + + )} +
+ + {/* Nome e Email */} +
+
+ {item.nome || "-"} +
+
+ {item.email || "-"} +
+
+
+
+ + {/* CPF/CNPJ */} + + {item.cpf_cnpj + ? item.pessoa_tipo === "F" + ? item.cpf_cnpj.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, "$1.$2.$3-$4") + : item.cpf_cnpj.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, "$1.$2.$3/$4-$5") + : "-"} + + + {/* Telefone */} + + {item.telefone + ? `(${item.ddd || ""}) ${item.telefone.replace(/(\d{5})(\d{4})/, "$1-$2")}` + : "-"} + + + {/* Cidade / UF */} + + {item.cidade && item.uf ? `${item.cidade} - ${item.uf}` : "-"} + + + {/* Data Cadastro */} + + {item.data_cadastro + ? new Date(item.data_cadastro).toLocaleDateString("pt-BR") + : "-"} + + + {/* Status (Exemplo: enviado_cnncnb) */} + + + {item.enviado_cnncnb ? "Enviado" : "Pendente"} + + + + {/* Ações */} + + + + + + + + + onEdit(item, true)} + > + + Editar + + + + + onDelete(item, true)} + > + + Remover + + + + + +
+ ))} +
+
+ + ); +} diff --git a/src/app/(protected)/(cadastros)/cadastros/_components/t_pessoa/TPessoaTable.tsx b/src/app/(protected)/(cadastros)/cadastros/_components/t_pessoa/TPessoaTable.tsx index 2a8641b..12c426b 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_components/t_pessoa/TPessoaTable.tsx +++ b/src/app/(protected)/(cadastros)/cadastros/_components/t_pessoa/TPessoaTable.tsx @@ -18,8 +18,11 @@ import { TableRow } from "@/components/ui/table"; -import { EllipsisIcon, PencilIcon, Trash2Icon } from "lucide-react"; +import { ArrowUpDownIcon, EllipsisIcon, PencilIcon, Trash2Icon } from "lucide-react"; import TPessoaInterface from "../../_interfaces/TPessoaInterface"; +import { TPessoaIndexData } from "../../_data/TPessoa/TPessoaIndexData"; +import { ColumnDef } from "@tanstack/react-table"; +import GetNameInitials from "@/actions/text/GetNameInitials"; interface TPessoaTableProps { data: TPessoaInterface[]; @@ -27,191 +30,188 @@ interface TPessoaTableProps { onDelete: (item: TPessoaInterface, isEditingFormStatus: boolean) => void; } -/** - * Renderiza o badge de situação - */ -function StatusBadge({ situacao }: { situacao: string }) { - const isActive = situacao === "A"; +const pessoas = await TPessoaIndexData(); - const baseClasses = - "text-xs font-medium px-2.5 py-0.5 rounded-sm me-2"; +const columns: ColumnDef[] = [ - const activeClasses = - "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300"; + // ID + { + accessorKey: "pessoa_id", + header: ({ column }) => ( + + ), + cell: ({ row }) => ( + Number(row.getValue("pessoa_id")) + ), + }, - const inactiveClasses = - "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300"; + // Nome / Email / Foto + { + id: "nome_completo", + header: ({ column }) => ( + + ), + accessorFn: (row) => row, + cell: ({ row }) => { + const pessoa = row.original; + return ( +
+
+ {pessoa.foto ? ( + {pessoa.nome + ) : ( + + {GetNameInitials(pessoa.nome)} + + )} +
+
+
+ {pessoa.nome || "-"} +
+
{pessoa.email || "-"}
+
+
+ ); + }, + sortingFn: (a, b) => { + const nameA = a.original.nome?.toLowerCase() || ""; + const nameB = b.original.nome?.toLowerCase() || ""; + return nameA.localeCompare(nameB); + }, + }, - return ( - - {isActive ? "Ativo" : "Inativo"} - - ); -} + // CPF + { + accessorKey: "cpf_cnpj", + header: ({ column }) => ( + + ), + cell: ({ row }) => ( + row.getValue("cpf_cnpj") + ), + }, -export default function TCensecTable({ + // Telefone + { + accessorKey: "telefone", + header: ({ column }) => ( + + ), + cell: ({ row }) => ( + {row.getValue("telefone") || "-"} + ), + }, + + // Cidade / UF + { + id: "cidade_uf", + header: ({ column }) => ( + + + ), + accessorFn: (row) => `${row.cidade}/${row.uf}`, + cell: ({ row }) => {row.getValue("cidade_uf") || "-"}, + sortingFn: (a, b) => { + const cityA = `${a.original.cidade}/${a.original.uf}`.toLowerCase(); + const cityB = `${b.original.cidade}/${b.original.uf}`.toLowerCase(); + return cityA.localeCompare(cityB); + }, + }, + + // Data de cadastro + { + accessorKey: "data_cadastro", + header: ({ column }) => ( + + ), + cell: ({ row }) => {row.getValue("data_cadastro") || "-"}, + sortingFn: "datetime", // você pode usar função própria se precisar + }, + + // Ações (não ordenável) + { + id: "actions", + header: "Actions", + cell: ({ row }) => { + const pessoa = row.original; + return ( + + + + + + + + { }}> + + Editar + + + + + { }} + > + + Remover + + + + + ); + }, + enableSorting: false, + enableHiding: false, + }, +]; + +export default function TPessoaTable({ data, onEdit, onDelete }: TPessoaTableProps) { return ( - - - - # - Tipo - - Nome / Email - - CPF / CNPJ - Telefone - Cidade / UF - Data Cadastro - Status - Ações - - - - - {data.map((item) => ( - - {/* ID */} - - {Number(item.pessoa_id)} - - - {/* Tipo de pessoa */} - - - {item.pessoa_tipo === "F" ? "Física" : "Jurídica"} - - - - {/* Nome e Email*/} - -
- {/* Avatar */} -
- {item?.foto ? ( - {item.nome - ) : ( - - {item.nome - ? item.nome - .split(" ") - .slice(0, 2) // Pega no máximo 2 palavras - .map((n) => n[0]) - .join("") - .toUpperCase() - : "?"} - - )} -
- - {/* Nome e Email */} -
-
- {item.nome || "-"} -
-
- {item.email || "-"} -
-
-
-
- - {/* CPF/CNPJ */} - - {item.cpf_cnpj - ? item.pessoa_tipo === "F" - ? item.cpf_cnpj.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, "$1.$2.$3-$4") - : item.cpf_cnpj.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, "$1.$2.$3/$4-$5") - : "-"} - - - {/* Telefone */} - - {item.telefone - ? `(${item.ddd || ""}) ${item.telefone.replace(/(\d{5})(\d{4})/, "$1-$2")}` - : "-"} - - - {/* Cidade / UF */} - - {item.cidade && item.uf ? `${item.cidade} - ${item.uf}` : "-"} - - - {/* Data Cadastro */} - - {item.data_cadastro - ? new Date(item.data_cadastro).toLocaleDateString("pt-BR") - : "-"} - - - {/* Status (Exemplo: enviado_cnncnb) */} - - - {item.enviado_cnncnb ? "Enviado" : "Pendente"} - - - - {/* Ações */} - - - - - - - - - onEdit(item, true)} - > - - Editar - - - - - onDelete(item, true)} - > - - Remover - - - - - -
- ))} -
-
- +
+ aqui +
); } diff --git a/src/app/(protected)/(cadastros)/cadastros/_interfaces/TPessoaInterface.ts b/src/app/(protected)/(cadastros)/cadastros/_interfaces/TPessoaInterface.ts index 5f66fd9..6087a8b 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_interfaces/TPessoaInterface.ts +++ b/src/app/(protected)/(cadastros)/cadastros/_interfaces/TPessoaInterface.ts @@ -59,4 +59,5 @@ export default interface TPessoaInterface { tb_tipologradouro_id?: number; unidade?: string; numero_end?: string; + foto?: string; } \ No newline at end of file diff --git a/src/app/_components/dataTable/dataTable.tsx b/src/app/_components/dataTable/dataTable.tsx new file mode 100644 index 0000000..fb26950 --- /dev/null +++ b/src/app/_components/dataTable/dataTable.tsx @@ -0,0 +1,134 @@ +import { Button } from "@/components/ui/button"; +import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; +import { Input } from "@/components/ui/input"; +import { Table, TableBody, TableCell, TableHeader, TableRow } from "@/components/ui/table"; +import { ColumnFiltersState, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, RowSelectionState, SortingState, useReactTable, VisibilityState } from "@tanstack/react-table"; +import React from "react"; + +interface dataTableProps { + data: any, + columns: any +} + +export default function dataTable({ data, columns }, dataTableProps) { + + const [sorting, setSorting] = React.useState([]); + const [columnFilters, setColumnFilters] = React.useState([]); + const [columnVisibility, setColumnVisibility] = React.useState({}); + const [rowSelection, setRowSelection] = React.useState({}); + + const table = useReactTable({ + data: data, + columns, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + onSortingChange: setSorting, + onColumnFiltersChange: setColumnFilters, + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + getCoreRowModel: getCoreRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getPaginationRowModel: getPaginationRowModel(), + }); + + + return ( +
+ + {/* Filtro */} +
+ table.getColumn("nome_completo")?.setFilterValue(e.target.value)} + className="w-full" + /> + + + + + + {table + .getAllColumns() + .filter((col) => col.getCanHide()) + .map((col) => ( + col.toggleVisibility(!!v)} + > + {col.id} + + ))} + + +
+ + {/* Tabela */} +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + {header.isPlaceholder + ? null + : flexRender(header.column.columnDef.header, header.getContext())} + + ))} + + ))} + + + {table.getRowModel().rows.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + Nenhum resultado encontrado. + + + )} + +
+
+ + {/* Paginação */} +
+ + +
+ +
+ ); +} \ No newline at end of file