From 42b47aa4e87d2e065388e01b4da15369b8e53411 Mon Sep 17 00:00:00 2001 From: Pattadon Date: Tue, 29 Oct 2024 11:24:40 +0700 Subject: [PATCH 001/190] 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 002/190] 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 003/190] 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 004/190] 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 005/190] 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 006/190] 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 007/190] 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 008/190] 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 009/190] 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 019/190] 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 020/190] 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 022/190] 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 023/190] 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 024/190] 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 025/190] 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 026/190] 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 027/190] 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 029/190] 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 030/190] 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 09293644963d048b85d9f5772e6a3de2ff482f29 Mon Sep 17 00:00:00 2001 From: Sosokker Date: Mon, 4 Nov 2024 20:16:11 +0700 Subject: [PATCH 031/190] refactor: use server action for login signup logout action --- src/app/auth/error/page.tsx | 3 - src/components/auth/action.ts | 50 ++++++++++++++ src/components/auth/loginForm.tsx | 76 +++++++++++++++------- src/components/auth/logoutButton.tsx | 30 +++++---- src/components/auth/signupForm.tsx | 53 ++++++++++----- src/types/schemas/authentication.schema.ts | 17 +++++ 6 files changed, 173 insertions(+), 56 deletions(-) delete mode 100644 src/app/auth/error/page.tsx create mode 100644 src/components/auth/action.ts create mode 100644 src/types/schemas/authentication.schema.ts diff --git a/src/app/auth/error/page.tsx b/src/app/auth/error/page.tsx deleted file mode 100644 index 7552b02..0000000 --- a/src/app/auth/error/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function AuthError() { - return
Authentication Error
; -} diff --git a/src/components/auth/action.ts b/src/components/auth/action.ts new file mode 100644 index 0000000..e4718fa --- /dev/null +++ b/src/components/auth/action.ts @@ -0,0 +1,50 @@ +"use server"; + +import { revalidatePath } from "next/cache"; +import { createSupabaseClient } from "@/lib/supabase/serverComponentClient"; +import { redirect } from "next/navigation"; + +export async function login(formData: FormData) { + const supabase = await createSupabaseClient(); + + const data = { + email: formData.get("email") as string, + password: formData.get("password") as string, + }; + + const { error } = await supabase.auth.signInWithPassword(data); + + if (error) { + throw error; + } + + revalidatePath("/", "layout"); + redirect("/"); +} + +export async function signup(formData: FormData) { + const supabase = await createSupabaseClient(); + + const data = { + email: formData.get("email") as string, + password: formData.get("password") as string, + }; + + const { error } = await supabase.auth.signUp(data); + + if (error) { + throw error; + } + + revalidatePath("/", "layout"); + redirect("/"); +} + +export async function logout() { + const supabase = await createSupabaseClient(); + const { error } = await supabase.auth.signOut(); + + if (error) { + throw new Error("Logout failed: " + error.message); + } +} diff --git a/src/components/auth/loginForm.tsx b/src/components/auth/loginForm.tsx index c0c7ac1..3cc7c2c 100644 --- a/src/components/auth/loginForm.tsx +++ b/src/components/auth/loginForm.tsx @@ -1,40 +1,70 @@ "use client"; -import React from "react"; -import { createSupabaseClient } from "@/lib/supabase/clientComponentClient"; -import { useState } from "react"; +import React, { useState } from "react"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; -import { useRouter } from "next/navigation"; +import { login } from "./action"; +import { LoginFormSchema } from "@/types/schemas/authentication.schema"; +import toast from "react-hot-toast"; export function LoginForm() { - const router = useRouter(); - const supabase = createSupabaseClient(); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); + const [errors, setErrors] = useState<{ email?: string; password?: string; server?: string }>({}); - const handleLogin = async (event: React.MouseEvent) => { + const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); - await supabase.auth.signInWithPassword({ - email, - password, - }); - router.push("/"); + + const formData = { email, password }; + + const result = LoginFormSchema.safeParse(formData); + + if (!result.success) { + const formErrors: { email?: string; password?: string } = {}; + result.error.errors.forEach((error) => { + formErrors[error.path[0] as keyof typeof formErrors] = error.message; + }); + setErrors(formErrors); + return; + } + + setErrors({}); + + const form = new FormData(); + form.append("email", email); + form.append("password", password); + + try { + await login(form); + toast.success("Login succesfully!"); + } catch (authError: any) { + setErrors((prevErrors) => ({ + ...prevErrors, + server: authError.message || "An error occurred during login.", + })); + } }; return ( -
- setEmail(e.target.value)} placeholder="Email" /> - setPassword(e.target.value)} - placeholder="Password" - /> - -
+ ); } diff --git a/src/components/auth/logoutButton.tsx b/src/components/auth/logoutButton.tsx index d84b562..502d1b8 100644 --- a/src/components/auth/logoutButton.tsx +++ b/src/components/auth/logoutButton.tsx @@ -1,24 +1,30 @@ "use client"; -import { createSupabaseClient } from "@/lib/supabase/clientComponentClient"; -import { usePathname } from "next/navigation"; -import { useRouter } from "next/navigation"; +import { logout } from "./action"; // Adjust the import path accordingly +import { usePathname, useRouter } from "next/navigation"; +import toast from "react-hot-toast"; export function LogoutButton() { - const supabase = createSupabaseClient(); const pathname = usePathname(); const router = useRouter(); const handleLogout = async () => { - await supabase.auth.signOut(); - - if (pathname === "/") { - window.location.reload(); - } else { - await router.push("/"); - window.location.reload(); + try { + await logout(); + if (pathname === "/") { + window.location.reload(); + } else { + await router.push("/"); + window.location.reload(); + } + } catch (error: any) { + toast.error(error.message || "An error occurred during logout."); } }; - return ; + return ( +
+ +
+ ); } diff --git a/src/components/auth/signupForm.tsx b/src/components/auth/signupForm.tsx index c4f2885..a589f15 100644 --- a/src/components/auth/signupForm.tsx +++ b/src/components/auth/signupForm.tsx @@ -1,50 +1,65 @@ "use client"; -import React from "react"; -import { createSupabaseClient } from "@/lib/supabase/clientComponentClient"; -import { useState } from "react"; +import React, { useState } from "react"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { useRouter } from "next/navigation"; import toast from "react-hot-toast"; +import { signup } from "./action"; +import { signupSchema } from "@/types/schemas/authentication.schema"; export function SignupForm() { const router = useRouter(); - const supabase = createSupabaseClient(); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); + const [error, setError] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); - const handleSignup = async (event: React.MouseEvent) => { + const handleSignup = async (event: React.FormEvent) => { event.preventDefault(); - if (password !== confirmPassword) { - alert("Passwords do not match!"); + const parsedData = signupSchema.safeParse({ + email, + password, + confirmPassword, + }); + + if (!parsedData.success) { + setError(parsedData.error.errors[0].message); return; } - const { error } = await supabase.auth.signUp({ - email, - password, - }); + const formData = new FormData(); + formData.append("email", email); + formData.append("password", password); + formData.append("confirmPassword", confirmPassword); - if (error) { - toast.error(error.message); - } else { + try { + await signup(formData); toast.success("Account created successfully!"); router.push("/"); + } catch (error: any) { + setError(error.message); } }; return ( -
- setEmail(e.target.value)} placeholder="Email" /> +
+ setEmail(e.target.value)} + placeholder="Email" + required + /> setPassword(e.target.value)} placeholder="Password" + required /> setConfirmPassword(e.target.value)} placeholder="Confirm Password" + required /> - -
+ ); } diff --git a/src/types/schemas/authentication.schema.ts b/src/types/schemas/authentication.schema.ts new file mode 100644 index 0000000..5733333 --- /dev/null +++ b/src/types/schemas/authentication.schema.ts @@ -0,0 +1,17 @@ +import * as z from "zod"; + +export const LoginFormSchema = z.object({ + email: z.string().email("Invalid email address"), + password: z.string().min(6, "Password must be at least 6 characters"), +}); + +export const signupSchema = z + .object({ + email: z.string().email("Invalid email format"), + password: z.string().min(6, "Password must be at least 6 characters long"), + confirmPassword: z.string().min(6, "Confirm password must be at least 6 characters long"), + }) + .refine((data) => data.password === data.confirmPassword, { + message: "Passwords must match", + path: ["confirmPassword"], + }); From b752008e86d25b86e0edfa9b8d7137458f615088 Mon Sep 17 00:00:00 2001 From: Sosokker Date: Mon, 4 Nov 2024 20:16:52 +0700 Subject: [PATCH 032/190] fix: profile not reload on password signin --- ...ileBar.tsx => AuthenticatedComponents.tsx} | 54 +++---------------- .../UnAuthenticatedComponents.tsx | 19 +++++++ src/components/navigationBar/nav.tsx | 11 ++-- src/lib/supabase/actions/getUserId.ts | 12 +++++ 4 files changed, 45 insertions(+), 51 deletions(-) rename src/components/navigationBar/{profileBar.tsx => AuthenticatedComponents.tsx} (64%) create mode 100644 src/components/navigationBar/UnAuthenticatedComponents.tsx create mode 100644 src/lib/supabase/actions/getUserId.ts diff --git a/src/components/navigationBar/profileBar.tsx b/src/components/navigationBar/AuthenticatedComponents.tsx similarity index 64% rename from src/components/navigationBar/profileBar.tsx rename to src/components/navigationBar/AuthenticatedComponents.tsx index c04e2db..4468ac6 100644 --- a/src/components/navigationBar/profileBar.tsx +++ b/src/components/navigationBar/AuthenticatedComponents.tsx @@ -1,6 +1,5 @@ "use client"; -import { useState, useEffect } from "react"; import Link from "next/link"; import { Button } from "@/components/ui/button"; import { @@ -11,29 +10,16 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -import { Skeleton } from "@/components/ui/skeleton"; import { Bell, Heart, Wallet } from "lucide-react"; import { LogoutButton } from "@/components/auth/logoutButton"; -import useSession from "@/lib/supabase/useSession"; import { useUserRole } from "@/hooks/useUserRole"; -const UnAuthenticatedComponents = () => { - return ( -
- - - - - - -
- ); -}; +interface AuthenticatedComponentsProps { + uid: string; +} -const AuthenticatedComponents = ({ uid }: { uid: string }) => { - let notifications = 100; +export const AuthenticatedComponents = ({ uid }: AuthenticatedComponentsProps) => { + const notifications = 100; const displayValue = notifications >= 100 ? "..." : notifications; const { data } = useUserRole(); @@ -68,7 +54,7 @@ const AuthenticatedComponents = ({ uid }: { uid: string }) => { Settings Support - {data != null && data != undefined && data.role === "admin" && ( + {data?.role === "admin" && ( Admin @@ -82,31 +68,3 @@ const AuthenticatedComponents = ({ uid }: { uid: string }) => {
); }; - -export function ProfileBar() { - const { session } = useSession(); - const user = session?.user; - const [sessionLoaded, setSessionLoaded] = useState(false); - - useEffect(() => { - if (!session) { - setSessionLoaded(true); - } - }, [session]); - - return ( - <> - {sessionLoaded ? ( - user ? ( - - ) : ( - - ) - ) : ( -
- -
- )} - - ); -} diff --git a/src/components/navigationBar/UnAuthenticatedComponents.tsx b/src/components/navigationBar/UnAuthenticatedComponents.tsx new file mode 100644 index 0000000..b2a8f60 --- /dev/null +++ b/src/components/navigationBar/UnAuthenticatedComponents.tsx @@ -0,0 +1,19 @@ +"use client"; + +import Link from "next/link"; +import { Button } from "@/components/ui/button"; + +export const UnAuthenticatedComponents = () => { + return ( +
+ + + + + + +
+ ); +}; diff --git a/src/components/navigationBar/nav.tsx b/src/components/navigationBar/nav.tsx index c51dbc8..59869fd 100644 --- a/src/components/navigationBar/nav.tsx +++ b/src/components/navigationBar/nav.tsx @@ -14,7 +14,10 @@ import { NavigationMenuTrigger, } from "@/components/ui/navigation-menu"; import { SearchBar } from "./serchBar"; -import { ProfileBar } from "./profileBar"; +import { AuthenticatedComponents } from "./AuthenticatedComponents"; +import { UnAuthenticatedComponents } from "./UnAuthenticatedComponents"; + +import { getUserId } from "@/lib/supabase/actions/getUserId"; const ListItem = React.forwardRef, React.ComponentPropsWithoutRef<"a">>( ({ className, title, children, ...props }, ref) => { @@ -40,7 +43,9 @@ const ListItem = React.forwardRef, React.ComponentPropsWit ); ListItem.displayName = "ListItem"; -export function NavigationBar() { +export async function NavigationBar() { + const userId = await getUserId(); + const businessComponents = [ { title: "Business", @@ -112,7 +117,7 @@ export function NavigationBar() {
- + {userId ? : }
diff --git a/src/lib/supabase/actions/getUserId.ts b/src/lib/supabase/actions/getUserId.ts new file mode 100644 index 0000000..3fa9e68 --- /dev/null +++ b/src/lib/supabase/actions/getUserId.ts @@ -0,0 +1,12 @@ +import { createSupabaseClient } from "@/lib/supabase/serverComponentClient"; + +export async function getUserId() { + const supabase = createSupabaseClient(); + const { data, error } = await supabase.auth.getUser(); + + if (error || !data?.user) { + return null; + } + + return data.user.id; +} 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 033/190] 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 034/190] 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 96e1aed6224555087e8c9c1b60429069877c8e94 Mon Sep 17 00:00:00 2001 From: Sosokker Date: Mon, 4 Nov 2024 22:31:47 +0700 Subject: [PATCH 035/190] feat: add markdown text editor --- package-lock.json | 1826 ++++++++++++++++++++++++++++- package.json | 1 + src/components/MarkdownEditor.tsx | 100 ++ 3 files changed, 1921 insertions(+), 6 deletions(-) create mode 100644 src/components/MarkdownEditor.tsx diff --git a/package-lock.json b/package-lock.json index d140a95..e1b7e63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "@hookform/resolvers": "^3.9.0", + "@mdxeditor/editor": "^3.15.0", "@radix-ui/react-alert-dialog": "^1.1.2", "@radix-ui/react-avatar": "^1.1.0", "@radix-ui/react-checkbox": "^1.1.2", @@ -454,6 +455,431 @@ "node": ">=6.9.0" } }, + "node_modules/@codemirror/autocomplete": { + "version": "6.18.2", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.2.tgz", + "integrity": "sha512-wJGylKtMFR/Ds6Gh01+OovXE/pncPiKZNNBKuC39pKnH+XK5d9+WsNqcrdxPjFPFTigRBqse0rfxw9UxrfyhPg==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + }, + "peerDependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.7.1.tgz", + "integrity": "sha512-llTrboQYw5H4THfhN4U3qCnSZ1SOJ60ohhz+SzU0ADGtwlc533DtklQP0vSFaQuCPDn3BPpOd1GbbnUtwNjsrw==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.27.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/lang-angular": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@codemirror/lang-angular/-/lang-angular-0.1.3.tgz", + "integrity": "sha512-xgeWGJQQl1LyStvndWtruUvb4SnBZDAu/gvFH/ZU+c0W25tQR8e5hq7WTwiIY2dNxnf+49mRiGI/9yxIwB6f5w==", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-javascript": "^6.1.2", + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.3" + } + }, + "node_modules/@codemirror/lang-cpp": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-cpp/-/lang-cpp-6.0.2.tgz", + "integrity": "sha512-6oYEYUKHvrnacXxWxYa6t4puTlbN3dgV662BDfSH8+MfjQjVmP697/KYTDOqpxgerkvoNm7q5wlFMBeX8ZMocg==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/cpp": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-css": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.0.tgz", + "integrity": "sha512-CyR4rUNG9OYcXDZwMPvJdtb6PHbBDKUc/6Na2BIwZ6dKab1JQqKa4di+RNRY9Myn7JB81vayKwJeQ7jEdmNVDA==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/css": "^1.1.7" + } + }, + "node_modules/@codemirror/lang-go": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-go/-/lang-go-6.0.1.tgz", + "integrity": "sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/go": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-html": { + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz", + "integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/css": "^1.1.0", + "@lezer/html": "^1.3.0" + } + }, + "node_modules/@codemirror/lang-java": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-java/-/lang-java-6.0.1.tgz", + "integrity": "sha512-OOnmhH67h97jHzCuFaIEspbmsT98fNdhVhmA3zCxW0cn7l8rChDhZtwiwJ/JOKXgfm4J+ELxQihxaI7bj7mJRg==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/java": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-javascript": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.2.tgz", + "integrity": "sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-json": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz", + "integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/json": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-less": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-less/-/lang-less-6.0.2.tgz", + "integrity": "sha512-EYdQTG22V+KUUk8Qq582g7FMnCZeEHsyuOJisHRft/mQ+ZSZ2w51NupvDUHiqtsOy7It5cHLPGfHQLpMh9bqpQ==", + "dependencies": { + "@codemirror/lang-css": "^6.2.0", + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-liquid": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-liquid/-/lang-liquid-6.2.1.tgz", + "integrity": "sha512-J1Mratcm6JLNEiX+U2OlCDTysGuwbHD76XwuL5o5bo9soJtSbz2g6RU3vGHFyS5DC8rgVmFSzi7i6oBftm7tnA==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.1" + } + }, + "node_modules/@codemirror/lang-markdown": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.3.0.tgz", + "integrity": "sha512-lYrI8SdL/vhd0w0aHIEvIRLRecLF7MiiRfzXFZY94dFwHqC9HtgxgagJ8fyYNBldijGatf9wkms60d8SrAj6Nw==", + "dependencies": { + "@codemirror/autocomplete": "^6.7.1", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.3.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/markdown": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-php": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-php/-/lang-php-6.0.1.tgz", + "integrity": "sha512-ublojMdw/PNWa7qdN5TMsjmqkNuTBD3k6ndZ4Z0S25SBAiweFGyY68AS3xNcIOlb6DDFDvKlinLQ40vSLqf8xA==", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/php": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-python": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.1.6.tgz", + "integrity": "sha512-ai+01WfZhWqM92UqjnvorkxosZ2aq2u28kHvr+N3gu012XqY2CThD67JPMHnGceRfXPDBmn1HnyqowdpF57bNg==", + "dependencies": { + "@codemirror/autocomplete": "^6.3.2", + "@codemirror/language": "^6.8.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/python": "^1.1.4" + } + }, + "node_modules/@codemirror/lang-rust": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-rust/-/lang-rust-6.0.1.tgz", + "integrity": "sha512-344EMWFBzWArHWdZn/NcgkwMvZIWUR1GEBdwG8FEp++6o6vT6KL9V7vGs2ONsKxxFUPXKI0SPcWhyYyl2zPYxQ==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/rust": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-sass": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-sass/-/lang-sass-6.0.2.tgz", + "integrity": "sha512-l/bdzIABvnTo1nzdY6U+kPAC51czYQcOErfzQ9zSm9D8GmNPD0WTW8st/CJwBTPLO8jlrbyvlSEcN20dc4iL0Q==", + "dependencies": { + "@codemirror/lang-css": "^6.2.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/sass": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-sql": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-sql/-/lang-sql-6.8.0.tgz", + "integrity": "sha512-aGLmY4OwGqN3TdSx3h6QeA1NrvaYtF7kkoWR/+W7/JzB0gQtJ+VJxewlnE3+VImhA4WVlhmkJr109PefOOhjLg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-vue": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@codemirror/lang-vue/-/lang-vue-0.1.3.tgz", + "integrity": "sha512-QSKdtYTDRhEHCfo5zOShzxCmqKJvgGrZwDQSdbvCRJ5pRLWBS7pD/8e/tH44aVQT6FKm0t6RVNoSUWHOI5vNug==", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-javascript": "^6.1.2", + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.1" + } + }, + "node_modules/@codemirror/lang-wast": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-wast/-/lang-wast-6.0.2.tgz", + "integrity": "sha512-Imi2KTpVGm7TKuUkqyJ5NRmeFWF7aMpNiwHnLQe0x9kmrxElndyH0K6H/gXtWwY6UshMRAhpENsgfpSwsgmC6Q==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-xml": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.1.0.tgz", + "integrity": "sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/xml": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-yaml": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-yaml/-/lang-yaml-6.1.1.tgz", + "integrity": "sha512-HV2NzbK9bbVnjWxwObuZh5FuPCowx51mEfoFT9y3y+M37fA3+pbxx4I7uePuygFzDsAmCTwQSc/kXh/flab4uw==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.2.0", + "@lezer/yaml": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.3.tgz", + "integrity": "sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.1.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/language-data": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@codemirror/language-data/-/language-data-6.5.1.tgz", + "integrity": "sha512-0sWxeUSNlBr6OmkqybUTImADFUP0M3P0IiSde4nc24bz/6jIYzqYSgkOSLS+CBIoW1vU8Q9KUWXscBXeoMVC9w==", + "dependencies": { + "@codemirror/lang-angular": "^0.1.0", + "@codemirror/lang-cpp": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-go": "^6.0.0", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-java": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/lang-json": "^6.0.0", + "@codemirror/lang-less": "^6.0.0", + "@codemirror/lang-liquid": "^6.0.0", + "@codemirror/lang-markdown": "^6.0.0", + "@codemirror/lang-php": "^6.0.0", + "@codemirror/lang-python": "^6.0.0", + "@codemirror/lang-rust": "^6.0.0", + "@codemirror/lang-sass": "^6.0.0", + "@codemirror/lang-sql": "^6.0.0", + "@codemirror/lang-vue": "^0.1.1", + "@codemirror/lang-wast": "^6.0.0", + "@codemirror/lang-xml": "^6.0.0", + "@codemirror/lang-yaml": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/legacy-modes": "^6.4.0" + } + }, + "node_modules/@codemirror/legacy-modes": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.4.1.tgz", + "integrity": "sha512-vdg3XY7OAs5uLDx2Iw+cGfnwtd7kM+Et/eMsqAGTfT/JKiVBQZXosTzjEbWAi/FrY6DcQIz8mQjBozFHZEUWQA==", + "dependencies": { + "@codemirror/language": "^6.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.2.tgz", + "integrity": "sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/merge": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@codemirror/merge/-/merge-6.7.2.tgz", + "integrity": "sha512-HSzuWoV4E+F0DROOSwGZMYIDXh+y4iA64ffRADXPBbKKSwx9bsYNM4i7qN8t0mc8H0PYNBoehOvsW2Nitmnx9g==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/highlight": "^1.0.0", + "style-mod": "^4.1.0" + } + }, + "node_modules/@codemirror/search": { + "version": "6.5.7", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.7.tgz", + "integrity": "sha512-6+iLsXvITWKHYlkgHPCs/qiX4dNzn8N78YfhOFvPtPYCkuXqZq10rAfsUMhOq7O/1VjJqdXRflyExlfVcu/9VQ==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz", + "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==" + }, + "node_modules/@codemirror/view": { + "version": "6.34.1", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.34.1.tgz", + "integrity": "sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==", + "dependencies": { + "@codemirror/state": "^6.4.0", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@codesandbox/nodebox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@codesandbox/nodebox/-/nodebox-0.1.8.tgz", + "integrity": "sha512-2VRS6JDSk+M+pg56GA6CryyUSGPjBEe8Pnae0QL3jJF1mJZJVMDKr93gJRtBbLkfZN6LD/DwMtf+2L0bpWrjqg==", + "dependencies": { + "outvariant": "^1.4.0", + "strict-event-emitter": "^0.4.3" + } + }, + "node_modules/@codesandbox/sandpack-client": { + "version": "2.19.8", + "resolved": "https://registry.npmjs.org/@codesandbox/sandpack-client/-/sandpack-client-2.19.8.tgz", + "integrity": "sha512-CMV4nr1zgKzVpx4I3FYvGRM5YT0VaQhALMW9vy4wZRhEyWAtJITQIqZzrTGWqB1JvV7V72dVEUCUPLfYz5hgJQ==", + "dependencies": { + "@codesandbox/nodebox": "0.1.8", + "buffer": "^6.0.3", + "dequal": "^2.0.2", + "mime-db": "^1.52.0", + "outvariant": "1.4.0", + "static-browser-server": "1.0.3" + } + }, + "node_modules/@codesandbox/sandpack-react": { + "version": "2.19.9", + "resolved": "https://registry.npmjs.org/@codesandbox/sandpack-react/-/sandpack-react-2.19.9.tgz", + "integrity": "sha512-a5uXWYdg5Wtz6VHwXIegdS7C63foCofFa/eHO9crtPp1Yf5/npKimds0S3kKJL7jpOmMAascEvAOqOy5S9e6qQ==", + "dependencies": { + "@codemirror/autocomplete": "^6.4.0", + "@codemirror/commands": "^6.1.3", + "@codemirror/lang-css": "^6.0.1", + "@codemirror/lang-html": "^6.4.0", + "@codemirror/lang-javascript": "^6.1.2", + "@codemirror/language": "^6.3.2", + "@codemirror/state": "^6.2.0", + "@codemirror/view": "^6.7.1", + "@codesandbox/sandpack-client": "^2.19.8", + "@lezer/highlight": "^1.1.3", + "@react-hook/intersection-observer": "^3.1.1", + "@stitches/core": "^1.2.6", + "anser": "^2.1.1", + "clean-set": "^1.1.2", + "dequal": "^2.0.2", + "escape-carriage": "^1.3.1", + "lz-string": "^1.4.4", + "react-devtools-inline": "4.4.0", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, + "node_modules/@codesandbox/sandpack-react/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, "node_modules/@date-fns/tz": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.2.0.tgz", @@ -706,6 +1132,477 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lexical/clipboard": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.17.1.tgz", + "integrity": "sha512-OVqnEfWX8XN5xxuMPo6BfgGKHREbz++D5V5ISOiml0Z8fV/TQkdgwqbBJcUdJHGRHWSUwdK7CWGs/VALvVvZyw==", + "dependencies": { + "@lexical/html": "0.17.1", + "@lexical/list": "0.17.1", + "@lexical/selection": "0.17.1", + "@lexical/utils": "0.17.1", + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/code": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/code/-/code-0.17.1.tgz", + "integrity": "sha512-ZspfTm6g6dN3nAb4G5bPp3SqxzdkB/bjGfa0uRKMU6/eBKtrMUgZsGxt0a8JRZ1eq2TZrQhx+l1ceRoLXii/bQ==", + "dependencies": { + "@lexical/utils": "0.17.1", + "lexical": "0.17.1", + "prismjs": "^1.27.0" + } + }, + "node_modules/@lexical/devtools-core": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/devtools-core/-/devtools-core-0.17.1.tgz", + "integrity": "sha512-SzL1EX9Rt5GptIo87t6nDxAc9TtYtl6DyAPNz/sCltspdd69KQgs23sTRa26/tkNFCS1jziRN7vpN3mlnmm5wA==", + "dependencies": { + "@lexical/html": "0.17.1", + "@lexical/link": "0.17.1", + "@lexical/mark": "0.17.1", + "@lexical/table": "0.17.1", + "@lexical/utils": "0.17.1", + "lexical": "0.17.1" + }, + "peerDependencies": { + "react": ">=17.x", + "react-dom": ">=17.x" + } + }, + "node_modules/@lexical/dragon": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.17.1.tgz", + "integrity": "sha512-lhBRKP7RlhiVCLtF0qiNqmMhEO6cQB43sMe7d4bvuY1G2++oKY/XAJPg6QJZdXRrCGRQ6vZ26QRNhRPmCxL5Ng==", + "dependencies": { + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/hashtag": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/hashtag/-/hashtag-0.17.1.tgz", + "integrity": "sha512-XtP0BI8vEewAe7tzq9MC49UPUvuChuNJI/jqFp+ezZlt/RUq0BClQCOPuSlrTJhluvE2rWnUnOnVMk8ILRvggQ==", + "dependencies": { + "@lexical/utils": "0.17.1", + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/history": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.17.1.tgz", + "integrity": "sha512-OU/ohajz4FXchUhghsWC7xeBPypFe50FCm5OePwo767G7P233IztgRKIng2pTT4zhCPW7S6Mfl53JoFHKehpWA==", + "dependencies": { + "@lexical/utils": "0.17.1", + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/html": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.17.1.tgz", + "integrity": "sha512-yGG+K2DXl7Wn2DpNuZ0Y3uCHJgfHkJN3/MmnFb4jLnH1FoJJiuy7WJb/BRRh9H+6xBJ9v70iv+kttDJ0u1xp5w==", + "dependencies": { + "@lexical/selection": "0.17.1", + "@lexical/utils": "0.17.1", + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/link": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/link/-/link-0.17.1.tgz", + "integrity": "sha512-qFJEKBesZAtR8kfJfIVXRFXVw6dwcpmGCW7duJbtBRjdLjralOxrlVKyFhW9PEXGhi4Mdq2Ux16YnnDncpORdQ==", + "dependencies": { + "@lexical/utils": "0.17.1", + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/list": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.17.1.tgz", + "integrity": "sha512-k9ZnmQuBvW+xVUtWJZwoGtiVG2cy+hxzkLGU4jTq1sqxRIoSeGcjvhFAK8JSEj4i21SgkB1FmkWXoYK5kbwtRA==", + "dependencies": { + "@lexical/utils": "0.17.1", + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/mark": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/mark/-/mark-0.17.1.tgz", + "integrity": "sha512-V82SSRjvygmV+ZMwVpy5gwgr2ZDrJpl3TvEDO+G5I4SDSjbgvua8hO4dKryqiDVlooxQq9dsou0GrZ9Qtm6rYg==", + "dependencies": { + "@lexical/utils": "0.17.1", + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/markdown": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/markdown/-/markdown-0.17.1.tgz", + "integrity": "sha512-uexR9snyT54jfQTrbr/GZAtzX+8Oyykr4p1HS0vCVL1KU5MDuP2PoyFfOv3rcfB2TASc+aYiINhU2gSXzwCHNg==", + "dependencies": { + "@lexical/code": "0.17.1", + "@lexical/link": "0.17.1", + "@lexical/list": "0.17.1", + "@lexical/rich-text": "0.17.1", + "@lexical/text": "0.17.1", + "@lexical/utils": "0.17.1", + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/offset": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/offset/-/offset-0.17.1.tgz", + "integrity": "sha512-fX0ZSIFWwUKAjxf6l21vyXFozJGExKWyWxA+EMuOloNAGotHnAInxep0Mt8t/xcvHs7luuyQUxEPw7YrTJP7aw==", + "dependencies": { + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/overflow": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/overflow/-/overflow-0.17.1.tgz", + "integrity": "sha512-oElVDq486R3rO2+Zz0EllXJGpW3tN0tfcH+joZ5h36+URKuNeKddqkJuDRvgSLOr9l8Jhtv3+/YKduPJVKMz6w==", + "dependencies": { + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/plain-text": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.17.1.tgz", + "integrity": "sha512-CSvi4j1a4ame0OAvOKUCCmn2XrNsWcST4lExGTa9Ei/VIh8IZ+a97h4Uby8T3lqOp10x+oiizYWzY30pb9QaBg==", + "dependencies": { + "@lexical/clipboard": "0.17.1", + "@lexical/selection": "0.17.1", + "@lexical/utils": "0.17.1", + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/react": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/react/-/react-0.17.1.tgz", + "integrity": "sha512-DI4k25tO0E1WyozrjaLgKMOmLjOB7+39MT4eZN9brPlU7g+w0wzdGbTZUPgPmFGIKPK+MSLybCwAJCK97j8HzQ==", + "dependencies": { + "@lexical/clipboard": "0.17.1", + "@lexical/code": "0.17.1", + "@lexical/devtools-core": "0.17.1", + "@lexical/dragon": "0.17.1", + "@lexical/hashtag": "0.17.1", + "@lexical/history": "0.17.1", + "@lexical/link": "0.17.1", + "@lexical/list": "0.17.1", + "@lexical/mark": "0.17.1", + "@lexical/markdown": "0.17.1", + "@lexical/overflow": "0.17.1", + "@lexical/plain-text": "0.17.1", + "@lexical/rich-text": "0.17.1", + "@lexical/selection": "0.17.1", + "@lexical/table": "0.17.1", + "@lexical/text": "0.17.1", + "@lexical/utils": "0.17.1", + "@lexical/yjs": "0.17.1", + "lexical": "0.17.1", + "react-error-boundary": "^3.1.4" + }, + "peerDependencies": { + "react": ">=17.x", + "react-dom": ">=17.x" + } + }, + "node_modules/@lexical/rich-text": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.17.1.tgz", + "integrity": "sha512-T3kvj4P1OpedX9jvxN3WN8NP1Khol6mCW2ScFIRNRz2dsXgyN00thH1Q1J/uyu7aKyGS7rzcY0rb1Pz1qFufqQ==", + "dependencies": { + "@lexical/clipboard": "0.17.1", + "@lexical/selection": "0.17.1", + "@lexical/utils": "0.17.1", + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/selection": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.17.1.tgz", + "integrity": "sha512-qBKVn+lMV2YIoyRELNr1/QssXx/4c0id9NCB/BOuYlG8du5IjviVJquEF56NEv2t0GedDv4BpUwkhXT2QbNAxA==", + "dependencies": { + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/table": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.17.1.tgz", + "integrity": "sha512-2fUYPmxhyuMQX3MRvSsNaxbgvwGNJpHaKx1Ldc+PT2MvDZ6ALZkfsxbi0do54Q3i7dOon8/avRp4TuVaCnqvoA==", + "dependencies": { + "@lexical/utils": "0.17.1", + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/text": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/text/-/text-0.17.1.tgz", + "integrity": "sha512-zD2pAGXaMfPpT8PeNrx3+n0+jGnQORHyn0NEBO+hnyacKfUq5z5sI6Gebsq5NwH789bRadmJM5LvX5w8fsuv6w==", + "dependencies": { + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/utils": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.17.1.tgz", + "integrity": "sha512-jCQER5EsvhLNxKH3qgcpdWj/necUb82Xjp8qWQ3c0tyL07hIRm2tDRA/s9mQmvcP855HEZSmGVmR5SKtkcEAVg==", + "dependencies": { + "@lexical/list": "0.17.1", + "@lexical/selection": "0.17.1", + "@lexical/table": "0.17.1", + "lexical": "0.17.1" + } + }, + "node_modules/@lexical/yjs": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@lexical/yjs/-/yjs-0.17.1.tgz", + "integrity": "sha512-9mn5PDtaH5uLMH6hQ59EAx5FkRzmJJFcVs3E6zSIbtgkG3UASR3CFEfgsLKTjl/GC5NnTGuMck+jXaupDVBhOg==", + "dependencies": { + "@lexical/offset": "0.17.1", + "lexical": "0.17.1" + }, + "peerDependencies": { + "yjs": ">=13.5.22" + } + }, + "node_modules/@lezer/common": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", + "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==" + }, + "node_modules/@lezer/cpp": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.1.2.tgz", + "integrity": "sha512-macwKtyeUO0EW86r3xWQCzOV9/CF8imJLpJlPv3sDY57cPGeUZ8gXWOWNlJr52TVByMV3PayFQCA5SHEERDmVQ==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/css": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.9.tgz", + "integrity": "sha512-TYwgljcDv+YrV0MZFFvYFQHCfGgbPMR6nuqLabBdmZoFH3EP1gvw8t0vae326Ne3PszQkbXfVBjCnf3ZVCr0bA==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/go": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/go/-/go-1.0.0.tgz", + "integrity": "sha512-co9JfT3QqX1YkrMmourYw2Z8meGC50Ko4d54QEcQbEYpvdUvN4yb0NBZdn/9ertgvjsySxHsKzH3lbm3vqJ4Jw==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/highlight": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz", + "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/html": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz", + "integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/java": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@lezer/java/-/java-1.1.3.tgz", + "integrity": "sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/javascript": { + "version": "1.4.19", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.19.tgz", + "integrity": "sha512-j44kbR1QL26l6dMunZ1uhKBFteVGLVCBGNUD2sUaMnic+rbTviVuoK0CD1l9FTW31EueWvFFswCKMH7Z+M3JRA==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/json": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.2.tgz", + "integrity": "sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", + "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/markdown": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.3.2.tgz", + "integrity": "sha512-Wu7B6VnrKTbBEohqa63h5vxXjiC4pO5ZQJ/TDbhJxPQaaIoRD/6UVDhSDtVsCwVZV12vvN9KxuLL3ATMnlG0oQ==", + "dependencies": { + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@lezer/php": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.2.tgz", + "integrity": "sha512-GN7BnqtGRpFyeoKSEqxvGvhJQiI4zkgmYnDk/JIyc7H7Ifc1tkPnUn/R2R8meH3h/aBf5rzjvU8ZQoyiNDtDrA==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.1.0" + } + }, + "node_modules/@lezer/python": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.14.tgz", + "integrity": "sha512-ykDOb2Ti24n76PJsSa4ZoDF0zH12BSw1LGfQXCYJhJyOGiFTfGaX0Du66Ze72R+u/P35U+O6I9m8TFXov1JzsA==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/rust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@lezer/rust/-/rust-1.0.2.tgz", + "integrity": "sha512-Lz5sIPBdF2FUXcWeCu1//ojFAZqzTQNRga0aYv6dYXqJqPfMdCAI0NzajWUd4Xijj1IKJLtjoXRPMvTKWBcqKg==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/sass": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@lezer/sass/-/sass-1.0.7.tgz", + "integrity": "sha512-8HLlOkuX/SMHOggI2DAsXUw38TuURe+3eQ5hiuk9QmYOUyC55B1dYEIMkav5A4IELVaW4e1T4P9WRiI5ka4mdw==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/xml": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.5.tgz", + "integrity": "sha512-VFouqOzmUWfIg+tfmpcdV33ewtK+NSwd4ngSe1aG7HFb4BN0ExyY1b8msp+ndFrnlG4V4iC8yXacjFtrwERnaw==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/yaml": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.3.tgz", + "integrity": "sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.4.0" + } + }, + "node_modules/@mdxeditor/editor": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/@mdxeditor/editor/-/editor-3.15.0.tgz", + "integrity": "sha512-kpnNdog+MAeiBZhImyG6FOaIFU9ho9YQBYuZASZEooJzFPn5e1g8yE2EU0mWUlNToZoVzCK3NuaTWXVoGc/PVA==", + "dependencies": { + "@codemirror/lang-markdown": "^6.2.3", + "@codemirror/language-data": "^6.5.1", + "@codemirror/merge": "^6.4.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.23.0", + "@codesandbox/sandpack-react": "^2.10.0", + "@lexical/clipboard": "^0.17.1", + "@lexical/link": "^0.17.1", + "@lexical/list": "^0.17.1", + "@lexical/markdown": "^0.17.1", + "@lexical/plain-text": "^0.17.1", + "@lexical/react": "^0.17.1", + "@lexical/rich-text": "^0.17.1", + "@lexical/selection": "^0.17.1", + "@lexical/utils": "^0.17.1", + "@mdxeditor/gurx": "^1.1.4", + "@radix-ui/colors": "^3.0.0", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-select": "^2.0.0", + "@radix-ui/react-toggle-group": "^1.0.4", + "@radix-ui/react-toolbar": "^1.0.4", + "@radix-ui/react-tooltip": "^1.0.7", + "classnames": "^2.3.2", + "cm6-theme-basic-light": "^0.2.0", + "codemirror": "^6.0.1", + "downshift": "^7.6.0", + "js-yaml": "4.1.0", + "lexical": "^0.17.1", + "mdast-util-directive": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-frontmatter": "^2.0.1", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-mdx": "^3.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-to-markdown": "^2.1.0", + "micromark-extension-directive": "^3.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.1", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs": "^3.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.1", + "micromark-util-symbol": "^2.0.0", + "react-hook-form": "^7.44.2", + "unidiff": "^1.0.2" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">= 18 || >= 19", + "react-dom": ">= 18 || >= 19" + } + }, + "node_modules/@mdxeditor/gurx": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@mdxeditor/gurx/-/gurx-1.1.6.tgz", + "integrity": "sha512-6Rroyj477hInSG5iFe5ko7XBWTvmSUWq/N38Z+19njVsAjtUqqsFRblpuOJG0ELSZHhDjOfIfOQxbeOLrQxi0g==", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">= 18 || >= 19", + "react-dom": ">= 18 || >= 19" + } + }, "node_modules/@next/env": { "version": "14.2.16", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.16.tgz", @@ -896,6 +1793,11 @@ "node": ">=12.4.0" } }, + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==" + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -932,6 +1834,11 @@ "node": ">=18" } }, + "node_modules/@radix-ui/colors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-3.0.0.tgz", + "integrity": "sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==" + }, "node_modules/@radix-ui/number": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz", @@ -1283,6 +2190,14 @@ } } }, + "node_modules/@radix-ui/react-icons": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.1.tgz", + "integrity": "sha512-QvYompk0X+8Yjlo/Fv4McrzxohDdM5GgLHyQcPpcsPvlOSXCGFjdbuyGL5dzRbg0GpknAjQJJZzdiRK7iWVuFQ==", + "peerDependencies": { + "react": "^16.x || ^17.x || ^18.x || ^19.x" + } + }, "node_modules/@radix-ui/react-id": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", @@ -1795,6 +2710,114 @@ } } }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.0.tgz", + "integrity": "sha512-gwoxaKZ0oJ4vIgzsfESBuSgJNdc0rv12VhHgcqN0TEJmmZixXG/2XpsLK8kzNWYcnaoRIEEQc0bEi3dIvdUpjw==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.0.tgz", + "integrity": "sha512-PpTJV68dZU2oqqgq75Uzto5o/XfOVgkrJ9rulVmfTKxWp3HfUjHE6CP/WLRR4AzPX9HWxw7vFow2me85Yu+Naw==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-roving-focus": "1.1.0", + "@radix-ui/react-toggle": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toolbar": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.0.tgz", + "integrity": "sha512-ZUKknxhMTL/4hPh+4DuaTot9aO7UD6Kupj4gqXCsBTayX1pD1L+0C2/2VZKXb4tIifQklZ3pf2hG9T+ns+FclQ==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-roving-focus": "1.1.0", + "@radix-ui/react-separator": "1.1.0", + "@radix-ui/react-toggle-group": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-tooltip": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.3.tgz", @@ -1965,6 +2988,26 @@ "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==" }, + "node_modules/@react-hook/intersection-observer": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@react-hook/intersection-observer/-/intersection-observer-3.1.2.tgz", + "integrity": "sha512-mWU3BMkmmzyYMSuhO9wu3eJVP21N8TcgYm9bZnTrMwuM818bEk+0NRM3hP+c/TqA9Ln5C7qE53p1H0QMtzYdvQ==", + "dependencies": { + "@react-hook/passive-layout-effect": "^1.2.0", + "intersection-observer": "^0.10.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/@react-hook/passive-layout-effect": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@react-hook/passive-layout-effect/-/passive-layout-effect-1.2.1.tgz", + "integrity": "sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg==", + "peerDependencies": { + "react": ">=16.8" + } + }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.24.3", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.3.tgz", @@ -1989,6 +3032,11 @@ "integrity": "sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==", "dev": true }, + "node_modules/@stitches/core": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@stitches/core/-/core-1.2.8.tgz", + "integrity": "sha512-Gfkvwk9o9kE9r9XNBmJRfV8zONvXThnm1tcuojL04Uy5uRyqg93DC83lDebl0rocZCfKSjUv+fWYtMQmEDJldg==" + }, "node_modules/@stripe/react-stripe-js": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-2.8.1.tgz", @@ -2230,6 +3278,14 @@ } } }, + "node_modules/@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@types/d3-array": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", @@ -3047,7 +4103,6 @@ "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -3059,7 +4114,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -3092,6 +4146,11 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/anser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/anser/-/anser-2.3.0.tgz", + "integrity": "sha512-pGGR7Nq1K/i9KGs29PvHDXA8AsfZ3OiYRMDClT3FIC085Kbns9CJ7ogq9MEiGnrjd9THOGoh7B+kWzePHzZyJQ==" + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -3139,8 +4198,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/aria-hidden": { "version": "1.2.4", @@ -3432,6 +4490,25 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -3489,6 +4566,29 @@ "node": ">=8" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -3686,6 +4786,16 @@ "node": ">=6" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, + "node_modules/clean-set": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/clean-set/-/clean-set-1.1.2.tgz", + "integrity": "sha512-cA8uCj0qSoG9e0kevyOWXwPaELRPVg5Pxp6WskLMwerx257Zfnh8Nl0JBH59d7wQzij2CK7qEfJQK3RjuKKIug==" + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -3699,6 +4809,17 @@ "node": ">=6" } }, + "node_modules/cm6-theme-basic-light": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/cm6-theme-basic-light/-/cm6-theme-basic-light-0.2.0.tgz", + "integrity": "sha512-1prg2gv44sYfpHscP26uLT/ePrh0mlmVwMSoSd3zYKQ92Ab3jPRLzyCnpyOCQLJbK+YdNs4HvMRqMNYdy4pMhA==", + "peerDependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, "node_modules/cmd-shim": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-7.0.0.tgz", @@ -4068,6 +5189,20 @@ } } }, + "node_modules/codemirror": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", + "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4163,6 +5298,11 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/compute-scroll-into-view": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz", + "integrity": "sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g==" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4217,6 +5357,11 @@ "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.8.0.tgz", "integrity": "sha512-f7xEhX0awl4NOElHulrl4XRfKoNH3rB+qfNSZZyjSZhaAoUk6elvhH+MNxMmlmuUJ2/QNTWPSA7U4mNtIAKljQ==" }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==" + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -4267,6 +5412,18 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/d3-array": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", @@ -4587,6 +5744,14 @@ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -4636,6 +5801,26 @@ "url": "https://dotenvx.com" } }, + "node_modules/downshift": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/downshift/-/downshift-7.6.2.tgz", + "integrity": "sha512-iOv+E1Hyt3JDdL9yYcOgW7nZ7GQ2Uz6YbggwXvKUSleetYhU2nXD482Rz6CzvM4lvI1At34BYruKAL4swRGxaA==", + "dependencies": { + "@babel/runtime": "^7.14.8", + "compute-scroll-into-view": "^2.0.4", + "prop-types": "^15.7.2", + "react-is": "^17.0.2", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "react": ">=16.12.0" + } + }, + "node_modules/downshift/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -4864,6 +6049,48 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/escape-carriage": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/escape-carriage/-/escape-carriage-1.3.1.tgz", + "integrity": "sha512-GwBr6yViW3ttx1kb7/Oh+gKQ1/TrhYwxKqVmg5gS+BK+Qe2KrOa/Vh7w3HPBvgGf0LfcDGoY9I6NHKoA5Hozhw==" + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -5313,6 +6540,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -5372,6 +6613,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -5390,11 +6644,28 @@ "node": ">= 0.6" } }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dependencies": { + "type": "^2.7.2" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -5466,6 +6737,18 @@ "reusify": "^1.0.4" } }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", @@ -5597,6 +6880,14 @@ "node": ">= 6" } }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -6027,6 +7318,25 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -6105,6 +7415,11 @@ "node": ">=12" } }, + "node_modules/intersection-observer": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.10.0.tgz", + "integrity": "sha512-fn4bQ0Xq8FTej09YC/jqKZwtijpvARlRp6wxL5WTA6yPe2YWSJ5RJh7Nm79rK2qB0wr6iDQzH60XGq5V/7u8YQ==" + }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -6559,6 +7874,16 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "node_modules/isomorphic.js": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz", + "integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==", + "peer": true, + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + } + }, "node_modules/iterator.prototype": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", @@ -6615,7 +7940,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -6720,6 +8044,32 @@ "node": ">= 0.8.0" } }, + "node_modules/lexical": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.17.1.tgz", + "integrity": "sha512-72/MhR7jqmyqD10bmJw8gztlCm4KDDT+TPtU4elqXrEvHoO5XENi34YAEUD9gIkPfqSwyLa9mwAX1nKzIr5xEA==" + }, + "node_modules/lib0": { + "version": "0.2.98", + "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.98.tgz", + "integrity": "sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA==", + "peer": true, + "dependencies": { + "isomorphic.js": "^0.2.4" + }, + "bin": { + "0ecdsa-generate-keypair": "bin/0ecdsa-generate-keypair.js", + "0gentesthtml": "bin/gentesthtml.js", + "0serve": "bin/0serve.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + } + }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -6823,6 +8173,42 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.0.0.tgz", + "integrity": "sha512-JUpYOqKI4mM3sZcNxmF/ox04XYFFkNwr0CFlrQIkCwbvH0xzMCqkMqAde9wRd80VAhaUrwFwKm2nxretdT1h7Q==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdast-util-from-markdown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", @@ -6846,6 +8232,95 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdast-util-mdx-expression": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", @@ -7057,6 +8532,186 @@ "micromark-util-types": "^2.0.0" } }, + "node_modules/micromark-extension-directive": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz", + "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz", + "integrity": "sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", + "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.1.tgz", + "integrity": "sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==", + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/micromark-factory-destination": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", @@ -7098,6 +8753,32 @@ "micromark-util-types": "^2.0.0" } }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.2.tgz", + "integrity": "sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, "node_modules/micromark-factory-space": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", @@ -7289,6 +8970,31 @@ } ] }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", + "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, "node_modules/micromark-util-html-tag-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", @@ -7439,7 +9145,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -7633,6 +9338,11 @@ "react-dom": "^16.8 || ^17 || ^18" } }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -7878,6 +9588,11 @@ "node": ">= 0.8.0" } }, + "node_modules/outvariant": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz", + "integrity": "sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==" + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -8296,6 +10011,14 @@ "node": ">=6.0.0" } }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/proc-log": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", @@ -8450,6 +10173,14 @@ "react": ">=16.8.0" } }, + "node_modules/react-devtools-inline": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/react-devtools-inline/-/react-devtools-inline-4.4.0.tgz", + "integrity": "sha512-ES0GolSrKO8wsKbsEkVeiR/ZAaHQTY4zDh1UW8DImVmm8oaGLl3ijJDvSGe+qDRKPZdPRnDtWWnSvvrgxXdThQ==", + "dependencies": { + "es6-symbol": "^3" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -8462,6 +10193,21 @@ "react": "^18.3.1" } }, + "node_modules/react-error-boundary": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", + "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, "node_modules/react-file-icon": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/react-file-icon/-/react-file-icon-1.5.0.tgz", @@ -9145,6 +10891,17 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/static-browser-server": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/static-browser-server/-/static-browser-server-1.0.3.tgz", + "integrity": "sha512-ZUyfgGDdFRbZGGJQ1YhiM930Yczz5VlbJObrQLlk24+qNHVQx4OlLcYswEUo3bIyNAbQUIUR9Yr5/Hqjzqb4zA==", + "dependencies": { + "@open-draft/deferred-promise": "^2.1.0", + "dotenv": "^16.0.3", + "mime-db": "^1.52.0", + "outvariant": "^1.3.0" + } + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -9162,6 +10919,11 @@ "node": ">=10.0.0" } }, + "node_modules/strict-event-emitter": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz", + "integrity": "sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==" + }, "node_modules/string-hash": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", @@ -9396,6 +11158,11 @@ "node": ">=12.*" } }, + "node_modules/style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==" + }, "node_modules/style-to-object": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", @@ -9736,6 +11503,11 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -10049,6 +11821,14 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, + "node_modules/unidiff": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unidiff/-/unidiff-1.0.4.tgz", + "integrity": "sha512-ynU0vsAXw0ir8roa+xPCUHmnJ5goc5BTM2Kuc3IJd8UwgaeRs7VSD5+eeaQL+xp1JtB92hu/Zy/Lgy7RZcr1pQ==", + "dependencies": { + "diff": "^5.1.0" + } + }, "node_modules/unified": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", @@ -10091,6 +11871,18 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", @@ -10273,6 +12065,11 @@ "d3-timer": "^3.0.1" } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==" + }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -10552,6 +12349,23 @@ "node": ">= 14" } }, + "node_modules/yjs": { + "version": "13.6.20", + "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.20.tgz", + "integrity": "sha512-Z2YZI+SYqK7XdWlloI3lhMiKnCdFCVC4PchpdO+mCYwtiTwncjUbnRK9R1JmkNfdmHyDXuWN3ibJAt0wsqTbLQ==", + "peer": true, + "dependencies": { + "lib0": "^0.2.98" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + }, + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index a9a75f8..2b3da91 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@hookform/resolvers": "^3.9.0", + "@mdxeditor/editor": "^3.15.0", "@radix-ui/react-alert-dialog": "^1.1.2", "@radix-ui/react-avatar": "^1.1.0", "@radix-ui/react-checkbox": "^1.1.2", diff --git a/src/components/MarkdownEditor.tsx b/src/components/MarkdownEditor.tsx new file mode 100644 index 0000000..b4c09f1 --- /dev/null +++ b/src/components/MarkdownEditor.tsx @@ -0,0 +1,100 @@ +"use client"; + +import "@mdxeditor/editor/style.css"; +import React, { useEffect, useRef, useState } from "react"; + +import { + MDXEditor, + MDXEditorMethods, + codeBlockPlugin, + codeMirrorPlugin, + frontmatterPlugin, + headingsPlugin, + linkPlugin, + listsPlugin, + markdownShortcutPlugin, + quotePlugin, + tablePlugin, + thematicBreakPlugin, + toolbarPlugin, + UndoRedo, + BoldItalicUnderlineToggles, + InsertTable, + InsertCodeBlock, +} from "@mdxeditor/editor"; + +export interface MdxEditorProps { + content: string; + // eslint-disable-next-line no-unused-vars + setContentInParent: (content: string) => void; + // eslint-disable-next-line no-unused-vars + setEditorErrorInParent?: (error: { error: string; source: string }) => void; +} + +export const MdxEditor: React.FC = ({ content, setContentInParent, setEditorErrorInParent }) => { + const ref = useRef(null); + const [markdownContent, setMarkdownContent] = useState(content); + + useEffect(() => { + setMarkdownContent(content); + }, [content]); + + useEffect(() => { + setContentInParent(markdownContent); + }, [markdownContent, setContentInParent]); + + const handleDivClick = () => { + if (ref.current) { + ref.current.focus(); + } + }; + + return ( +
+ setMarkdownContent(markdownContent)} + markdown={markdownContent} + contentEditableClassName="prose" + suppressHtmlProcessing={true} + onError={(error) => { + console.error("MDXEditor error:", error); + if (setEditorErrorInParent) { + setEditorErrorInParent({ error: error.error, source: "MDXEditor" }); + } + }} + plugins={[ + toolbarPlugin({ + toolbarClassName: "my-toolbar", + toolbarContents: () => ( + <> + + + + + + ), + }), + listsPlugin(), + quotePlugin(), + headingsPlugin({ allowedHeadingLevels: [1, 2, 3] }), + linkPlugin(), + tablePlugin(), + thematicBreakPlugin(), + frontmatterPlugin(), + codeBlockPlugin({ defaultCodeBlockLanguage: "txt" }), + codeMirrorPlugin({ + codeBlockLanguages: { + js: "JavaScript", + css: "CSS", + txt: "text", + tsx: "TypeScript", + }, + }), + markdownShortcutPlugin(), + ]} + /> +
+ ); +}; From 03e862445112955f80c6f96e6397fde2b372ea23 Mon Sep 17 00:00:00 2001 From: Sosokker Date: Mon, 4 Nov 2024 22:32:23 +0700 Subject: [PATCH 036/190] fix: make markdown text invert for darkmode --- 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 15398c3..d0a3bd8 100644 --- a/src/app/(investment)/deals/[id]/page.tsx +++ b/src/app/(investment)/deals/[id]/page.tsx @@ -152,7 +152,7 @@ export default async function ProjectDealPage({ params }: { params: { id: number -
+
{projectData?.project_description || "No pitch available."}
From 2df7d9c514cd480b1848c25baab23b957151becf Mon Sep 17 00:00:00 2001 From: Sosokker Date: Mon, 4 Nov 2024 22:32:44 +0700 Subject: [PATCH 037/190] feat: add markdown editor for profile bio --- src/app/(user)/profile/[uid]/edit/page.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/app/(user)/profile/[uid]/edit/page.tsx b/src/app/(user)/profile/[uid]/edit/page.tsx index f741e21..3046e2d 100644 --- a/src/app/(user)/profile/[uid]/edit/page.tsx +++ b/src/app/(user)/profile/[uid]/edit/page.tsx @@ -8,13 +8,14 @@ import { profileSchema } from "@/types/schemas/profile.schema"; import { zodResolver } from "@hookform/resolvers/zod"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; -import { Textarea } from "@/components/ui/textarea"; import { createSupabaseClient } from "@/lib/supabase/clientComponentClient"; import { uploadAvatar } from "@/lib/data/bucket/uploadAvatar"; import toast from "react-hot-toast"; import { useRouter } from "next/navigation"; import { Separator } from "@/components/ui/separator"; import useSession from "@/lib/supabase/useSession"; +import React, { useState } from "react"; +import { MdxEditor } from "@/components/MarkdownEditor"; export default function EditProfilePage({ params }: { params: { uid: string } }) { const uid = params.uid; @@ -26,6 +27,8 @@ export default function EditProfilePage({ params }: { params: { uid: string } }) resolver: zodResolver(profileSchema), }); + const [bioContent, setBioContent] = useState(""); + if (isLoadingSession) { return (
@@ -35,7 +38,7 @@ export default function EditProfilePage({ params }: { params: { uid: string } }) } const onProfileSubmit = async (updates: z.infer) => { - const { avatars, username, full_name, bio } = updates; + const { avatars, username, full_name } = updates; try { let avatarUrl = null; @@ -50,7 +53,7 @@ export default function EditProfilePage({ params }: { params: { uid: string } }) const result = await updateProfile(client, uid, { username, full_name, - bio, + bio: bioContent, ...(avatarUrl && { avatar_url: avatarUrl }), }); @@ -129,13 +132,13 @@ export default function EditProfilePage({ params }: { params: { uid: string } }) ( + render={() => ( Bio -