From 42b47aa4e87d2e065388e01b4da15369b8e53411 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Tue, 29 Oct 2024 11:24:40 +0700 Subject: [PATCH 01/48] Refactor file upload path and add loading animation to ApplyProject component --- package-lock.json | 10 +- package.json | 4 +- src/app/api/dealApi.ts | 42 +++---- src/app/business/apply/page.tsx | 11 +- src/app/dashboard/page.tsx | 53 ++++++++- src/app/portfolio/[uid]/page.tsx | 35 ++++++ src/app/project/apply/page.tsx | 2 +- src/components/ui/overview.tsx | 193 +++++++++++++++---------------- src/lib/data/query.ts | 41 ++++--- 9 files changed, 247 insertions(+), 144 deletions(-) create mode 100644 src/app/portfolio/[uid]/page.tsx diff --git a/package-lock.json b/package-lock.json index 0bc78fd..461b0fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "lucide-react": "^0.428.0", "next": "^14.2.15", "next-themes": "^0.3.0", - "react": "^18", + "react": "^18.3.1", "react-countup": "^6.5.3", "react-dom": "^18", "react-hook-form": "^7.53.0", @@ -62,7 +62,7 @@ "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/next": "^8.0.7", "@types/node": "^20", - "@types/react": "^18", + "@types/react": "^18.3.12", "@types/react-dom": "^18", "@types/react-fade-in": "^2.0.2", "@types/react-lottie": "^1.2.10", @@ -2363,9 +2363,9 @@ "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" }, "node_modules/@types/react": { - "version": "18.3.10", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.10.tgz", - "integrity": "sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg==", + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" diff --git a/package.json b/package.json index 80c2a9a..eaf2743 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "lucide-react": "^0.428.0", "next": "^14.2.15", "next-themes": "^0.3.0", - "react": "^18", + "react": "^18.3.1", "react-countup": "^6.5.3", "react-dom": "^18", "react-hook-form": "^7.53.0", @@ -63,7 +63,7 @@ "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/next": "^8.0.7", "@types/node": "^20", - "@types/react": "^18", + "@types/react": "^18.3.12", "@types/react-dom": "^18", "@types/react-fade-in": "^2.0.2", "@types/react-lottie": "^1.2.10", diff --git a/src/app/api/dealApi.ts b/src/app/api/dealApi.ts index 31b2094..a7fdd99 100644 --- a/src/app/api/dealApi.ts +++ b/src/app/api/dealApi.ts @@ -6,12 +6,13 @@ export type Deal = { created_time: Date; investor_id: string; }; +const supabase = createSupabaseClient(); export async function getDealList() { - const supabase = createSupabaseClient(); const { data: dealData, error } = await supabase - .from('business') - .select(` + .from("business") + .select( + ` id, project ( id, @@ -21,24 +22,25 @@ export async function getDealList() { investor_id ) ) - `) - .eq('user_id', await getCurrentUserID()) + ` + ) + .eq("user_id", await getCurrentUserID()) .single(); - if (error || !dealData) { - alert(JSON.stringify(error)); - console.error('Error fetching deal list:', error); - } else { - const dealList = dealData.project[0].investment_deal; + if (error || !dealData) { + alert(JSON.stringify(error)); + console.error("Error fetching deal list:", error); + } else { + const dealList = dealData.project[0].investment_deal; - if (!dealList.length) { - alert("No data available"); - return; // Exit early if there's no data - } - - // Sort the dealList by created_time in descending order - const byCreatedTimeDesc = (a: Deal, b: Deal) => - new Date(b.created_time).getTime() - new Date(a.created_time).getTime(); - return dealList.sort(byCreatedTimeDesc); + if (!dealList.length) { + alert("No data available"); + return; // Exit early if there's no data } -}; \ No newline at end of file + + // Sort the dealList by created_time in descending order + const byCreatedTimeDesc = (a: Deal, b: Deal) => + new Date(b.created_time).getTime() - new Date(a.created_time).getTime(); + return dealList.sort(byCreatedTimeDesc); + } +} diff --git a/src/app/business/apply/page.tsx b/src/app/business/apply/page.tsx index 1e18c81..6eab724 100644 --- a/src/app/business/apply/page.tsx +++ b/src/app/business/apply/page.tsx @@ -89,11 +89,16 @@ export default function ApplyBusiness() { .from("business") .select("*") .eq("user_id", userID); - console.table(business); - if (error) { + let { data: businessApplication, error: applicationError } = await supabase + .from("business_application") + .select("*") + .eq("user_id", userID); + // console.table(business); + if (error || applicationError) { console.error(error); + console.error(applicationError); } - if (business) { + if ((business && business.length != 0) || (businessApplication && businessApplication.length != 0)) { return true; } return false; diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 3d2840f..67dbdf8 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -14,6 +14,57 @@ import { useState } from "react"; import { useDealList } from "./hook"; +const data = [ + { + name: "Jan", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Feb", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Mar", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Apr", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "May", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Jun", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Jul", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Aug", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Sep", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Oct", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Nov", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Dec", + value: Math.floor(Math.random() * 5000) + 1000, + }, +]; + export default function Dashboard() { const [graphType, setGraphType] = useState("line"); const dealList = useDealList(); @@ -166,7 +217,7 @@ export default function Dashboard() { Overview - + {/* tab to switch between line and bar graph */} { + const date = new Date(dateString); + return date.toLocaleString("default", { month: "long" }); + }; + + const graphData = deals + ? deals.map((item) => ({ + // convert month's index to string + name: getMonthName(item.created_time), + value: item.deal_amount as number, + })) + : []; + + return ( +
+ {/* {JSON.stringify(deals)} */} + {JSON.stringify(graphData)} + +
+ ); +} diff --git a/src/app/project/apply/page.tsx b/src/app/project/apply/page.tsx index 204164b..abbb012 100644 --- a/src/app/project/apply/page.tsx +++ b/src/app/project/apply/page.tsx @@ -17,7 +17,7 @@ const BUCKET_PITCH_APPLICATION_NAME = "project-application"; export default function ApplyProject() { const [isSuccess, setIsSuccess] = useState(true); const onSubmit: SubmitHandler = async (data) => { - alert("มาแน้ววว"); + // alert("มาแน้ววว"); await sendApplication(data); // console.table(data); // console.log(typeof data["projectPhotos"], data["projectPhotos"]); diff --git a/src/components/ui/overview.tsx b/src/components/ui/overview.tsx index dbe45f8..1834549 100644 --- a/src/components/ui/overview.tsx +++ b/src/components/ui/overview.tsx @@ -2,109 +2,106 @@ import { Bar, BarChart, ResponsiveContainer, XAxis, YAxis, LineChart, Line } from "recharts"; -const data = [ - { - name: "Jan", - total: Math.floor(Math.random() * 5000) + 1000, - }, - { - name: "Feb", - total: Math.floor(Math.random() * 5000) + 1000, - }, - { - name: "Mar", - total: Math.floor(Math.random() * 5000) + 1000, - }, - { - name: "Apr", - total: Math.floor(Math.random() * 5000) + 1000, - }, - { - name: "May", - total: Math.floor(Math.random() * 5000) + 1000, - }, - { - name: "Jun", - total: Math.floor(Math.random() * 5000) + 1000, - }, - { - name: "Jul", - total: Math.floor(Math.random() * 5000) + 1000, - }, - { - name: "Aug", - total: Math.floor(Math.random() * 5000) + 1000, - }, - { - name: "Sep", - total: Math.floor(Math.random() * 5000) + 1000, - }, - { - name: "Oct", - total: Math.floor(Math.random() * 5000) + 1000, - }, - { - name: "Nov", - total: Math.floor(Math.random() * 5000) + 1000, - }, - { - name: "Dec", - total: Math.floor(Math.random() * 5000) + 1000, - }, -]; +// const data = [ +// { +// name: "Jan", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Feb", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Mar", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Apr", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "May", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Jun", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Jul", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Aug", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Sep", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Oct", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Nov", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Dec", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// ]; interface OverViewProps{ graphType:string; + data: {name: string, value: number}[]; } export function Overview(props: OverViewProps) { return ( - - {props.graphType === 'line' ? ( - - - `$${value}`} - /> - - - ) : ( - - - `$${value}`} - /> - - - )} - - ); + + {props.graphType === "line" ? ( + + + `$${value}`} + /> + + + ) : ( + + + `$${value}`} + /> + + + )} + + ); } diff --git a/src/lib/data/query.ts b/src/lib/data/query.ts index 6689a34..da4a9da 100644 --- a/src/lib/data/query.ts +++ b/src/lib/data/query.ts @@ -1,10 +1,10 @@ import { SupabaseClient } from "@supabase/supabase-js"; function getBusinesses(client: SupabaseClient, query: string | null) { - return client.from("business").select("id, business_name, joined_date").ilike( - "business_name", - `%${query}%`, - ); + return client + .from("business") + .select("id, business_name, joined_date") + .ilike("business_name", `%${query}%`); } function getProjects(client: SupabaseClient, businessIds: string[]) { @@ -22,23 +22,36 @@ function getProjects(client: SupabaseClient, businessIds: string[]) { total_investment, target_investment ) - `, + ` ) .in("business_id", businessIds); } function getTags(client: SupabaseClient, projectIds: string[]) { - return client.from("item_tag").select("item_id, tag (value)").in( - "item_id", - projectIds, - ); + return client + .from("item_tag") + .select("item_id, tag (value)") + .in("item_id", projectIds); } function getInvestmentCounts(client: SupabaseClient, projectIds: string[]) { - return client.from("investment_deal").select("*", { - count: "exact", - head: true, - }).in("project_id", projectIds); + return client + .from("investment_deal") + .select("*", { + count: "exact", + head: true, + }) + .in("project_id", projectIds); } -export { getBusinesses, getInvestmentCounts, getProjects, getTags }; +function getInvestorDeal(client: SupabaseClient, userId: string) { + return client.from("investment_deal").select("*").in("investor_id", [userId]); +} + +export { + getBusinesses, + getInvestmentCounts, + getProjects, + getTags, + getInvestorDeal, +}; From 44a389c488751f6f0debaadc6533db4d1635f9e2 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Tue, 29 Oct 2024 13:03:45 +0700 Subject: [PATCH 02/48] Refactor date filtering and data aggregation in Portfolio component --- src/app/portfolio/[uid]/page.tsx | 80 +++++++++++++++++++++++++++----- src/components/ui/overview.tsx | 4 +- src/lib/data/query.ts | 7 ++- 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index d100da5..1922125 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -12,24 +12,82 @@ export default async function Portfolio({ if (error) { console.error(error); } - const getMonthName = (dateString: string) => { - const date = new Date(dateString); - return date.toLocaleString("default", { month: "long" }); + const yearAgo = (num: number) => { + const newDate = new Date(); + newDate.setFullYear(newDate.getFullYear() - num); + return newDate; }; - const graphData = deals - ? deals.map((item) => ({ - // convert month's index to string - name: getMonthName(item.created_time), - value: item.deal_amount as number, - })) + const getMonthName = (dateString: string) => { + const date = new Date(dateString); + return date.toLocaleString("default", { month: "long", year: "numeric" }); + }; + + const overAllGraphData = deals + ? deals + .filter((item) => new Date(item.created_time) >= yearAgo(1)) + .reduce( + (acc, item) => { + const monthName = getMonthName(item.created_time).slice(0, 3); + const existingMonth = acc.find( + (entry: { name: string }) => entry.name === monthName + ); + + if (existingMonth) { + existingMonth.value += item.deal_amount; + } else { + acc.push({ name: monthName, value: item.deal_amount }); + } + + return acc; + }, + [] as { name: string; value: number }[] + ) : []; +const threeYearGraphData = deals + ? deals + .filter((item) => new Date(item.created_time) >= yearAgo(3)) + .reduce( + (acc, item) => { + const year = new Date(item.created_time).getFullYear(); + const existingYear = acc.find( + (entry: { name: string; }) => entry.name === year.toString() + ); + + if (existingYear) { + existingYear.value += item.deal_amount; + } else { + acc.push({ name: year.toString(), value: item.deal_amount }) + } + + return acc; + }, + [] as { name: string; value: number }[] + ) + : []; + + + + // const graphData = [ + // { name: "October", value: 500 }, + // { name: "October", value: 500 }, + // { name: "November", value: 500 }, + // { name: "December", value: 500 }, + // { name: "January", value: 500 }, + // { name: "Febuary", value: 500 }, + // { name: "March", value: 500 }, + // ]; + return (
{/* {JSON.stringify(deals)} */} - {JSON.stringify(graphData)} - + {/* {JSON.stringify(deals)} */} + {/* {JSON.stringify(threeYearGraphData)} */} +
+ + +
); } diff --git a/src/components/ui/overview.tsx b/src/components/ui/overview.tsx index 1834549..8c4cf9f 100644 --- a/src/components/ui/overview.tsx +++ b/src/components/ui/overview.tsx @@ -78,7 +78,7 @@ export function Overview(props: OverViewProps) { tickFormatter={(value) => `$${value}`} /> @@ -99,7 +99,7 @@ export function Overview(props: OverViewProps) { axisLine={false} tickFormatter={(value) => `$${value}`} /> - + )} diff --git a/src/lib/data/query.ts b/src/lib/data/query.ts index da4a9da..9a06cd1 100644 --- a/src/lib/data/query.ts +++ b/src/lib/data/query.ts @@ -45,9 +45,14 @@ function getInvestmentCounts(client: SupabaseClient, projectIds: string[]) { } function getInvestorDeal(client: SupabaseClient, userId: string) { - return client.from("investment_deal").select("*").in("investor_id", [userId]); + return client + .from("investment_deal") + .select("*") + .in("investor_id", [userId]) + .order("created_time", { ascending: true }); } + export { getBusinesses, getInvestmentCounts, From 8b9663f0f234cc8677ab2970c71766071bb2f306 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Wed, 30 Oct 2024 10:04:38 +0700 Subject: [PATCH 03/48] Refactor dependencies and add PieChart component --- package-lock.json | 27 ++++++++++++ package.json | 2 + src/app/portfolio/[uid]/page.tsx | 74 +++++++++++++++++++------------- src/components/pieChart.tsx | 33 ++++++++++++++ src/components/ui/overview.tsx | 34 ++++++++++++++- 5 files changed, 137 insertions(+), 33 deletions(-) create mode 100644 src/components/pieChart.tsx diff --git a/package-lock.json b/package-lock.json index 461b0fc..31baf1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "@tanstack/react-query": "^5.59.0", "@tanstack/react-query-devtools": "^5.59.0", "b2d-ventures": "file:", + "chart.js": "^4.4.6", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cmdk": "1.0.0", @@ -43,6 +44,7 @@ "next": "^14.2.15", "next-themes": "^0.3.0", "react": "^18.3.1", + "react-chartjs-2": "^5.2.0", "react-countup": "^6.5.3", "react-dom": "^18", "react-hook-form": "^7.53.0", @@ -717,6 +719,11 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + }, "node_modules/@next/env": { "version": "14.2.15", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.15.tgz", @@ -3194,6 +3201,17 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chart.js": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.6.tgz", + "integrity": "sha512-8Y406zevUPbbIBA/HRk33khEmQPk5+cxeflWE/2rx1NJsjVWMPw/9mSP9rxHP5eqi6LNoPBVMfZHxbwLSgldYA==", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -7650,6 +7668,15 @@ "node": ">=0.10.0" } }, + "node_modules/react-chartjs-2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", + "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-countup": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/react-countup/-/react-countup-6.5.3.tgz", diff --git a/package.json b/package.json index eaf2743..0d07a28 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@tanstack/react-query": "^5.59.0", "@tanstack/react-query-devtools": "^5.59.0", "b2d-ventures": "file:", + "chart.js": "^4.4.6", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cmdk": "1.0.0", @@ -44,6 +45,7 @@ "next": "^14.2.15", "next-themes": "^0.3.0", "react": "^18.3.1", + "react-chartjs-2": "^5.2.0", "react-countup": "^6.5.3", "react-dom": "^18", "react-hook-form": "^7.53.0", diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 1922125..5fc290c 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -1,6 +1,7 @@ import { Overview } from "@/components/ui/overview"; import { createSupabaseClient } from "@/lib/supabase/serverComponentClient"; import { getInvestorDeal } from "@/lib/data/query"; +import PieChart from "@/components/pieChart"; export default async function Portfolio({ params, @@ -8,6 +9,8 @@ export default async function Portfolio({ params: { uid: string }; }) { const supabase = createSupabaseClient(); + const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + const dayOfWeekData = daysOfWeek.map((day) => ({ name: day, value: 0 })); const { data: deals, error } = await getInvestorDeal(supabase, params.uid); if (error) { console.error(error); @@ -23,6 +26,7 @@ export default async function Portfolio({ return date.toLocaleString("default", { month: "long", year: "numeric" }); }; + // only use deal that were made at most year ago const overAllGraphData = deals ? deals .filter((item) => new Date(item.created_time) >= yearAgo(1)) @@ -45,49 +49,57 @@ export default async function Portfolio({ ) : []; -const threeYearGraphData = deals - ? deals - .filter((item) => new Date(item.created_time) >= yearAgo(3)) - .reduce( - (acc, item) => { - const year = new Date(item.created_time).getFullYear(); - const existingYear = acc.find( - (entry: { name: string; }) => entry.name === year.toString() - ); + const threeYearGraphData = deals + ? deals + .filter((item) => new Date(item.created_time) >= yearAgo(3)) + .reduce( + (acc, item) => { + const year = new Date(item.created_time).getFullYear(); + const existingYear = acc.find( + (entry: { name: string }) => entry.name === year.toString() + ); - if (existingYear) { - existingYear.value += item.deal_amount; - } else { - acc.push({ name: year.toString(), value: item.deal_amount }) - } + if (existingYear) { + existingYear.value += item.deal_amount; + } else { + acc.push({ name: year.toString(), value: item.deal_amount }); + } - return acc; - }, - [] as { name: string; value: number }[] - ) - : []; + return acc; + }, + [] as { name: string; value: number }[] + ) + : []; + const getDayAbbreviation = (dateString: string | number | Date) => { + const date = new Date(dateString); + return date.toLocaleString("default", { weekday: "short" }); + }; - - - // const graphData = [ - // { name: "October", value: 500 }, - // { name: "October", value: 500 }, - // { name: "November", value: 500 }, - // { name: "December", value: 500 }, - // { name: "January", value: 500 }, - // { name: "Febuary", value: 500 }, - // { name: "March", value: 500 }, - // ]; + if (deals) { + deals + .filter((item) => new Date(item.created_time) >= yearAgo(1)) + .forEach((item) => { + const day = getDayAbbreviation(item.created_time); + const dayEntry = dayOfWeekData.find((entry) => entry.name === day); + if (dayEntry) { + dayEntry.value += item.deal_amount; + } + }); + } return (
+ {/* {JSON.stringify(params.uid)} */} {/* {JSON.stringify(deals)} */} - {/* {JSON.stringify(deals)} */} + {/* {JSON.stringify(dayOfWeekData)} */} + {/* {JSON.stringify(overAllGraphData)} */} {/* {JSON.stringify(threeYearGraphData)} */}
+
+ {/* */}
); } diff --git a/src/components/pieChart.tsx b/src/components/pieChart.tsx new file mode 100644 index 0000000..be988fb --- /dev/null +++ b/src/components/pieChart.tsx @@ -0,0 +1,33 @@ +import { Pie } from "react-chartjs-2"; +import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js"; + +ChartJS.register(ArcElement, Tooltip, Legend); + +interface PieChartProps { + labels: string[]; + data: string[]; + header:string +} + +const PieChart = (props: PieChartProps) => { + const chartData = { + labels: props.labels, + datasets: [ + { + label: props.header, + data: props.data, + backgroundColor: ["#FF6384", "#36A2EB", "#FFCE56"], + hoverBackgroundColor: ["#FF6384", "#36A2EB", "#FFCE56"], + borderWidth: 1, + }, + ], + }; + + return ( +
+ +
+ ); +}; + +export default PieChart; diff --git a/src/components/ui/overview.tsx b/src/components/ui/overview.tsx index 8c4cf9f..a912c7b 100644 --- a/src/components/ui/overview.tsx +++ b/src/components/ui/overview.tsx @@ -1,6 +1,15 @@ "use client"; -import { Bar, BarChart, ResponsiveContainer, XAxis, YAxis, LineChart, Line } from "recharts"; +import { + Bar, + BarChart, + ResponsiveContainer, + XAxis, + YAxis, + LineChart, + Line, + Tooltip, +} from "recharts"; // const data = [ // { @@ -77,6 +86,14 @@ export function Overview(props: OverViewProps) { axisLine={false} tickFormatter={(value) => `$${value}`} /> + `$${value}`} + contentStyle={{ + backgroundColor: "#f5f5f5", + borderRadius: "5px", + color: "#000", + }} + /> `$${value}`} /> - + `$${value}`} + contentStyle={{ + backgroundColor: "#f5f5f5", + borderRadius: "5px", + color: "#000", + }} + /> + )} From f4a1c287c1d1bc2b1c84e960cf39fcf05bc964a9 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Wed, 30 Oct 2024 11:41:35 +0700 Subject: [PATCH 04/48] Refactor dependencies and add PieChart component --- src/app/api/generalApi.ts | 17 ++++++ src/app/portfolio/[uid]/page.tsx | 88 +++++++++++++++++++++++++++++--- src/components/pieChart.tsx | 2 +- src/lib/data/query.ts | 25 ++++++--- 4 files changed, 115 insertions(+), 17 deletions(-) diff --git a/src/app/api/generalApi.ts b/src/app/api/generalApi.ts index aa7c50b..ceeebe7 100644 --- a/src/app/api/generalApi.ts +++ b/src/app/api/generalApi.ts @@ -34,6 +34,23 @@ async function clearFolder( return errors; } +export async function getProjectTag(projectId: number) { + return supabase + .from("project_tag") + .select("tag_id") + .in("item_id", [projectId]); +} +export async function getTagName(tagId: number) { + return supabase.from("tag").select("value").in("id", [tagId]); +} +export async function getInvestorDeal(userId: string) { + return supabase + .from("investment_deal") + .select("*") + .in("investor_id", [userId]) + .order("created_time", { ascending: true }); +} + async function uploadToFolder( bucketName: string, filePath: string, diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 5fc290c..db22942 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -1,20 +1,78 @@ +"use client"; import { Overview } from "@/components/ui/overview"; -import { createSupabaseClient } from "@/lib/supabase/serverComponentClient"; -import { getInvestorDeal } from "@/lib/data/query"; +import { + getInvestorDeal, + getProjectTag, + getTagName, +} from "@/app/api/generalApi"; +import { useQuery } from "@supabase-cache-helpers/postgrest-react-query"; import PieChart from "@/components/pieChart"; -export default async function Portfolio({ +export default function Portfolio({ params, }: { params: { uid: string }; }) { - const supabase = createSupabaseClient(); const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; const dayOfWeekData = daysOfWeek.map((day) => ({ name: day, value: 0 })); - const { data: deals, error } = await getInvestorDeal(supabase, params.uid); - if (error) { - console.error(error); + const { data: deals, error: investorDealError } = useQuery( + getInvestorDeal(params.uid) + ); + + const projectTag = async () => { + const uniqueProjectIds = Array.from( + new Set(deals?.map((deal) => deal.project_id)) + ); + + const tagIds = ( + await Promise.all( + uniqueProjectIds.map(async (projectId: number) => { + const { data: tagIdsArray, error: tagError } = + await getProjectTag(projectId); + if (tagError) { + console.error(tagError); + return []; + } + return tagIdsArray?.map((tag) => tag.tag_id) || []; + }) + ) + ).flat(); + + // console.log(tagIds); + const tagNames = await Promise.all( + tagIds + .filter((tagId) => tagId !== null) + .map(async (id: number) => { + const { data: tagName, error: nameError } = await getTagName(id); + if (nameError) { + console.error(nameError); + return null; + } + return tagName; + }) + ); + + return tagNames.filter((tagName) => tagName !== null); + }; + const countTags = (tags: any[]) => { + const tagCounts = tags.flat().reduce((acc, tag) => { + const tagName = tag.value; + acc[tagName] = (acc[tagName] || 0) + 1; + return acc; + }, {}); + + return Object.entries(tagCounts).map(([name, count]) => ({ + name, + count: count as number, + })); + }; + const {data:tags, error: projectTagError, isLoading: projectTagLoading} = useQuery(projectTag()); + const tagCount = countTags(tags); + + if (investorDealError) { + console.error(investorDealError); } + const yearAgo = (num: number) => { const newDate = new Date(); newDate.setFullYear(newDate.getFullYear() - num); @@ -75,6 +133,7 @@ export default async function Portfolio({ return date.toLocaleString("default", { weekday: "short" }); }; + let totalInvest = 0; if (deals) { deals .filter((item) => new Date(item.created_time) >= yearAgo(1)) @@ -85,21 +144,34 @@ export default async function Portfolio({ dayEntry.value += item.deal_amount; } }); + totalInvest = deals.reduce((acc, item) => acc + item.deal_amount, 0); } return (
{/* {JSON.stringify(params.uid)} */} + {JSON.stringify(tagCount)} {/* {JSON.stringify(deals)} */} {/* {JSON.stringify(dayOfWeekData)} */} {/* {JSON.stringify(overAllGraphData)} */} {/* {JSON.stringify(threeYearGraphData)} */} + {/* {JSON.stringify(uniqueProjectIds)} */} + {/*
+

Total Invest :

+
{totalInvest}
+
*/}
- {/* */} + { + return item.name; + })} + data={tagCount.map((item: { count: number }) => item.count)} + header="Ratio of Investment's project category" + />
); } diff --git a/src/components/pieChart.tsx b/src/components/pieChart.tsx index be988fb..5bd121f 100644 --- a/src/components/pieChart.tsx +++ b/src/components/pieChart.tsx @@ -5,7 +5,7 @@ ChartJS.register(ArcElement, Tooltip, Legend); interface PieChartProps { labels: string[]; - data: string[]; + data: number[]; header:string } diff --git a/src/lib/data/query.ts b/src/lib/data/query.ts index 9a06cd1..b0ee842 100644 --- a/src/lib/data/query.ts +++ b/src/lib/data/query.ts @@ -44,19 +44,28 @@ function getInvestmentCounts(client: SupabaseClient, projectIds: string[]) { .in("project_id", projectIds); } -function getInvestorDeal(client: SupabaseClient, userId: string) { - return client - .from("investment_deal") - .select("*") - .in("investor_id", [userId]) - .order("created_time", { ascending: true }); -} +// function getInvestorDeal(client: SupabaseClient, userId: string) { +// return client +// .from("investment_deal") +// .select("*") +// .in("investor_id", [userId]) +// .order("created_time", { ascending: true }); +// } +// function getProjectTag(client: SupabaseClient, projectId: number) { +// return client.from("project_tag").select("tag_id").in("item_id", [projectId]); +// } + +// function getTagName(client: SupabaseClient, tagId: number){ +// return client.from("tag").select("value").in("id", [tagId]); +// } export { getBusinesses, getInvestmentCounts, getProjects, getTags, - getInvestorDeal, + // getInvestorDeal, + // getProjectTag, + // getTagName, }; From 209d6f1f73f1c7cdf88010ba51fb2a3d2f470663 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Wed, 30 Oct 2024 12:07:59 +0700 Subject: [PATCH 05/48] Refactor generalApi.ts and portfolio/[uid]/page.tsx --- src/app/api/generalApi.ts | 17 ---------- src/app/portfolio/[uid]/page.tsx | 57 ++++++++++++++------------------ src/lib/data/query.ts | 32 +++++++++--------- 3 files changed, 40 insertions(+), 66 deletions(-) diff --git a/src/app/api/generalApi.ts b/src/app/api/generalApi.ts index ceeebe7..aa7c50b 100644 --- a/src/app/api/generalApi.ts +++ b/src/app/api/generalApi.ts @@ -34,23 +34,6 @@ async function clearFolder( return errors; } -export async function getProjectTag(projectId: number) { - return supabase - .from("project_tag") - .select("tag_id") - .in("item_id", [projectId]); -} -export async function getTagName(tagId: number) { - return supabase.from("tag").select("value").in("id", [tagId]); -} -export async function getInvestorDeal(userId: string) { - return supabase - .from("investment_deal") - .select("*") - .in("investor_id", [userId]) - .order("created_time", { ascending: true }); -} - async function uploadToFolder( bucketName: string, filePath: string, diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index db22942..97751af 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -1,22 +1,19 @@ -"use client"; import { Overview } from "@/components/ui/overview"; -import { - getInvestorDeal, - getProjectTag, - getTagName, -} from "@/app/api/generalApi"; -import { useQuery } from "@supabase-cache-helpers/postgrest-react-query"; +import { createSupabaseClient } from "@/lib/supabase/serverComponentClient"; +import { getInvestorDeal, getProjectTag, getTagName } from "@/lib/data/query"; import PieChart from "@/components/pieChart"; -export default function Portfolio({ +export default async function Portfolio({ params, }: { params: { uid: string }; }) { + const supabase = createSupabaseClient(); const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; const dayOfWeekData = daysOfWeek.map((day) => ({ name: day, value: 0 })); - const { data: deals, error: investorDealError } = useQuery( - getInvestorDeal(params.uid) + const { data: deals, error: investorDealError } = await getInvestorDeal( + supabase, + params.uid ); const projectTag = async () => { @@ -28,7 +25,7 @@ export default function Portfolio({ await Promise.all( uniqueProjectIds.map(async (projectId: number) => { const { data: tagIdsArray, error: tagError } = - await getProjectTag(projectId); + await getProjectTag(supabase, projectId); if (tagError) { console.error(tagError); return []; @@ -43,7 +40,7 @@ export default function Portfolio({ tagIds .filter((tagId) => tagId !== null) .map(async (id: number) => { - const { data: tagName, error: nameError } = await getTagName(id); + const { data: tagName, error: nameError } = await getTagName(supabase, id); if (nameError) { console.error(nameError); return null; @@ -55,19 +52,20 @@ export default function Portfolio({ return tagNames.filter((tagName) => tagName !== null); }; const countTags = (tags: any[]) => { - const tagCounts = tags.flat().reduce((acc, tag) => { - const tagName = tag.value; - acc[tagName] = (acc[tagName] || 0) + 1; - return acc; - }, {}); - - return Object.entries(tagCounts).map(([name, count]) => ({ - name, - count: count as number, - })); - }; - const {data:tags, error: projectTagError, isLoading: projectTagLoading} = useQuery(projectTag()); - const tagCount = countTags(tags); + const tagCounts = tags.flat().reduce((acc, tag) => { + const tagName = tag.value; + acc[tagName] = (acc[tagName] || 0) + 1; + return acc; + }, {} as Record); + + return Object.entries(tagCounts).map(([name, count]) => ({ + name, + count: count as number, + })); + }; + const tags = await projectTag(); + console.log(tags) + // const tagCount = countTags(tags); if (investorDealError) { console.error(investorDealError); @@ -150,7 +148,7 @@ export default function Portfolio({ return (
{/* {JSON.stringify(params.uid)} */} - {JSON.stringify(tagCount)} + {/* {JSON.stringify(tagCount)} */} {/* {JSON.stringify(deals)} */} {/* {JSON.stringify(dayOfWeekData)} */} {/* {JSON.stringify(overAllGraphData)} */} @@ -165,13 +163,6 @@ export default function Portfolio({
- { - return item.name; - })} - data={tagCount.map((item: { count: number }) => item.count)} - header="Ratio of Investment's project category" - /> ); } diff --git a/src/lib/data/query.ts b/src/lib/data/query.ts index b0ee842..5c21498 100644 --- a/src/lib/data/query.ts +++ b/src/lib/data/query.ts @@ -44,28 +44,28 @@ function getInvestmentCounts(client: SupabaseClient, projectIds: string[]) { .in("project_id", projectIds); } -// function getInvestorDeal(client: SupabaseClient, userId: string) { -// return client -// .from("investment_deal") -// .select("*") -// .in("investor_id", [userId]) -// .order("created_time", { ascending: true }); -// } +function getInvestorDeal(client: SupabaseClient, userId: string) { + return client + .from("investment_deal") + .select("*") + .in("investor_id", [userId]) + .order("created_time", { ascending: true }); +} -// function getProjectTag(client: SupabaseClient, projectId: number) { -// return client.from("project_tag").select("tag_id").in("item_id", [projectId]); -// } +function getProjectTag(client: SupabaseClient, projectId: number) { + return client.from("project_tag").select("tag_id").in("item_id", [projectId]); +} -// function getTagName(client: SupabaseClient, tagId: number){ -// return client.from("tag").select("value").in("id", [tagId]); -// } +function getTagName(client: SupabaseClient, tagId: number){ + return client.from("project_tag").select("tag_id").in("item_id", [tagId]); +} export { getBusinesses, getInvestmentCounts, getProjects, getTags, - // getInvestorDeal, - // getProjectTag, - // getTagName, + getInvestorDeal, + getProjectTag, + getTagName }; From 62e20c282a62d23ce7bc22b80d7688a5effb18da Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Wed, 30 Oct 2024 14:30:00 +0700 Subject: [PATCH 06/48] Refactor projectTag function and add PieChart component --- src/app/portfolio/[uid]/page.tsx | 49 ++++++++++++++++++++++---------- src/components/pieChart.tsx | 4 ++- src/lib/data/query.ts | 6 ++-- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 97751af..42a8676 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -17,6 +17,7 @@ export default async function Portfolio({ ); const projectTag = async () => { + // get unique project id from deals const uniqueProjectIds = Array.from( new Set(deals?.map((deal) => deal.project_id)) ); @@ -24,8 +25,10 @@ export default async function Portfolio({ const tagIds = ( await Promise.all( uniqueProjectIds.map(async (projectId: number) => { - const { data: tagIdsArray, error: tagError } = - await getProjectTag(supabase, projectId); + const { data: tagIdsArray, error: tagError } = await getProjectTag( + supabase, + projectId + ); if (tagError) { console.error(tagError); return []; @@ -35,12 +38,15 @@ export default async function Portfolio({ ) ).flat(); - // console.log(tagIds); + // console.log(tagIds, uniqueProjectIds); const tagNames = await Promise.all( tagIds .filter((tagId) => tagId !== null) .map(async (id: number) => { - const { data: tagName, error: nameError } = await getTagName(supabase, id); + const { data: tagName, error: nameError } = await getTagName( + supabase, + id + ); if (nameError) { console.error(nameError); return null; @@ -48,24 +54,28 @@ export default async function Portfolio({ return tagName; }) ); - + // console.log(tagNames); return tagNames.filter((tagName) => tagName !== null); }; const countTags = (tags: any[]) => { - const tagCounts = tags.flat().reduce((acc, tag) => { + const tagCounts = tags.flat().reduce( + (acc, tag) => { const tagName = tag.value; acc[tagName] = (acc[tagName] || 0) + 1; return acc; - }, {} as Record); - - return Object.entries(tagCounts).map(([name, count]) => ({ - name, - count: count as number, - })); - }; + }, + {} as Record + ); + + return Object.entries(tagCounts).map(([name, count]) => ({ + name, + count: count as number, + })); + }; const tags = await projectTag(); - console.log(tags) - // const tagCount = countTags(tags); + // console.log(tags); + const tagCount = countTags(tags); + // console.log(tagCount); if (investorDealError) { console.error(investorDealError); @@ -163,6 +173,15 @@ export default async function Portfolio({ + item.count + )} + labels={tagCount.map( + (item: { name: string; count: number }) => item.name + )} + header="Total" + /> ); } diff --git a/src/components/pieChart.tsx b/src/components/pieChart.tsx index 5bd121f..7edbfc2 100644 --- a/src/components/pieChart.tsx +++ b/src/components/pieChart.tsx @@ -1,3 +1,5 @@ +"use client"; + import { Pie } from "react-chartjs-2"; import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js"; @@ -6,7 +8,7 @@ ChartJS.register(ArcElement, Tooltip, Legend); interface PieChartProps { labels: string[]; data: number[]; - header:string + header: string; } const PieChart = (props: PieChartProps) => { diff --git a/src/lib/data/query.ts b/src/lib/data/query.ts index 5c21498..e3ae04f 100644 --- a/src/lib/data/query.ts +++ b/src/lib/data/query.ts @@ -56,8 +56,8 @@ function getProjectTag(client: SupabaseClient, projectId: number) { return client.from("project_tag").select("tag_id").in("item_id", [projectId]); } -function getTagName(client: SupabaseClient, tagId: number){ - return client.from("project_tag").select("tag_id").in("item_id", [tagId]); +function getTagName(client: SupabaseClient, tagId: number) { + return client.from("tag").select("value").in("id", [tagId]); } export { @@ -67,5 +67,5 @@ export { getTags, getInvestorDeal, getProjectTag, - getTagName + getTagName, }; From 16a171db3c8d86ff20f3c7844d3fc19b54013a50 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Wed, 30 Oct 2024 14:52:20 +0700 Subject: [PATCH 07/48] Refactor Portfolio component and add data aggregation hooks --- src/app/portfolio/[uid]/hook.ts | 106 +++++++++++++++++++++++++++++++ src/app/portfolio/[uid]/page.tsx | 104 +++++------------------------- src/components/pieChart.tsx | 13 +++- 3 files changed, 133 insertions(+), 90 deletions(-) create mode 100644 src/app/portfolio/[uid]/hook.ts diff --git a/src/app/portfolio/[uid]/hook.ts b/src/app/portfolio/[uid]/hook.ts new file mode 100644 index 0000000..0308e21 --- /dev/null +++ b/src/app/portfolio/[uid]/hook.ts @@ -0,0 +1,106 @@ +// only use deal that were made at most year ago +interface Deal { + created_time: string | number | Date; + deal_amount: any; +} + +interface GraphData { + name: string; + value: number; +} + +function overAllGraphData(deals: Deal[]): GraphData[] { + return deals + ? deals + .filter((item: Deal) => new Date(item.created_time) >= yearAgo(1)) + .reduce((acc: GraphData[], item: Deal) => { + // get the first three initial letter of the month + const monthName = getMonthName(item.created_time.toString()).slice( + 0, + 3 + ); + const existingMonth = acc.find( + (entry: GraphData) => entry.name === monthName + ); + + if (existingMonth) { + existingMonth.value += item.deal_amount; + } + // if month doesnt exist yet, create new record + else { + acc.push({ name: monthName, value: item.deal_amount }); + } + + return acc; + }, [] as GraphData[]) + : []; +} + +interface Deal { + created_time: string | number | Date; + deal_amount: any; +} + +interface GraphData { + name: string; + value: number; +} + +function fourYearGraphData(deals: Deal[]): GraphData[] { + return deals + .filter((item: Deal) => new Date(item.created_time) >= yearAgo(3)) + .reduce((acc: GraphData[], item: Deal) => { + const year = new Date(item.created_time).getFullYear(); + const existingYear = acc.find( + (entry: GraphData) => entry.name === year.toString() + ); + + if (existingYear) { + existingYear.value += item.deal_amount; + } else { + acc.push({ name: year.toString(), value: item.deal_amount }); + } + + return acc; + }, [] as GraphData[]); +} + +interface DayOfWeekData { + name: string; + value: number; +} + +function dayOftheWeekData(deals: Deal[]): DayOfWeekData[] { + const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + const dayOfWeekData: DayOfWeekData[] = daysOfWeek.map((day) => ({ + name: day, + value: 0, + })); + deals + .filter((item: Deal) => new Date(item.created_time) >= yearAgo(1)) + .forEach((item: Deal) => { + const day = getDayAbbreviation(item.created_time); + const dayEntry = dayOfWeekData.find((entry) => entry.name === day); + if (dayEntry) { + dayEntry.value += item.deal_amount; + } + }); + return dayOfWeekData; +} +const getDayAbbreviation = (dateString: string | number | Date) => { + const date = new Date(dateString); + return date.toLocaleString("default", { weekday: "short" }); +}; + +const yearAgo = (num: number) => { + const newDate = new Date(); + newDate.setFullYear(newDate.getFullYear() - num); + return newDate; +}; + +const getMonthName = (dateString: string) => { + const date = new Date(dateString); + return date.toLocaleString("default", { month: "long", year: "numeric" }); +}; + +export { overAllGraphData, fourYearGraphData, dayOftheWeekData }; diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 42a8676..03df61e 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -2,6 +2,7 @@ import { Overview } from "@/components/ui/overview"; import { createSupabaseClient } from "@/lib/supabase/serverComponentClient"; import { getInvestorDeal, getProjectTag, getTagName } from "@/lib/data/query"; import PieChart from "@/components/pieChart"; +import { overAllGraphData, fourYearGraphData, dayOftheWeekData } from "./hook"; export default async function Portfolio({ params, @@ -9,12 +10,13 @@ export default async function Portfolio({ params: { uid: string }; }) { const supabase = createSupabaseClient(); - const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; - const dayOfWeekData = daysOfWeek.map((day) => ({ name: day, value: 0 })); const { data: deals, error: investorDealError } = await getInvestorDeal( supabase, params.uid ); + const overAllData = deals ? overAllGraphData(deals) : []; + const fourYearData = deals ? fourYearGraphData(deals) : []; + const dayOfWeekData = deals ? dayOftheWeekData(deals) : []; const projectTag = async () => { // get unique project id from deals @@ -81,80 +83,6 @@ export default async function Portfolio({ console.error(investorDealError); } - const yearAgo = (num: number) => { - const newDate = new Date(); - newDate.setFullYear(newDate.getFullYear() - num); - return newDate; - }; - - const getMonthName = (dateString: string) => { - const date = new Date(dateString); - return date.toLocaleString("default", { month: "long", year: "numeric" }); - }; - - // only use deal that were made at most year ago - const overAllGraphData = deals - ? deals - .filter((item) => new Date(item.created_time) >= yearAgo(1)) - .reduce( - (acc, item) => { - const monthName = getMonthName(item.created_time).slice(0, 3); - const existingMonth = acc.find( - (entry: { name: string }) => entry.name === monthName - ); - - if (existingMonth) { - existingMonth.value += item.deal_amount; - } else { - acc.push({ name: monthName, value: item.deal_amount }); - } - - return acc; - }, - [] as { name: string; value: number }[] - ) - : []; - - const threeYearGraphData = deals - ? deals - .filter((item) => new Date(item.created_time) >= yearAgo(3)) - .reduce( - (acc, item) => { - const year = new Date(item.created_time).getFullYear(); - const existingYear = acc.find( - (entry: { name: string }) => entry.name === year.toString() - ); - - if (existingYear) { - existingYear.value += item.deal_amount; - } else { - acc.push({ name: year.toString(), value: item.deal_amount }); - } - - return acc; - }, - [] as { name: string; value: number }[] - ) - : []; - const getDayAbbreviation = (dateString: string | number | Date) => { - const date = new Date(dateString); - return date.toLocaleString("default", { weekday: "short" }); - }; - - let totalInvest = 0; - if (deals) { - deals - .filter((item) => new Date(item.created_time) >= yearAgo(1)) - .forEach((item) => { - const day = getDayAbbreviation(item.created_time); - const dayEntry = dayOfWeekData.find((entry) => entry.name === day); - if (dayEntry) { - dayEntry.value += item.deal_amount; - } - }); - totalInvest = deals.reduce((acc, item) => acc + item.deal_amount, 0); - } - return (
{/* {JSON.stringify(params.uid)} */} @@ -169,19 +97,21 @@ export default async function Portfolio({
{totalInvest}
*/}
- - + +
- item.count - )} - labels={tagCount.map( - (item: { name: string; count: number }) => item.name - )} - header="Total" - /> +
+ item.count + )} + labels={tagCount.map( + (item: { name: string; count: number }) => item.name + )} + header="Total" + /> +
); } diff --git a/src/components/pieChart.tsx b/src/components/pieChart.tsx index 7edbfc2..2f09a16 100644 --- a/src/components/pieChart.tsx +++ b/src/components/pieChart.tsx @@ -24,11 +24,18 @@ const PieChart = (props: PieChartProps) => { }, ], }; + const options = { + plugins: { + legend: { + position: "bottom" as const, + }, + }, + }; return ( -
- -
+ <> + + ); }; From 2fba56288d91ce55af0bcfe1c4ded8167b951fbe Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Wed, 30 Oct 2024 15:04:01 +0700 Subject: [PATCH 08/48] Refactor portfolio/[uid]/hook.ts and portfolio/[uid]/page.tsx --- src/app/portfolio/[uid]/hook.ts | 72 ++++++++++++++++++++++++++- src/app/portfolio/[uid]/page.tsx | 84 +++++++------------------------- 2 files changed, 88 insertions(+), 68 deletions(-) diff --git a/src/app/portfolio/[uid]/hook.ts b/src/app/portfolio/[uid]/hook.ts index 0308e21..676dfb3 100644 --- a/src/app/portfolio/[uid]/hook.ts +++ b/src/app/portfolio/[uid]/hook.ts @@ -1,3 +1,6 @@ +import { SupabaseClient } from "@supabase/supabase-js"; +import { getProjectTag, getTagName } from "@/lib/data/query"; + // only use deal that were made at most year ago interface Deal { created_time: string | number | Date; @@ -87,6 +90,67 @@ function dayOftheWeekData(deals: Deal[]): DayOfWeekData[] { }); return dayOfWeekData; } +async function getInvestorProjectTag( + supabase: SupabaseClient, + deals: number | { project_id: number }[] +) { + // get unique project id from deals + const uniqueProjectIds: number[] = Array.isArray(deals) + ? Array.from( + new Set(deals.map((deal: { project_id: number }) => deal.project_id)) + ) + : []; + + const tagIds = ( + await Promise.all( + uniqueProjectIds.map(async (projectId: number) => { + const { data: tagIdsArray, error: tagError } = await getProjectTag( + supabase, + projectId + ); + if (tagError) { + console.error(tagError); + return []; + } + return tagIdsArray?.map((tag: { tag_id: any }) => tag.tag_id) || []; + }) + ) + ).flat(); + + // console.log(tagIds, uniqueProjectIds); + const tagNames = await Promise.all( + tagIds + .filter((tagId) => tagId !== null) + .map(async (id: number) => { + const { data: tagName, error: nameError } = await getTagName( + supabase, + id + ); + if (nameError) { + console.error(nameError); + return null; + } + return tagName; + }) + ); + // console.log(tagNames); + return tagNames.filter((tagName) => tagName !== null); +} +const countTags = (tags: any[]) => { + const tagCounts = tags.flat().reduce( + (acc, tag) => { + const tagName = tag.value; + acc[tagName] = (acc[tagName] || 0) + 1; + return acc; + }, + {} as Record + ); + + return Object.entries(tagCounts).map(([name, count]) => ({ + name, + count: count as number, + })); +}; const getDayAbbreviation = (dateString: string | number | Date) => { const date = new Date(dateString); return date.toLocaleString("default", { weekday: "short" }); @@ -103,4 +167,10 @@ const getMonthName = (dateString: string) => { return date.toLocaleString("default", { month: "long", year: "numeric" }); }; -export { overAllGraphData, fourYearGraphData, dayOftheWeekData }; +export { + overAllGraphData, + fourYearGraphData, + dayOftheWeekData, + getInvestorProjectTag, + countTags, +}; diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 03df61e..c4fde36 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -1,8 +1,14 @@ import { Overview } from "@/components/ui/overview"; import { createSupabaseClient } from "@/lib/supabase/serverComponentClient"; -import { getInvestorDeal, getProjectTag, getTagName } from "@/lib/data/query"; +import { getInvestorDeal } from "@/lib/data/query"; import PieChart from "@/components/pieChart"; -import { overAllGraphData, fourYearGraphData, dayOftheWeekData } from "./hook"; +import { + overAllGraphData, + fourYearGraphData, + dayOftheWeekData, + getInvestorProjectTag, + countTags, +} from "./hook"; export default async function Portfolio({ params, @@ -14,74 +20,18 @@ export default async function Portfolio({ supabase, params.uid ); - const overAllData = deals ? overAllGraphData(deals) : []; - const fourYearData = deals ? fourYearGraphData(deals) : []; - const dayOfWeekData = deals ? dayOftheWeekData(deals) : []; - - const projectTag = async () => { - // get unique project id from deals - const uniqueProjectIds = Array.from( - new Set(deals?.map((deal) => deal.project_id)) - ); - - const tagIds = ( - await Promise.all( - uniqueProjectIds.map(async (projectId: number) => { - const { data: tagIdsArray, error: tagError } = await getProjectTag( - supabase, - projectId - ); - if (tagError) { - console.error(tagError); - return []; - } - return tagIdsArray?.map((tag) => tag.tag_id) || []; - }) - ) - ).flat(); - - // console.log(tagIds, uniqueProjectIds); - const tagNames = await Promise.all( - tagIds - .filter((tagId) => tagId !== null) - .map(async (id: number) => { - const { data: tagName, error: nameError } = await getTagName( - supabase, - id - ); - if (nameError) { - console.error(nameError); - return null; - } - return tagName; - }) - ); - // console.log(tagNames); - return tagNames.filter((tagName) => tagName !== null); - }; - const countTags = (tags: any[]) => { - const tagCounts = tags.flat().reduce( - (acc, tag) => { - const tagName = tag.value; - acc[tagName] = (acc[tagName] || 0) + 1; - return acc; - }, - {} as Record - ); - - return Object.entries(tagCounts).map(([name, count]) => ({ - name, - count: count as number, - })); - }; - const tags = await projectTag(); - // console.log(tags); - const tagCount = countTags(tags); - // console.log(tagCount); - if (investorDealError) { console.error(investorDealError); } + const overAllData = deals ? overAllGraphData(deals) : []; + const fourYearData = deals ? fourYearGraphData(deals) : []; + const dayOfWeekData = deals ? dayOftheWeekData(deals) : []; + const tags = deals ? await getInvestorProjectTag(supabase, deals) : []; + const tagCount = countTags(tags); + + // console.log(tags); + + // console.log(tagCount); return (
From ca895bd60535ec6991f0cbda4962a879269886a5 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Wed, 30 Oct 2024 15:07:13 +0700 Subject: [PATCH 09/48] Refactor ApplyBusiness component and BusinessForm component --- src/app/business/apply/page.tsx | 24 +++++++++--------------- src/components/BusinessForm.tsx | 33 --------------------------------- 2 files changed, 9 insertions(+), 48 deletions(-) diff --git a/src/app/business/apply/page.tsx b/src/app/business/apply/page.tsx index 6eab724..cd7dbc6 100644 --- a/src/app/business/apply/page.tsx +++ b/src/app/business/apply/page.tsx @@ -15,7 +15,6 @@ const BUCKET_PITCH_NAME = "business-application"; let supabase = createSupabaseClient(); export default function ApplyBusiness() { - const [applyProject, setApplyProject] = useState(false); const alertShownRef = useRef(false); const [success, setSucess] = useState(false); @@ -75,12 +74,8 @@ export default function ApplyBusiness() { text: error == null ? "Your application has been submitted" : error.message, confirmButtonColor: error == null ? "green" : "red", - }).then((result) => { - if (result.isConfirmed && applyProject) { - window.location.href = "/project/apply"; - } else { - window.location.href = "/"; - } + }).then(() => { + window.location.href = "/"; }); }; @@ -98,7 +93,10 @@ export default function ApplyBusiness() { console.error(error); console.error(applicationError); } - if ((business && business.length != 0) || (businessApplication && businessApplication.length != 0)) { + if ( + (business && business.length != 0) || + (businessApplication && businessApplication.length != 0) + ) { return true; } return false; @@ -156,8 +154,8 @@ export default function ApplyBusiness() { console.error("Error fetching user ID:", error); } }; - // setSucess(true); - fetchUserData(); + setSucess(true); + // fetchUserData(); }, []); return ( @@ -180,11 +178,7 @@ export default function ApplyBusiness() {
{/* form */} {/*
*/} - + ); } diff --git a/src/components/BusinessForm.tsx b/src/components/BusinessForm.tsx index ced01a8..dd0fdc5 100644 --- a/src/components/BusinessForm.tsx +++ b/src/components/BusinessForm.tsx @@ -17,25 +17,14 @@ import { businessFormSchema } from "@/types/schemas/application.schema"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { Label } from "@/components/ui/label"; -import { Switch } from "@/components/ui/switch"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@radix-ui/react-tooltip"; import { createSupabaseClient } from "@/lib/supabase/clientComponentClient"; type businessSchema = z.infer; interface BusinessFormProps { - applyProject: boolean; - setApplyProject: Function; onSubmit: SubmitHandler; } const BusinessForm = ({ - applyProject, - setApplyProject, onSubmit, }: BusinessFormProps & { onSubmit: SubmitHandler }) => { const communitySize = [ @@ -461,28 +450,6 @@ const BusinessForm = ({ )} /> -
- setApplyProject(!applyProject)} - > - - - - - Would you like to apply for your first fundraising project - as well? - - - -

- Toggling this option allows you to begin your first - project,
which is crucial for unlocking the tools - necessary to raise funds. -

-
-
-
-
@@ -125,8 +185,11 @@ export default async function ProjectDealPage({ params }: { params: { id: number -
- {projectData?.project_description || "No pitch available."} +
+ + {projectData?.project_description || + "No pitch available."} +
diff --git a/src/app/page.tsx b/src/app/page.tsx index 78f00bf..f8bb62b 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -19,7 +19,7 @@ interface Project { id: number; project_name: string; project_short_description: string; - card_image_url: string; + project_logo: string; published_time: string; business: { location: string }[]; project_tag: { tag: { id: number; value: string }[] }[]; @@ -44,7 +44,7 @@ const TopProjects: FC = ({ projects }) => { Date: Thu, 31 Oct 2024 14:26:26 +0700 Subject: [PATCH 19/48] Refactor investment check to fix formatting issue in ProjectDealPage component --- src/app/(investment)/deals/[id]/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(investment)/deals/[id]/page.tsx b/src/app/(investment)/deals/[id]/page.tsx index 024c17b..0403c24 100644 --- a/src/app/(investment)/deals/[id]/page.tsx +++ b/src/app/(investment)/deals/[id]/page.tsx @@ -135,7 +135,7 @@ export default async function ProjectDealPage({

{" "} - 5% raised of \$5M max goal + 5% raised of $5M max goal

Date: Thu, 31 Oct 2024 14:43:27 +0700 Subject: [PATCH 20/48] Refactor profileBar component to add link to user's portfolio page --- src/components/navigationBar/profileBar.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/navigationBar/profileBar.tsx b/src/components/navigationBar/profileBar.tsx index e701ddb..0dce422 100644 --- a/src/components/navigationBar/profileBar.tsx +++ b/src/components/navigationBar/profileBar.tsx @@ -46,10 +46,16 @@ const AuthenticatedComponents = ({ uid }: { uid: string }) => {
- + + + -
From 22fe709ce8ea076cbce9960f3d4c1a6cef03965d Mon Sep 17 00:00:00 2001 From: Pattadon Date: Thu, 31 Oct 2024 15:19:06 +0700 Subject: [PATCH 22/48] Refactor profileBar component to fix notification count display --- src/components/navigationBar/profileBar.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/navigationBar/profileBar.tsx b/src/components/navigationBar/profileBar.tsx index 0dce422..903273b 100644 --- a/src/components/navigationBar/profileBar.tsx +++ b/src/components/navigationBar/profileBar.tsx @@ -33,14 +33,14 @@ const UnAuthenticatedComponents = () => { }; const AuthenticatedComponents = ({ uid }: { uid: string }) => { - let notifications = 100; + let notifications = 1; const displayValue = notifications >= 100 ? "..." : notifications; return (
- - + + {displayValue}
From 7356831e2e650d0b82946fc96eda4938edd9fc1f Mon Sep 17 00:00:00 2001 From: Pattadon Date: Fri, 1 Nov 2024 14:32:33 +0700 Subject: [PATCH 23/48] Refactor portfolio hook and page components - Add functions to calculate total investment and get latest investment - Update graph data calculations for overall and four-year graphs - Update recent funds component to display latest investment deals - Minor code formatting and error handling improvements --- src/app/portfolio/[uid]/hook.ts | 111 +++++++++++++++++++++---------- src/app/portfolio/[uid]/page.tsx | 33 ++++++++- src/components/recent-funds.tsx | 19 +++--- 3 files changed, 114 insertions(+), 49 deletions(-) diff --git a/src/app/portfolio/[uid]/hook.ts b/src/app/portfolio/[uid]/hook.ts index 4675324..8efb2bd 100644 --- a/src/app/portfolio/[uid]/hook.ts +++ b/src/app/portfolio/[uid]/hook.ts @@ -1,6 +1,38 @@ import { SupabaseClient } from "@supabase/supabase-js"; import { getProjectTag, getTagName } from "@/lib/data/query"; +function getTotalInvestment(deals: { deal_amount : number}[]) { + let total = 0; + for (let index = 0; index < deals.length; index++) { + total += deals[index].deal_amount; + } + return total; +} +async function getLatestInvestment( + supabase: SupabaseClient, + deals: { project_id: number; deal_amount: number; created_time: Date }[] +) { + const llist = []; + const count = 8; + + for (let i = deals.length - 1; i >= 0 && llist.length < count; --i) { + let { data: project, error } = await supabase + .from("project") + .select("project_name") + .eq("id", deals[i].project_id); + if (error) { + console.error(error); + } + llist.push({ + name: project?.[0]?.project_name, + amount: deals[i].deal_amount, + date: new Date(deals[i].created_time), + }); + } + + return llist; +} + async function checkForInvest(supabase: SupabaseClient, userId: string) { let { count, error } = await supabase .from("investment_deal") @@ -30,7 +62,6 @@ function countValues(arr: { value: string }[][]): Record { return counts; } - async function getBusinessTypeName( supabase: SupabaseClient, projectId: number @@ -75,32 +106,38 @@ interface GraphData { } function overAllGraphData(deals: Deal[]): GraphData[] { - return deals - ? deals - .filter((item: Deal) => new Date(item.created_time) >= yearAgo(1)) - .reduce((acc: GraphData[], item: Deal) => { - // get the first three initial letter of the month - const monthName = getMonthName(item.created_time.toString()).slice( - 0, - 3 - ); - const existingMonth = acc.find( - (entry: GraphData) => entry.name === monthName - ); + // Initialize all months with value 0 + const months = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ]; + const acc: GraphData[] = months.map((month) => ({ name: month, value: 0 })); - if (existingMonth) { - existingMonth.value += item.deal_amount; - } - // if month doesnt exist yet, create new record - else { - acc.push({ name: monthName, value: item.deal_amount }); - } + deals + .filter((item: Deal) => new Date(item.created_time) >= yearAgo(1)) + .forEach((item: Deal) => { + const monthName = getMonthName(item.created_time.toString()).slice(0, 3); + const monthEntry = acc.find((entry) => entry.name === monthName); - return acc; - }, [] as GraphData[]) - : []; + if (monthEntry) { + monthEntry.value += item.deal_amount; + } + }); + + return acc; } + interface Deal { created_time: string | number | Date; deal_amount: any; @@ -112,24 +149,26 @@ interface GraphData { } function fourYearGraphData(deals: Deal[]): GraphData[] { - return deals + const currentYear = new Date().getFullYear(); + const acc: GraphData[] = Array.from({ length: 4 }, (_, i) => ({ + name: (currentYear - i).toString(), + value: 0, + })).reverse(); + deals .filter((item: Deal) => new Date(item.created_time) >= yearAgo(3)) - .reduce((acc: GraphData[], item: Deal) => { - const year = new Date(item.created_time).getFullYear(); - const existingYear = acc.find( - (entry: GraphData) => entry.name === year.toString() - ); + .forEach((item: Deal) => { + const year = new Date(item.created_time).getFullYear().toString(); + const yearEntry = acc.find((entry) => entry.name === year); - if (existingYear) { - existingYear.value += item.deal_amount; - } else { - acc.push({ name: year.toString(), value: item.deal_amount }); + if (yearEntry) { + yearEntry.value += item.deal_amount; } + }); - return acc; - }, [] as GraphData[]); + return acc; } + interface DayOfWeekData { name: string; value: number; @@ -238,4 +277,6 @@ export { getBusinessTypeName, countValues, checkForInvest, + getLatestInvestment, + getTotalInvestment, }; diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 6416885..05b40ee 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -11,6 +11,8 @@ import { getBusinessTypeName, countValues, checkForInvest, + getLatestInvestment, + getTotalInvestment, } from "./hook"; import CountUpComponent from "@/components/countUp"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; @@ -24,6 +26,7 @@ import { RecentFunds } from "@/components/recent-funds"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import QuestionMarkIcon from "@/components/icon/questionMark"; import { NoDataAlert } from "@/components/alert/noData/alert"; +import { error } from "console"; export default async function Portfolio({ params, @@ -33,7 +36,6 @@ export default async function Portfolio({ const supabase = createSupabaseClient(); // if user hasn't invest in anything if (!(await checkForInvest(supabase, params.uid))) { - return (
@@ -47,10 +49,22 @@ export default async function Portfolio({ if (investorDealError) { console.error(investorDealError); } + const { + data: { user }, + error: userError, + } = await supabase.auth.getUser(); + if (userError) { + console.error("Error while fetching user" + error); + } + const username = user ? user.user_metadata.name : "Anonymous"; + // console.log(username) const overAllData = deals ? overAllGraphData(deals) : []; const fourYearData = deals ? fourYearGraphData(deals) : []; const dayOfWeekData = deals ? dayOftheWeekData(deals) : []; const tags = deals ? await getInvestorProjectTag(supabase, deals) : []; + const latestDeals = deals ? await getLatestInvestment(supabase, deals) : []; + const totalInvestment = deals ? getTotalInvestment(deals) : 0; + // console.log(latestDeals); const tagCount = countTags(tags); // console.log(investedBusinessIds); const businessType = deals @@ -80,9 +94,22 @@ export default async function Portfolio({
{totalInvest}
*/} {/* */} +
+

+ Welcome to your Portfolio, {username}! +

+

+ Here's an overview of your investment journey and progress. +

+

+ Total Investment: $ + +

+
+
- + Daily Monthly Yearly @@ -246,7 +273,7 @@ export default async function Portfolio({ - +
diff --git a/src/components/recent-funds.tsx b/src/components/recent-funds.tsx index 97b9224..b078846 100644 --- a/src/components/recent-funds.tsx +++ b/src/components/recent-funds.tsx @@ -38,26 +38,23 @@ const data = [ }, ]; -interface RecentFundsProps{ - name?: string; - email?: string; - amount?: number; - avatar?: string; +interface RecentFundsProps { + data?: { name?: string; amount?: number; avatar?: string ; date?: Date}[]; } export function RecentFunds(props: RecentFundsProps) { return (
- {data.map((person, index) => ( + {(props?.data || []).map((deal, index) => (
- - {person.initials} + + {(deal.name ?? "").slice(0, 3)}
-

{person.name}

-

{person.email}

+

{deal.name}

+

{deal?.date?.toLocaleDateString()}

-
+${person.amount}
+
+${deal.amount}
))}
From bca431ee263083360ba9bbd8c1bf25819dc96781 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Fri, 1 Nov 2024 15:23:50 +0700 Subject: [PATCH 24/48] Refactor unauthorized alert component and add user authorization check to portfolio page --- src/app/portfolio/[uid]/page.tsx | 22 +- src/components/alert/unauthorized/alert.json | 2066 ++++++++++++++++++ src/components/alert/unauthorized/alert.tsx | 20 + 3 files changed, 2101 insertions(+), 7 deletions(-) create mode 100644 src/components/alert/unauthorized/alert.json create mode 100644 src/components/alert/unauthorized/alert.tsx diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index 05b40ee..825730f 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -27,6 +27,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import QuestionMarkIcon from "@/components/icon/questionMark"; import { NoDataAlert } from "@/components/alert/noData/alert"; import { error } from "console"; +import { UnAuthorizedAlert } from "@/components/alert/unauthorized/alert"; export default async function Portfolio({ params, @@ -35,7 +36,8 @@ export default async function Portfolio({ }) { const supabase = createSupabaseClient(); // if user hasn't invest in anything - if (!(await checkForInvest(supabase, params.uid))) { + const hasInvestments = await checkForInvest(supabase, params.uid); + if (!hasInvestments) { return (
@@ -49,14 +51,20 @@ export default async function Portfolio({ if (investorDealError) { console.error(investorDealError); } - const { - data: { user }, - error: userError, - } = await supabase.auth.getUser(); - if (userError) { + const { data: localUser, error: localUserError } = + await supabase.auth.getUser(); + if (localUserError) { console.error("Error while fetching user" + error); } - const username = user ? user.user_metadata.name : "Anonymous"; + // block user from try to see other user portfolio + if (params.uid != localUser.user?.id) { + return ( + <> + + + ); + } + const username = localUser ? localUser.user.user_metadata.name : "Anonymous"; // console.log(username) const overAllData = deals ? overAllGraphData(deals) : []; const fourYearData = deals ? fourYearGraphData(deals) : []; diff --git a/src/components/alert/unauthorized/alert.json b/src/components/alert/unauthorized/alert.json new file mode 100644 index 0000000..abdd2cf --- /dev/null +++ b/src/components/alert/unauthorized/alert.json @@ -0,0 +1,2066 @@ +{ + "v": "5.6.6", + "ip": 0, + "op": 160, + "fr": 60, + "w": 230, + "h": 181, + "layers": [ + { + "ind": 32159, + "nm": "surface156187", + "ao": 0, + "ip": 0, + "op": 264, + "st": 0, + "ty": 4, + "ks": { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [0, 0] }, + "a": { "k": [0, 0] }, + "s": { "k": [133.33, 133.33] }, + "sk": { "k": 0 }, + "sa": { "k": 0 } + }, + "shapes": [ + { + "ty": "gr", + "hd": false, + "nm": "surface156187", + "it": [ + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.7, 0.04] + ], + "o": [ + [0, -0.06], + [0, 0.92], + [0, 0] + ], + "v": [ + [2.56, 5.01], + [2.56, 6.3], + [0, 7.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [119.24, 10.15] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.71, 0.04] + ], + "o": [ + [0, -0.06], + [0, 0.92], + [0, 0] + ], + "v": [ + [7.56, 5.01], + [7.56, 6.3], + [5, 7.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [128.66, 10.15] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.71, 0.04] + ], + "o": [ + [0, -0.05], + [0, 0.92], + [0, 0] + ], + "v": [ + [7.56, 0], + [7.56, 1.3], + [5, 2.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [128.66, 0.68] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.7, 0.04] + ], + "o": [ + [0, -0.05], + [0, 0.92], + [0, 0] + ], + "v": [ + [2.56, 0], + [2.56, 1.3], + [0, 2.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [119.24, 0.68] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.7, 0.04] + ], + "o": [ + [0, -0.06], + [0, 0.92], + [0, 0] + ], + "v": [ + [2.56, 5.01], + [2.56, 6.3], + [0, 7.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [117.74, 46.15] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.71, 0.04] + ], + "o": [ + [0, -0.06], + [0, 0.92], + [0, 0] + ], + "v": [ + [7.56, 5.01], + [7.56, 6.3], + [5, 7.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [127.16, 46.15] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.71, 0.04] + ], + "o": [ + [0, -0.05], + [0, 0.92], + [0, 0] + ], + "v": [ + [7.56, 0], + [7.56, 1.3], + [5, 2.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [127.16, 36.68] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.7, 0.04] + ], + "o": [ + [0, -0.05], + [0, 0.92], + [0, 0] + ], + "v": [ + [2.56, 0], + [2.56, 1.3], + [0, 2.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [117.74, 36.68] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.7, 0.04] + ], + "o": [ + [0, -0.06], + [0, 0.92], + [0, 0] + ], + "v": [ + [2.56, 5.01], + [2.56, 6.3], + [0, 7.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [47.99, 55.9] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.71, 0.04] + ], + "o": [ + [0, -0.06], + [0, 0.92], + [0, 0] + ], + "v": [ + [7.56, 5.01], + [7.56, 6.3], + [5, 7.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [57.41, 55.9] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.71, 0.04] + ], + "o": [ + [0, -0.05], + [0, 0.92], + [0, 0] + ], + "v": [ + [7.56, 0], + [7.56, 1.3], + [5, 2.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [57.41, 46.43] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.7, 0.04] + ], + "o": [ + [0, -0.05], + [0, 0.92], + [0, 0] + ], + "v": [ + [2.56, 0], + [2.56, 1.3], + [0, 2.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [47.99, 46.43] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.7, 0.04] + ], + "o": [ + [0, -0.06], + [0, 0.92], + [0, 0] + ], + "v": [ + [2.56, 5.01], + [2.56, 6.3], + [0, 7.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [ + 0.9333333333333333, 0.5686274509803921, + 0.7843137254901961, 1 + ] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [23.99, 10.15] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.71, 0.04] + ], + "o": [ + [0, -0.06], + [0, 0.92], + [0, 0] + ], + "v": [ + [7.56, 5.01], + [7.56, 6.3], + [5, 7.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [ + 0.9333333333333333, 0.5686274509803921, + 0.7843137254901961, 1 + ] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [33.41, 10.15] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.71, 0.04] + ], + "o": [ + [0, -0.05], + [0, 0.92], + [0, 0] + ], + "v": [ + [7.56, 0], + [7.56, 1.3], + [5, 2.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [ + 0.9333333333333333, 0.5686274509803921, + 0.7843137254901961, 1 + ] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [33.41, 0.68] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.7, 0.04] + ], + "o": [ + [0, -0.05], + [0, 0.92], + [0, 0] + ], + "v": [ + [2.56, 0], + [2.56, 1.3], + [0, 2.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [ + 0.9333333333333333, 0.5686274509803921, + 0.7843137254901961, 1 + ] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [23.99, 0.68] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.7, 0.04] + ], + "o": [ + [0, -0.06], + [0, 0.92], + [0, 0] + ], + "v": [ + [2.56, 5.01], + [2.56, 6.3], + [0, 7.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { "k": [0.85, 0.12, 0.16, 1] }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [134.99, 136.9] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [0, 0] }, + "a": { "k": [0, 0] }, + "s": { "k": [100, 100] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.71, 0.04] + ], + "o": [ + [0, -0.06], + [0, 0.92], + [0, 0] + ], + "v": [ + [7.56, 5.01], + [7.56, 6.3], + [5, 7.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { "k": [0.85, 0.12, 0.16, 1] }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [144.41, 136.9] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [0, 0] }, + "a": { "k": [0, 0] }, + "s": { "k": [100, 100] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.71, 0.04] + ], + "o": [ + [0, -0.05], + [0, 0.92], + [0, 0] + ], + "v": [ + [7.56, 0], + [7.56, 1.3], + [5, 2.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [144.41, 127.43] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, -0.92], + [1.7, 0.04] + ], + "o": [ + [0, -0.05], + [0, 0.92], + [0, 0] + ], + "v": [ + [2.56, 0], + [2.56, 1.3], + [0, 2.63] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [134.99, 127.43] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [33.69, 20.69] + ], + "o": [ + [-24.8, -16.03], + [0, 0] + ], + "v": [ + [18.91, 94.7], + [0.27, 89.11] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [ + 0.7529411764705882, 0.20784313725490197, + 0.5294117647058824, 1 + ] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [1.46, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [-30.91, 20.85] + ], + "o": [ + [22.56, -15.59], + [0, 0] + ], + "v": [ + [211.76, 58.93], + [227.02, 52.7] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { "k": [1, 0.51, 0.54, 1] }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [1.46, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [0, 0] }, + "a": { "k": [0, 0] }, + "s": { "k": [100, 100] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, 5.42], + [10.77, 0], + [0, -10.73], + [0, -3.89] + ], + "o": [ + [0, -5.62], + [0, -10.73], + [-10.77, 0], + [0, 7.16], + [0, 0] + ], + "v": [ + [132.06, 52.99], + [132.06, 36.42], + [112.56, 16.99], + [93.06, 36.42], + [93.06, 52.99] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 4 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [1.46, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [214, 116], + [223.98, 126] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 2, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 2 }, + "c": { "k": [0.85, 0.12, 0.16, 1] }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [329.94, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [214, 116], + [223.98, 126] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 2, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 2 }, + "c": { "k": [0.85, 0.12, 0.16, 1] }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [1.46, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [0, 0] }, + "a": { "k": [0, 0] }, + "s": { "k": [100, 100] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [22, 126], + [27.99, 132] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 2, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 2 }, + "c": { + "k": [ + 0.592156862745098, 0.34509803921568627, + 0.49019607843137253, 1 + ] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [38.95, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [22, 126], + [27.99, 132] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 2, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 2 }, + "c": { + "k": [ + 0.592156862745098, 0.34509803921568627, + 0.49019607843137253, 1 + ] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [1.46, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [0, 31], + [7.99, 39] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 2, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 2 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [7.45, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [0, 31], + [7.98, 39] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 2, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 2 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [1.46, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [105, 122], + [109.99, 127] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 2, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 2 }, + "c": { + "k": [ + 0.7529411764705882, 0.20784313725490197, + 0.5294117647058824, 1 + ] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [162.7, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [105, 122], + [109.99, 127] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 2, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 2 }, + "c": { + "k": [ + 0.7529411764705882, 0.20784313725490197, + 0.5294117647058824, 1 + ] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [1.46, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [194, 0], + [198.99, 5] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 2, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [ + 0.592156862745098, 0.34509803921568627, + 0.49019607843137253, 1 + ] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [296.2, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [194, 0], + [198.99, 5] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 2, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 1 }, + "c": { + "k": [ + 0.592156862745098, 0.34509803921568627, + 0.49019607843137253, 1 + ] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [1.46, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [102, 65], + [123.01, 86.04] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 2, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 4 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 180 }, + "p": { "k": [170.21, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, -75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [102, 65], + [123.01, 86.04] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 2, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 4 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [1.46, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [16.29, 0], + [0, 16.29], + [-16.29, 0], + [0, -16.29] + ], + "o": [ + [0, 16.29], + [-16.29, 0], + [0, -16.29], + [16.29, 0], + [0, 0] + ], + "v": [ + [142.06, 75.49], + [112.56, 104.99], + [83.06, 75.49], + [112.56, 45.99], + [142.06, 75.49] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 4 }, + "c": { + "k": [0.8, 0.09803921568627451, 0.5137254901960784, 1] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [1.46, 18.76] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "gr", + "hd": false, + "it": [ + { + "ty": "sh", + "ks": { + "k": { + "i": [ + [0, 0], + [24.3, 0], + [0, 24.3], + [-24.3, 0], + [0, -24.3] + ], + "o": [ + [0, 24.3], + [-24.3, 0], + [0, -24.3], + [24.3, 0], + [0, 0] + ], + "v": [ + [156.06, 91.09], + [112.06, 135.09], + [68.06, 91.09], + [112.06, 47.09], + [156.06, 91.09] + ], + "c": false + } + } + }, + { + "ty": "st", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { "k": 100 }, + "w": { "k": 90 }, + "c": { + "k": [ + 0.9647058823529412, 0.9333333333333333, + 0.9529411764705882, 1 + ] + }, + "hd": false + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [1.46, 0.68] }, + "a": { "k": [0, 0] }, + "s": { "k": [75, 75] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "tr", + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [0, 0] }, + "a": { "k": [0, 0] }, + "s": { "k": [100, 100] }, + "sk": { "k": 0 }, + "sa": { "k": 0 }, + "hd": false + } + ] + }, + { + "ty": "tm", + "s": { "a": 0, "k": 0, "ix": 1 }, + "e": { + "a": 1, + "k": [ + { + "i": { "x": [0.27], "y": [1] }, + "o": { "x": [0.5], "y": [0] }, + "t": 0, + "s": [0] + }, + { "t": 66, "s": [100] } + ], + "ix": 2 + }, + "o": { "a": 0, "k": 0, "ix": 3 }, + "m": 1, + "ix": 2, + "hd": false + } + ] + } + ], + "meta": { "g": "LF SVG to Lottie" }, + "assets": [] +} diff --git a/src/components/alert/unauthorized/alert.tsx b/src/components/alert/unauthorized/alert.tsx new file mode 100644 index 0000000..2ff6c4a --- /dev/null +++ b/src/components/alert/unauthorized/alert.tsx @@ -0,0 +1,20 @@ +"use client"; +import Lottie from "react-lottie"; +import * as alertData from "./alert.json"; + +const alertOption = { + loop: true, + autoplay: true, + animationData: alertData, + rendererSettings: { + preserveAspectRatio: "xMidYMid slice", + }, +}; + +export function UnAuthorizedAlert() { + return ( +
+ +
+ ); +} From 2188d2b33f506a6d1ecc9107ca0b1ade14795cc0 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Fri, 1 Nov 2024 15:25:23 +0700 Subject: [PATCH 25/48] Refactor RecentFunds component to display only the first two characters of the deal name in the AvatarFallback --- src/components/recent-funds.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/recent-funds.tsx b/src/components/recent-funds.tsx index b078846..1f712e1 100644 --- a/src/components/recent-funds.tsx +++ b/src/components/recent-funds.tsx @@ -48,7 +48,7 @@ export function RecentFunds(props: RecentFundsProps) {
- {(deal.name ?? "").slice(0, 3)} + {(deal.name ?? "").slice(0, 2)}

{deal.name}

From 475c6eb9c22eac75143b231cf88d68eca6eb6f00 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Fri, 1 Nov 2024 15:25:44 +0700 Subject: [PATCH 26/48] Refactor RecentFunds component to display only the first two characters of the deal name in the AvatarFallback --- src/components/recent-funds.tsx | 44 +++------------------------------ 1 file changed, 4 insertions(+), 40 deletions(-) diff --git a/src/components/recent-funds.tsx b/src/components/recent-funds.tsx index 1f712e1..de9d218 100644 --- a/src/components/recent-funds.tsx +++ b/src/components/recent-funds.tsx @@ -1,45 +1,7 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -const data = [ - { - name: "Olivia Martin", - email: "olivia.martin@email.com", - amount: "1900.00", - avatar: "/avatars/01.png", // psuedo avatar image - initials: "OM", - }, - { - name: "Jackson Lee", - email: "jackson.lee@email.com", - amount: "39.00", - avatar: "/avatars/02.png", - initials: "JL", - }, - { - name: "Isabella Nguyen", - email: "isabella.nguyen@email.com", - amount: "299.00", - avatar: "/avatars/03.png", - initials: "IN", - }, - { - name: "William Kim", - email: "will@email.com", - amount: "99.00", - avatar: "/avatars/04.png", - initials: "WK", - }, - { - name: "Sofia Davis", - email: "sofia.davis@email.com", - amount: "39.00", - avatar: "/avatars/05.png", - initials: "SD", - }, -]; - interface RecentFundsProps { - data?: { name?: string; amount?: number; avatar?: string ; date?: Date}[]; + data?: { name?: string; amount?: number; avatar?: string; date?: Date }[]; } export function RecentFunds(props: RecentFundsProps) { return ( @@ -52,7 +14,9 @@ export function RecentFunds(props: RecentFundsProps) {

{deal.name}

-

{deal?.date?.toLocaleDateString()}

+

+ {deal?.date?.toLocaleDateString()} +

+${deal.amount}
From 7535afef67b2bfacd01c5259b6e5d10636b2b953 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Mon, 4 Nov 2024 11:09:33 +0700 Subject: [PATCH 27/48] Refactor ProjectSection and Invest components for improved type safety and formatting --- src/app/(investment)/deals/page.tsx | 17 +++++++- src/app/overview/page.tsx | 68 ++++++++++++++++++++++++----- src/app/portfolio/[uid]/page.tsx | 2 +- 3 files changed, 73 insertions(+), 14 deletions(-) diff --git a/src/app/(investment)/deals/page.tsx b/src/app/(investment)/deals/page.tsx index 799cad4..ba8d94d 100644 --- a/src/app/(investment)/deals/page.tsx +++ b/src/app/(investment)/deals/page.tsx @@ -13,7 +13,20 @@ import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import Link from "next/link"; -const ProjectSection = ({ filteredProjects }) => { +interface Project { + project_id: string; + project_name: string; + project_short_description: string; + published_time: string; + card_image_url: string; + business_location: string; + min_investment: number; + total_investment: number; + target_investment: number; + tags: { tag_name: string }[]; +} + +const ProjectSection = ({ filteredProjects }: { filteredProjects: Project[] }) => { interface Tags { tag_name: string; } @@ -266,7 +279,7 @@ export default function Deals() { {/* Project Cards Section */} - +
); diff --git a/src/app/overview/page.tsx b/src/app/overview/page.tsx index cd07319..afc6732 100644 --- a/src/app/overview/page.tsx +++ b/src/app/overview/page.tsx @@ -64,7 +64,13 @@ export default function Invest() { {/* Name, star and share button packed */}
- logo + logo
NVIDIA
@@ -72,7 +78,11 @@ export default function Invest() { - +

Follow NIVIDIA

@@ -86,10 +96,16 @@ export default function Invest() {
{/* end of pack */} -

World's first non-metal sustainable battery

+

+ {" "} + World's first non-metal sustainable battery +

{["Technology", "Gaming"].map((tag) => ( - + {tag} ))} @@ -101,7 +117,11 @@ export default function Invest() { {Array.from({ length: 5 }).map((_, index) => ( - + ))} {" "} @@ -132,19 +152,36 @@ export default function Invest() {

- +

5% raised of $5M max goal

{" "} - +

Investors

- hours + {" "} + hours

Left to invest

*/} {/* */}
-

- Welcome to your Portfolio, {username}! -

+

Welcome to your Portfolio, {username}!

Here‘s an overview of your investment journey and progress.

@@ -125,9 +104,7 @@ export default async function Portfolio({ - - Monthly Investment Trend - + Monthly Investment Trend @@ -135,8 +112,7 @@ export default async function Portfolio({

- Displays total investments each month over the past 12{" "} -
+ Displays total investments each month over the past 12
months, up to today.

@@ -144,20 +120,14 @@ export default async function Portfolio({
- +
- - Yearly Investment Summary - + Yearly Investment Summary @@ -165,8 +135,7 @@ export default async function Portfolio({

- Shows total investments for each of the last four years,{" "} -
+ Shows total investments for each of the last four years,
including the current year to date.

@@ -174,20 +143,14 @@ export default async function Portfolio({
- +
- - Daily Investment Breakdown - + Daily Investment Breakdown @@ -195,8 +158,7 @@ export default async function Portfolio({

- Illustrates total investments for each day over the past{" "} -
+ Illustrates total investments for each day over the past
year, up to today.

@@ -204,11 +166,7 @@ export default async function Portfolio({
- +
@@ -217,9 +175,7 @@ export default async function Portfolio({
- - Categories of Invested Projects - + Categories of Invested Projects @@ -236,21 +192,15 @@ export default async function Portfolio({ item.count - )} - labels={tagCount.map( - (item: { name: string; count: number }) => item.name - )} + data={tagCount.map((item: { name: string; count: number }) => item.count)} + labels={tagCount.map((item: { name: string; count: number }) => item.name)} header="Total" /> - - Types of Businesses Invested In - + Types of Businesses Invested In @@ -258,8 +208,7 @@ export default async function Portfolio({

- Shows the breakdown of business types in your portfolio,{" "} -
+ Shows the breakdown of business types in your portfolio,
illustrating sector diversity.

@@ -276,9 +225,7 @@ export default async function Portfolio({
- - Recent investment - + Recent investment diff --git a/src/lib/data/investmentQuery.ts b/src/lib/data/investmentQuery.ts index bf8b349..da17b3b 100644 --- a/src/lib/data/investmentQuery.ts +++ b/src/lib/data/investmentQuery.ts @@ -29,3 +29,11 @@ export const getInvestmentByUserId = (client: SupabaseClient, userId: string) => ) .eq("investor_id", userId); }; + +export function getInvestorDeal(client: SupabaseClient, userId: string) { + return client + .from("investment_deal") + .select("*") + .in("investor_id", [userId]) + .order("created_time", { ascending: true }); +} From a440110098ea2d40045e2b4c8bed329e5b58b465 Mon Sep 17 00:00:00 2001 From: Sosokker Date: Mon, 4 Nov 2024 11:56:18 +0700 Subject: [PATCH 29/48] fix: can't access portfolio page --- src/app/portfolio/[uid]/hook.ts | 57 +++++----------------- src/components/recent-funds.tsx | 43 ++++++----------- src/components/ui/overview.tsx | 86 ++++++++++++++++++++++++++++----- src/lib/data/tagQuery.ts | 8 +++ 4 files changed, 107 insertions(+), 87 deletions(-) diff --git a/src/app/portfolio/[uid]/hook.ts b/src/app/portfolio/[uid]/hook.ts index 8efb2bd..7ce663c 100644 --- a/src/app/portfolio/[uid]/hook.ts +++ b/src/app/portfolio/[uid]/hook.ts @@ -1,7 +1,7 @@ import { SupabaseClient } from "@supabase/supabase-js"; -import { getProjectTag, getTagName } from "@/lib/data/query"; +import { getProjectTag, getTagName } from "@/lib/data/tagQuery"; -function getTotalInvestment(deals: { deal_amount : number}[]) { +function getTotalInvestment(deals: { deal_amount: number }[]) { let total = 0; for (let index = 0; index < deals.length; index++) { total += deals[index].deal_amount; @@ -16,10 +16,7 @@ async function getLatestInvestment( const count = 8; for (let i = deals.length - 1; i >= 0 && llist.length < count; --i) { - let { data: project, error } = await supabase - .from("project") - .select("project_name") - .eq("id", deals[i].project_id); + let { data: project, error } = await supabase.from("project").select("project_name").eq("id", deals[i].project_id); if (error) { console.error(error); } @@ -62,15 +59,9 @@ function countValues(arr: { value: string }[][]): Record { return counts; } -async function getBusinessTypeName( - supabase: SupabaseClient, - projectId: number -) { +async function getBusinessTypeName(supabase: SupabaseClient, projectId: number) { // step 1: get business id from project id - let { data: project, error: projectError } = await supabase - .from("project") - .select("business_id") - .eq("id", projectId); + let { data: project, error: projectError } = await supabase.from("project").select("business_id").eq("id", projectId); if (projectError) { console.error(projectError); } @@ -107,20 +98,7 @@ interface GraphData { function overAllGraphData(deals: Deal[]): GraphData[] { // Initialize all months with value 0 - const months = [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ]; + const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; const acc: GraphData[] = months.map((month) => ({ name: month, value: 0 })); deals @@ -137,7 +115,6 @@ function overAllGraphData(deals: Deal[]): GraphData[] { return acc; } - interface Deal { created_time: string | number | Date; deal_amount: any; @@ -153,7 +130,7 @@ function fourYearGraphData(deals: Deal[]): GraphData[] { const acc: GraphData[] = Array.from({ length: 4 }, (_, i) => ({ name: (currentYear - i).toString(), value: 0, - })).reverse(); + })).reverse(); deals .filter((item: Deal) => new Date(item.created_time) >= yearAgo(3)) .forEach((item: Deal) => { @@ -168,7 +145,6 @@ function fourYearGraphData(deals: Deal[]): GraphData[] { return acc; } - interface DayOfWeekData { name: string; value: number; @@ -191,24 +167,16 @@ function dayOftheWeekData(deals: Deal[]): DayOfWeekData[] { }); return dayOfWeekData; } -async function getInvestorProjectTag( - supabase: SupabaseClient, - deals: number | { project_id: number }[] -) { +async function getInvestorProjectTag(supabase: SupabaseClient, deals: number | { project_id: number }[]) { // get unique project id from deals const uniqueProjectIds: number[] = Array.isArray(deals) - ? Array.from( - new Set(deals.map((deal: { project_id: number }) => deal.project_id)) - ) + ? Array.from(new Set(deals.map((deal: { project_id: number }) => deal.project_id))) : []; const tagIds = ( await Promise.all( uniqueProjectIds.map(async (projectId: number) => { - const { data: tagIdsArray, error: tagError } = await getProjectTag( - supabase, - projectId - ); + const { data: tagIdsArray, error: tagError } = await getProjectTag(supabase, projectId); if (tagError) { console.error(tagError); return []; @@ -223,10 +191,7 @@ async function getInvestorProjectTag( tagIds .filter((tagId) => tagId !== null) .map(async (id: number) => { - const { data: tagName, error: nameError } = await getTagName( - supabase, - id - ); + const { data: tagName, error: nameError } = await getTagName(supabase, id); if (nameError) { console.error(nameError); return null; diff --git a/src/components/recent-funds.tsx b/src/components/recent-funds.tsx index b321077..432c4b0 100644 --- a/src/components/recent-funds.tsx +++ b/src/components/recent-funds.tsx @@ -1,39 +1,24 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -export type RecentDealData = { - created_time: Date; - deal_amount: number; - investor_id: string; - username: string; - avatar_url?: string; - // email: string; -}; - interface RecentFundsProps { - recentDealData: RecentDealData[]; + data?: { name?: string; amount?: number; avatar?: string; date?: Date }[]; } - -export function RecentFunds({ recentDealData }: RecentFundsProps) { +export function RecentFunds(props: RecentFundsProps) { return (
- {recentDealData?.length > 0 ? ( - recentDealData.map((data) => ( -
- - - {/* #TODO make this not quick fix */} - {data.username ? data.username[0] : ""} - -
-

{data.username}

- {/*

{data.email}

*/} -
-
+${data.deal_amount}
+ {(props?.data || []).map((deal, index) => ( +
+ + + {(deal.name ?? "").slice(0, 2)} + +
+

{deal.name}

+

{deal?.date?.toLocaleDateString()}

- )) - ) : ( -

No recent deals available.

- )} +
+${deal.amount}
+
+ ))}
); } diff --git a/src/components/ui/overview.tsx b/src/components/ui/overview.tsx index 3e6fdad..82ad859 100644 --- a/src/components/ui/overview.tsx +++ b/src/components/ui/overview.tsx @@ -2,22 +2,68 @@ import { Bar, BarChart, ResponsiveContainer, XAxis, YAxis, LineChart, Line, Tooltip } from "recharts"; +// const data = [ +// { +// name: "Jan", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Feb", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Mar", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Apr", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "May", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Jun", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Jul", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Aug", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Sep", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Oct", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Nov", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// { +// name: "Dec", +// total: Math.floor(Math.random() * 5000) + 1000, +// }, +// ]; + interface OverViewProps { graphType: string; - graphData: Record; // Object with month-year as keys and sum as value + data: { name: string; value: number }[]; + graphHeight?: number | string; } export function Overview(props: OverViewProps) { - // Transform the grouped data into the format for the chart - const chartData = Object.entries(props.graphData).map(([monthYear, totalArray]) => ({ - name: monthYear, - total: totalArray, // Get the total amount for the month - })); - return ( - + {props.graphType === "line" ? ( - + `$${value}`} /> - + `$${value}`} + contentStyle={{ + backgroundColor: "#f5f5f5", + borderRadius: "5px", + color: "#000", + }} + /> + ) : ( - + `$${value}`} /> - + `$${value}`} + contentStyle={{ + backgroundColor: "#f5f5f5", + borderRadius: "5px", + color: "#000", + }} + /> + )} diff --git a/src/lib/data/tagQuery.ts b/src/lib/data/tagQuery.ts index a3f92cb..bb1bb76 100644 --- a/src/lib/data/tagQuery.ts +++ b/src/lib/data/tagQuery.ts @@ -3,3 +3,11 @@ import { SupabaseClient } from "@supabase/supabase-js"; export const getTagsByProjectIds = (client: SupabaseClient, projectIds: string[]) => { return client.from("project_tag").select(`item_id, ...tag (tag_value:value)`).in("item_id", projectIds); }; + +export function getProjectTag(client: SupabaseClient, projectId: number) { + return client.from("project_tag").select("tag_id").in("item_id", [projectId]); +} + +export function getTagName(client: SupabaseClient, tagId: number) { + return client.from("tag").select("value").in("id", [tagId]); +} From 2ead19ec67501b9b1065b67bd7aa72318f282d81 Mon Sep 17 00:00:00 2001 From: Sosokker Date: Mon, 4 Nov 2024 19:08:00 +0700 Subject: [PATCH 30/48] fix: fix build fail and eslint --- src/app/api/dealApi.ts | 1 - src/app/dashboard/hook.ts | 8 ++-- src/app/dashboard/page.tsx | 71 +++++++++++++++++++++++++++++---- src/app/overview/page.tsx | 0 src/app/page.tsx | 4 +- src/app/portfolio/[uid]/hook.ts | 10 ----- src/components/recent-funds.tsx | 10 +++++ 7 files changed, 79 insertions(+), 25 deletions(-) delete mode 100644 src/app/overview/page.tsx diff --git a/src/app/api/dealApi.ts b/src/app/api/dealApi.ts index 7cdaa0d..cd56925 100644 --- a/src/app/api/dealApi.ts +++ b/src/app/api/dealApi.ts @@ -5,7 +5,6 @@ export type Deal = { created_time: Date; investor_id: string; }; -const supabase = createSupabaseClient(); export async function getDealList(userId: string | undefined) { if (!userId) { diff --git a/src/app/dashboard/hook.ts b/src/app/dashboard/hook.ts index 676d249..0b2cdb8 100644 --- a/src/app/dashboard/hook.ts +++ b/src/app/dashboard/hook.ts @@ -10,7 +10,7 @@ export function useDealList() { const fetchDealList = async () => { // set the state to the deal list of current business user setDealList(await getDealList(await getCurrentUserID())); - } + }; useEffect(() => { fetchDealList(); @@ -28,7 +28,7 @@ export function useGraphData() { if (dealList) { setGraphData(convertToGraphData(dealList)); } - } + }; useEffect(() => { fetchGraphData(); @@ -43,11 +43,11 @@ export function useRecentDealData() { const fetchRecentDealData = async () => { // set the state to the deal list of current business user setRecentDealData(await getRecentDealData(await getCurrentUserID())); - } + }; useEffect(() => { fetchRecentDealData(); }, []); return recentDealData; -} \ No newline at end of file +} diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index e59b7f3..d506482 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -6,18 +6,73 @@ import { Overview } from "@/components/ui/overview"; import { RecentFunds } from "@/components/recent-funds"; import { useState } from "react"; -import { useDealList, useGraphData, useRecentDealData } from "./hook"; -import { sumByKey } from "@/lib/utils"; +import { useDealList } from "./hook"; + +const data = [ + { + name: "Jan", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Feb", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Mar", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Apr", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "May", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Jun", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Jul", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Aug", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Sep", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Oct", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Nov", + value: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: "Dec", + value: Math.floor(Math.random() * 5000) + 1000, + }, +]; export default function Dashboard() { const [graphType, setGraphType] = useState("line"); - const graphData = useGraphData(); const dealList = useDealList(); - // #TODO dependency injection refactor + define default value inside function (and not here) - const recentDealData = useRecentDealData() || []; + const totalDealAmount = dealList?.reduce((sum, deal) => sum + deal.deal_amount, 0) || 0; return ( <> + {dealList?.map((deal, index) => ( +
+

Deal Amount: {deal.deal_amount}

+

Created Time: {new Date(deal.created_time).toUTCString()}

+

Investor ID: {deal.investor_id}

+
+ ))}
-
${sumByKey(dealList, "deal_amount")}
+
${totalDealAmount}
{/*

+20.1% from last month

*/} @@ -150,7 +205,7 @@ export default function Dashboard() { Overview - + {/* tab to switch between line and bar graph */} @@ -170,7 +225,7 @@ export default function Dashboard() { You made {dealList?.length || 0} sales this month. - +
diff --git a/src/app/overview/page.tsx b/src/app/overview/page.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/page.tsx b/src/app/page.tsx index 5f586f6..19cc657 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -13,7 +13,7 @@ interface Project { id: number; project_name: string; project_short_description: string; - project_logo: string; + card_image_url: string; published_time: string; business: { location: string }[]; project_tag: { tag: { id: number; value: string }[] }[]; @@ -38,7 +38,7 @@ const TopProjects: FC = ({ projects }) => { diff --git a/src/app/portfolio/[uid]/hook.ts b/src/app/portfolio/[uid]/hook.ts index 7ce663c..4d59dfa 100644 --- a/src/app/portfolio/[uid]/hook.ts +++ b/src/app/portfolio/[uid]/hook.ts @@ -115,16 +115,6 @@ function overAllGraphData(deals: Deal[]): GraphData[] { return acc; } -interface Deal { - created_time: string | number | Date; - deal_amount: any; -} - -interface GraphData { - name: string; - value: number; -} - function fourYearGraphData(deals: Deal[]): GraphData[] { const currentYear = new Date().getFullYear(); const acc: GraphData[] = Array.from({ length: 4 }, (_, i) => ({ diff --git a/src/components/recent-funds.tsx b/src/components/recent-funds.tsx index 432c4b0..5a1c71b 100644 --- a/src/components/recent-funds.tsx +++ b/src/components/recent-funds.tsx @@ -1,8 +1,18 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +export type RecentDealData = { + created_time: Date; + deal_amount: number; + investor_id: string; + username: string; + avatar_url?: string; + // email: string; +}; + interface RecentFundsProps { data?: { name?: string; amount?: number; avatar?: string; date?: Date }[]; } + export function RecentFunds(props: RecentFundsProps) { return (
From a007a649f00718fe275af988fe78cae62e13875c Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Mon, 4 Nov 2024 20:34:30 +0700 Subject: [PATCH 31/48] feat: enhance loading component with Lottie animation and improve data handling --- package-lock.json | 1 + src/app/business/apply/page.tsx | 4 ++-- src/app/loading.tsx | 20 +++----------------- src/components/loading/loader.tsx | 8 +++++--- 4 files changed, 11 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index e6e2970..e2c2f49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8541,6 +8541,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/react-lottie/-/react-lottie-1.2.4.tgz", "integrity": "sha512-kBGxI+MIZGBf4wZhNCWwHkMcVP+kbpmrLWH/SkO0qCKc7D7eSPcxQbfpsmsCo8v2KCBYjuGSou+xTqK44D/jMg==", + "license": "MIT", "dependencies": { "babel-runtime": "^6.26.0", "lottie-web": "^5.1.3" diff --git a/src/app/business/apply/page.tsx b/src/app/business/apply/page.tsx index e277932..b425e16 100644 --- a/src/app/business/apply/page.tsx +++ b/src/app/business/apply/page.tsx @@ -48,7 +48,7 @@ export default function ApplyBusiness() { } } - const { error } = await supabase + const { data, error } = await supabase .from("business_application") .insert([ { @@ -66,7 +66,7 @@ export default function ApplyBusiness() { ]) .select(); setSucess(true); - + // console.table(data); Swal.fire({ icon: error == null ? "success" : "error", title: error == null ? "success" : "Error: " + error.code, diff --git a/src/app/loading.tsx b/src/app/loading.tsx index 97af30b..0f8be55 100644 --- a/src/app/loading.tsx +++ b/src/app/loading.tsx @@ -1,22 +1,8 @@ +import { Loader } from "@/components/loading/loader"; export default function Loading() { return ( -
-
- - - - -

Loading data...

-
+
+
); } diff --git a/src/components/loading/loader.tsx b/src/components/loading/loader.tsx index cedb548..408d164 100644 --- a/src/components/loading/loader.tsx +++ b/src/components/loading/loader.tsx @@ -1,3 +1,5 @@ +"use client"; + import Lottie from "react-lottie"; import * as loadingData from "./loading.json"; @@ -11,17 +13,17 @@ const loadingOption = { }; interface LoaderProps { - isSuccess: boolean; + isSuccess?: boolean; } export function Loader(props: LoaderProps) { return ( - <> +
{!props.isSuccess && (
)} - +
); } From 2d67eedc59cce8395f4f07e7c72dbad3ee6de973 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Mon, 4 Nov 2024 21:02:34 +0700 Subject: [PATCH 32/48] feat: add logo URL fetching for investment deals and update recent funds component --- src/app/portfolio/[uid]/hook.ts | 19 +++++++++++++++++++ src/app/portfolio/[uid]/page.tsx | 10 +++++++++- src/components/recent-funds.tsx | 6 +++--- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/app/portfolio/[uid]/hook.ts b/src/app/portfolio/[uid]/hook.ts index 4d59dfa..151d0eb 100644 --- a/src/app/portfolio/[uid]/hook.ts +++ b/src/app/portfolio/[uid]/hook.ts @@ -1,6 +1,22 @@ import { SupabaseClient } from "@supabase/supabase-js"; import { getProjectTag, getTagName } from "@/lib/data/tagQuery"; +async function fetchLogoURL(supabase: SupabaseClient, projectId: number) { + const logoIndex = 1; + let { data: project_material, error } = await supabase + .from("project_material") + .select("material_url") + .eq("project_id", projectId) + .eq("material_type_id", logoIndex); + if (error) { + console.error("Error while fetching golo url" + error); + } + if (project_material && project_material.length > 0) { + return project_material[0].material_url; + } + return ""; +} + function getTotalInvestment(deals: { deal_amount: number }[]) { let total = 0; for (let index = 0; index < deals.length; index++) { @@ -20,10 +36,12 @@ async function getLatestInvestment( if (error) { console.error(error); } + let url = fetchLogoURL(supabase, deals[i].project_id); llist.push({ name: project?.[0]?.project_name, amount: deals[i].deal_amount, date: new Date(deals[i].created_time), + logo_url: url, }); } @@ -234,4 +252,5 @@ export { checkForInvest, getLatestInvestment, getTotalInvestment, + fetchLogoURL, }; diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx index dd8ec1a..052e7ca 100644 --- a/src/app/portfolio/[uid]/page.tsx +++ b/src/app/portfolio/[uid]/page.tsx @@ -57,9 +57,17 @@ export default async function Portfolio({ params }: { params: { uid: string } }) const fourYearData = deals ? fourYearGraphData(deals) : []; const dayOfWeekData = deals ? dayOftheWeekData(deals) : []; const tags = deals ? await getInvestorProjectTag(supabase, deals) : []; - const latestDeals = deals ? await getLatestInvestment(supabase, deals) : []; + const latestDeals = deals + ? await Promise.all( + (await getLatestInvestment(supabase, deals)).map(async (deal) => ({ + ...deal, + logo_url: await deal.logo_url, + })) + ) + : []; const totalInvestment = deals ? getTotalInvestment(deals) : 0; // console.log(latestDeals); + const tagCount = countTags(tags); // console.log(investedBusinessIds); const businessType = deals diff --git a/src/components/recent-funds.tsx b/src/components/recent-funds.tsx index 5a1c71b..3707d2d 100644 --- a/src/components/recent-funds.tsx +++ b/src/components/recent-funds.tsx @@ -5,12 +5,12 @@ export type RecentDealData = { deal_amount: number; investor_id: string; username: string; - avatar_url?: string; + logo_url?: string; // email: string; }; interface RecentFundsProps { - data?: { name?: string; amount?: number; avatar?: string; date?: Date }[]; + data?: { name?: string; amount?: number; avatar?: string; date?: Date; logo_url?: string }[]; } export function RecentFunds(props: RecentFundsProps) { @@ -19,7 +19,7 @@ export function RecentFunds(props: RecentFundsProps) { {(props?.data || []).map((deal, index) => (
- + {(deal.name ?? "").slice(0, 2)}
From 79d5d9615d2d806811b17d43b7c80eabdcf6d5ab Mon Sep 17 00:00:00 2001 From: Pattadon Date: Tue, 5 Nov 2024 10:13:35 +0700 Subject: [PATCH 33/48] fix: adjust ThemeToggle positioning and add Dataroom link for business role --- src/components/navigationBar/nav.tsx | 4 +++- src/components/navigationBar/profileBar.tsx | 11 ++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/navigationBar/nav.tsx b/src/components/navigationBar/nav.tsx index c51dbc8..e31bdf3 100644 --- a/src/components/navigationBar/nav.tsx +++ b/src/components/navigationBar/nav.tsx @@ -110,7 +110,9 @@ export function NavigationBar() {
- +
+ +
diff --git a/src/components/navigationBar/profileBar.tsx b/src/components/navigationBar/profileBar.tsx index 92abdd9..c605177 100644 --- a/src/components/navigationBar/profileBar.tsx +++ b/src/components/navigationBar/profileBar.tsx @@ -56,11 +56,7 @@ const AuthenticatedComponents = ({ uid }: { uid: string }) => { -
From 686f065d3c85e867dd32e4fd3e7b08b37fc5252f Mon Sep 17 00:00:00 2001 From: Pattadon Date: Wed, 6 Nov 2024 11:04:15 +0700 Subject: [PATCH 35/48] feat: implement image display modal and refactor FollowShareButtons component --- .../(investment)/deals/[id]/displayImage.tsx | 35 +++++++++++++++++++ .../deals/[id]/followShareButton.tsx | 2 -- src/app/(investment)/deals/[id]/page.tsx | 9 +++-- 3 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 src/app/(investment)/deals/[id]/displayImage.tsx diff --git a/src/app/(investment)/deals/[id]/displayImage.tsx b/src/app/(investment)/deals/[id]/displayImage.tsx new file mode 100644 index 0000000..7e48f8b --- /dev/null +++ b/src/app/(investment)/deals/[id]/displayImage.tsx @@ -0,0 +1,35 @@ +"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"; +import { it } from "node:test"; + +const ImageModal = ({ item, width }: { item: { src: string | StaticImport; alt: string;} }, number ) => { + return ( + + + {item.alt} + + + + Image Preview + Click outside to close the image preview. + + {item.alt} + + + + ); +}; + +export function DisplayFullImage({ item }: { item: { src: string | StaticImport; alt: string; width: number; height: number } }) { + return ; +} diff --git a/src/app/(investment)/deals/[id]/followShareButton.tsx b/src/app/(investment)/deals/[id]/followShareButton.tsx index ed34336..9242b98 100644 --- a/src/app/(investment)/deals/[id]/followShareButton.tsx +++ b/src/app/(investment)/deals/[id]/followShareButton.tsx @@ -10,8 +10,6 @@ import useSession from "@/lib/supabase/useSession"; import toast from "react-hot-toast"; const FollowShareButtons = () => { - const [progress, setProgress] = useState(0); - const [tab, setTab] = useState("Pitch"); const { session, loading } = useSession(); const user = session?.user; const [sessionLoaded, setSessionLoaded] = useState(false); diff --git a/src/app/(investment)/deals/[id]/page.tsx b/src/app/(investment)/deals/[id]/page.tsx index f99fc58..83b7779 100644 --- a/src/app/(investment)/deals/[id]/page.tsx +++ b/src/app/(investment)/deals/[id]/page.tsx @@ -11,6 +11,7 @@ import { Progress } from "@/components/ui/progress"; import { Separator } from "@/components/ui/separator"; import { createSupabaseClient } from "@/lib/supabase/serverComponentClient"; import FollowShareButtons from "./followShareButton"; +import { DisplayFullImage } from "./displayImage"; import { getProjectData } from "@/lib/data/projectQuery"; import { getDealList } from "@/app/api/dealApi"; @@ -19,7 +20,6 @@ import { redirect } from "next/navigation"; export default async function ProjectDealPage({ params }: { params: { id: number } }) { const supabase = createSupabaseClient(); - const { data: projectData, error: projectDataError } = await getProjectData(supabase, params.id); if (!projectData) { @@ -49,6 +49,7 @@ export default async function ProjectDealPage({ params }: { params: { id: number alt: `${projectData.project_name} Image`, }); + return (
@@ -91,7 +92,7 @@ export default async function ProjectDealPage({ params }: { params: { id: number {carouselData.map((item, index) => ( - {item.alt} + ))} @@ -140,7 +141,9 @@ export default async function ProjectDealPage({ params }: { params: { id: number
- Pitch + + Pitch + General Data Updates From 7084d4d0aafc924be24bf285387eff3caa5482c8 Mon Sep 17 00:00:00 2001 From: Naytitorn Chaovirachot Date: Wed, 6 Nov 2024 14:41:37 +0700 Subject: [PATCH 36/48] add about page --- src/app/about/page.tsx | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/app/about/page.tsx diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx new file mode 100644 index 0000000..a9ef962 --- /dev/null +++ b/src/app/about/page.tsx @@ -0,0 +1,26 @@ +export default async function About() { + return ( +
+

+ About us +

+

+ Welcome to B2D Ventures! We're a dynamic platform committed to bridging the gap + between visionary entrepreneurs and passionate investors. Our mission is to empower + innovation by connecting groundbreaking ideas with the resources they need to thrive. + Through B2D Ventures, we foster a community where investors and innovators come together + to transform concepts into impactful, real-world solutions. +

+

+ At B2D Ventures, we believe in the power of collaboration. Whether you're an investor + looking to support the next big idea or a founder aiming to bring your vision to life, + our platform offers the tools and connections to make it happen. + + Join us on a journey to reshape industries, drive positive change, and make a lasting impact. +

+

+ Let's build the future, together. +

+
+ ) +} \ No newline at end of file From 3191d4d2c8dce725f57e2b9ef0d70c860c619cff Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Wed, 6 Nov 2024 15:18:09 +0700 Subject: [PATCH 37/48] feat: refactor ImageModal and DisplayFullImage components to use destructured props --- .../(investment)/deals/[id]/displayImage.tsx | 20 ++++++++++++------- src/app/(investment)/deals/[id]/page.tsx | 5 +++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/app/(investment)/deals/[id]/displayImage.tsx b/src/app/(investment)/deals/[id]/displayImage.tsx index 7e48f8b..b1b6557 100644 --- a/src/app/(investment)/deals/[id]/displayImage.tsx +++ b/src/app/(investment)/deals/[id]/displayImage.tsx @@ -10,26 +10,32 @@ import { } from "@/components/ui/dialog"; import Image from "next/image"; import { StaticImport } from "next/dist/shared/lib/get-img-props"; -import { it } from "node:test"; -const ImageModal = ({ item, width }: { item: { src: string | StaticImport; alt: string;} }, number ) => { +interface ItemProps { + src: string | StaticImport; + alt: string; + width: number; + height: number; +} + +const ImageModal = ({ src, alt, width, height }: ItemProps) => { return ( - {item.alt} + {alt} - + Image Preview Click outside to close the image preview. - {item.alt} + {alt} ); }; -export function DisplayFullImage({ item }: { item: { src: string | StaticImport; alt: string; width: number; height: number } }) { - return ; +export function DisplayFullImage({ src, alt, width, height }: ItemProps) { + return ; } diff --git a/src/app/(investment)/deals/[id]/page.tsx b/src/app/(investment)/deals/[id]/page.tsx index 83b7779..cc6dc13 100644 --- a/src/app/(investment)/deals/[id]/page.tsx +++ b/src/app/(investment)/deals/[id]/page.tsx @@ -49,7 +49,6 @@ export default async function ProjectDealPage({ params }: { params: { id: number alt: `${projectData.project_name} Image`, }); - return (
@@ -92,7 +91,9 @@ export default async function ProjectDealPage({ params }: { params: { id: number {carouselData.map((item, index) => ( - + + + ))} From 2b7f3409576b7a541c8218e0354e13e6f97757eb Mon Sep 17 00:00:00 2001 From: Naytitorn Chaovirachot Date: Wed, 6 Nov 2024 15:19:53 +0700 Subject: [PATCH 38/48] fix: link github on homepage and fix project search not clickable --- .../(investment)/deals/[id]/displayImage.tsx | 2 +- src/app/find/page.tsx | 33 +++++++++++-------- src/app/loading.tsx | 6 +--- src/app/page.tsx | 14 ++++---- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/app/(investment)/deals/[id]/displayImage.tsx b/src/app/(investment)/deals/[id]/displayImage.tsx index 7e48f8b..0e28f72 100644 --- a/src/app/(investment)/deals/[id]/displayImage.tsx +++ b/src/app/(investment)/deals/[id]/displayImage.tsx @@ -10,7 +10,7 @@ import { } from "@/components/ui/dialog"; import Image from "next/image"; import { StaticImport } from "next/dist/shared/lib/get-img-props"; -import { it } from "node:test"; + const ImageModal = ({ item, width }: { item: { src: string | StaticImport; alt: string;} }, number ) => { return ( diff --git a/src/app/find/page.tsx b/src/app/find/page.tsx index 729609c..a159ab9 100644 --- a/src/app/find/page.tsx +++ b/src/app/find/page.tsx @@ -8,6 +8,7 @@ import { ProjectCard } from "@/components/projectCard"; import { Separator } from "@/components/ui/separator"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { getBusinessAndProject } from "@/lib/data/businessQuery"; +import Link from "next/link"; function FindContent() { const searchParams = useSearchParams(); @@ -43,7 +44,11 @@ function FindContent() {
  • - {business.business_name} + + {/* */} + {business.business_name} + {/* */} + Joined Date: {new Date(business.joined_date).toLocaleDateString()} @@ -51,18 +56,20 @@ function FindContent() { {business?.projects && business.projects.length > 0 ? ( business.projects.map((project) => ( - String(tag.tag_value)) || []} - imageUri={project.card_image_url} - /> + + String(tag.tag_value)) || []} + imageUri={project.card_image_url} + /> + )) ) : (

    No Projects

    diff --git a/src/app/loading.tsx b/src/app/loading.tsx index 0f8be55..c38f7da 100644 --- a/src/app/loading.tsx +++ b/src/app/loading.tsx @@ -1,8 +1,4 @@ import { Loader } from "@/components/loading/loader"; export default function Loading() { - return ( -
    - -
    - ); + return ; } diff --git a/src/app/page.tsx b/src/app/page.tsx index 19cc657..184e9b7 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -121,14 +121,12 @@ export default async function Home() { Follow Us
    - - + + +
  • From 80b63c02bcf33c2dbcccabcc60485e989d95d0ed Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Wed, 6 Nov 2024 16:07:54 +0700 Subject: [PATCH 39/48] feat: enhance ImageModal and DisplayFullImage components to support className prop and improve image handling --- .../(investment)/deals/[id]/displayImage.tsx | 11 +- src/app/(investment)/deals/[id]/page.tsx | 193 ++++++++++-------- 2 files changed, 114 insertions(+), 90 deletions(-) diff --git a/src/app/(investment)/deals/[id]/displayImage.tsx b/src/app/(investment)/deals/[id]/displayImage.tsx index b1b6557..a39df0f 100644 --- a/src/app/(investment)/deals/[id]/displayImage.tsx +++ b/src/app/(investment)/deals/[id]/displayImage.tsx @@ -16,26 +16,27 @@ interface ItemProps { alt: string; width: number; height: number; + className?: string; } -const ImageModal = ({ src, alt, width, height }: ItemProps) => { +const ImageModal = ({ src, alt, width, height, className }: ItemProps) => { return ( - {alt} + {alt} Image Preview Click outside to close the image preview. - {alt} + {alt} ); }; -export function DisplayFullImage({ src, alt, width, height }: ItemProps) { - return ; +export function DisplayFullImage({ src, alt, width, height, className }: ItemProps) { + return ; } diff --git a/src/app/(investment)/deals/[id]/page.tsx b/src/app/(investment)/deals/[id]/page.tsx index cc6dc13..f223de3 100644 --- a/src/app/(investment)/deals/[id]/page.tsx +++ b/src/app/(investment)/deals/[id]/page.tsx @@ -12,16 +12,25 @@ import { Separator } from "@/components/ui/separator"; import { createSupabaseClient } from "@/lib/supabase/serverComponentClient"; import FollowShareButtons from "./followShareButton"; import { DisplayFullImage } from "./displayImage"; - import { getProjectData } from "@/lib/data/projectQuery"; import { getDealList } from "@/app/api/dealApi"; import { sumByKey, toPercentage } from "@/lib/utils"; import { redirect } from "next/navigation"; +const PHOTO_MATERIAL_ID = 2; export default async function ProjectDealPage({ params }: { params: { id: number } }) { const supabase = createSupabaseClient(); const { data: projectData, error: projectDataError } = await getProjectData(supabase, params.id); + const { data: projectMaterial, error: projectMaterialError } = await supabase + .from("project_material") + .select("material_url") + .eq("project_id", params.id) + .eq("material_type_id", PHOTO_MATERIAL_ID); + // console.log(projectMaterial); + if (projectMaterialError) { + console.error("Error while fetching project material" + projectMaterialError); + } if (!projectData) { redirect("/deals"); } @@ -44,96 +53,110 @@ export default async function ProjectDealPage({ params }: { params: { id: number const timeDiff = Math.max(new Date(projectData.investment_deadline).getTime() - new Date().getTime(), 0); const hourLeft = Math.floor(timeDiff / (1000 * 60 * 60)); - const carouselData = Array(5).fill({ - src: projectData.card_image_url || "/boiler1.jpg", - alt: `${projectData.project_name} Image`, - }); + // const carouselData = Array(5).fill({ + // src: projectData.card_image_url || "/boiler1.jpg", + // alt: `${projectData.project_name} Image`, + // }); + const carouselData = projectMaterial + ? projectMaterial.flatMap((item) => + (item.material_url || ["/boiler1.jpg"]).map((url: string) => ({ + src: url, + alt: "Image", + })) + ) + : []; + + console.log(carouselData); return (
    -
    - {/* Name, star and share button packed */} -