diff --git a/next.config.mjs b/next.config.mjs
index 9bf4e22..881ad15 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -15,6 +15,11 @@ const nextConfig = {
hostname: "upload.wikimedia.org",
pathname: "/wikipedia/**",
},
+ {
+ protocol: "https",
+ hostname: "avatars.githubusercontent.com",
+ pathname: "/**",
+ }
],
},
};
diff --git a/package-lock.json b/package-lock.json
index 0ce8bbd..c7bd8bd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -35,6 +35,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,7 +45,8 @@
"lucide-react": "^0.428.0",
"next": "^14.2.15",
"next-themes": "^0.3.0",
- "react": "^18",
+ "react": "^18.3.1",
+ "react-chartjs-2": "^5.2.0",
"react-countup": "^6.5.3",
"react-day-picker": "^9",
"react-dom": "^18",
@@ -68,7 +70,7 @@
"@types/eslint__js": "^8.42.3",
"@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-file-icon": "^1.0.4",
@@ -1132,6 +1134,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/@lexical/clipboard": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.17.1.tgz",
@@ -4724,6 +4731,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",
@@ -10143,6 +10161,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",
@@ -10260,6 +10287,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/package.json b/package.json
index 2b3da91..15c0586 100644
--- a/package.json
+++ b/package.json
@@ -37,6 +37,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",
@@ -46,7 +47,8 @@
"lucide-react": "^0.428.0",
"next": "^14.2.15",
"next-themes": "^0.3.0",
- "react": "^18",
+ "react": "^18.3.1",
+ "react-chartjs-2": "^5.2.0",
"react-countup": "^6.5.3",
"react-day-picker": "^9",
"react-dom": "^18",
@@ -70,7 +72,7 @@
"@types/eslint__js": "^8.42.3",
"@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-file-icon": "^1.0.4",
diff --git a/src/app/(investment)/deals/[id]/displayImage.tsx b/src/app/(investment)/deals/[id]/displayImage.tsx
new file mode 100644
index 0000000..6bea6bf
--- /dev/null
+++ b/src/app/(investment)/deals/[id]/displayImage.tsx
@@ -0,0 +1,42 @@
+"use client";
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from "@/components/ui/dialog";
+import Image from "next/image";
+import { StaticImport } from "next/dist/shared/lib/get-img-props";
+
+interface ItemProps {
+ src: string | StaticImport;
+ alt: string;
+ width: number;
+ height: number;
+ className?: string;
+}
+
+const ImageModal = ({ src, alt, width, height, className }: ItemProps) => {
+ return (
+
+
+
+
+
+
+ Image Preview
+ Click outside to close the image preview.
+
+
+
+
+
+ );
+};
+
+export function DisplayFullImage({ src, alt, width, height, className }: ItemProps) {
+ return ;
+}
diff --git a/src/app/(investment)/deals/[id]/followShareButton.tsx b/src/app/(investment)/deals/[id]/followShareButton.tsx
index ed34336..9242b98 100644
--- a/src/app/(investment)/deals/[id]/followShareButton.tsx
+++ b/src/app/(investment)/deals/[id]/followShareButton.tsx
@@ -10,8 +10,6 @@ import useSession from "@/lib/supabase/useSession";
import toast from "react-hot-toast";
const FollowShareButtons = () => {
- const [progress, setProgress] = useState(0);
- const [tab, setTab] = useState("Pitch");
const { session, loading } = useSession();
const user = session?.user;
const [sessionLoaded, setSessionLoaded] = useState(false);
diff --git a/src/app/(investment)/deals/[id]/page.tsx b/src/app/(investment)/deals/[id]/page.tsx
index d0a3bd8..36f09a8 100644
--- a/src/app/(investment)/deals/[id]/page.tsx
+++ b/src/app/(investment)/deals/[id]/page.tsx
@@ -11,17 +11,26 @@ import { Progress } from "@/components/ui/progress";
import { Separator } from "@/components/ui/separator";
import { createSupabaseClient } from "@/lib/supabase/serverComponentClient";
import FollowShareButtons from "./followShareButton";
-
+import { DisplayFullImage } from "./displayImage";
import { getProjectData } from "@/lib/data/projectQuery";
import { getDealList } from "@/app/api/dealApi";
import { sumByKey, toPercentage } from "@/lib/utils";
import { redirect } from "next/navigation";
+const PHOTO_MATERIAL_ID = 2;
export default async function ProjectDealPage({ params }: { params: { id: number } }) {
const supabase = createSupabaseClient();
-
const { data: projectData, error: projectDataError } = await getProjectData(supabase, params.id);
+ const { data: projectMaterial, error: projectMaterialError } = await supabase
+ .from("project_material")
+ .select("material_url")
+ .eq("project_id", params.id)
+ .eq("material_type_id", PHOTO_MATERIAL_ID);
+ // console.log(projectMaterial);
+ if (projectMaterialError) {
+ console.error("Error while fetching project material" + projectMaterialError);
+ }
if (!projectData) {
redirect("/deals");
}
@@ -44,94 +53,107 @@ export default async function ProjectDealPage({ params }: { params: { id: number
const timeDiff = Math.max(new Date(projectData.investment_deadline).getTime() - new Date().getTime(), 0);
const hourLeft = Math.floor(timeDiff / (1000 * 60 * 60));
- const carouselData = Array(5).fill({
- src: projectData.card_image_url || "/boiler1.jpg",
- alt: `${projectData.project_name} Image`,
- });
+ const carouselData =
+ projectMaterial && projectMaterial.length > 0
+ ? projectMaterial.flatMap((item) =>
+ (item.material_url || ["/boiler1.jpg"]).map((url: string) => ({
+ src: url,
+ alt: "Image",
+ }))
+ )
+ : [{ src: "/boiler1.jpg", alt: "Default Boiler Image" }];
+
+ // console.log(carouselData);
return (
-
- {/* Name, star and share button packed */}
-
diff --git a/src/app/portfolio/[uid]/page.tsx b/src/app/portfolio/[uid]/page.tsx
new file mode 100644
index 0000000..d9a7ff9
--- /dev/null
+++ b/src/app/portfolio/[uid]/page.tsx
@@ -0,0 +1,245 @@
+import { Overview } from "@/components/ui/overview";
+import { createSupabaseClient } from "@/lib/supabase/serverComponentClient";
+import { getInvestorDeal } from "@/lib/data/investmentQuery";
+import PieChart from "@/components/pieChart";
+import {
+ overAllGraphData,
+ fourYearGraphData,
+ dayOftheWeekData,
+ getInvestorProjectTag,
+ countTags,
+ getBusinessTypeName,
+ countValues,
+ checkForInvest,
+ getLatestInvestment,
+ getTotalInvestment,
+} from "./query";
+import CountUpComponent from "@/components/countUp";
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
+import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
+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";
+import { UnAuthorizedAlert } from "@/components/alert/unauthorized/alert";
+
+export default async function Portfolio({ params }: { params: { uid: string } }) {
+ const supabase = createSupabaseClient();
+ // if user hasn't invest in anything
+ const hasInvestments = await checkForInvest(supabase, params.uid);
+ if (!hasInvestments) {
+ return (
+
+
+
+ );
+ }
+ const { data: deals, error: investorDealError } = await getInvestorDeal(supabase, params.uid);
+ if (investorDealError) {
+ console.error(investorDealError);
+ }
+ const { data: localUser, error: localUserError } = await supabase.auth.getUser();
+ if (localUserError) {
+ console.error("Error while fetching user" + error);
+ }
+ // 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) : [];
+ const dayOfWeekData = deals ? dayOftheWeekData(deals) : [];
+ const tags = deals ? await getInvestorProjectTag(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
+ ? await Promise.all(deals.map(async (item) => await getBusinessTypeName(supabase, item.project_id)))
+ : [];
+ const countedBusinessType = countValues(businessType.filter((item) => item !== null));
+ // console.log(countedBusinessType);
+
+ // console.log(tagCount);
+ 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}
+
*/}
+ {/*
*/}
+
+
Welcome to your Portfolio, {username}!
+
+ Here‘s an overview of your investment journey and progress.
+
+
+ Total Investment: $
+
+
+
+
+
+
+
+ Daily
+ Monthly
+ Yearly
+
+
+
+
+ Monthly Investment Trend
+
+
+
+
+
+
+
+ Displays total investments each month over the past 12
+ months, up to today.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Yearly Investment Summary
+
+
+
+
+
+
+
+ Shows total investments for each of the last four years,
+ including the current year to date.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Daily Investment Breakdown
+
+
+
+
+
+
+
+ Illustrates total investments for each day over the past
+ year, up to today.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Categories of Invested Projects
+
+
+
+
+
+
+
+ Displays the distribution of project tags in your
+ investments, highlighting areas of interest.
+
+
+
+
+
+
+ item.count)}
+ labels={tagCount.map((item: { name: string; count: number }) => item.name)}
+ header="Total"
+ />
+
+
+
+
+ Types of Businesses Invested In
+
+
+
+
+
+
+
+ Shows the breakdown of business types in your portfolio,
+ illustrating sector diversity.
+
+
+
+
+
+
+
+
+
+
+
+ Recent investment
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/portfolio/[uid]/query.ts b/src/app/portfolio/[uid]/query.ts
new file mode 100644
index 0000000..151d0eb
--- /dev/null
+++ b/src/app/portfolio/[uid]/query.ts
@@ -0,0 +1,256 @@
+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++) {
+ 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);
+ }
+ 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,
+ });
+ }
+
+ return llist;
+}
+
+async function checkForInvest(supabase: SupabaseClient, userId: string) {
+ let { count, error } = await supabase
+ .from("investment_deal")
+ .select("*", { count: "exact" })
+ .eq("investor_id", userId);
+ if (error) {
+ console.error(error);
+ return false;
+ }
+ // if user already invest in something
+ if (count !== null && count > 0) {
+ return true;
+ }
+ return false;
+}
+
+function countValues(arr: { value: string }[][]): Record
{
+ const counts: Record = {};
+
+ arr.forEach((subArray) => {
+ subArray.forEach((item) => {
+ const value = item.value;
+ counts[value] = (counts[value] || 0) + 1;
+ });
+ });
+
+ return counts;
+}
+
+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);
+ if (projectError) {
+ console.error(projectError);
+ }
+
+ // step 2: get business type's id from business id
+ let { data: business, error: businessError } = await supabase
+ .from("business")
+ .select("business_type")
+ .eq("id", project?.[0]?.business_id);
+ if (businessError) {
+ console.error(businessError);
+ }
+ // step 3: get business type from its id
+ let { data: business_type, error: businessTypeError } = await supabase
+ .from("business_type")
+ .select("value")
+ .eq("id", business?.[0]?.business_type);
+ if (businessTypeError) {
+ console.error(businessError);
+ }
+ return business_type;
+}
+
+// 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[] {
+ // 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 }));
+
+ 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);
+
+ if (monthEntry) {
+ monthEntry.value += item.deal_amount;
+ }
+ });
+
+ return acc;
+}
+
+function fourYearGraphData(deals: Deal[]): GraphData[] {
+ 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))
+ .forEach((item: Deal) => {
+ const year = new Date(item.created_time).getFullYear().toString();
+ const yearEntry = acc.find((entry) => entry.name === year);
+
+ if (yearEntry) {
+ yearEntry.value += item.deal_amount;
+ }
+ });
+
+ return acc;
+}
+
+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;
+}
+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" });
+};
+
+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,
+ getInvestorProjectTag,
+ countTags,
+ getBusinessTypeName,
+ countValues,
+ checkForInvest,
+ getLatestInvestment,
+ getTotalInvestment,
+ fetchLogoURL,
+};
diff --git a/src/components/BusinessForm.tsx b/src/components/BusinessForm.tsx
index 5e9dac8..b26d583 100644
--- a/src/components/BusinessForm.tsx
+++ b/src/components/BusinessForm.tsx
@@ -9,22 +9,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 BusinessForm = ({ onSubmit }: BusinessFormProps & { onSubmit: SubmitHandler }) => {
const communitySize = [
{ id: 1, name: "N/A" },
{ id: 2, name: "0-5K" },
@@ -385,24 +377,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.
-
-
-
-
-
Submit application
diff --git a/src/components/ProjectForm.tsx b/src/components/ProjectForm.tsx
index 9a0a81b..427aa40 100644
--- a/src/components/ProjectForm.tsx
+++ b/src/components/ProjectForm.tsx
@@ -2,14 +2,7 @@ import { useEffect, useState } from "react";
import { SubmitHandler, useForm, ControllerRenderProps } from "react-hook-form";
import { Button } from "@/components/ui/button";
import { MultipleOptionSelector } from "@/components/multipleSelector";
-import {
- Form,
- FormControl,
- FormField,
- FormItem,
- FormLabel,
- FormMessage,
-} from "@/components/ui/form";
+import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { projectFormSchema } from "@/types/schemas/application.schema";
import { z } from "zod";
@@ -17,19 +10,8 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { Label } from "@/components/ui/label";
import { createSupabaseClient } from "@/lib/supabase/clientComponentClient";
import { Textarea } from "./ui/textarea";
-import {
- Command,
- CommandEmpty,
- CommandGroup,
- CommandInput,
- CommandItem,
- CommandList,
-} from "@/components/ui/command";
-import {
- Popover,
- PopoverContent,
- PopoverTrigger,
-} from "@/components/ui/popover";
+import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
+import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { cn } from "@/lib/utils";
import { ChevronsUpDown, Check, X } from "lucide-react";
@@ -39,30 +21,21 @@ type FieldType = ControllerRenderProps;
interface ProjectFormProps {
onSubmit: SubmitHandler;
}
-const ProjectForm = ({
- onSubmit,
-}: ProjectFormProps & { onSubmit: SubmitHandler }) => {
+const ProjectForm = ({ onSubmit }: ProjectFormProps & { onSubmit: SubmitHandler }) => {
const form = useForm({
resolver: zodResolver(projectFormSchema),
defaultValues: {},
});
let supabase = createSupabaseClient();
- const [projectType, setProjectType] = useState<
- { id: number; name: string }[]
- >([]);
+ const [projectType, setProjectType] = useState<{ id: number; name: string }[]>([]);
const [projectPitch, setProjectPitch] = useState("text");
const [selectedImages, setSelectedImages] = useState([]);
const [projectPitchFile, setProjectPitchFile] = useState("");
const [tag, setTag] = useState<{ id: number; value: string }[]>([]);
const [open, setOpen] = useState(false);
- const [selectedTag, setSelectedTag] = useState<
- { id: number; value: string }[]
- >([]);
+ const [selectedTag, setSelectedTag] = useState<{ id: number; value: string }[]>([]);
- const handleFileChange = (
- event: React.ChangeEvent,
- field: FieldType
- ) => {
+ const handleFileChange = (event: React.ChangeEvent, field: FieldType) => {
if (event.target.files) {
const filesArray = Array.from(event.target.files);
console.log("first file", filesArray);
@@ -86,9 +59,7 @@ const ProjectForm = ({
};
const fetchProjectType = async () => {
- let { data: ProjectType, error } = await supabase
- .from("project_type")
- .select("id, value");
+ let { data: ProjectType, error } = await supabase.from("project_type").select("id, value");
if (error) {
console.error(error);
@@ -125,10 +96,7 @@ const ProjectForm = ({
}, []);
return (