"use client" import * as React from "react" import { closestCenter, DndContext, KeyboardSensor, MouseSensor, TouchSensor, useSensor, useSensors, type DragEndEvent, type UniqueIdentifier, } from "@dnd-kit/core" import { restrictToVerticalAxis } from "@dnd-kit/modifiers" import { arrayMove, SortableContext, useSortable, verticalListSortingStrategy, } from "@dnd-kit/sortable" import { CSS } from "@dnd-kit/utilities" import { IconChevronDown, IconChevronLeft, IconChevronRight, IconChevronsLeft, IconChevronsRight, IconCircleCheckFilled, IconDotsVertical, IconGripVertical, IconLayoutColumns, IconLoader, IconPlus, IconTrendingUp, } from "@tabler/icons-react" import { ColumnDef, ColumnFiltersState, flexRender, getCoreRowModel, getFacetedRowModel, getFacetedUniqueValues, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, Row, SortingState, useReactTable, VisibilityState, } from "@tanstack/react-table" import { Area, AreaChart, CartesianGrid, XAxis } from "recharts" import { toast } from "sonner" import { z } from "zod" import { useIsMobile } from "@/hooks/use-mobile" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, } from "@/components/ui/chart" import { Checkbox } from "@/components/ui/checkbox" import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger, } from "@/components/ui/drawer" import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Separator } from "@/components/ui/separator" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import { Tabs, TabsContent, TabsList, TabsTrigger, } from "@/components/ui/tabs" export const schema = z.object({ id: z.number(), header: z.string(), type: z.string(), status: z.string(), target: z.string(), limit: z.string(), reviewer: z.string(), }) // Create a separate component for the drag handle function DragHandle({ id }: { id: number }) { const { attributes, listeners } = useSortable({ id, }) return ( Drag to reorder ) } const columns: ColumnDef>[] = [ { id: "drag", header: () => null, cell: ({ row }) => , }, { 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: "header", header: "Header", cell: ({ row }) => { return }, enableHiding: false, }, { accessorKey: "type", header: "Section Type", cell: ({ row }) => ( {row.original.type} ), }, { accessorKey: "status", header: "Status", cell: ({ row }) => ( {row.original.status === "Done" ? ( ) : ( )} {row.original.status} ), }, { accessorKey: "target", header: () => Target, cell: ({ row }) => ( { e.preventDefault() toast.promise(new Promise((resolve) => setTimeout(resolve, 1000)), { loading: `Saving ${row.original.header}`, success: "Done", error: "Error", }) }} > Target ), }, { accessorKey: "limit", header: () => Limit, cell: ({ row }) => ( { e.preventDefault() toast.promise(new Promise((resolve) => setTimeout(resolve, 1000)), { loading: `Saving ${row.original.header}`, success: "Done", error: "Error", }) }} > Limit ), }, { accessorKey: "reviewer", header: "Reviewer", cell: ({ row }) => { const isAssigned = row.original.reviewer !== "Assign reviewer" if (isAssigned) { return row.original.reviewer } return ( <> Reviewer Eddie Lake Jamik Tashpulatov > ) }, }, { id: "actions", cell: () => ( Open menu Edit Make a copy Favorite Delete ), }, ] function DraggableRow({ row }: { row: Row> }) { const { transform, transition, setNodeRef, isDragging } = useSortable({ id: row.original.id, }) return ( {row.getVisibleCells().map((cell) => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} ))} ) } export function DataTable({ data: initialData, }: { data: z.infer[] }) { const [data, setData] = React.useState(() => initialData) const [rowSelection, setRowSelection] = React.useState({}) const [columnVisibility, setColumnVisibility] = React.useState({}) const [columnFilters, setColumnFilters] = React.useState( [] ) const [sorting, setSorting] = React.useState([]) const [pagination, setPagination] = React.useState({ pageIndex: 0, pageSize: 10, }) const sortableId = React.useId() const sensors = useSensors( useSensor(MouseSensor, {}), useSensor(TouchSensor, {}), useSensor(KeyboardSensor, {}) ) const dataIds = React.useMemo( () => data?.map(({ id }) => id) || [], [data] ) const table = useReactTable({ data, columns, state: { sorting, columnVisibility, rowSelection, columnFilters, pagination, }, getRowId: (row) => row.id.toString(), enableRowSelection: true, onRowSelectionChange: setRowSelection, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, onColumnVisibilityChange: setColumnVisibility, onPaginationChange: setPagination, getCoreRowModel: getCoreRowModel(), getFilteredRowModel: getFilteredRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFacetedRowModel: getFacetedRowModel(), getFacetedUniqueValues: getFacetedUniqueValues(), }) function handleDragEnd(event: DragEndEvent) { const { active, over } = event if (active && over && active.id !== over.id) { setData((data) => { const oldIndex = dataIds.indexOf(active.id) const newIndex = dataIds.indexOf(over.id) return arrayMove(data, oldIndex, newIndex) }) } } return ( View Outline Past Performance Key Personnel Focus Documents Outline Past Performance 3 Key Personnel 2 Focus Documents Customize Columns Columns {table .getAllColumns() .filter( (column) => typeof column.accessorFn !== "undefined" && column.getCanHide() ) .map((column) => { return ( column.toggleVisibility(!!value) } > {column.id} ) })} Add Section {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) => ( ))} ) : ( No results. )} {table.getFilteredSelectedRowModel().rows.length} of{" "} {table.getFilteredRowModel().rows.length} row(s) selected. Rows per page { table.setPageSize(Number(value)) }} > {[10, 20, 30, 40, 50].map((pageSize) => ( {pageSize} ))} Page {table.getState().pagination.pageIndex + 1} of{" "} {table.getPageCount()} table.setPageIndex(0)} disabled={!table.getCanPreviousPage()} > Go to first page table.previousPage()} disabled={!table.getCanPreviousPage()} > Go to previous page table.nextPage()} disabled={!table.getCanNextPage()} > Go to next page table.setPageIndex(table.getPageCount() - 1)} disabled={!table.getCanNextPage()} > Go to last page ) } const chartData = [ { month: "January", desktop: 186, mobile: 80 }, { month: "February", desktop: 305, mobile: 200 }, { month: "March", desktop: 237, mobile: 120 }, { month: "April", desktop: 73, mobile: 190 }, { month: "May", desktop: 209, mobile: 130 }, { month: "June", desktop: 214, mobile: 140 }, ] const chartConfig = { desktop: { label: "Desktop", color: "var(--primary)", }, mobile: { label: "Mobile", color: "var(--primary)", }, } satisfies ChartConfig function TableCellViewer({ item }: { item: z.infer }) { const isMobile = useIsMobile() return ( {item.header} {item.header} Showing total visitors for the last 6 months {!isMobile && ( <> value.slice(0, 3)} hide /> } /> Trending up by 5.2% this month{" "} Showing total visitors for the last 6 months. This is just some random text to test the layout. It spans multiple lines and should wrap around. > )} Header Type Table of Contents Executive Summary Technical Approach Design Capabilities Focus Documents Narrative Cover Page Status Done In Progress Not Started Target Limit Reviewer Eddie Lake Jamik Tashpulatov Emily Whalen Submit Done ) }