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
This commit is contained in:
Pattadon 2024-11-01 14:32:33 +07:00
parent 22fe709ce8
commit 7356831e2e
3 changed files with 114 additions and 49 deletions

View File

@ -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<string, number> {
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,
};

View File

@ -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 (
<div>
<NoDataAlert />
@ -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({
<div>{totalInvest}</div>
</div> */}
{/* <CountUpComponent end={100} duration={3} /> */}
<div className="text-center py-4">
<h1 className="text-2xl font-semibold">
Welcome to your Portfolio, {username}!
</h1>
<p className="text-lg text-muted-foreground">
Here's an overview of your investment journey and progress.
</p>
<p className="text-xl font-medium text-green-400">
Total Investment: $
<CountUpComponent end={totalInvestment} duration={1} />
</p>
</div>
<div className="flex flew-rows-3 gap-10 mt-5 w-full">
<Tabs defaultValue="daily" className="space-y-4 w-full">
<TabsList className="grid w-full grid-cols-3">
<TabsList className="grid w-96 grid-cols-3">
<TabsTrigger value="daily">Daily</TabsTrigger>
<TabsTrigger value="monthly">Monthly</TabsTrigger>
<TabsTrigger value="yearly">Yearly</TabsTrigger>
@ -246,7 +273,7 @@ export default async function Portfolio({
</CardTitle>
</CardHeader>
<CardContent className="mt-5">
<RecentFunds />
<RecentFunds data={latestDeals} />
</CardContent>
</Card>
</div>

View File

@ -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 (
<div className="space-y-8">
{data.map((person, index) => (
{(props?.data || []).map((deal, index) => (
<div className="flex items-center" key={index}>
<Avatar className="h-9 w-9">
<AvatarImage src={person.avatar} alt={person.name} />
<AvatarFallback>{person.initials}</AvatarFallback>
<AvatarImage src={deal.avatar} alt={deal.name} />
<AvatarFallback>{(deal.name ?? "").slice(0, 3)}</AvatarFallback>
</Avatar>
<div className="ml-4 space-y-1">
<p className="text-sm font-medium leading-none">{person.name}</p>
<p className="text-sm text-muted-foreground">{person.email}</p>
<p className="text-sm font-medium leading-none">{deal.name}</p>
<p className="text-xs text-muted-foreground">{deal?.date?.toLocaleDateString()}</p>
</div>
<div className="ml-auto font-medium">+${person.amount}</div>
<div className="ml-auto font-medium">+${deal.amount}</div>
</div>
))}
</div>