"use client" import * as React from "react" import { type ColumnDef, type ColumnFiltersState, type SortingState, type VisibilityState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table" import { ArrowUpDown, ChevronDown, MoreHorizontal } from "lucide-react" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Input } from "@/components/ui/input" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Badge } from "@/components/ui/badge" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { useTranslation } from "@/lib/i18n" export type Deal = { id: string dealName: string client: string stage: "Lead" | "Qualified" | "Proposal" | "Negotiation" | "Closed Won" | "Closed Lost" value: number probability: number owner: string ownerAvatar: string lastContacted: string createdAt: string expectedClose: string } const data: Deal[] = [ { id: "DEAL-001", dealName: "Enterprise Software License", client: "TechCorp Inc.", stage: "Negotiation", value: 45000, probability: 75, owner: "Jane Doe", ownerAvatar: "https://images.unsplash.com/photo-1494790108755-2616b612b786?w=150&h=150&fit=crop&crop=face", lastContacted: "2024-01-15", createdAt: "2023-12-01", expectedClose: "2024-02-15", }, { id: "DEAL-002", dealName: "Marketing Automation Setup", client: "StartupXYZ", stage: "Proposal", value: 12500, probability: 60, owner: "Mike Roberts", ownerAvatar: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face", lastContacted: "2024-01-14", createdAt: "2023-12-15", expectedClose: "2024-01-30", }, { id: "DEAL-003", dealName: "Cloud Migration Project", client: "Global Solutions", stage: "Qualified", value: 78000, probability: 40, owner: "Sarah Johnson", ownerAvatar: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=150&h=150&fit=crop&crop=face", lastContacted: "2024-01-12", createdAt: "2023-11-20", expectedClose: "2024-03-01", }, { id: "DEAL-004", dealName: "CRM Implementation", client: "Retail Chain Co.", stage: "Closed Won", value: 25000, probability: 100, owner: "Alex Lee", ownerAvatar: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150&h=150&fit=crop&crop=face", lastContacted: "2024-01-08", createdAt: "2023-10-15", expectedClose: "2024-01-15", }, { id: "DEAL-005", dealName: "Security Audit Services", client: "FinanceFirst Bank", stage: "Lead", value: 35000, probability: 20, owner: "Emily Martinez", ownerAvatar: "https://images.unsplash.com/photo-1544005313-94ddf0286df2?w=150&h=150&fit=crop&crop=face", lastContacted: "2024-01-10", createdAt: "2024-01-05", expectedClose: "2024-04-01", }, { id: "DEAL-006", dealName: "Data Analytics Platform", client: "Healthcare Plus", stage: "Negotiation", value: 95000, probability: 80, owner: "David Chen", ownerAvatar: "https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?w=150&h=150&fit=crop&crop=face", lastContacted: "2024-01-16", createdAt: "2023-11-30", expectedClose: "2024-02-28", }, { id: "DEAL-007", dealName: "Mobile App Development", client: "E-commerce Co.", stage: "Proposal", value: 55000, probability: 50, owner: "Lisa Wang", ownerAvatar: "https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?w=150&h=150&fit=crop&crop=face", lastContacted: "2024-01-13", createdAt: "2023-12-20", expectedClose: "2024-03-15", }, { id: "DEAL-008", dealName: "IT Infrastructure Upgrade", client: "Manufacturing Corp", stage: "Closed Lost", value: 120000, probability: 0, owner: "Tom Wilson", ownerAvatar: "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=150&h=150&fit=crop&crop=face", lastContacted: "2024-01-05", createdAt: "2023-09-15", expectedClose: "2024-01-01", }, ] const getStageColor = (stage: Deal["stage"]) => { const colors = { Lead: "bg-gray-100 text-gray-800", Qualified: "bg-blue-100 text-blue-800", Proposal: "bg-yellow-100 text-yellow-800", Negotiation: "bg-orange-100 text-orange-800", "Closed Won": "bg-green-100 text-green-800", "Closed Lost": "bg-red-100 text-red-800", } return colors[stage] } function useColumns() { const { t } = useTranslation() const columns: ColumnDef[] = React.useMemo(() => [ { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Select row" /> ), enableSorting: false, enableHiding: false, }, { accessorKey: "dealName", header: ({ column }) => ( ), cell: ({ row }) =>
{row.getValue("dealName")}
, }, { accessorKey: "client", header: ({ column }) => ( ), cell: ({ row }) =>
{row.getValue("client")}
, }, { accessorKey: "stage", header: t("dataTable.stage"), cell: ({ row }) => { const stage = row.getValue("stage") as Deal["stage"] return {stage} }, }, { accessorKey: "value", header: ({ column }) => ( ), cell: ({ row }) => { const amount = Number.parseFloat(row.getValue("value")) const formatted = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(amount) return
{formatted}
}, }, { accessorKey: "probability", header: ({ column }) => ( ), cell: ({ row }) =>
{(row.getValue("probability") as number)}%
, }, { accessorKey: "owner", header: t("dataTable.owner"), cell: ({ row }) => { const owner = row.getValue("owner") as string const ownerAvatar = row.original.ownerAvatar return (
{owner.split(" ").map((n) => n[0]).join("")} {owner}
) }, }, { accessorKey: "expectedClose", header: ({ column }) => ( ), cell: ({ row }) => { const date = new Date(row.getValue("expectedClose")) return
{date.toLocaleDateString()}
}, }, { id: "actions", enableHiding: false, cell: ({ row }) => { const deal = row.original return ( {t("dataTable.actions")} navigator.clipboard.writeText(deal.id)}> {t("dataTable.copyDealId")} {t("dataTable.viewDealDetails")} {t("dataTable.editDeal")} {t("dataTable.updateStage")} {t("dataTable.deleteDeal")} ) }, }, ], [t]) return columns } export function DataTable() { const { t } = useTranslation() const columns = useColumns() const [sorting, setSorting] = React.useState([]) const [columnFilters, setColumnFilters] = React.useState([]) const [columnVisibility, setColumnVisibility] = React.useState({}) const [rowSelection, setRowSelection] = React.useState({}) const table = useReactTable({ data, columns, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), onColumnVisibilityChange: setColumnVisibility, onRowSelectionChange: setRowSelection, state: { sorting, columnFilters, columnVisibility, rowSelection }, }) return (
table.getColumn("dealName")?.setFilterValue(event.target.value)} className="max-w-sm" /> {table .getAllColumns() .filter((column) => column.getCanHide()) .map((column) => ( column.toggleVisibility(!!value)} > {column.id} ))}
{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())} ))} )) ) : ( {t("dataTable.noResults")} )}
{table.getFilteredSelectedRowModel().rows.length} / {table.getFilteredRowModel().rows.length} {t("dataTable.rowsSelected")}
) }