feat: update dashboard to enhance investment data handling and display

This commit is contained in:
Pattadon 2024-11-08 15:08:05 +07:00
parent 0933f86faf
commit 804de94cbe
6 changed files with 181 additions and 83 deletions

View File

@ -11,16 +11,27 @@ import { getProjectByUserId } from "@/lib/data/projectQuery";
import { Loader } from "@/components/loading/loader"; import { Loader } from "@/components/loading/loader";
import { getInvestmentByProjectsIds } from "@/lib/data/investmentQuery"; import { getInvestmentByProjectsIds } from "@/lib/data/investmentQuery";
import { useQuery } from "@supabase-cache-helpers/postgrest-react-query"; import { useQuery } from "@supabase-cache-helpers/postgrest-react-query";
import { getLatestInvestment, overAllGraphData, Deal } from "../portfolio/[uid]/query"; import { usePathname } from "next/navigation";
import { overAllGraphData, Deal } from "../portfolio/[uid]/query";
import { getUserProfile } from "@/lib/data/userQuery";
import { Item } from "@radix-ui/react-navigation-menu";
export default function Dashboard() { export default function Dashboard() {
let supabase = createSupabaseClient(); const supabase = createSupabaseClient();
const pathname = usePathname();
const userId = useSession().session?.user.id; const userId = useSession().session?.user.id;
const [projects, setProjects] = useState< const [projects, setProjects] = useState<
{ id: number; project_name: string; business_id: { user_id: number }[]; dataroom_id: number }[] { id: number; project_name: string; business_id: { user_id: number }[]; dataroom_id: number }[]
>([]); >([]);
const [latestInvestment, setLatestInvestment] = useState< const [latestInvestment, setLatestInvestment] = useState<
{ projectId: number; name: any; amount: number; date: Date; logo_url: string; status: string }[] {
avatarUrl: string;
createdTime: Date;
dealAmount: number;
dealStatus: string;
investorId: string;
username: string;
}[]
>([]); >([]);
const [isSuccess, setIsSuccess] = useState(false); const [isSuccess, setIsSuccess] = useState(false);
const [graphType, setGraphType] = useState("line"); const [graphType, setGraphType] = useState("line");
@ -34,36 +45,38 @@ export default function Dashboard() {
) )
); );
useEffect(() => { useEffect(() => {
const fetchLatestInvestment = async () => { const setTopLatestInvestment = () => {
const latest = await getLatestInvestment( if (investmentDetail?.data) {
supabase,
investmentDetail?.data?.map((deal) => {
return {
project_id: deal.project_id,
deal_amount: deal.deal_amount,
created_time: deal.created_time,
};
}) || []
);
const resolvedLatest = await Promise.all(
latest.map(async (investment) => ({
...investment,
logo_url: await investment.logo_url,
}))
);
setLatestInvestment( setLatestInvestment(
resolvedLatest.map((investment) => ({ investmentDetail.data
projectId: investment.projectId, .slice(0, 8)
name: investment.name, .map((item) => {
amount: investment.amount, // set the project according to current project id
date: investment.date, if (item.project_id === currentProjectId) {
logo_url: investment.logo_url, return {
status: investmentDetail?.data?.find((deal) => deal.project_id === investment.projectId)?.deal_status.value, avatarUrl: item.avatar_url,
})) createdTime: item.created_time,
); dealAmount: item.deal_amount,
// console.table(investmentDetail); dealStatus: item.deal_status,
investorId: item.investor_id,
username: item.username,
}; };
fetchLatestInvestment(); }
return undefined;
})
.filter((item) => item !== undefined) as {
avatarUrl: string;
createdTime: Date;
dealAmount: number;
dealStatus: string;
investorId: string;
username: string;
}[]
);
console.table(latestInvestment)
}
};
setTopLatestInvestment();
}, [supabase, investmentDetail]); }, [supabase, investmentDetail]);
useEffect(() => { useEffect(() => {
const fetchProjects = async () => { const fetchProjects = async () => {
@ -88,7 +101,7 @@ export default function Dashboard() {
// console.table(latestInvestment); // console.table(latestInvestment);
return ( return (
<> <div className="container max-w-screen-xl">
<Loader isSuccess={isSuccess} /> <Loader isSuccess={isSuccess} />
<div className="md:hidden"> <div className="md:hidden">
<Image <Image
@ -266,20 +279,16 @@ export default function Dashboard() {
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<RecentFunds <RecentFunds
data={latestInvestment data={latestInvestment.map((item) => {
.map((item) => {
if (item.projectId === currentProjectId) {
return { return {
name: item.name, name: item.username,
amount: item.amount, amount: item.dealAmount,
avatar: item.logo_url, avatar: item.avatarUrl,
date: item.date, date: new Date(item.createdTime),
status: item.status, status: item.dealStatus,
profile_url: `/profile/${item.investorId}`,
}; };
} })}
return undefined;
})
.filter((item) => item !== undefined)}
/> />
</CardContent> </CardContent>
</Card> </Card>
@ -289,6 +298,6 @@ export default function Dashboard() {
</Tabs> </Tabs>
</div> </div>
</div> </div>
</> </div>
); );
} }

View File

@ -0,0 +1 @@

View File

@ -26,7 +26,7 @@ function getTotalInvestment(deals: { deal_amount: number }[]) {
} }
async function getLatestInvestment( async function getLatestInvestment(
supabase: SupabaseClient, supabase: SupabaseClient,
deals: { project_id: number; deal_amount: number; created_time: Date }[] deals: { project_id: number; deal_amount: number; created_time: Date;}[]
) { ) {
const llist = []; const llist = [];
const count = 8; const count = 8;

View File

@ -117,7 +117,7 @@ export default function ApplyProject() {
confirmButtonColor: error == null ? "green" : "red", confirmButtonColor: error == null ? "green" : "red",
}).then((result) => { }).then((result) => {
if (result.isConfirmed) { if (result.isConfirmed) {
// window.location.href = "/"; window.location.href = "/";
} }
}); });
}; };

View File

@ -1,4 +1,5 @@
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import Link from "next/link";
export type RecentDealData = { export type RecentDealData = {
created_time: Date; created_time: Date;
@ -11,16 +12,28 @@ export type RecentDealData = {
}; };
interface RecentFundsProps { interface RecentFundsProps {
data?: { name?: string; amount?: number; avatar?: string; date?: Date; logo_url?: string; status?: string }[]; data?: { name?: string; amount?: number; avatar?: string; date?: Date; logo_url?: string; status?: string; profile_url?: string }[];
} }
export function RecentFunds(props: RecentFundsProps) { export function RecentFunds(props: RecentFundsProps) {
const content = (
<div>
</div>
)
return ( return (
<div className="space-y-8"> <div className="space-y-8">
{(props?.data || []).map((deal, index) => ( {(props?.data || []).map((deal, index) => (
<div className="flex items-center" key={index}> <div key={index}>
{deal.profile_url ? (
<Link
href={deal.profile_url}
className="flex items-center w-full"
target="_blank"
rel="noopener noreferrer"
>
<Avatar className="h-9 w-9"> <Avatar className="h-9 w-9">
<AvatarImage src={deal.logo_url} alt={deal.name} /> <AvatarImage src={deal.logo_url ? deal.logo_url : deal.avatar} alt={deal.name} />
<AvatarFallback>{(deal.name ?? "").slice(0, 2)}</AvatarFallback> <AvatarFallback>{(deal.name ?? "").slice(0, 2)}</AvatarFallback>
</Avatar> </Avatar>
<div className="ml-4 space-y-1"> <div className="ml-4 space-y-1">
@ -30,14 +43,79 @@ export function RecentFunds(props: RecentFundsProps) {
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
<span className="relative flex h-3 w-3"> <span className="relative flex h-3 w-3">
<span <span
className={`animate-ping absolute inline-flex h-3 w-3 rounded-full opacity-75 ${deal?.status === "In Progress" ? "bg-sky-400" : deal?.status === "Completed" ? "bg-green-400" : "bg-yellow-400"}`} className={`animate-ping absolute inline-flex h-3 w-3 rounded-full opacity-75 ${
deal?.status === "In Progress"
? "bg-sky-400"
: deal?.status === "Completed"
? "bg-green-400"
: "bg-yellow-400"
}`}
></span> ></span>
<span <span
className={`relative inline-flex rounded-full h-2 w-2 mt-[2px] ml-0.5 ${deal?.status === "In Progress" ? "bg-sky-500" : deal?.status === "Completed" ? "bg-green-500" : "bg-yellow-500"}`} className={`relative inline-flex rounded-full h-2 w-2 mt-[2px] ml-0.5 ${
deal?.status === "In Progress"
? "bg-sky-500"
: deal?.status === "Completed"
? "bg-green-500"
: "bg-yellow-500"
}`}
></span> ></span>
</span> </span>
<p <p
className={`text-xs m-0 ${deal?.status === "In Progress" ? "text-sky-500" : deal?.status === "Completed" ? "text-green-500" : "text-yellow-500"}`} className={`text-xs m-0 ${
deal?.status === "In Progress"
? "text-sky-500"
: deal?.status === "Completed"
? "text-green-500"
: "text-yellow-500"
}`}
>
{deal?.status}
</p>
</div>
)}
</div>
<div className="ml-auto font-medium">+${deal.amount}</div>
</Link>
) : (
<div className="flex items-center w-full">
<Avatar className="h-9 w-9">
<AvatarImage src={deal.logo_url ? deal.logo_url : deal.avatar} alt={deal.name} />
<AvatarFallback>{(deal.name ?? "").slice(0, 2)}</AvatarFallback>
</Avatar>
<div className="ml-4 space-y-1">
<p className="text-sm font-medium leading-none">{deal.name}</p>
<p className="text-xs text-muted-foreground">{deal?.date?.toLocaleDateString()}</p>
{deal.status && (
<div className="flex items-center space-x-1">
<span className="relative flex h-3 w-3">
<span
className={`animate-ping absolute inline-flex h-3 w-3 rounded-full opacity-75 ${
deal?.status === "In Progress"
? "bg-sky-400"
: deal?.status === "Completed"
? "bg-green-400"
: "bg-yellow-400"
}`}
></span>
<span
className={`relative inline-flex rounded-full h-2 w-2 mt-[2px] ml-0.5 ${
deal?.status === "In Progress"
? "bg-sky-500"
: deal?.status === "Completed"
? "bg-green-500"
: "bg-yellow-500"
}`}
></span>
</span>
<p
className={`text-xs m-0 ${
deal?.status === "In Progress"
? "text-sky-500"
: deal?.status === "Completed"
? "text-green-500"
: "text-yellow-500"
}`}
> >
{deal?.status} {deal?.status}
</p> </p>
@ -46,7 +124,10 @@ export function RecentFunds(props: RecentFundsProps) {
</div> </div>
<div className="ml-auto font-medium">+${deal.amount}</div> <div className="ml-auto font-medium">+${deal.amount}</div>
</div> </div>
)}
</div>
))} ))}
</div> </div>
); );
} }

View File

@ -16,14 +16,21 @@ export const getInvestmentByProjectsIds = (client: SupabaseClient, projectIds: s
.select( .select(
` `
id, id,
deal_status:deal_status_id(value), ...deal_status_id(
deal_status:value
),
project_id, project_id,
deal_amount, deal_amount,
investor:users_id(email), created_time,
created_time ...profiles (
investor_id:id,
username,
avatar_url
)
` `
) )
.in("project_id", projectIds); .in("project_id", projectIds)
.order("created_time", { ascending: false });
}; };
export const getInvestmentByUserId = (client: SupabaseClient, userId: string) => { export const getInvestmentByUserId = (client: SupabaseClient, userId: string) => {