From 0bef51750ce1ca4b260f1cfbb3a445aecc676d5e Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Mon, 11 Nov 2024 16:17:35 +0700 Subject: [PATCH] feat: add DataTable component and integrate with portfolio page; update dependencies --- package-lock.json | 34 +++ package.json | 1 + .../(investment)/deals/[id]/displayImage.tsx | 42 ---- src/app/portfolio/[uid]/page.tsx | 8 +- src/components/dataTable.tsx | 209 ++++++++++++++++++ 5 files changed, 251 insertions(+), 43 deletions(-) delete mode 100644 src/app/(investment)/deals/[id]/displayImage.tsx create mode 100644 src/components/dataTable.tsx diff --git a/package-lock.json b/package-lock.json index 342b62c..5a12811 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,6 +34,7 @@ "@supabase/supabase-js": "^2.46.1", "@tanstack/react-query": "^5.59.0", "@tanstack/react-query-devtools": "^5.59.0", + "@tanstack/react-table": "^8.20.5", "b2d-ventures": "file:", "chart.js": "^4.4.6", "class-variance-authority": "^0.7.0", @@ -3263,6 +3264,39 @@ "react": "^18 || ^19" } }, + "node_modules/@tanstack/react-table": { + "version": "8.20.5", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.20.5.tgz", + "integrity": "sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.20.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.20.5", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.20.5.tgz", + "integrity": "sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@trivago/prettier-plugin-sort-imports": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.3.0.tgz", diff --git a/package.json b/package.json index daa146e..32f6b05 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "@supabase/supabase-js": "^2.46.1", "@tanstack/react-query": "^5.59.0", "@tanstack/react-query-devtools": "^5.59.0", + "@tanstack/react-table": "^8.20.5", "b2d-ventures": "file:", "chart.js": "^4.4.6", "class-variance-authority": "^0.7.0", diff --git a/src/app/(investment)/deals/[id]/displayImage.tsx b/src/app/(investment)/deals/[id]/displayImage.tsx deleted file mode 100644 index 6bea6bf..0000000 --- a/src/app/(investment)/deals/[id]/displayImage.tsx +++ /dev/null @@ -1,42 +0,0 @@ -"use client"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog"; -import Image from "next/image"; -import { StaticImport } from "next/dist/shared/lib/get-img-props"; - -interface ItemProps { - src: string | StaticImport; - alt: string; - width: number; - height: number; - className?: string; -} - -const ImageModal = ({ src, alt, width, height, className }: ItemProps) => { - return ( - - - {alt} - - - - Image Preview - Click outside to close the image preview. - - {alt} - - - - ); -}; - -export function DisplayFullImage({ src, alt, width, height, className }: ItemProps) { - return ; -} diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 00115a6..d57db80 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -24,6 +24,8 @@ import { NoDataAlert } from "@/components/alert/noData/alert"; import { error } from "console"; import { UnAuthorizedAlert } from "@/components/alert/unauthorized/alert"; import Link from "next/link"; +import { DataTable } from "@/components/dataTable"; +import { Button } from "@/components/ui/button"; export default async function Portfolio({ params }: { params: { uid: string } }) { const supabase = createSupabaseClient(); @@ -230,8 +232,12 @@ export default async function Portfolio({ params }: { params: { uid: string } }) Recent investment - + +
+ {deals && deals.length > 5 ? : ""} + {/* */} +
diff --git a/src/components/dataTable.tsx b/src/components/dataTable.tsx new file mode 100644 index 0000000..e7f5d96 --- /dev/null +++ b/src/components/dataTable.tsx @@ -0,0 +1,209 @@ +"use client"; + +import * as React from "react"; +import { + ColumnDef, + ColumnFiltersState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; +import { ArrowUpDown, ChevronDown } from "lucide-react"; + +import { Button } from "@/components/ui/button"; +import { Checkbox } from "@/components/ui/checkbox"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Input } from "@/components/ui/input"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; + +export type Payment = { + data?: { + name?: string; + amount?: number; + avatar?: string; + date?: Date; + logo_url?: string; + status?: string; + profile_url?: string; + }[]; +}; + +export const columns: ColumnDef[] = [ + { + 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: "email", + header: ({ column }) => { + return ( + + ); + }, + cell: ({ row }) =>
{row.getValue("email")}
, + }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) =>
{row.getValue("status")}
, + }, + { + accessorKey: "amount", + header: () =>
Amount
, + cell: ({ row }) => { + const amount = parseFloat(row.getValue("amount")); + + // Format the amount as a dollar amount + const formatted = new Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + }).format(amount); + + return
{formatted}
; + }, + }, +]; + +export function DataTable({ data }: { data: Payment[] }) { + 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("email")?.setFilterValue(event.target.value)} + className="max-w-sm" + /> + + + + + + {table + .getAllColumns() + .filter((column) => column.getCanHide()) + .map((column) => { + return ( + column.toggleVisibility(!!value)} + > + {column.id} + + ); + })} + + +
+
+ + + {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())} + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+
+
+ {table.getFilteredSelectedRowModel().rows.length} of {table.getFilteredRowModel().rows.length} row(s) + selected. +
+
+ + +
+
+
+ ); +}