diff --git a/.vscode/launch.json b/.vscode/launch.json index 709b87b..0b0a325 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,6 +10,12 @@ "webRoot": "${workspaceFolder}/client" }, + { + "name": "Launch Chrome localhost", + "type": "pwa-chrome", + "port": 9222 + }, + { "type": "msedge", "request": "launch", diff --git a/client/src/app/catalog/components/CatalogDataTable.tsx b/client/src/app/catalog/components/CatalogDataTable.tsx index 8806553..3948d77 100644 --- a/client/src/app/catalog/components/CatalogDataTable.tsx +++ b/client/src/app/catalog/components/CatalogDataTable.tsx @@ -1,22 +1,59 @@ +import { Card, CardContent } from "@/ui"; + +import { DataTableSkeleton, ErrorOverlay, SimpleEmptyState } from "@/components"; + import { DataTable } from "@/components"; -import { useDataTable } from "@/lib/hooks"; -import { IListArticles_Response_DTO, IListResponse_DTO } from "@shared/contexts"; +import { DataTableToolbar } from "@/components/DataTable/DataTableToolbar"; +import { useDataTable, useDataTableContext } from "@/lib/hooks"; +import { IListArticles_Response_DTO, MoneyValue } from "@shared/contexts"; +import { ColumnDef, Row } from "@tanstack/react-table"; +import { t } from "i18next"; import { useMemo } from "react"; +import { useNavigate } from "react-router-dom"; +import { useCatalogList } from "../hooks"; -type CatalogTableViewProps = { - data: IListResponse_DTO; -}; +export const CatalogDataTable = () => { + const navigate = useNavigate(); + const { pagination, globalFilter, isFiltered } = useDataTableContext(); + console.log("pagination PADRE => ", pagination); -export const CatalogDataTable = ({ data }: CatalogTableViewProps) => { - const columns = useMemo( + const { data, isPending, isError, error } = useCatalogList({ + pagination: { + pageIndex: pagination.pageIndex, + pageSize: pagination.pageSize, + }, + searchTerm: globalFilter, + }); + + const columns = useMemo[]>( () => [ { id: "description" as const, accessorKey: "description", - size: 400, - enableHiding: false, - enableSorting: false, + header: () => <>{t("catalog.list.columns.description")}, enableResizing: false, + size: 300, + }, + { + id: "points" as const, + accessorKey: "points", + header: () =>
{t("catalog.list.columns.points")}
, + cell: ({ renderValue }: { renderValue: () => any }) => ( +
{renderValue()}
+ ), + enableResizing: false, + size: 20, + }, + { + id: "retail_price" as const, + accessorKey: "retail_price", + header: () =>
{t("catalog.list.columns.retail_price")}
, + cell: ({ row }: { row: Row }) => { + const price = MoneyValue.create(row.original.retail_price).object; + return
{price.toFormat()}
; + }, + enableResizing: false, + size: 20, }, ], [] @@ -28,9 +65,41 @@ export const CatalogDataTable = ({ data }: CatalogTableViewProps) => { pageCount: data?.total_pages ?? -1, }); + if (isError) { + return ; + } + + if (isPending) { + return ( + + + + + + ); + } + + if (data?.total_items === 0 && !isFiltered) { + return ( + navigate("/catalog/add")} + /> + ); + } + return ( <> - + + + ); }; diff --git a/client/src/app/catalog/layout.tsx b/client/src/app/catalog/layout.tsx index ef401dc..8d3982b 100644 --- a/client/src/app/catalog/layout.tsx +++ b/client/src/app/catalog/layout.tsx @@ -1,6 +1,6 @@ import { Layout, LayoutContent, LayoutHeader } from "@/components"; -import { DataTableProvider } from "@/lib/hooks"; import { PropsWithChildren } from "react"; +import { Trans } from "react-i18next"; import { CatalogProvider } from "./CatalogContext"; export const CatalogLayout = ({ children }: PropsWithChildren) => { @@ -9,8 +9,14 @@ export const CatalogLayout = ({ children }: PropsWithChildren) => { - {children} +
+

+ +

+
+ {children}
+ 1
); diff --git a/client/src/app/catalog/list.tsx b/client/src/app/catalog/list.tsx index e2c9b8e..0bbce4a 100644 --- a/client/src/app/catalog/list.tsx +++ b/client/src/app/catalog/list.tsx @@ -28,108 +28,17 @@ import { import { File, ListFilter, MoreHorizontal, PlusCircle } from "lucide-react"; -import { DataTable, DataTableSkeleton, ErrorOverlay, SimpleEmptyState } from "@/components"; - -import { useDataTable, useDataTableContext } from "@/lib/hooks"; -import { useMemo } from "react"; +import { DataTableProvider } from "@/lib/hooks"; import { Trans } from "react-i18next"; -import { useNavigate } from "react-router-dom"; import { CatalogDataTable } from "./components"; -import { useCatalogList } from "./hooks/useCatalogList"; export const CatalogList = () => { - const navigate = useNavigate(); - - const { pagination } = useDataTableContext(); - console.log("pagination PADRE => ", pagination); - - const { data, isPending, isError, error, refetch } = useCatalogList({ - pagination: { - pageIndex: pagination.pageIndex, - pageSize: pagination.pageSize, - }, - }); - - const columns = useMemo( - () => [ - { - id: "description" as const, - accessorKey: "description", - size: 400, - enableHiding: false, - enableSorting: false, - enableResizing: false, - }, - ], - [] - ); - - const { table } = useDataTable({ - data: data?.items ?? [], - columns: columns, - pageCount: data?.total_pages ?? -1, - }); - - return ; - - if (isError || isPending) { - return <>; - } - return ( - <> - - {data.items.map((row) => ( -

{row.description}

- ))} - ; - + + + ); - if (isError) { - return ; - } - - if (isPending) { - return ( - - - - - - Manage your products and view their sales performance. - - - - - - ); - } - - if (data?.total_items === 0) { - return ( - navigate("/catalog/add")} - /> - ); - } - return ( <> diff --git a/client/src/components/DataTable/DataTable.tsx b/client/src/components/DataTable/DataTable.tsx index 6128cc3..b604fcd 100644 --- a/client/src/components/DataTable/DataTable.tsx +++ b/client/src/components/DataTable/DataTable.tsx @@ -9,12 +9,12 @@ import { TableHeader, TableRow, } from "@/ui/table"; -import { ReactNode } from "react"; +import { PropsWithChildren, ReactNode } from "react"; -import { Card, CardContent, CardFooter, CardHeader } from "@/ui"; +import { cn } from "@/lib/utils"; +import { Card, CardContent, CardDescription, CardFooter, CardHeader } from "@/ui"; import { DataTableColumnHeader } from "./DataTableColumnHeader"; import { DataTablePagination, DataTablePaginationProps } from "./DataTablePagination"; -import { DataTableToolbar } from "./DataTableToolbar"; export type DataTableColumnProps = ColumnDef; @@ -23,25 +23,31 @@ export type DataTablePaginationOptionsProps = Pick< "visible" >; -export type DataTableProps = { +export type DataTableProps = PropsWithChildren<{ table: ReactTable; caption?: ReactNode; - className?: string; - paginationOptions?: DataTablePaginationOptionsProps; -}; + className?: string; +}>; -export function DataTable({ table, caption, paginationOptions }: DataTableProps) { +export function DataTable({ + table, + caption, + paginationOptions, + children, + className, + ...props +}: DataTableProps) { return ( <> - - - + + + {children} + diff --git a/client/src/components/DataTable/DataTableColumnHeader.tsx b/client/src/components/DataTable/DataTableColumnHeader.tsx index 5b1d1d8..321cda1 100644 --- a/client/src/components/DataTable/DataTableColumnHeader.tsx +++ b/client/src/components/DataTable/DataTableColumnHeader.tsx @@ -10,15 +10,10 @@ import { DropdownMenuTrigger, Separator, } from "@/ui"; -import { - ArrowDownIcon, - ArrowDownUpIcon, - ArrowUpIcon, - EyeOffIcon, -} from "lucide-react"; +import { t } from "i18next"; +import { ArrowDownIcon, ArrowDownUpIcon, ArrowUpIcon, EyeOffIcon } from "lucide-react"; -interface DataTableColumnHeaderProps - extends React.HTMLAttributes { +interface DataTableColumnHeaderProps extends React.HTMLAttributes { table: Table; header: Header; } @@ -34,20 +29,21 @@ export function DataTableColumnHeader({
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
+ {header.column.getCanResize() && ( header.column.resetSize(), @@ -55,12 +51,9 @@ export function DataTableColumnHeader({ onTouchStart: header.getResizeHandler(), style: { transform: - table.options.columnResizeMode === "onEnd" && - header.column.getIsResizing() + table.options.columnResizeMode === "onEnd" && header.column.getIsResizing() ? `translateX(${ - (table.options.columnResizeDirection === "rtl" - ? -1 - : 1) * + (table.options.columnResizeDirection === "rtl" ? -1 : 1) * (table.getState().columnSizingInfo.deltaOffset ?? 0) }px)` : "", @@ -79,41 +72,67 @@ export function DataTableColumnHeader({ - - header.column.toggleSorting(false)}> - - Ascendente - - header.column.toggleSorting(true)}> - - Descendente - - + + {header.column.getCanSort() && ( + <> + header.column.toggleSorting(false)} + aria-label={t("common.sort_asc")} + > + + header.column.toggleSorting(true)} + aria-label={t("common.sort_desc")} + > + + + )} + + {header.column.getCanSort() && header.column.getCanHide() && } + {header.column.getCanHide() && ( header.column.toggleVisibility(false)} + aria-label={t("Hide")} > - - Ocultar + )} diff --git a/client/src/components/DataTable/DataTablePagination.tsx b/client/src/components/DataTable/DataTablePagination.tsx index 1066d27..39adbdc 100644 --- a/client/src/components/DataTable/DataTablePagination.tsx +++ b/client/src/components/DataTable/DataTablePagination.tsx @@ -2,6 +2,7 @@ import { DEFAULT_PAGE_SIZES, INITIAL_PAGE_INDEX } from "@/lib/hooks"; import { cn } from "@/lib/utils"; import { Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/ui"; import { Table } from "@tanstack/react-table"; +import { t } from "i18next"; import { ChevronLeftIcon, ChevronRightIcon, @@ -31,12 +32,15 @@ export function DataTablePagination({ return (
- {table.getFilteredSelectedRowModel().rows.length} de{" "} - {table.getFilteredRowModel().rows.length} filas(s) seleccionadas. + {t("common.rows_selected", { + count: table.getFilteredSelectedRowModel().rows.length, + total: table.getFilteredRowModel().rows.length, + })}
-

Filas por página

+

{t("common.rows_per_page")}

+
- Página {table.getState().pagination.pageIndex + 1} de {table.getPageCount()} + {t("common.num_page_of_total", { + count: table.getState().pagination.pageIndex + 1, + total: table.getPageCount(), + })}
diff --git a/client/src/components/DataTable/DataTableSkeleton.tsx b/client/src/components/DataTable/DataTableSkeleton.tsx index 30ff5b6..1773718 100644 --- a/client/src/components/DataTable/DataTableSkeleton.tsx +++ b/client/src/components/DataTable/DataTableSkeleton.tsx @@ -1,12 +1,5 @@ -import { - Skeleton, - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/ui"; +import { cn } from "@/lib/utils"; +import { Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/ui"; interface DataTableSkeletonProps { /** @@ -53,11 +46,20 @@ interface DataTableSkeletonProps { cellWidths?: string[]; /** - * Flag to prevent the table from shrinking to fit the content. + * Flag to show the pagination bar. + * @default true + * @type boolean | undefined + */ + withPagination?: boolean; + + /** + * Flag to prevent the table cells from shrinking. * @default false * @type boolean | undefined */ shrinkZero?: boolean; + + className?: string; } export function DataTableSkeleton({ @@ -67,32 +69,33 @@ export function DataTableSkeleton({ filterableColumnCount = 0, showViewOptions = true, cellWidths = ["auto"], + withPagination = true, shrinkZero = false, + className, + ...skeletonProps }: DataTableSkeletonProps) { return ( -
-
-
+
+
+
{searchableColumnCount > 0 ? Array.from({ length: searchableColumnCount }).map((_, i) => ( - + )) : null} {filterableColumnCount > 0 ? Array.from({ length: filterableColumnCount }).map((_, i) => ( - + )) : null}
- {showViewOptions ? ( - - ) : null} + {showViewOptions ? : null}
-
+
{Array.from({ length: 1 }).map((_, i) => ( - + {Array.from({ length: columnCount }).map((_, j) => ( - + ))} @@ -109,7 +112,7 @@ export function DataTableSkeleton({ {Array.from({ length: rowCount }).map((_, i) => ( - + {Array.from({ length: columnCount }).map((_, j) => ( - + ))} @@ -126,24 +129,26 @@ export function DataTableSkeleton({
-
- -
-
- - -
-
- -
-
- - - - + {withPagination ? ( +
+ +
+
+ + +
+
+ +
+
+ + + + +
-
+ ) : null}
); } diff --git a/client/src/components/DataTable/DataTableToolbar/DataTableToolbar.tsx b/client/src/components/DataTable/DataTableToolbar/DataTableToolbar.tsx index 28ee7d6..5dead1c 100644 --- a/client/src/components/DataTable/DataTableToolbar/DataTableToolbar.tsx +++ b/client/src/components/DataTable/DataTableToolbar/DataTableToolbar.tsx @@ -1,138 +1,54 @@ import { Table } from "@tanstack/react-table"; //import { priorities, statuses } from './Data' -import { DataTableFilterField } from "@/lib/types"; +import { DataTableFilterField, useDataTableContext } from "@/lib/hooks"; import { cn } from "@/lib/utils"; import { Button, Input } from "@/ui"; -import { CrossIcon } from "lucide-react"; -import { useMemo } from "react"; -import { DataTableFacetedFilter } from "../DataTableFacetedFilter"; +import { t } from "i18next"; +import { XIcon } from "lucide-react"; import { DataTableColumnOptions } from "./DataTableColumnOptions"; -interface DataTableToolbarProps - extends React.HTMLAttributes { +interface DataTableToolbarProps extends React.HTMLAttributes { table: Table; filterFields?: DataTableFilterField[]; } export function DataTableToolbar({ table, - filterFields = [], - children, className, + children, ...props }: DataTableToolbarProps) { - const isFiltered = table.getState().columnFilters.length > 0; - - // Memoize computation of searchableColumns and filterableColumns - const { searchableColumns, filterableColumns } = useMemo(() => { - return { - searchableColumns: filterFields.filter((field) => !field.options), - filterableColumns: filterFields.filter((field) => field.options), - }; - }, [filterFields]); + const { globalFilter, isFiltered, setGlobalFilter, resetGlobalFilter } = useDataTableContext(); return (
-
- {searchableColumns.length > 0 && - searchableColumns.map( - (column) => - table.getColumn(column.value ? String(column.value) : "") && ( - - table - .getColumn(String(column.value)) - ?.setFilterValue(event.target.value) - } - className="w-40 h-8 lg:w-64" - /> - ), - )} - {filterableColumns.length > 0 && - filterableColumns.map( - (column) => - table.getColumn(column.value ? String(column.value) : "") && ( - - ), - )} +
+ setGlobalFilter(String(event.target.value))} + className='w-3/12 h-8 lg:w-6/12' + /> + {isFiltered && ( - )}
-
+
{children} {table.options.enableHiding && }
); - - /* - return ( -
-
- - table.getColumn("customer")?.setFilterValue(event.target.value) - } - className="h-8 w-[150px] lg:w-[250px]" - /> - {table.getColumn("status") && ( - - )} - {table.getColumn("priority") && ( - - )} - {isFiltered && ( - - )} -
- -
- ) - */ } diff --git a/client/src/components/Layout/Layout.tsx b/client/src/components/Layout/Layout.tsx index 939034e..d308420 100644 --- a/client/src/components/Layout/Layout.tsx +++ b/client/src/components/Layout/Layout.tsx @@ -1,7 +1,7 @@ import { PropsWithChildren } from "react"; -export const Layout = ({ children }: PropsWithChildren) => { - return
{children}
; -}; +export const Layout = ({ children }: PropsWithChildren) => ( +
{children}
+); Layout.displayName = "Layout"; diff --git a/client/src/lib/hooks/useDataTable/DataTableContext.tsx b/client/src/lib/hooks/useDataTable/DataTableContext.tsx index 422563a..4df1a2c 100644 --- a/client/src/lib/hooks/useDataTable/DataTableContext.tsx +++ b/client/src/lib/hooks/useDataTable/DataTableContext.tsx @@ -1,18 +1,44 @@ -import { usePaginationParams } from "@/lib/hooks"; -import { PropsWithChildren, createContext } from "react"; +import { PaginationState, usePaginationParams } from "@/lib/hooks"; +import { SortingState } from "@tanstack/react-table"; +import { PropsWithChildren, createContext, useCallback, useMemo, useState } from "react"; -export interface IDataTableContextState {} +export interface IDataTableContextState { + pagination: PaginationState; + setPagination: (newPagination: PaginationState) => void; + sorting: []; + setSorting: () => void; + globalFilter: string; + setGlobalFilter: (newGlobalFilter: string) => void; + resetGlobalFilter: () => void; + isFiltered: boolean; +} export const DataTableContext = createContext(null); -export const DataTableProvider = ({ children }: PropsWithChildren) => { +export const DataTableProvider = ({ + initialGlobalFilter = "", + children, +}: PropsWithChildren<{ + initialGlobalFilter?: string; +}>) => { const [pagination, setPagination] = usePaginationParams(); + const [globalFilter, setGlobalFilter] = useState(initialGlobalFilter); + const [sorting, setSorting] = useState([]); + + const isFiltered = useMemo(() => Boolean(globalFilter.length), [globalFilter]); + const resetGlobalFilter = useCallback(() => setGlobalFilter(""), []); return ( {children} diff --git a/client/src/lib/hooks/useDataTable/index.ts b/client/src/lib/hooks/useDataTable/index.ts index 0820968..5aa5252 100644 --- a/client/src/lib/hooks/useDataTable/index.ts +++ b/client/src/lib/hooks/useDataTable/index.ts @@ -1,4 +1,5 @@ export * from "./DataTableContext"; +export * from "./types"; export * from "./useDataTable"; export * from "./useDataTableColumns"; export * from "./useDataTableContext"; diff --git a/client/src/lib/hooks/useDataTable/useDataTable.tsx b/client/src/lib/hooks/useDataTable/useDataTable.tsx index b735289..b6f4286 100644 --- a/client/src/lib/hooks/useDataTable/useDataTable.tsx +++ b/client/src/lib/hooks/useDataTable/useDataTable.tsx @@ -8,14 +8,12 @@ import { getSortedRowModel, useReactTable, type ColumnDef, - type ColumnFiltersState, type SortingState, type VisibilityState, } from "@tanstack/react-table"; import { getDataTableSelectionColumn } from "@/components"; -import React, { useCallback, useMemo, useState } from "react"; -import { useSearchParams } from "react-router-dom"; +import React, { useCallback } from "react"; import { DataTableFilterField } from "./types"; import { useDataTableContext } from "./useDataTableContext"; @@ -63,6 +61,22 @@ interface UseDataTableProps { */ enableRowSelection?: boolean; + /** + * The default number of rows per page. + * @default 10 + * @type number | undefined + * @example 20 + */ + defaultPerPage?: number; + + /** + * The default sort order. + * @default undefined + * @type `${Extract}.${"asc" | "desc"}` | undefined + * @example "createdAt.desc" + */ + defaultSort?: `${Extract}.${"asc" | "desc"}`; + /** * Defines filter fields for the table. Supports both dynamic faceted filters and search filters. * - Faceted filters are rendered when `options` are provided for a filter field. @@ -110,78 +124,13 @@ export function useDataTable({ enableSorting = false, enableHiding = false, enableRowSelection = false, - onPaginationChange, - filterFields = [], - // eslint-disable-next-line @typescript-eslint/no-unused-vars - enableAdvancedFilter = false, }: UseDataTableProps) { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [searchParams, setSearchParams] = useSearchParams(); - - const { pagination, setPagination } = useDataTableContext(); - console.log("pagination TABLA =>", pagination); - - const [sorting, setSorting] = useState([]); - - // Memoize computation of searchableColumns and filterableColumns - const { searchableColumns, filterableColumns } = useMemo(() => { - return { - searchableColumns: filterFields.filter((field) => !field.options), - filterableColumns: filterFields.filter((field) => field.options), - }; - }, [filterFields]); - - // Create query string - /*const createQueryString = useCallback( - (params: Record) => { - const newSearchParams = new URLSearchParams(searchParams?.toString()); - - for (const [key, value] of Object.entries(params)) { - if (value === null) { - newSearchParams.delete(key); - } else { - newSearchParams.set(key, String(value)); - } - } - - return newSearchParams.toString(); - }, - [searchParams] - );*/ - - // Initial column filters - const initialColumnFilters: ColumnFiltersState = useMemo(() => { - return Array.from(searchParams.entries()).reduce( - (filters, [key, value]) => { - const filterableColumn = filterableColumns.find((column) => column.value === key); - const searchableColumn = searchableColumns.find((column) => column.value === key); - - if (filterableColumn) { - filters.push({ - id: key, - value: value.split("."), - }); - } else if (searchableColumn) { - filters.push({ - id: key, - value: [value], - }); - } - - return filters; - }, - [] - ); - }, [filterableColumns, searchableColumns, searchParams]); + const { pagination, setPagination, sorting, setSorting } = useDataTableContext(); // Table states const [rowSelection, setRowSelection] = React.useState({}); - const [columnVisibility, setColumnVisibility] = React.useState({}); - const [columnFilters, setColumnFilters] = - React.useState(initialColumnFilters); - const paginationUpdater: OnChangeFn = (updater) => { if (typeof updater === "function") { const newPagination = updater(pagination); @@ -191,84 +140,12 @@ export function useDataTable({ const sortingUpdater: OnChangeFn = (updater) => { if (typeof updater === "function") { - setSorting(updater(sorting)); + const newSorting = updater(sorting); + console.log(newSorting); + setSorting(newSorting); } }; - // Handle server-side filtering - /*const debouncedSearchableColumnFilters = JSON.parse( - useDebounce( - JSON.stringify( - columnFilters.filter((filter) => { - return searchableColumns.find((column) => column.value === filter.id); - }) - ), - 500 - ) - ) as ColumnFiltersState;*/ - - /*const filterableColumnFilters = columnFilters.filter((filter) => { - return filterableColumns.find((column) => column.value === filter.id); - }); - - const [mounted, setMounted] = useState(false);*/ - - /*useEffect(() => { - // Opt out when advanced filter is enabled, because it contains additional params - if (enableAdvancedFilter) return; - - // Prevent resetting the page on initial render - if (!mounted) { - setMounted(true); - return; - } - - // Initialize new params - const newParamsObject = { - page: 1, - }; - - // Handle debounced searchable column filters - for (const column of debouncedSearchableColumnFilters) { - if (typeof column.value === "string") { - Object.assign(newParamsObject, { - [column.id]: typeof column.value === "string" ? column.value : null, - }); - } - } - - // Handle filterable column filters - for (const column of filterableColumnFilters) { - if (typeof column.value === "object" && Array.isArray(column.value)) { - Object.assign(newParamsObject, { [column.id]: column.value.join(".") }); - } - } - - // Remove deleted values - for (const key of searchParams.keys()) { - if ( - (searchableColumns.find((column) => column.value === key) && - !debouncedSearchableColumnFilters.find( - (column) => column.id === key - )) || - (filterableColumns.find((column) => column.value === key) && - !filterableColumnFilters.find((column) => column.id === key)) - ) { - Object.assign(newParamsObject, { [key]: null }); - } - } - - // After cumulating all the changes, push new params - navigate(`${location.pathname}?${createQueryString(newParamsObject)}`); - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - // eslint-disable-next-line react-hooks/exhaustive-deps - //JSON.stringify(debouncedSearchableColumnFilters), - // eslint-disable-next-line react-hooks/exhaustive-deps - JSON.stringify(filterableColumnFilters), - ]);*/ - const getTableColumns = useCallback(() => { const _columns = columns; if (enableRowSelection) { @@ -278,17 +155,16 @@ export function useDataTable({ }, [columns, enableRowSelection]); const table = useReactTable({ - columns: getTableColumns(), data, + columns: getTableColumns(), + pageCount: pageCount ?? -1, getCoreRowModel: getCoreRowModel(), - //getPaginationRowModel: getPaginationRowModel(), state: { pagination, sorting, columnVisibility, rowSelection, - columnFilters, }, enableRowSelection, @@ -303,16 +179,17 @@ export function useDataTable({ onColumnVisibilityChange: setColumnVisibility, manualPagination: true, - pageCount: pageCount ?? -1, onPaginationChange: paginationUpdater, - getFilteredRowModel: getFilteredRowModel(), - manualFiltering: true, - onColumnFiltersChange: setColumnFilters, + getFilteredRowModel: getFilteredRowModel(), getFacetedRowModel: getFacetedRowModel(), getFacetedUniqueValues: getFacetedUniqueValues(), + + debugTable: true, + debugHeaders: true, + debugColumns: true, }); return { table }; diff --git a/client/src/lib/hooks/usePagination/usePaginationParams.tsx b/client/src/lib/hooks/usePagination/usePaginationParams.tsx index dd24df0..6cb2237 100644 --- a/client/src/lib/hooks/usePagination/usePaginationParams.tsx +++ b/client/src/lib/hooks/usePagination/usePaginationParams.tsx @@ -40,22 +40,6 @@ export const usePaginationParams = ( const [pagination, setPagination] = usePagination(calculatedPageIndex, calculatedPageSize); - /*useEffect(() => { - // Actualizar la URL cuando cambia la paginación - const actualSearchParam = Object.fromEntries(new URLSearchParams(urlSearchParams)); - - if ( - String(pagination.pageIndex) !== actualSearchParam.page_index || - String(pagination.pageSize) !== actualSearchParam.page_size - ) { - setUrlSearchParams({ - ...actualSearchParam, - page_index: String(pagination.pageIndex), - page_size: String(pagination.pageSize), - }); - } - }, [pagination]);*/ - const updatePagination = (newPagination: PaginationState) => { const _validatedPagination = setPagination(newPagination); diff --git a/client/src/locales/es.json b/client/src/locales/es.json index 87d6479..cf12374 100644 --- a/client/src/locales/es.json +++ b/client/src/locales/es.json @@ -4,7 +4,21 @@ "cancel": "Cancelar", "no": "No", "yes": "Sí", - "Accept": "Aceptar" + "accept": "Aceptar", + "hide": "Ocultar", + "sort_asc": "Asc", + "sort_asc_description": "En order ascendente. Click para ordenar descendentemente.", + "sort_desc": "Desc", + "sort_desc_description": "En orden descendente. Click para ordenar ascendentemente.", + "sort_none_description": "Sin orden. Click para ordenar ascendentemente.", + "rows_selected": "{{count}} de {{total}} fila(s) seleccionadas.", + "rows_per_page": "Filas por página", + "num_page_of_total": "Página {{count}} de {{total}}", + "go_to_first_page": "Ir a la primera página", + "go_to_prev_page": "Ir a la página anterior", + "go_to_next_page": "Ir a la página siguiente", + "go_to_last_page": "Ir a la última página", + "reset_filter": "Quitar el filtro" }, "main_menu": { "home": "Inicio", @@ -39,7 +53,15 @@ "welcome": "Bienvenido" }, "catalog": { - "title": "Catálogo de artículos" + "title": "Catálogo de artículos", + "list": { + "global_filter_placeholder": "Escribe aquí para filtrar los artículos...", + "columns": { + "description": "Descripción", + "points": "Puntos", + "retail_price": "PVP" + } + } } } } diff --git a/client/src/ui/table.tsx b/client/src/ui/table.tsx index fac8321..fcd1c8e 100644 --- a/client/src/ui/table.tsx +++ b/client/src/ui/table.tsx @@ -2,18 +2,13 @@ import * as React from "react"; import { cn } from "@/lib/utils"; -const Table = React.forwardRef< - HTMLTableElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
- - -)); +const Table = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+
+ + ) +); Table.displayName = "Table"; const TableHeader = React.forwardRef< @@ -28,11 +23,7 @@ const TableBody = React.forwardRef< HTMLTableSectionElement, React.HTMLAttributes >(({ className, ...props }, ref) => ( - + )); TableBody.displayName = "TableBody"; @@ -42,28 +33,24 @@ const TableFooter = React.forwardRef< >(({ className, ...props }, ref) => ( tr]:last:border-b-0", - className - )} + className={cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className)} {...props} /> )); TableFooter.displayName = "TableFooter"; -const TableRow = React.forwardRef< - HTMLTableRowElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( - -)); +const TableRow = React.forwardRef>( + ({ className, ...props }, ref) => ( + + ) +); TableRow.displayName = "TableRow"; const TableHead = React.forwardRef< @@ -87,7 +74,7 @@ const TableCell = React.forwardRef< >(({ className, ...props }, ref) => (
)); @@ -97,21 +84,8 @@ const TableCaption = React.forwardRef< HTMLTableCaptionElement, React.HTMLAttributes >(({ className, ...props }, ref) => ( -
+ )); TableCaption.displayName = "TableCaption"; -export { - Table, - TableBody, - TableCaption, - TableCell, - TableFooter, - TableHead, - TableHeader, - TableRow, -}; +export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow };