"use client"; import type { Column, ColumnDef, PaginationState, Row, RowSelectionState, SortingState, } from "@tanstack/react-table"; import { flexRender, getCoreRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table"; import { ArrowDown, ArrowUp, CheckCircle, ChevronsUpDown, Clock, LoaderIcon, MoreHorizontal, SquareMinusIcon, SquarePlusIcon, Truck, XCircle, } from "lucide-react"; import * as React from "react"; import { z } from "zod"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { cn } from "@/lib/utils"; const formatNumber = (value: number) => value.toLocaleString("fa-IR"); 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; initialGlobalFilter?: string; initialSelection?: RowSelectionState; enableRowSelection?: boolean; }; export function useDataTable(options: UseDataTableOptions) { const { data, columns, getRowId, initialSorting = [], initialGlobalFilter = "", initialSelection = {}, enableRowSelection = true, } = options; const [sorting, setSorting] = React.useState(initialSorting); const [globalFilter, setGlobalFilter] = React.useState(initialGlobalFilter); const [rowSelection, setRowSelection] = React.useState(initialSelection); const table = useReactTable({ data, columns, getRowId, state: { sorting, globalFilter, rowSelection, }, onSortingChange: setSorting, onRowSelectionChange: setRowSelection, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), enableRowSelection, }); return { table, sorting, setSorting, globalFilter, setGlobalFilter, rowSelection, setRowSelection, }; } 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 ( ); }; interface DataTableRowActionsProps { row: Row; schema: z.ZodSchema; itemName: string; idField?: string; } export function DataTableRowActions({ row, schema, itemName, idField = "id", }: DataTableRowActionsProps) { const item = schema.parse(row.original) as TData; const itemRecord = item as Record; return ( عملیات navigator.clipboard.writeText( String(itemRecord[idField] || itemRecord.id), ) } > کپی شناسه {itemName} ویرایش {itemName} مشاهده جزئیات ); } type StatusVariant = "info" | "primary" | "success" | "warning" | "destructive"; const OrderItemSchema = z.object({ id: z.string(), productName: z.string(), category: z.string(), price: z.number(), quantity: z.number(), }); const OrderStatusSchema = z.object({ label: z.string(), variant: z.enum(["info", "primary", "success", "warning", "destructive"]), }); export const CustomerRecordSchema = z.object({ id: z.string(), latestOrder: z.string(), customer: z.object({ name: z.string(), email: z.string(), avatar: z.string(), }), total: z.number(), totalItems: z.number(), status: OrderStatusSchema, items: z.array(OrderItemSchema), }); type CustomerRecord = z.infer; type OrderItem = z.infer; type RawOrder = { id: string; orderNumber: string; customer: string; customerEmail: string; customerAvatar: string; total: string; status: { label: string; variant: StatusVariant; }; items: Array<{ id: string; productName: string; category: string; price: string; quantity: number; }>; }; const rawOrders: RawOrder[] = [ { id: "1", orderNumber: "ORD-2401", customer: "Marcus Chen", customerEmail: "marcus.chen@email.com", customerAvatar: "1.png", total: "$384.92", status: { label: "Processing", variant: "info", }, items: [ { id: "1-1", productName: "USB-C Hub", category: "Electronics", price: "$49.99", quantity: 1, }, { id: "1-2", productName: "Laptop Bag", category: "Accessories", price: "$79.99", quantity: 1, }, { id: "1-3", productName: "Portable SSD", category: "Electronics", price: "$129.99", quantity: 1, }, { id: "1-4", productName: "Cable Sleeve", category: "Accessories", price: "$14.99", quantity: 2, }, { id: "1-5", productName: "Webcam Cover", category: "Accessories", price: "$9.99", quantity: 3, }, { id: "1-6", productName: "Laptop Stand", category: "Office", price: "$54.99", quantity: 1, }, { id: "1-7", productName: "USB Cable Pack", category: "Electronics", price: "$19.99", quantity: 1, }, ], }, { id: "2", orderNumber: "ORD-2402", customer: "Nina Patel", customerEmail: "nina.patel@email.com", customerAvatar: "2.png", total: "$567.45", status: { label: "Shipped", variant: "primary", }, items: [ { id: "2-1", productName: "Air Purifier", category: "Home", price: "$189.99", quantity: 1, }, { id: "2-2", productName: "Essential Oil Set", category: "Home", price: "$44.99", quantity: 1, }, { id: "2-3", productName: "Humidifier", category: "Home", price: "$69.99", quantity: 1, }, { id: "2-4", productName: "Room Spray", category: "Home", price: "$24.99", quantity: 2, }, { id: "2-5", productName: "Aromatherapy Diffuser", category: "Home", price: "$39.99", quantity: 1, }, { id: "2-6", productName: "Scented Candles", category: "Home", price: "$34.99", quantity: 3, }, { id: "2-7", productName: "Pillow Spray", category: "Home", price: "$16.99", quantity: 1, }, { id: "2-8", productName: "Room Thermometer", category: "Home", price: "$19.99", quantity: 1, }, ], }, { id: "3", orderNumber: "ORD-2403", customer: "Oliver Martinez", customerEmail: "oliver.martinez@email.com", customerAvatar: "3.png", total: "$892.34", status: { label: "Delivered", variant: "success", }, items: [ { id: "3-1", productName: "Digital Camera", category: "Electronics", price: "$449.99", quantity: 1, }, { id: "3-2", productName: "Camera Bag", category: "Accessories", price: "$89.99", quantity: 1, }, { id: "3-3", productName: "Memory Card 128GB", category: "Electronics", price: "$34.99", quantity: 2, }, { id: "3-4", productName: "Tripod", category: "Accessories", price: "$79.99", quantity: 1, }, { id: "3-5", productName: "Camera Lens", category: "Electronics", price: "$199.99", quantity: 1, }, { id: "3-6", productName: "Lens Cleaning Kit", category: "Accessories", price: "$12.99", quantity: 1, }, { id: "3-7", productName: "Extra Battery", category: "Electronics", price: "$44.99", quantity: 2, }, { id: "3-8", productName: "Camera Strap", category: "Accessories", price: "$24.99", quantity: 1, }, { id: "3-9", productName: "Lens Filter", category: "Accessories", price: "$29.99", quantity: 1, }, { id: "3-10", productName: "Remote Shutter", category: "Electronics", price: "$19.99", quantity: 1, }, ], }, { id: "4", orderNumber: "ORD-2404", customer: "Sophia Kim", customerEmail: "sophia.kim@email.com", customerAvatar: "4.png", total: "$246.78", status: { label: "Pending", variant: "warning", }, items: [ { id: "4-1", productName: "Art Supplies Set", category: "Art", price: "$89.99", quantity: 1, }, { id: "4-2", productName: "Sketchbook", category: "Art", price: "$24.99", quantity: 2, }, { id: "4-3", productName: "Colored Pencils", category: "Art", price: "$39.99", quantity: 1, }, { id: "4-4", productName: "Watercolor Set", category: "Art", price: "$44.99", quantity: 1, }, { id: "4-5", productName: "Paint Brushes", category: "Art", price: "$29.99", quantity: 1, }, { id: "4-6", productName: "Canvas Pack", category: "Art", price: "$34.99", quantity: 1, }, ], }, { id: "5", orderNumber: "ORD-2405", customer: "Jackson Wu", customerEmail: "jackson.wu@email.com", customerAvatar: "5.png", total: "$1,234.56", status: { label: "Processing", variant: "info", }, items: [ { id: "5-1", productName: "Electric Bike", category: "Sports", price: "$899.99", quantity: 1, }, { id: "5-2", productName: "Bike Helmet", category: "Sports", price: "$79.99", quantity: 1, }, { id: "5-3", productName: "Bike Lock", category: "Accessories", price: "$49.99", quantity: 1, }, { id: "5-4", productName: "Bike Lights", category: "Accessories", price: "$39.99", quantity: 1, }, { id: "5-5", productName: "Water Bottle Holder", category: "Accessories", price: "$14.99", quantity: 1, }, { id: "5-6", productName: "Bike Phone Mount", category: "Accessories", price: "$24.99", quantity: 1, }, { id: "5-7", productName: "Repair Kit", category: "Tools", price: "$29.99", quantity: 1, }, { id: "5-8", productName: "Bike Pump", category: "Tools", price: "$34.99", quantity: 1, }, { id: "5-9", productName: "Bike Bell", category: "Accessories", price: "$9.99", quantity: 1, }, { id: "5-10", productName: "Reflective Vest", category: "Clothing", price: "$19.99", quantity: 1, }, { id: "5-11", productName: "Cycling Gloves", category: "Clothing", price: "$24.99", quantity: 1, }, ], }, { id: "6", orderNumber: "ORD-2406", customer: "Emma Thompson", customerEmail: "emma.thompson@email.com", customerAvatar: "6.png", total: "$678.90", status: { label: "Shipped", variant: "primary", }, items: [ { id: "6-1", productName: "Robot Vacuum", category: "Home", price: "$299.99", quantity: 1, }, { id: "6-2", productName: "Vacuum Filters", category: "Home", price: "$19.99", quantity: 3, }, { id: "6-3", productName: "Cleaning Solution", category: "Home", price: "$24.99", quantity: 2, }, { id: "6-4", productName: "Microfiber Cloths", category: "Home", price: "$14.99", quantity: 2, }, { id: "6-5", productName: "Dustpan Set", category: "Home", price: "$29.99", quantity: 1, }, { id: "6-6", productName: "Mop System", category: "Home", price: "$79.99", quantity: 1, }, { id: "6-7", productName: "Broom", category: "Home", price: "$34.99", quantity: 1, }, { id: "6-8", productName: "Trash Bags", category: "Home", price: "$19.99", quantity: 2, }, { id: "6-9", productName: "Gloves Pack", category: "Home", price: "$12.99", quantity: 1, }, { id: "6-10", productName: "Sponge Set", category: "Home", price: "$9.99", quantity: 1, }, { id: "6-11", productName: "Air Freshener", category: "Home", price: "$16.99", quantity: 2, }, { id: "6-12", productName: "Duster", category: "Home", price: "$19.99", quantity: 1, }, ], }, { id: "7", orderNumber: "ORD-2407", customer: "Lucas Gonzalez", customerEmail: "lucas.gonzalez@email.com", customerAvatar: "7.png", total: "$423.67", status: { label: "Delivered", variant: "success", }, items: [ { id: "7-1", productName: "Mechanical Keyboard", category: "Electronics", price: "$149.99", quantity: 1, }, { id: "7-2", productName: "Keycap Set", category: "Accessories", price: "$59.99", quantity: 1, }, { id: "7-3", productName: "Keyboard Wrist Rest", category: "Accessories", price: "$29.99", quantity: 1, }, { id: "7-4", productName: "Switch Puller", category: "Tools", price: "$9.99", quantity: 1, }, { id: "7-5", productName: "Stabilizers", category: "Parts", price: "$19.99", quantity: 1, }, { id: "7-6", productName: "Keyboard Cable", category: "Accessories", price: "$39.99", quantity: 1, }, { id: "7-7", productName: "Cleaning Brush", category: "Tools", price: "$7.99", quantity: 1, }, { id: "7-8", productName: "Lubricant", category: "Tools", price: "$14.99", quantity: 1, }, { id: "7-9", productName: "Extra Switches", category: "Parts", price: "$44.99", quantity: 2, }, ], }, { id: "8", orderNumber: "ORD-2408", customer: "Ava Robinson", customerEmail: "ava.robinson@email.com", customerAvatar: "8.png", total: "$789.23", status: { label: "Cancelled", variant: "destructive", }, items: [ { id: "8-1", productName: "Standing Desk", category: "Furniture", price: "$399.99", quantity: 1, }, { id: "8-2", productName: "Desk Converter", category: "Furniture", price: "$149.99", quantity: 1, }, { id: "8-3", productName: "Monitor Arm", category: "Accessories", price: "$119.99", quantity: 1, }, { id: "8-4", productName: "Cable Tray", category: "Accessories", price: "$24.99", quantity: 1, }, { id: "8-5", productName: "Desk Pad", category: "Office", price: "$29.99", quantity: 1, }, { id: "8-6", productName: "Footrest", category: "Office", price: "$39.99", quantity: 1, }, { id: "8-7", productName: "LED Desk Light", category: "Lighting", price: "$64.99", quantity: 1, }, ], }, { id: "9", orderNumber: "ORD-2409", customer: "Ethan Foster", customerEmail: "ethan.foster@email.com", customerAvatar: "9.png", total: "$534.12", status: { label: "Processing", variant: "info", }, items: [ { id: "9-1", productName: "Espresso Machine", category: "Kitchen", price: "$299.99", quantity: 1, }, { id: "9-2", productName: "Coffee Grinder", category: "Kitchen", price: "$89.99", quantity: 1, }, { id: "9-3", productName: "Milk Pitcher", category: "Kitchen", price: "$24.99", quantity: 1, }, { id: "9-4", productName: "Coffee Beans", category: "Food", price: "$29.99", quantity: 2, }, { id: "9-5", productName: "Tamper", category: "Tools", price: "$39.99", quantity: 1, }, { id: "9-6", productName: "Cleaning Tablets", category: "Kitchen", price: "$14.99", quantity: 1, }, { id: "9-7", productName: "Descaling Solution", category: "Kitchen", price: "$19.99", quantity: 1, }, { id: "9-8", productName: "Knock Box", category: "Kitchen", price: "$34.99", quantity: 1, }, { id: "9-9", productName: "Thermometer", category: "Tools", price: "$24.99", quantity: 1, }, { id: "9-10", productName: "Scale", category: "Tools", price: "$49.99", quantity: 1, }, ], }, { id: "10", orderNumber: "ORD-2410", customer: "Isabella Hayes", customerEmail: "isabella.hayes@email.com", customerAvatar: "10.png", total: "$312.45", status: { label: "Shipped", variant: "primary", }, items: [ { id: "10-1", productName: "Plant Pots Set", category: "Garden", price: "$49.99", quantity: 1, }, { id: "10-2", productName: "Potting Soil", category: "Garden", price: "$24.99", quantity: 2, }, { id: "10-3", productName: "Garden Tools", category: "Garden", price: "$39.99", quantity: 1, }, { id: "10-4", productName: "Watering Can", category: "Garden", price: "$29.99", quantity: 1, }, { id: "10-5", productName: "Plant Food", category: "Garden", price: "$19.99", quantity: 2, }, { id: "10-6", productName: "Garden Gloves", category: "Garden", price: "$14.99", quantity: 1, }, { id: "10-7", productName: "Plant Labels", category: "Garden", price: "$9.99", quantity: 1, }, { id: "10-8", productName: "Spray Bottle", category: "Garden", price: "$12.99", quantity: 1, }, { id: "10-9", productName: "Pruning Shears", category: "Garden", price: "$34.99", quantity: 1, }, { id: "10-10", productName: "Kneeling Pad", category: "Garden", price: "$19.99", quantity: 1, }, ], }, ]; const parseCurrency = (value: string) => Number(value.replace(/[^0-9.-]+/g, "")) || 0; const customerNameMap: Record = { "1": "مانی چن", "2": "نینا پاتل", "3": "اولیور مارتینز", "4": "سوفیا کیم", "5": "جکسون", "6": "اما تامپسون", "7": "لوقاس گونزالز", "8": "آوا رابینسون", "9": "ایتان فاستر", "10": "ایزابلا هایز", }; const statusLabelMap: Record = { Processing: "در حال پردازش", Shipped: "ارسال‌شده", Delivered: "تحویل‌شده", Pending: "در انتظار پیگیری", Cancelled: "لغو‌شده", }; const categoryMap: Record = { Electronics: "الکترونیک", Accessories: "لوازم جانبی", Home: "خانه", Office: "اداری", Art: "هنر", Sports: "ورزشی", Tools: "ابزار", Clothing: "پوشاک", Furniture: "مبلمان", Lighting: "روشنایی", Kitchen: "آشپزخانه", Food: "مواد غذایی", Garden: "باغبانی", Parts: "قطعات", }; const productNameMap: Record = { "1-1": "هاب USB-C", "1-2": "کیف لپ‌تاپ", "1-3": "SSD قابل حمل", "1-4": "روکش کابل", "1-5": "پوشش وب‌کم", "1-6": "پایه لپ‌تاپ", "1-7": "بسته کابل USB", "2-1": "تصفیه‌کننده هوا", "2-2": "ست روغن‌های ضروری", "2-3": "رطوبت‌ساز", "2-4": "اسپری اتاق", "2-5": "پخش‌کننده رایحه", "2-6": "شمع‌های معطر", "2-7": "اسپری بالش", "2-8": "دماسنج اتاق", "3-1": "دوربین دیجیتال", "3-2": "کیف دوربین", "3-3": "کارت حافظه ۱۲۸ گیگ", "3-4": "سه‌پایه", "3-5": "لنز دوربین", "3-6": "کیت تمیزکننده لنز", "3-7": "باتری یدک", "3-8": "بند دوربین", "3-9": "فیلتر لنز", "3-10": "ریموت شاتر", "4-1": "ست لوازم هنری", "4-2": "دفتر طراحی", "4-3": "مداد رنگی", "4-4": "ست آبرنگ", "4-5": "قلم‌مو", "4-6": "بسته بوم", "5-1": "دوچرخه برقی", "5-2": "کلاه ایمنی دوچرخه", "5-3": "قفل دوچرخه", "5-4": "چراغ دوچرخه", "5-5": "نگهدارنده بطری", "5-6": "پایه نگهدارنده گوشی", "5-7": "کیت تعمیر", "5-8": "پمپ دوچرخه", "5-9": "زنگ دوچرخه", "5-10": "جلیقه بازتابنده", "5-11": "دستکش دوچرخه‌سواری", "6-1": "جاروبرقی رباتیک", "6-2": "فیلتر جاروبرقی", "6-3": "محلول تمیزکننده", "6-4": "دستمال میکروفایبر", "6-5": "ست جارو و خاک‌انداز", "6-6": "سیستم تی", "6-7": "جارو", "6-8": "کیسه زباله", "6-9": "بسته دستکش", "6-10": "ست اسفنج", "6-11": "خوشبوکننده هوا", "6-12": "گردگیر", "7-1": "کیبورد مکانیکی", "7-2": "ست کلید", "7-3": "پد مچ دست", "7-4": "کشنده سوئیچ", "7-5": "ثبات‌دهنده", "7-6": "کابل کیبورد", "7-7": "برس تمیزکننده", "7-8": "روغن روان‌کننده", "7-9": "سوئیچ یدک", "8-1": "میز ایستاده", "8-2": "تبدیل‌کننده میز", "8-3": "بازوی مانیتور", "8-4": "سینی کابل", "8-5": "پد میز", "8-6": "پاورقی", "8-7": "چراغ LED میز", "9-1": "دستگاه اسپرسو", "9-2": "آسیاب قهوه", "9-3": "پیچر شیر", "9-4": "دانه قهوه", "9-5": "تمپر", "9-6": "قرص تمیزکننده", "9-7": "محلول رسوب‌زدا", "9-8": "جعبه ضربه", "9-9": "دماسنج", "9-10": "ترازو", "10-1": "ست گلدان", "10-2": "خاک گلدان", "10-3": "ابزار باغبانی", "10-4": "آبپاش", "10-5": "کود گیاه", "10-6": "دستکش باغبانی", "10-7": "برچسب گیاه", "10-8": "اسپری آب", "10-9": "قیچی هرس", "10-10": "زانوبند", }; export const validatedData = CustomerRecordSchema.array().parse( rawOrders.map((order) => { const parsedItems = order.items.map((item) => ({ ...item, productName: productNameMap[item.id] ?? item.productName, category: categoryMap[item.category] ?? item.category, price: parseCurrency(item.price), })); const totalItems = parsedItems.reduce( (acc, item) => acc + item.quantity, 0, ); return { id: order.id, latestOrder: order.orderNumber, customer: { name: customerNameMap[order.id] ?? order.customer, email: order.customerEmail, avatar: order.customerAvatar, }, total: parseCurrency(order.total), totalItems, status: { ...order.status, label: statusLabelMap[order.status.label] ?? order.status.label, }, items: parsedItems, }; }), ); const statusBadgeClassMap: Record = { info: "border-sky-200 bg-sky-50 text-sky-700 dark:border-sky-500/40 dark:bg-sky-500/10 dark:text-sky-400", primary: "border-violet-200 bg-violet-50 text-violet-700 dark:border-violet-500/40 dark:bg-violet-500/10 dark:text-violet-400", success: "border-emerald-200 bg-emerald-50 text-emerald-700 dark:border-emerald-500/40 dark:bg-emerald-500/10 dark:text-emerald-400", warning: "border-amber-200 bg-amber-50 text-amber-700 dark:border-amber-500/40 dark:bg-amber-500/10 dark:text-amber-400", destructive: "border-rose-200 bg-rose-50 text-rose-700 dark:border-rose-500/40 dark:bg-rose-500/10 dark:text-rose-400", }; const getStatusBadgeClasses = (variant: StatusVariant) => statusBadgeClassMap[variant] ?? statusBadgeClassMap.info; const avatarColorClasses = [ "bg-slate-100 text-slate-700 dark:bg-slate-800 dark:text-slate-300", "bg-emerald-100 text-emerald-700 dark:bg-emerald-800 dark:text-emerald-300", "bg-indigo-100 text-indigo-700 dark:bg-indigo-800 dark:text-indigo-300", "bg-amber-100 text-amber-700 dark:bg-amber-800 dark:text-amber-300", "bg-rose-100 text-rose-700 dark:bg-rose-800 dark:text-rose-300", "bg-sky-100 text-sky-700 dark:bg-sky-800 dark:text-sky-300", ]; const getAvatarColor = (value: string) => { const hash = value .split("") .reduce((acc, char) => acc + char.charCodeAt(0), 0); return avatarColorClasses[hash % avatarColorClasses.length]; }; const getInitials = (name: string) => { const parts = name.trim().split(" "); const first = parts[0]?.charAt(0) ?? ""; const second = parts[1]?.charAt(0) ?? parts[0]?.charAt(1) ?? ""; return `${first}${second}`; }; export type StatusOption = { label: string; value: string; icon?: React.ComponentType<{ className?: string }>; }; export const orderStatuses: StatusOption[] = [ { label: "در حال پردازش", value: "در حال پردازش", icon: LoaderIcon }, { label: "ارسال‌شده", value: "ارسال‌شده", icon: Truck }, { label: "تحویل‌شده", value: "تحویل‌شده", icon: CheckCircle }, { label: "در انتظار پیگیری", value: "در انتظار پیگیری", icon: Clock }, { label: "لغو‌شده", value: "لغو‌شده", icon: XCircle }, ]; const createStatusLookup = (options: StatusOption[]) => options.reduce>((acc, option) => { acc[option.value] = option; return acc; }, {}); const orderStatusLookup = createStatusLookup(orderStatuses); export const getOrderStatusMeta = (status: string) => orderStatusLookup[status]; // Sub-table component for order items function OrderItemsSubTable({ items }: { items: OrderItem[] }) { const [sorting, setSorting] = React.useState([]); const [pagination, setPagination] = React.useState({ pageIndex: 0, pageSize: 5, }); const columns = React.useMemo[]>( () => [ { accessorKey: "productName", header: ({ column }) => ( ), cell: (info) => ( {info.getValue() as string} ), enableSorting: true, }, { accessorKey: "category", header: ({ column }) => ( ), cell: (info) => ( {info.getValue() as string} ), enableSorting: true, }, { accessorKey: "quantity", header: ({ column }) => ( ), cell: (info) => ( {formatNumber(info.getValue() as number)} ), meta: { align: "right", className: "tabular-nums" }, enableSorting: true, }, { accessorKey: "price", header: ({ column }) => ( ), cell: (info) => ( {formatPrice(info.getValue() as number)} ), meta: { align: "right", className: "tabular-nums" }, enableSorting: true, }, ], [], ); const table = useReactTable({ data: items, columns, pageCount: Math.ceil(items.length / pagination.pageSize), state: { sorting, pagination, }, onSortingChange: setSorting, onPaginationChange: setPagination, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), getPaginationRowModel: getPaginationRowModel(), getRowId: (row: OrderItem) => row.id, }); return (

اقلام سفارش

{formatNumber(items.length)} مورد
{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(), )} ))} )) ) : ( اقلامی یافت نشد )}
{items.length > pagination.pageSize && (
نمایش {formatNumber(table.getRowModel().rows.length)} از{" "} {formatNumber(items.length)} مورد
)}
); } export const columns: ColumnDef[] = [ { id: "expand", cell: ({ row }) => { const toggleExpand = (e: React.MouseEvent) => { e.stopPropagation(); row.toggleExpanded(); }; return (
); }, }, { accessorKey: "customer", header: ({ column }) => ( ), cell: ({ row }) => { const { name, email, avatar } = row.original.customer; return (
{getInitials(name)}
{name}
{email}
); }, enableSorting: false, enableHiding: false, }, { accessorKey: "total", header: ({ column }) => ( ), cell: ({ row }) => ( {formatPrice(row.original.total)} ), meta: { align: "right", className: "tabular-nums" }, enableSorting: true, }, { accessorKey: "status", header: ({ column }) => ( ), cell: ({ row }) => { const status = row.original.status; const statusMeta = getOrderStatusMeta(status.label); const StatusIcon = statusMeta?.icon; return ( {StatusIcon ? : null} {status.label} ); }, enableSorting: false, }, { accessorKey: "totalItems", header: ({ column }) => ( ), cell: ({ row }) => ( {formatNumber(row.original.totalItems)} مورد ), meta: { align: "right" }, enableSorting: true, }, ]; export function DataTable22({ className }: { className?: string }) { const { table } = useDataTable({ data: validatedData, columns, getRowId: (row) => row.id, }); return (

جدول با زیرجدول

جدول داده مشتریان با جزئیات اقلام سفارش در رکورد گسترش‌یافته.

{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => { return ( {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(), )} ))} {row.getIsExpanded() && ( )} )) ) : ( نتیجه‌ای یافت نشد )}
); }