-
-
Save saulin18/18137b3f3b5472f36bdfdb1e898147b3 to your computer and use it in GitHub Desktop.
Generic Table used in Merco Sistema at NOX Creation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // This is an example table using the GenericTableComponent.tsx | |
| // mockData is generated randomly | |
| import { Image, Text, Checkbox, Badge, Box, Flex } from "@chakra-ui/react"; | |
| import { ColumnDef } from "@tanstack/react-table"; | |
| import React from "react"; | |
| import GenericTable from "@/frontend/core/components/GenericTable"; | |
| import TransitActionsButtonGroup from "./TransitTableActions"; | |
| import { formatDate } from "@/frontend/core/utils/formatDate"; | |
| import { ChevronDownIcon, ChevronRightIcon } from "@chakra-ui/icons"; | |
| import TransitTableActions from "./TransitTableActions"; | |
| const mockData: MerchancyItem[] = [ | |
| { | |
| id: "001", | |
| category: "Electrónica", | |
| product: "Laptop Dell XPS 13", | |
| deliveryDate: new Date("2024-07-15"), | |
| paymentDate: new Date("2024-08-01"), | |
| quantity: 1, | |
| amount: "USD", | |
| amortized: "Pagado", | |
| type: "Compra", | |
| }, | |
| { | |
| id: "002", | |
| category: "Libros", | |
| product: "El Principito", | |
| deliveryDate: new Date("2024-06-20"), | |
| quantity: 3, | |
| amount: "USD", | |
| amortized: "Pendiente", | |
| type: "Venta", | |
| subRows: [ | |
| { | |
| id: "002a", | |
| category: "Libros", | |
| product: "El Principito - Edición Especial", | |
| deliveryDate: new Date("2024-06-22"), | |
| quantity: 1, | |
| amount: "USD", | |
| amortized: "Pendiente", | |
| type: "Venta", | |
| }, | |
| ], | |
| }, | |
| { | |
| id: "003", | |
| category: "Ropa", | |
| product: "Camiseta Manga Larga", | |
| deliveryDate: new Date("2024-07-10"), | |
| paymentDate: new Date("2024-07-30"), | |
| quantity: 5, | |
| amount: "USD", | |
| amortized: "Pagado", | |
| type: "Compra", | |
| }, | |
| { | |
| id: "004", | |
| category: "Herramientas", | |
| product: "Martillo", | |
| deliveryDate: new Date("2024-05-25"), | |
| quantity: 2, | |
| amount: "USD", | |
| amortized: "Pendiente", | |
| type: "Compra", | |
| }, | |
| { | |
| id: "005", | |
| category: "Jardín", | |
| product: "Regadera", | |
| deliveryDate: new Date("2024-06-01"), | |
| paymentDate: new Date("2024-06-15"), | |
| quantity: 1, | |
| amount: "USD", | |
| amortized: "Pagado", | |
| type: "Venta", | |
| subRows: [ | |
| { | |
| id: "005a", | |
| category: "Jardín", | |
| product: "Manguera", | |
| deliveryDate: new Date("2024-06-03"), | |
| quantity: 1, | |
| amount: "USD", | |
| amortized: "Pagado", | |
| type: "Venta", | |
| }, | |
| ], | |
| }, | |
| ]; | |
| type MerchancyItem = { | |
| id: string; | |
| category: string; | |
| product: string; | |
| deliveryDate: Date; | |
| paymentDate?: Date; | |
| quantity: number; | |
| amount: string; | |
| amortized: "Pagado" | "Pendiente"; | |
| type: string; | |
| subRows?: MerchancyItem[]; | |
| }; | |
| interface Props {} | |
| export default function TransitTable({}: Props) { | |
| const page = 1; | |
| const pageSize = 10; | |
| const columns: ColumnDef<MerchancyItem>[] = React.useMemo( | |
| () => [ | |
| { | |
| header: ({ table }) => ( | |
| <Checkbox | |
| size={"sm"} | |
| colorScheme="cyan" | |
| isChecked={table.getIsAllRowsSelected()} | |
| isIndeterminate={table.getIsSomeRowsSelected()} | |
| onChange={(event) => { | |
| table.toggleAllRowsSelected(event.target.checked); | |
| }} | |
| > | |
| Id | |
| </Checkbox> | |
| ), | |
| accessorKey: "code", | |
| cell: ({ row, getValue }) => ( | |
| <Flex alignItems={"center"} gap={"10px"}> | |
| <Checkbox | |
| size={"sm"} | |
| colorScheme="cyan" | |
| type="checkbox" | |
| isChecked={row.getIsSelected()} | |
| onChange={(event) => row.toggleSelected(event.target.checked)} | |
| > | |
| {getValue<string>()} | |
| </Checkbox> | |
| {row.getCanExpand() && ( | |
| <Box onClick={() => row.toggleExpanded()} cursor={"pointer"}> | |
| {row.getIsExpanded() ? ( | |
| <ChevronDownIcon /> | |
| ) : ( | |
| <ChevronRightIcon /> | |
| )} | |
| </Box> | |
| )} | |
| </Flex> | |
| ), | |
| }, | |
| { | |
| header: "Categoria", | |
| accessorKey: "category", | |
| }, | |
| { | |
| header: "Producto", | |
| accessorKey: "product", | |
| }, | |
| { | |
| header: "Fecha de entrega", | |
| accessorKey: "deliveryDate", | |
| cell: (date) => formatDate(date.getValue<Date>()), | |
| }, | |
| { | |
| header: "Fecha Pago", | |
| accessorKey: "paymentDate", | |
| cell: (date) => formatDate(date.getValue<Date>()), | |
| }, | |
| { | |
| header: "Cantidad", | |
| accessorKey: "quantity", | |
| }, | |
| { | |
| header: "Importe", | |
| accessorKey: "amount", | |
| cell: (amount) => <Badge>{amount.getValue<string>()}</Badge>, | |
| }, | |
| { | |
| header: "Amortizado", | |
| accessorKey: "amortized", | |
| cell: (amortized) => ( | |
| <Badge | |
| boxShadow={"none"} | |
| backgroundColor={ | |
| amortized.getValue<string>() === "Pagado" | |
| ? "green.500" | |
| : "red.500" | |
| } | |
| color={"white"} | |
| > | |
| {amortized.getValue<string>()} | |
| </Badge> | |
| ), | |
| }, | |
| { | |
| header: "Tipo", | |
| accessorKey: "type", | |
| }, | |
| { | |
| id: "actions", | |
| cell: (props) => <TransitTableActions />, | |
| }, | |
| ], | |
| [] | |
| ); | |
| return ( | |
| <GenericTable | |
| onFind={() => {}} | |
| columns={columns} | |
| data={mockData} | |
| title="Mercancías en Tránsito" | |
| pagination={{ | |
| count: 10, | |
| page, | |
| pageSize, | |
| }} | |
| /> | |
| ); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Generic Table using Tantack Table lib | |
| // WARNING: Pagination support is managed by other developer | |
| // Tanstack offers support for pagination too, next time that I use this feature | |
| // find in tanstack docs for pagination support instead of implement my own like this | |
| import { | |
| ColumnDef, | |
| flexRender, | |
| getCoreRowModel, | |
| getExpandedRowModel, | |
| getSortedRowModel, | |
| useReactTable, | |
| } from "@tanstack/react-table"; | |
| import { | |
| Box, | |
| Flex, | |
| Text, | |
| Table, | |
| TableContainer, | |
| Tbody, | |
| Td, | |
| Th, | |
| Thead, | |
| Tr, | |
| Stack, | |
| } from "@chakra-ui/react"; | |
| import React, { useEffect } from "react"; | |
| import { SearchIcon } from "@chakra-ui/icons"; | |
| import OrderByIcon from "../icons/OrderByIcon"; | |
| import ExportableTableContainer from "./ExportableTableContainer"; | |
| import SearchIconButton from "./SearchIconButton"; | |
| import { Pagination } from "./Pagination"; | |
| import TableFilterCount from "./TableFilterCount"; | |
| interface Props<T> { | |
| title: string; | |
| noExportable?: boolean; | |
| columns: ColumnDef<T>[]; | |
| data: T[]; | |
| pagination: { | |
| count: number; | |
| page: number; | |
| pageSize: number; | |
| onChange?: (e: number) => void; | |
| }; | |
| onChangeFilterCount?: (e: number) => void; | |
| onSelectItems?: (items: Array<any>) => void; | |
| onFind?: (column: string, value: string) => void; | |
| onDownloadExcel?: () => void; | |
| } | |
| // IMPORTANTE: La columna de acciones debe tener como id: "actions" | |
| // para que no tenga header | |
| interface RowWithSubItems { | |
| subRows?: []; | |
| } | |
| export default function GenericTable<T>({ | |
| data, | |
| title, | |
| columns, | |
| pagination, | |
| onChangeFilterCount, | |
| onSelectItems, | |
| onFind, | |
| onDownloadExcel, | |
| noExportable = false, | |
| }: Props<T>) { | |
| const { getRowModel, getHeaderGroups, getSelectedRowModel, toggleAllRowsSelected } = useReactTable({ | |
| data: data, | |
| columns: columns, | |
| getCoreRowModel: getCoreRowModel(), | |
| getSortedRowModel: getSortedRowModel(), | |
| getExpandedRowModel: getExpandedRowModel(), | |
| getSubRows: (row) => (row as RowWithSubItems).subRows, | |
| enableExpanding: true, | |
| enableRowSelection: true, | |
| }); | |
| useEffect(()=>{ | |
| toggleAllRowsSelected(false) | |
| }, [data]) | |
| useEffect(() => { | |
| if (onSelectItems) | |
| onSelectItems(getSelectedRowModel().rows.map((t) => t.original)); | |
| }, [getSelectedRowModel()]); | |
| const tableContent = ( | |
| <TableContainer> | |
| <Table fontSize={"13px"} minH={"100px"} variant={"striped"}> | |
| <Thead position="sticky" top={0} bg={"white"}> | |
| {getHeaderGroups().map((headerGroup) => ( | |
| <Tr key={headerGroup.id}> | |
| {headerGroup.headers.map((header, i) => ( | |
| <Th | |
| key={header.id} | |
| justifyContent={"space-between"} | |
| alignItems={"center"} | |
| cursor={"pointer"} | |
| > | |
| {header.id !== "actions" && ( | |
| <Flex width={"full"} justifyContent={"space-between"}> | |
| <Text lineHeight={2}> | |
| {flexRender( | |
| header.column.columnDef.header, | |
| header.getContext() | |
| )} | |
| </Text> | |
| {columns[i].id && ( | |
| <Flex alignItems={"center"} gap={"2px"}> | |
| <Box onClick={() => header.column.toggleSorting()}> | |
| <OrderByIcon /> | |
| </Box> | |
| <Box> | |
| <SearchIconButton | |
| ButtonIcon={<SearchIcon />} | |
| onFind={onFind} | |
| column_name={columns[i].id as string} | |
| /> | |
| </Box> | |
| </Flex> | |
| )} | |
| </Flex> | |
| )} | |
| </Th> | |
| ))} | |
| </Tr> | |
| ))} | |
| </Thead> | |
| <Tbody> | |
| {getRowModel().rows.map((row) => ( | |
| <React.Fragment key={row.id}> | |
| <Tr | |
| key={row.id} | |
| borderColor={"red.400 !important"} | |
| borderY={"none"} /* row.getIsSelected() ? "2px solid" : */ | |
| > | |
| {row.getVisibleCells().map((cell) => ( | |
| <Td key={cell.id}> | |
| {flexRender(cell.column.columnDef.cell, cell.getContext())} | |
| </Td> | |
| ))} | |
| </Tr> | |
| {row.subRows.map( | |
| (subRow) => | |
| row.getIsExpanded() && ( | |
| <Tr | |
| key={subRow.id} | |
| borderColor={"red.400!important"} | |
| borderY={"none"} | |
| > | |
| {subRow.getVisibleCells().map((cell) => ( | |
| <Td key={cell.id}> | |
| {flexRender( | |
| cell.column.columnDef.cell, | |
| cell.getContext() | |
| )} | |
| </Td> | |
| ))} | |
| </Tr> | |
| ) | |
| )} | |
| </React.Fragment> | |
| ))} | |
| </Tbody> | |
| </Table> | |
| </TableContainer> | |
| ); | |
| const paginationElement = ( | |
| <React.Fragment> | |
| {data.length > 0 && ( | |
| <Pagination | |
| count={pagination.count} | |
| pageSize={pagination.pageSize} | |
| /* siblingCount={2} */ | |
| page={pagination.page} | |
| onChange={(e) => { | |
| if (pagination.onChange) { | |
| pagination.onChange(e.page); | |
| window.scrollTo({ | |
| top: 0, | |
| left: 0, | |
| behavior: "smooth", | |
| }); | |
| } | |
| }} | |
| /> | |
| )} | |
| </React.Fragment> | |
| ); | |
| if (!noExportable) | |
| return ( | |
| <ExportableTableContainer | |
| title={title} | |
| onChangeFilterCount={onChangeFilterCount} | |
| onDownloadExcel={onDownloadExcel} | |
| > | |
| {tableContent} | |
| {paginationElement} | |
| </ExportableTableContainer> | |
| ); | |
| if (noExportable) | |
| return ( | |
| <Stack spacing={1}> | |
| <TableFilterCount onChangeFilterCount={onChangeFilterCount} /> | |
| {tableContent} | |
| {paginationElement} | |
| </Stack> | |
| ); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment