"use client"; import { type Column, type ColumnDef, flexRender, getCoreRowModel, getSortedRowModel, type SortingState, useReactTable, } from "@tanstack/react-table"; import { ArrowDown, ArrowUp, ChevronsUpDown } from "lucide-react"; import * as React from "react"; import { z } from "zod"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { cn } from "@/lib/utils"; const formatPrice = (value: number) => new Intl.NumberFormat("fa-IR", { style: "currency", currency: "IRR", }).format(value); type UseDataTableOptions = { data: Array; columns: Array>; getRowId?: (row: TData) => string; initialSorting?: SortingState; }; export function useDataTable(options: UseDataTableOptions) { const { data, columns, getRowId, initialSorting = [] } = options; const [sorting, setSorting] = React.useState(initialSorting); const table = useReactTable({ data, columns, getRowId, state: { sorting }, columnResizeMode: "onChange", onSortingChange: setSorting, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), defaultColumn: { size: 150, minSize: 50, maxSize: 500, }, }); return { table, sorting, setSorting, }; } type DataTableColumnHeaderProps = { column: Column; title: string; }; export const DataTableColumnHeader = ({ column, title, }: DataTableColumnHeaderProps) => { const canSort = column.getCanSort(); const sorted = column.getIsSorted(); if (!canSort) { return ( {title} ); } return ( ); }; export const schema = z.object({ id: z.string(), item: z.string(), type: z.string(), stock: z.boolean(), sku: z.string(), price: z.number(), availability: z.array(z.enum(["فروشگاه", "آنلاین"])), }); const data = [ { id: "prod-001", item: "قاب تبلت", type: "الکترونیک", stock: true, sku: "TC-001", price: 83.24, availability: ["فروشگاه", "آنلاین"], }, { id: "prod-002", item: "ساعت هوشمند", type: "الکترونیک", stock: true, sku: "SW-002", price: 246.27, availability: ["فروشگاه", "آنلاین"], }, { id: "prod-003", item: "پلیور پشمی", type: "لوازم جانبی", stock: true, sku: "WS-003", price: 168.27, availability: ["فروشگاه"], }, { id: "prod-004", item: "هدفون بی‌سیم", type: "الکترونیک", stock: true, sku: "WE-004", price: 107.75, availability: ["فروشگاه", "آنلاین"], }, { id: "prod-005", item: "کاور لپ‌تاپ", type: "الکترونیک", stock: true, sku: "LS-005", price: 248.02, availability: ["فروشگاه", "آنلاین"], }, { id: "prod-006", item: "کفش دویدن", type: "کفش", stock: true, sku: "RS-006", price: 208.26, availability: ["فروشگاه"], }, { id: "prod-007", item: "کاپشن زمستانی", type: "پوشاک", stock: true, sku: "WJ-007", price: 148.06, availability: ["فروشگاه"], }, { id: "prod-008", item: "قاب گوشی", type: "لوازم جانبی", stock: true, sku: "PC-008", price: 298.08, availability: ["فروشگاه", "آنلاین"], }, { id: "prod-009", item: "ردیاب تناسب اندام", type: "پوشاک", stock: true, sku: "FT-009", price: 222.09, availability: ["فروشگاه"], }, { id: "prod-010", item: "عینک آفتابی", type: "لوازم جانبی", stock: true, sku: "SG-010", price: 60.17, availability: ["فروشگاه"], }, ]; export const validatedData = schema.array().parse(data); const COLUMN_SIZES = { sku: { default: 100, min: 80, max: 150 }, item: { default: 200, min: 100, max: 400 }, type: { default: 120, min: 80, max: 200 }, stock: { default: 100, min: 80, max: 150 }, price: { default: 120, min: 100, max: 200 }, availability: { default: 180, min: 120, max: 300 }, } as const; export const columns: ColumnDef>[] = [ { accessorKey: "sku", header: ({ column }) => ( ), size: COLUMN_SIZES.sku.default, minSize: COLUMN_SIZES.sku.min, maxSize: COLUMN_SIZES.sku.max, enableSorting: true, enableHiding: false, }, { accessorKey: "item", header: ({ column }) => ( ), cell: ({ row }) => (
{row.getValue("item")}
), size: COLUMN_SIZES.item.default, minSize: COLUMN_SIZES.item.min, maxSize: COLUMN_SIZES.item.max, enableSorting: true, enableHiding: false, }, { accessorKey: "type", header: ({ column }) => ( ), size: COLUMN_SIZES.type.default, minSize: COLUMN_SIZES.type.min, maxSize: COLUMN_SIZES.type.max, enableSorting: true, enableHiding: false, }, { accessorKey: "stock", header: ({ column }) => ( ), cell: ({ row }) => { const inStock = row.getValue("stock") as boolean; return inStock ? "بله" : "خیر"; }, size: COLUMN_SIZES.stock.default, minSize: COLUMN_SIZES.stock.min, maxSize: COLUMN_SIZES.stock.max, enableSorting: false, enableHiding: false, }, { accessorKey: "price", header: ({ column }) => ( ), cell: ({ row }) => { const price = row.getValue("price") as number; return (
{formatPrice(price)}
); }, size: COLUMN_SIZES.price.default, minSize: COLUMN_SIZES.price.min, maxSize: COLUMN_SIZES.price.max, enableSorting: true, enableHiding: false, }, { accessorKey: "availability", header: ({ column }) => ( ), cell: ({ row }) => { const availability = row.getValue("availability") as ( | "فروشگاه" | "آنلاین" )[]; return (
{availability.map((location) => ( {location} ))}
); }, size: COLUMN_SIZES.availability.default, minSize: COLUMN_SIZES.availability.min, maxSize: COLUMN_SIZES.availability.max, enableSorting: false, enableHiding: false, }, ]; export const DataTable20 = ({ className }: { className?: string }) => { const { table } = useDataTable({ data: validatedData, columns, getRowId: (row) => row.id.toString(), }); return (

جدول با ستون‌های قابل تغییر اندازه

جدول داده ساده با مرتب‌سازی و امکان تغییر عرض ستون‌ها.

{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => { return ( {header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext(), )} {header.column.getCanResize() && (
header.column.resetSize()} onMouseDown={header.getResizeHandler()} onTouchStart={header.getResizeHandler()} className="group/resize absolute top-0 -end-2 z-10 flex h-full w-4 cursor-col-resize touch-none justify-center select-none before:absolute before:inset-y-0 before:w-px before:bg-border before:transition-colors hover:before:bg-primary active:before:bg-primary" role="separator" aria-label="تغییر اندازه ستون" /> )} ); })} ))} {table.getRowModel().rows?.length ? ( table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext(), )} ))} )) ) : (

محصولی یافت نشد

)}
); };