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 01/17] 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. +
+
+ + +
+
+
+ ); +} From 7f68a31afa63a505206b508e252efc3a03f0d5ab Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Mon, 11 Nov 2024 16:33:50 +0700 Subject: [PATCH 02/17] feat: update Dashboard and Portfolio components; add Deals page and improve project filtering --- src/app/dashboard/deals/page.tsx | 9 +++++++++ src/app/dashboard/page.tsx | 20 ++++++++++++++------ src/app/portfolio/[uid]/page.tsx | 3 +-- 3 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 src/app/dashboard/deals/page.tsx diff --git a/src/app/dashboard/deals/page.tsx b/src/app/dashboard/deals/page.tsx new file mode 100644 index 0000000..4b70825 --- /dev/null +++ b/src/app/dashboard/deals/page.tsx @@ -0,0 +1,9 @@ +import { DataTable } from "@/components/dataTable"; + +export default function Deals() { + return ( +
+

hello นาา

+
+ ); +} diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index c1c58cc..f53a071 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -16,6 +16,7 @@ import { overAllGraphData, fourYearGraphData, dayOftheWeekData } from "../portfo import CountUp from "react-countup"; import { Button } from "@/components/ui/button"; import { useRouter } from "next/navigation"; +import Link from "next/link"; export default function Dashboard() { const supabase = createSupabaseClient(); @@ -50,17 +51,17 @@ export default function Dashboard() { ) ); let graphData = []; - const filteredData = (investmentDetail?.data || []).filter((deal) => deal.project_id === currentProjectId); + const filteredProject = (investmentDetail?.data || []).filter((deal) => deal.project_id === currentProjectId); const handleTabChange = (tab: string) => { setActiveTab(tab); }; if (activeTab === "daily") { - graphData = dayOftheWeekData(filteredData); + graphData = dayOftheWeekData(filteredProject); } else if (activeTab === "yearly") { - graphData = fourYearGraphData(filteredData); + graphData = fourYearGraphData(filteredProject); } else { - graphData = overAllGraphData(filteredData); + graphData = overAllGraphData(filteredProject); } useEffect(() => { @@ -173,7 +174,7 @@ export default function Dashboard() {
$ project.deal_status === "Completed") .reduce((sum, current) => sum + current.deal_amount, 0)} duration={1} @@ -282,7 +283,7 @@ export default function Dashboard() { Recent Funds - + { return { @@ -295,6 +296,13 @@ export default function Dashboard() { }; })} /> +
+ {filteredProject && filteredProject.length > 6 ? ( + + ) : undefined} +
diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index d57db80..3eebeec 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -235,8 +235,7 @@ export default async function Portfolio({ params }: { params: { uid: string } })
- {deals && deals.length > 5 ? : ""} - {/* */} + {deals && deals.length > 5 ? : undefined}
From 6e70bdf0846dce2ad420af576f52882e28978c1a Mon Sep 17 00:00:00 2001 From: Pattadon Date: Tue, 12 Nov 2024 09:37:45 +0700 Subject: [PATCH 03/17] feat: replace Tooltip with CustomTooltip in FollowShareButtons; pass projectName as prop --- .../deals/[id]/followShareButton.tsx | 18 ++++++------------ src/app/(investment)/deals/[id]/page.tsx | 2 +- src/app/portfolio/[uid]/page.tsx | 1 + .../navigationBar/AuthenticatedComponents.tsx | 9 ++++++--- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/app/(investment)/deals/[id]/followShareButton.tsx b/src/app/(investment)/deals/[id]/followShareButton.tsx index 5a2c8de..f6bb4b8 100644 --- a/src/app/(investment)/deals/[id]/followShareButton.tsx +++ b/src/app/(investment)/deals/[id]/followShareButton.tsx @@ -3,7 +3,7 @@ /* eslint-disable */ import { useState, useEffect } from "react"; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; +import CustomTooltip from "@/components/customToolTip"; import { ShareIcon, StarIcon } from "lucide-react"; import { deleteFollow, getFollow, insertFollow } from "@/lib/data/followQuery"; import toast from "react-hot-toast"; @@ -13,9 +13,10 @@ import { useQuery } from "@supabase-cache-helpers/postgrest-react-query"; interface FollowShareButtons { userId: string; projectId: number; + projectName: string; } -const FollowShareButtons = ({ userId, projectId }: FollowShareButtons) => { +const FollowShareButtons = ({ userId, projectId, projectName }: FollowShareButtons) => { const supabase = createSupabaseClient(); const { data: follow, isLoading: followIsLoading } = useQuery(getFollow(supabase, userId, projectId), { staleTime: 0, @@ -71,16 +72,9 @@ const FollowShareButtons = ({ userId, projectId }: FollowShareButtons) => { return (
- - - - - - -

Follow NVIDIA

-
-
-
+ + +
diff --git a/src/app/(investment)/deals/[id]/page.tsx b/src/app/(investment)/deals/[id]/page.tsx index 73ef4be..cdb057c 100644 --- a/src/app/(investment)/deals/[id]/page.tsx +++ b/src/app/(investment)/deals/[id]/page.tsx @@ -89,7 +89,7 @@ export default async function ProjectDealPage({ params }: { params: { id: number logo

{projectData?.project_name}

- +
{/* end of pack */}

{projectData?.project_short_description}

diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 3eebeec..5531e8f 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -26,6 +26,7 @@ import { UnAuthorizedAlert } from "@/components/alert/unauthorized/alert"; import Link from "next/link"; import { DataTable } from "@/components/dataTable"; import { Button } from "@/components/ui/button"; +import CustomTooltip from "@/components/customToolTip"; export default async function Portfolio({ params }: { params: { uid: string } }) { const supabase = createSupabaseClient(); diff --git a/src/components/navigationBar/AuthenticatedComponents.tsx b/src/components/navigationBar/AuthenticatedComponents.tsx index c2d45b3..1a9a004 100644 --- a/src/components/navigationBar/AuthenticatedComponents.tsx +++ b/src/components/navigationBar/AuthenticatedComponents.tsx @@ -34,9 +34,12 @@ export const AuthenticatedComponents = ({ uid, avatarUrl, notificationCount }: A
{notificationCount >= 1 && ( - - {notificationCount} - +
+ + + {notificationCount} + +
)}
From a05aacca592a9b9012fedef8fa7abb6ef6fcc2aa Mon Sep 17 00:00:00 2001 From: Pattadon Date: Tue, 12 Nov 2024 10:41:45 +0700 Subject: [PATCH 04/17] feat: remove Deals page component; integrate Modal in Portfolio for deal viewing --- src/app/dashboard/deals/page.tsx | 9 --------- src/app/portfolio/[uid]/page.tsx | 16 +++++++++++----- src/app/portfolio/[uid]/query.ts | 3 ++- src/components/modal.tsx | 26 ++++++++++++++++++++++++++ src/lib/data/investmentQuery.ts | 17 ++++++++++++++++- 5 files changed, 55 insertions(+), 16 deletions(-) delete mode 100644 src/app/dashboard/deals/page.tsx create mode 100644 src/components/modal.tsx diff --git a/src/app/dashboard/deals/page.tsx b/src/app/dashboard/deals/page.tsx deleted file mode 100644 index 4b70825..0000000 --- a/src/app/dashboard/deals/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { DataTable } from "@/components/dataTable"; - -export default function Deals() { - return ( -
-

hello นาา

-
- ); -} diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 5531e8f..14f0440 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -27,6 +27,7 @@ import Link from "next/link"; import { DataTable } from "@/components/dataTable"; import { Button } from "@/components/ui/button"; import CustomTooltip from "@/components/customToolTip"; +import { Modal } from "@/components/modal"; export default async function Portfolio({ params }: { params: { uid: string } }) { const supabase = createSupabaseClient(); @@ -75,7 +76,15 @@ export default async function Portfolio({ params }: { params: { uid: string } }) const tags = deals ? await getInvestorProjectTag(supabase, deals) : []; const latestDeals = deals ? await Promise.all( - (await getLatestInvestment(supabase, deals)).map(async (deal) => ({ + ( + await getLatestInvestment( + supabase, + deals.map((deal) => ({ + ...deal, + status: deal.deal_status, + })) + ) + ).map(async (deal) => ({ ...deal, logo_url: await deal.logo_url, })) @@ -99,7 +108,6 @@ export default async function Portfolio({ params }: { params: { uid: string } })

-
@@ -235,9 +243,7 @@ export default async function Portfolio({ params }: { params: { uid: string } }) -
- {deals && deals.length > 5 ? : undefined} -
+
{deals && deals.length ? : undefined}
diff --git a/src/app/portfolio/[uid]/query.ts b/src/app/portfolio/[uid]/query.ts index 3333de8..1ea68ff 100644 --- a/src/app/portfolio/[uid]/query.ts +++ b/src/app/portfolio/[uid]/query.ts @@ -26,7 +26,7 @@ function getTotalInvestment(deals: { deal_amount: number }[]) { } async function getLatestInvestment( supabase: SupabaseClient, - deals: { project_id: number; deal_amount: number; created_time: Date;}[] + deals: { project_id: number; deal_amount: number; created_time: Date; status: string}[] ) { const llist = []; const count = 5; @@ -43,6 +43,7 @@ async function getLatestInvestment( amount: deals[i].deal_amount, date: new Date(deals[i].created_time), logo_url: url, + status: deals[i].status, }); } diff --git a/src/components/modal.tsx b/src/components/modal.tsx new file mode 100644 index 0000000..ed3c435 --- /dev/null +++ b/src/components/modal.tsx @@ -0,0 +1,26 @@ +"use client"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { Button } from "./ui/button"; +import { DataTable } from "./dataTable"; + +export function Modal() { + return ( +
+ + + + + + {/* */} + + +
+ ); +} diff --git a/src/lib/data/investmentQuery.ts b/src/lib/data/investmentQuery.ts index df9a944..49f7b13 100644 --- a/src/lib/data/investmentQuery.ts +++ b/src/lib/data/investmentQuery.ts @@ -56,7 +56,22 @@ export const getInvestmentByUserId = (client: SupabaseClient, userId: string) => export function getInvestorDeal(client: SupabaseClient, userId: string) { return client .from("investment_deal") - .select("*") + .select( + ` + id, + ...deal_status_id( + deal_status:value + ), + project_id, + deal_amount, + created_time, + ...profiles ( + investor_id:id, + username, + avatar_url + ) + ` + ) .in("investor_id", [userId]) .order("created_time", { ascending: true }); } From b1fa74e8c65bcb492817ec05db01c62722e1dc53 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Tue, 12 Nov 2024 10:54:31 +0700 Subject: [PATCH 05/17] feat: enhance Modal component to accept deal data and display in DataTable --- src/app/portfolio/[uid]/page.tsx | 10 +++++++++- src/components/modal.tsx | 24 ++++++++++++++---------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 14f0440..08f255e 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -243,7 +243,15 @@ export default async function Portfolio({ params }: { params: { uid: string } }) -
{deals && deals.length ? : undefined}
+
+ {deals && deals.length ? { + return { + name: deal.name, + amount: deal.amount, + date: deal.date, + }; + })} /> : undefined} +
diff --git a/src/components/modal.tsx b/src/components/modal.tsx index ed3c435..2de0b43 100644 --- a/src/components/modal.tsx +++ b/src/components/modal.tsx @@ -1,16 +1,20 @@ "use client"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog"; +import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"; import { Button } from "./ui/button"; import { DataTable } from "./dataTable"; -export function Modal() { +export type Payment = { + data?: { + name?: string; + amount?: number; + avatar?: string; + date?: Date; + logo_url?: string; + status?: string; + profile_url?: string; + }[]; +}; +export function Modal({ data }: { data: Payment[] }) { return (
@@ -18,7 +22,7 @@ export function Modal() { - {/* */} +
From 48b03c355212a295ae16c8f6cdc709083f37cc26 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Tue, 12 Nov 2024 10:54:54 +0700 Subject: [PATCH 06/17] refactor: comment out Modal rendering logic in Portfolio component --- src/app/portfolio/[uid]/page.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 08f255e..0ac0a4c 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -244,13 +244,13 @@ export default async function Portfolio({ params }: { params: { uid: string } })
- {deals && deals.length ? { + {/* {deals && deals.length ? { return { name: deal.name, amount: deal.amount, date: deal.date, }; - })} /> : undefined} + })} /> : undefined} */}
From ef6e8cf6c00875fffc697134f2bcf43a4cea067e Mon Sep 17 00:00:00 2001 From: Pattadon Date: Tue, 12 Nov 2024 15:17:43 +0700 Subject: [PATCH 07/17] feat: update Modal and DataTable components to handle additional deal properties and improve rendering logic --- src/app/portfolio/[uid]/page.tsx | 22 ++++++--- src/components/dataTable.tsx | 77 ++++++++++++++++++++++++-------- src/components/modal.tsx | 21 +++++---- 3 files changed, 83 insertions(+), 37 deletions(-) diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 0ac0a4c..163f77c 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -244,13 +244,21 @@ export default async function Portfolio({ params }: { params: { uid: string } })
- {/* {deals && deals.length ? { - return { - name: deal.name, - amount: deal.amount, - date: deal.date, - }; - })} /> : undefined} */} + {/* {latestDeals.length} */} + {deals && deals.length ? ( + { + return { + date: item.date, + name: item.name, + amount: item.amount, + status: item.status, + logoURL: item.logo_url, + profileURL: `deals/${item.projectId}` + }; + })} + /> + ) : undefined}
diff --git a/src/components/dataTable.tsx b/src/components/dataTable.tsx index e7f5d96..d4d80f3 100644 --- a/src/components/dataTable.tsx +++ b/src/components/dataTable.tsx @@ -26,19 +26,17 @@ import { 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 type ModalProps = { + date: Date; + amount: number; + name: string; + investorId?: string; + profileURL?: string; + logoURL?: string; + status?: string; }; -export const columns: ColumnDef[] = [ +export const columns: ColumnDef[] = [ { id: "select", header: ({ table }) => ( @@ -59,21 +57,62 @@ export const columns: ColumnDef[] = [ enableHiding: false, }, { - accessorKey: "email", + accessorKey: "name", header: ({ column }) => { return ( ); }, - cell: ({ row }) =>
{row.getValue("email")}
, + cell: ({ row }) =>
{row.getValue("name")}
, }, { accessorKey: "status", header: "Status", - cell: ({ row }) =>
{row.getValue("status")}
, + cell: ({ row }) => ( +
+ + + + +

+

+ +
{row.getValue("status")}
+
+ ), }, { accessorKey: "amount", @@ -92,7 +131,7 @@ export const columns: ColumnDef[] = [ }, ]; -export function DataTable({ data }: { data: Payment[] }) { +export function DataTable({ data }: { data: ModalProps[] }) { const [sorting, setSorting] = React.useState([]); const [columnFilters, setColumnFilters] = React.useState([]); const [columnVisibility, setColumnVisibility] = React.useState({}); @@ -121,9 +160,9 @@ export function DataTable({ data }: { data: Payment[] }) {
table.getColumn("email")?.setFilterValue(event.target.value)} + placeholder="Filter names..." + value={(table.getColumn("name")?.getFilterValue() as string) ?? ""} + onChange={(event) => table.getColumn("name")?.setFilterValue(event.target.value)} className="max-w-sm" /> diff --git a/src/components/modal.tsx b/src/components/modal.tsx index 2de0b43..aa58f19 100644 --- a/src/components/modal.tsx +++ b/src/components/modal.tsx @@ -3,18 +3,17 @@ import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"; import { Button } from "./ui/button"; import { DataTable } from "./dataTable"; -export type Payment = { - data?: { - name?: string; - amount?: number; - avatar?: string; - date?: Date; - logo_url?: string; - status?: string; - profile_url?: string; - }[]; +export type ModalProps = { + date: Date; + amount: number; + name: string; + investorId?: string; + profileURL?: string; + logoURL?: string; + status?: string; }; -export function Modal({ data }: { data: Payment[] }) { + +export function Modal({ data }: { data: ModalProps[] }) { return (
From 00c4080b21117f7402fe6fa97d3a79eaa27d2e08 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Tue, 12 Nov 2024 22:24:35 +0700 Subject: [PATCH 08/17] feat: update Portfolio and DataTable components to enhance deal data handling and improve rendering --- src/app/portfolio/[uid]/page.tsx | 21 ++++++----- src/app/portfolio/[uid]/query.ts | 2 +- src/components/dataTable.tsx | 60 ++++++++++++++++++++++++++------ src/components/modal.tsx | 2 +- src/lib/data/investmentQuery.ts | 3 ++ 5 files changed, 66 insertions(+), 22 deletions(-) diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 163f77c..44fafdd 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -57,6 +57,7 @@ export default async function Portfolio({ params }: { params: { uid: string } }) if (investorDealError) { console.error(investorDealError); } + const { data: localUser, error: localUserError } = await supabase.auth.getUser(); if (localUserError) { console.error("Error while fetching user" + error); @@ -82,6 +83,7 @@ export default async function Portfolio({ params }: { params: { uid: string } }) deals.map((deal) => ({ ...deal, status: deal.deal_status, + project_id: deal.project_id, })) ) ).map(async (deal) => ({ @@ -96,6 +98,7 @@ export default async function Portfolio({ params }: { params: { uid: string } }) ? await Promise.all(deals.map(async (item) => await getBusinessTypeName(supabase, item.project_id))) : []; const countedBusinessType = countValues(businessType.filter((item) => item !== null)); + console.table(deals); return (
@@ -244,17 +247,17 @@ export default async function Portfolio({ params }: { params: { uid: string } })
- {/* {latestDeals.length} */} - {deals && deals.length ? ( + {deals?.length} + {deals && deals.length > 5 ? ( { + data={deals.map((item) => { return { - date: item.date, - name: item.name, - amount: item.amount, - status: item.status, - logoURL: item.logo_url, - profileURL: `deals/${item.projectId}` + date: item.created_time, + name: item.username, + amount: item.deal_amount, + status: item.deal_status, + logoURL: Array.isArray(item.avatar_url) ? item.avatar_url[0] : item.avatar_url, + profileURL: `deals/${item.project_id}` as string, }; })} /> diff --git a/src/app/portfolio/[uid]/query.ts b/src/app/portfolio/[uid]/query.ts index 1ea68ff..311a865 100644 --- a/src/app/portfolio/[uid]/query.ts +++ b/src/app/portfolio/[uid]/query.ts @@ -26,7 +26,7 @@ function getTotalInvestment(deals: { deal_amount: number }[]) { } async function getLatestInvestment( supabase: SupabaseClient, - deals: { project_id: number; deal_amount: number; created_time: Date; status: string}[] + deals: { project_id: number; deal_amount: number; created_time: Date; status: string }[] ) { const llist = []; const count = 5; diff --git a/src/components/dataTable.tsx b/src/components/dataTable.tsx index d4d80f3..2ddeeb6 100644 --- a/src/components/dataTable.tsx +++ b/src/components/dataTable.tsx @@ -25,6 +25,8 @@ import { } from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import Link from "next/link"; export type ModalProps = { date: Date; @@ -66,7 +68,25 @@ export const columns: ColumnDef[] = [ ); }, - cell: ({ row }) =>
{row.getValue("name")}
, + cell: ({ row }) => ( +
+ + + + {(row.getValue("name") as string).slice(0, 2)} + + {row.getValue("name")} + +
+ ), + }, + { + accessorKey: "date", + header: () =>
Date
, + cell: ({ row }) => { + const formatted = new Date(row.getValue("date")).toUTCString(); + return
{formatted}
; + }, }, { accessorKey: "status", @@ -101,16 +121,19 @@ export const columns: ColumnDef[] = [ ? "text-green-500" : "text-yellow-500" }`} - > -

+ >

-
{row.getValue("status")}
+
+ {row.getValue("status")} +
), }, @@ -129,6 +152,18 @@ export const columns: ColumnDef[] = [ return
{formatted}
; }, }, + { + accessorKey: "logoURL", + id: "logoURL", + header: () => null, + cell: () => null, + }, + { + accessorKey: "profileURL", + id: "profileURL", + header: () => null, + cell: () => null, + }, ]; export function DataTable({ data }: { data: ModalProps[] }) { @@ -151,7 +186,10 @@ export function DataTable({ data }: { data: ModalProps[] }) { state: { sorting, columnFilters, - columnVisibility, + columnVisibility: { + profileURL: false, + logoURL: false, + }, rowSelection, }, }); diff --git a/src/components/modal.tsx b/src/components/modal.tsx index aa58f19..b6c06c0 100644 --- a/src/components/modal.tsx +++ b/src/components/modal.tsx @@ -20,7 +20,7 @@ export function Modal({ data }: { data: ModalProps[] }) { - +
diff --git a/src/lib/data/investmentQuery.ts b/src/lib/data/investmentQuery.ts index 49f7b13..7c11aa0 100644 --- a/src/lib/data/investmentQuery.ts +++ b/src/lib/data/investmentQuery.ts @@ -63,6 +63,9 @@ export function getInvestorDeal(client: SupabaseClient, userId: string) { deal_status:value ), project_id, + ...project_id ( + project_name + ), deal_amount, created_time, ...profiles ( From b2837dd4a85454709f4240d6b197acf852bfd057 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Tue, 12 Nov 2024 22:32:05 +0700 Subject: [PATCH 09/17] feat: update deal data mapping in Portfolio component to use project name instead of username --- src/app/portfolio/[uid]/page.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 44fafdd..5b1ed70 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -247,13 +247,12 @@ export default async function Portfolio({ params }: { params: { uid: string } })
- {deals?.length} {deals && deals.length > 5 ? ( { return { date: item.created_time, - name: item.username, + name: item.project_name, amount: item.deal_amount, status: item.deal_status, logoURL: Array.isArray(item.avatar_url) ? item.avatar_url[0] : item.avatar_url, From 8a95cf50db5d7c5c6df24df364de9f60fa294dc7 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Wed, 13 Nov 2024 09:54:27 +0700 Subject: [PATCH 10/17] feat: update DataTable component to improve column visibility handling and filtering logic --- src/components/dataTable.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/dataTable.tsx b/src/components/dataTable.tsx index 2ddeeb6..17d2b7c 100644 --- a/src/components/dataTable.tsx +++ b/src/components/dataTable.tsx @@ -186,13 +186,11 @@ export function DataTable({ data }: { data: ModalProps[] }) { state: { sorting, columnFilters, - columnVisibility: { - profileURL: false, - logoURL: false, - }, + columnVisibility, rowSelection, }, }); + console.table(columnVisibility) return (
@@ -212,7 +210,7 @@ export function DataTable({ data }: { data: ModalProps[] }) { {table .getAllColumns() - .filter((column) => column.getCanHide()) + .filter((column) => column.getCanHide() && column.id != "logoURL" && column.id != "profileURL") .map((column) => { return ( Date: Wed, 13 Nov 2024 10:32:48 +0700 Subject: [PATCH 11/17] feat: integrate Modal component for project details in Dashboard and Portfolio, enhance RecentFunds data mapping --- src/app/dashboard/page.tsx | 20 +++++++++++++++----- src/app/portfolio/[uid]/page.tsx | 21 ++++++++++++++++----- src/components/dataTable.tsx | 9 +++++++-- src/lib/data/investmentQuery.ts | 3 +++ 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index f53a071..13746b8 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -17,6 +17,7 @@ import CountUp from "react-countup"; import { Button } from "@/components/ui/button"; import { useRouter } from "next/navigation"; import Link from "next/link"; +import { Modal } from "@/components/modal"; export default function Dashboard() { const supabase = createSupabaseClient(); @@ -296,11 +297,20 @@ export default function Dashboard() { }; })} /> -
- {filteredProject && filteredProject.length > 6 ? ( - +
+ {filteredProject && filteredProject.length > 1 ? ( + { + return { + date: item.created_time, + name: item.username, + amount: item.deal_amount, + status: item.deal_status, + logoURL: Array.isArray(item.avatar_url) ? item.avatar_url[0] : item.avatar_url, + profileURL: `/profile/${item.investor_id}`, + }; + })} + /> ) : undefined}
diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 5b1ed70..4a362d2 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -189,8 +189,8 @@ export default async function Portfolio({ params }: { params: { uid: string } })
-
- +
+ Categories of Invested Projects @@ -215,7 +215,7 @@ export default async function Portfolio({ params }: { params: { uid: string } }) /> - + Types of Businesses Invested In @@ -245,7 +245,18 @@ export default async function Portfolio({ params }: { params: { uid: string } }) Recent investment - + { + return { + name: item.name, + amount: item.amount, + avatar: item.logo_url, + date: new Date(item.date), + status: item.status, + profile_url: `/deals/${item.projectId}`, + }; + })} + />
{deals && deals.length > 5 ? ( diff --git a/src/components/dataTable.tsx b/src/components/dataTable.tsx index 17d2b7c..16e5e3b 100644 --- a/src/components/dataTable.tsx +++ b/src/components/dataTable.tsx @@ -70,13 +70,18 @@ export const columns: ColumnDef[] = [ }, cell: ({ row }) => (
- +
), }, diff --git a/src/lib/data/investmentQuery.ts b/src/lib/data/investmentQuery.ts index 7c11aa0..dfbabd2 100644 --- a/src/lib/data/investmentQuery.ts +++ b/src/lib/data/investmentQuery.ts @@ -20,6 +20,9 @@ export const getInvestmentByProjectsIds = (client: SupabaseClient, projectIds: s deal_status:value ), project_id, + ...project_id ( + project_name + ), deal_amount, created_time, ...profiles ( From 52204c4a6f00024d38d594f782cc9531d29ee1e9 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Wed, 13 Nov 2024 10:54:35 +0700 Subject: [PATCH 12/17] feat: add pagination state management to DataTable component --- src/components/dataTable.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/dataTable.tsx b/src/components/dataTable.tsx index 16e5e3b..4b440e4 100644 --- a/src/components/dataTable.tsx +++ b/src/components/dataTable.tsx @@ -176,6 +176,10 @@ export function DataTable({ data }: { data: ModalProps[] }) { const [columnFilters, setColumnFilters] = React.useState([]); const [columnVisibility, setColumnVisibility] = React.useState({}); const [rowSelection, setRowSelection] = React.useState({}); + const [pagination, setPagination] = React.useState({ + pageIndex: 0, //initial page index + pageSize: 5, //default page size + }); const table = useReactTable({ data, @@ -187,15 +191,16 @@ export function DataTable({ data }: { data: ModalProps[] }) { getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), onColumnVisibilityChange: setColumnVisibility, + onPaginationChange: setPagination, onRowSelectionChange: setRowSelection, state: { sorting, columnFilters, columnVisibility, rowSelection, + pagination, }, }); - console.table(columnVisibility) return (
From 63efe5ffa29332e06a69cff8dd1ecb719770f2d0 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Wed, 13 Nov 2024 15:26:40 +0700 Subject: [PATCH 13/17] feat: enhance carousel component with synchronization and improve accessibility in project deal page --- src/app/(investment)/deals/[id]/page.tsx | 5 +- src/components/carousel.tsx | 90 +++++++++++++++--------- src/components/ui/carousel.tsx | 12 ++-- 3 files changed, 66 insertions(+), 41 deletions(-) diff --git a/src/app/(investment)/deals/[id]/page.tsx b/src/app/(investment)/deals/[id]/page.tsx index cdb057c..8cb6b8b 100644 --- a/src/app/(investment)/deals/[id]/page.tsx +++ b/src/app/(investment)/deals/[id]/page.tsx @@ -1,8 +1,6 @@ import Image from "next/image"; import Link from "next/link"; - import ReactMarkdown from "react-markdown"; - import * as Tabs from "@radix-ui/react-tabs"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from "@/components/ui/card"; @@ -10,7 +8,6 @@ import { Progress } from "@/components/ui/progress"; import { Separator } from "@/components/ui/separator"; import { createSupabaseClient } from "@/lib/supabase/serverComponentClient"; import FollowShareButtons from "./followShareButton"; - import { getProjectData } from "@/lib/data/projectQuery"; import { getDealList } from "@/app/api/dealApi"; import { sumByKey, toPercentage } from "@/lib/utils"; @@ -89,7 +86,7 @@ export default async function ProjectDealPage({ params }: { params: { id: number logo

{projectData?.project_name}

- +
{/* end of pack */}

{projectData?.project_short_description}

diff --git a/src/components/carousel.tsx b/src/components/carousel.tsx index eb994e1..7951303 100644 --- a/src/components/carousel.tsx +++ b/src/components/carousel.tsx @@ -1,5 +1,5 @@ "use client"; -import { useEffect, useState, useMemo } from "react"; +import { useEffect, useState, useMemo, useCallback } from "react"; import { Carousel, CarouselContent, CarouselItem, type CarouselApi } from "./ui/carousel"; import Image from "next/image"; @@ -8,15 +8,40 @@ interface GalleryProps { } const Gallery = ({ images }: GalleryProps) => { - const [mainApi, setMainApi] = useState(); - const [thumbnailApi, setThumbnailApi] = useState(); + const [mainApi, setMainApi] = useState(null); + const [thumbnailApi, setThumbnailApi] = useState(null); const [current, setCurrent] = useState(0); + const [isReady, setIsReady] = useState(false); + + const syncCarousels = useCallback( + (index: number) => { + if (mainApi && thumbnailApi) { + setCurrent(index); + mainApi.scrollTo(index); + thumbnailApi.scrollTo(index); + } + }, + [mainApi, thumbnailApi] + ); + + const handleClick = useCallback( + (index: number) => { + syncCarousels(index); + }, + [syncCarousels] + ); const mainImage = useMemo( () => images.map((image, index) => ( - {`Carousel + {`Carousel )), [images] @@ -25,61 +50,60 @@ const Gallery = ({ images }: GalleryProps) => { const thumbnailImages = useMemo( () => images.map((image, index) => ( - handleClick(index)}> + handleClick(index)} + > {`Carousel )), - // eslint-disable-next-line react-hooks/exhaustive-deps - [images, current] + [images, current, handleClick] ); useEffect(() => { - if (!mainApi || !thumbnailApi) { - return; - } + if (!mainApi || !thumbnailApi) return; + if (isReady) return; - const handleTopSelect = () => { + const handleMainSelect = () => { const selected = mainApi.selectedScrollSnap(); - setCurrent(selected); - thumbnailApi.scrollTo(selected); + if (selected !== current) { + syncCarousels(selected); + } }; - const handleBottomSelect = () => { + const handleThumbnailSelect = () => { const selected = thumbnailApi.selectedScrollSnap(); - setCurrent(selected); - mainApi.scrollTo(selected); + if (selected !== current) { + syncCarousels(selected); + } }; - mainApi.on("select", handleTopSelect); - thumbnailApi.on("select", handleBottomSelect); + mainApi.on("select", handleMainSelect); + thumbnailApi.on("select", handleThumbnailSelect); + + syncCarousels(0); + setIsReady(true); return () => { - mainApi.off("select", handleTopSelect); - thumbnailApi.off("select", handleBottomSelect); + mainApi.off("select", handleMainSelect); + thumbnailApi.off("select", handleThumbnailSelect); }; - }, [mainApi, thumbnailApi]); - - const handleClick = (index: number) => { - if (!mainApi || !thumbnailApi) { - return; - } - thumbnailApi.scrollTo(index); - mainApi.scrollTo(index); - setCurrent(index); - }; + }, [mainApi, thumbnailApi, current, syncCarousels, isReady]); return (
- + {mainImage} - + {thumbnailImages}
diff --git a/src/components/ui/carousel.tsx b/src/components/ui/carousel.tsx index 59831f9..2ff1992 100644 --- a/src/components/ui/carousel.tsx +++ b/src/components/ui/carousel.tsx @@ -115,14 +115,16 @@ const Carousel = React.forwardRef + }} + >
+ {...props} + > {children}
@@ -183,7 +185,8 @@ const CarouselPrevious = React.forwardRef + {...props} + > Previous slide @@ -210,7 +213,8 @@ const CarouselNext = React.forwardRef + {...props} + > Next slide From 8a09cbae85af2634276fac359289407e65bf3081 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Thu, 14 Nov 2024 14:14:38 +0700 Subject: [PATCH 14/17] feat: refactor layout in Portfolio and ProjectSection components for improved responsiveness and update DataTable pagination state management --- src/app/portfolio/[uid]/page.tsx | 9 ++++----- src/components/ProjectSection.tsx | 2 +- src/components/dataTable.tsx | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 4a362d2..4dee08c 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -98,7 +98,6 @@ export default async function Portfolio({ params }: { params: { uid: string } }) ? await Promise.all(deals.map(async (item) => await getBusinessTypeName(supabase, item.project_id))) : []; const countedBusinessType = countValues(businessType.filter((item) => item !== null)); - console.table(deals); return (
@@ -189,8 +188,8 @@ export default async function Portfolio({ params }: { params: { uid: string } })
-
- +
+ Categories of Invested Projects @@ -215,7 +214,7 @@ export default async function Portfolio({ params }: { params: { uid: string } }) /> - + Types of Businesses Invested In @@ -240,7 +239,7 @@ export default async function Portfolio({ params }: { params: { uid: string } }) /> - + Recent investment diff --git a/src/components/ProjectSection.tsx b/src/components/ProjectSection.tsx index 92dbd06..13b41ad 100644 --- a/src/components/ProjectSection.tsx +++ b/src/components/ProjectSection.tsx @@ -20,7 +20,7 @@ export function ProjectSection({ projectsData }: { projectsData: ProjectCardProp } return ( -
+
{projectsData.map((project) => (
diff --git a/src/components/dataTable.tsx b/src/components/dataTable.tsx index 4b440e4..195aea8 100644 --- a/src/components/dataTable.tsx +++ b/src/components/dataTable.tsx @@ -177,8 +177,8 @@ export function DataTable({ data }: { data: ModalProps[] }) { const [columnVisibility, setColumnVisibility] = React.useState({}); const [rowSelection, setRowSelection] = React.useState({}); const [pagination, setPagination] = React.useState({ - pageIndex: 0, //initial page index - pageSize: 5, //default page size + pageIndex: 0, + pageSize: 5, }); const table = useReactTable({ From b47891ee647e0698c0c612ad782bf83bb304e387 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Thu, 14 Nov 2024 14:17:42 +0700 Subject: [PATCH 15/17] feat: implement new filtering options in DataTable component for enhanced user experience --- src/app/dashboard/page.tsx | 374 ++++++++++++++++++------------------- 1 file changed, 178 insertions(+), 196 deletions(-) diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 13746b8..15a639a 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -118,209 +118,191 @@ export default function Dashboard() { return (
{" "} -
- Dashboard - Dashboard -
-
-
-
-

Business Dashboard

-
- {projects && projects.length > 0 && ( - - - {projects.map((project) => ( - setCurrentProjectId(project.id)} - > - {project.project_name} - - ))} - +
+
+

Business Dashboard

+
+ {projects && projects.length > 0 && ( + + {projects.map((project) => ( - -
- - - Total Funds Raised - - - - - -
- $ - project.deal_status === "Completed") - .reduce((sum, current) => sum + current.deal_amount, 0)} - duration={1} - /> -
-
-
- - - Profile Views - - - - - - -
- + -
- {/*

+ setCurrentProjectId(project.id)} + > + {project.project_name} + + ))} + + {projects.map((project) => ( + +

+ + + Total Funds Raised + + + + + +
+ $ + project.deal_status === "Completed") + .reduce((sum, current) => sum + current.deal_amount, 0)} + duration={1} + /> +
+
+
+ + + Profile Views + + + + + + +
+ + +
+ {/*

+180.1% from last month

*/} -
-
- - - Total Followers - - - - - - - -
- + -
- {/*

+ + + + + Total Followers + + + + + + + +

+ + +
+ {/*

+19% from last month

*/} -
-
- -
-
- - - Overview - - - - {tabOptions.map((tab) => ( - - {tab.charAt(0).toUpperCase() + tab.slice(1)} - - ))} - - - + + + +
+
+ + + Overview + + + + {tabOptions.map((tab) => ( + + {tab.charAt(0).toUpperCase() + tab.slice(1)} + + ))} + + + - - - setGraphType("line")}> - Line - - setGraphType("bar")}> - Bar - - - - - - - - - Recent Funds - - - { - return { - name: item.username, - amount: item.dealAmount, - avatar: item.avatarUrl, - date: new Date(item.createdTime), - status: item.dealStatus, - profile_url: `/profile/${item.investorId}`, - }; - })} - /> -
- {filteredProject && filteredProject.length > 1 ? ( - { - return { - date: item.created_time, - name: item.username, - amount: item.deal_amount, - status: item.deal_status, - logoURL: Array.isArray(item.avatar_url) ? item.avatar_url[0] : item.avatar_url, - profileURL: `/profile/${item.investor_id}`, - }; - })} - /> - ) : undefined} -
+ + + setGraphType("line")}> + Line + + setGraphType("bar")}> + Bar + + +
-
-
- - ))} - - )} -
+
+ + + + Recent Funds + + + { + return { + name: item.username, + amount: item.dealAmount, + avatar: item.avatarUrl, + date: new Date(item.createdTime), + status: item.dealStatus, + profile_url: `/profile/${item.investorId}`, + }; + })} + /> +
+ {filteredProject && filteredProject.length > 1 ? ( + { + return { + date: item.created_time, + name: item.username, + amount: item.deal_amount, + status: item.deal_status, + logoURL: Array.isArray(item.avatar_url) ? item.avatar_url[0] : item.avatar_url, + profileURL: `/profile/${item.investor_id}`, + }; + })} + /> + ) : undefined} +
+
+
+
+ + ))} +
+ )}
); From 2ab3964a8170932123a570e6032e67acc2fdf90d Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Thu, 14 Nov 2024 19:08:46 +0700 Subject: [PATCH 16/17] feat: update layout and responsiveness of Dashboard, DataTable, and Modal components for improved user experience --- src/app/dashboard/page.tsx | 4 ++-- src/components/dataTable.tsx | 2 +- src/components/modal.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 15a639a..7bed7a5 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -263,11 +263,11 @@ export default function Dashboard() { - + Recent Funds - + { return { diff --git a/src/components/dataTable.tsx b/src/components/dataTable.tsx index 195aea8..8385d7e 100644 --- a/src/components/dataTable.tsx +++ b/src/components/dataTable.tsx @@ -203,7 +203,7 @@ export function DataTable({ data }: { data: ModalProps[] }) { }); return ( -
+
- + From a98321d6d5a2fe4c91a9592f7ecb0117826a04ce Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Sat, 16 Nov 2024 16:45:47 +0700 Subject: [PATCH 17/17] feat: add mobile menu component and integrate with navigation bar for improved accessibility --- package-lock.json | 26 ++++++++++++++++++++++++++ package.json | 1 + src/components/mobileMenu.tsx | 27 +++++++++++++++++++++++++++ src/components/navigationBar/nav.tsx | 10 +++++++--- 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 src/components/mobileMenu.tsx diff --git a/package-lock.json b/package-lock.json index 5a12811..eff5883 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,7 @@ "date-fns": "^4.1.0", "dotenv": "^16.4.5", "embla-carousel-react": "^8.2.0", + "framer-motion": "^11.11.17", "lucide-react": "^0.428.0", "next": "^14.2.15", "next-themes": "^0.3.0", @@ -6953,6 +6954,31 @@ "node": ">=12.20.0" } }, + "node_modules/framer-motion": { + "version": "11.11.17", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.11.17.tgz", + "integrity": "sha512-O8QzvoKiuzI5HSAHbcYuL6xU+ZLXbrH7C8Akaato4JzQbX2ULNeniqC2Vo5eiCtFktX9XsJ+7nUhxcl2E2IjpA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", diff --git a/package.json b/package.json index 32f6b05..c7803bb 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "date-fns": "^4.1.0", "dotenv": "^16.4.5", "embla-carousel-react": "^8.2.0", + "framer-motion": "^11.11.17", "lucide-react": "^0.428.0", "next": "^14.2.15", "next-themes": "^0.3.0", diff --git a/src/components/mobileMenu.tsx b/src/components/mobileMenu.tsx new file mode 100644 index 0000000..9c513a8 --- /dev/null +++ b/src/components/mobileMenu.tsx @@ -0,0 +1,27 @@ +"use client"; +import { useState } from "react"; +import { Menu, X } from "lucide-react"; +import { Button } from "./ui/button"; +import { motion } from "framer-motion"; + +export function MobileMenu() { + const [isVisible, setIsVisible] = useState(false); + return ( +
+ + {isVisible && ( + + setIsVisible(false)} /> + + )} +
+ ); +} diff --git a/src/components/navigationBar/nav.tsx b/src/components/navigationBar/nav.tsx index 5d27fa3..e4f0233 100644 --- a/src/components/navigationBar/nav.tsx +++ b/src/components/navigationBar/nav.tsx @@ -21,6 +21,8 @@ import { createSupabaseClient } from "@/lib/supabase/serverComponentClient"; import { getUserId } from "@/lib/supabase/actions/getUserId"; import { getUnreadNotificationCountByUserId } from "@/lib/data/notificationQuery"; +import { MobileMenu } from "../mobileMenu"; + const ListItem = React.forwardRef, React.ComponentPropsWithoutRef<"a">>( ({ className, title, children, ...props }, ref) => { return ( @@ -97,8 +99,10 @@ export async function NavigationBar() {
- -
+
+ +
+
@@ -146,7 +150,7 @@ export async function NavigationBar() { -
+