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 { getInvestmentByProjectsIds } from "@/lib/data/investmentQuery";
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() {
let supabase = createSupabaseClient();
const supabase = createSupabaseClient();
const pathname = usePathname();
const userId = useSession().session?.user.id;
const [projects, setProjects] = useState<
{ id: number; project_name: string; business_id: { user_id: number }[]; dataroom_id: number }[]
>([]);
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 [graphType, setGraphType] = useState("line");
@ -34,36 +45,38 @@ export default function Dashboard() {
)
);
useEffect(() => {
const fetchLatestInvestment = async () => {
const latest = await getLatestInvestment(
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(
resolvedLatest.map((investment) => ({
projectId: investment.projectId,
name: investment.name,
amount: investment.amount,
date: investment.date,
logo_url: investment.logo_url,
status: investmentDetail?.data?.find((deal) => deal.project_id === investment.projectId)?.deal_status.value,
}))
);
// console.table(investmentDetail);
const setTopLatestInvestment = () => {
if (investmentDetail?.data) {
setLatestInvestment(
investmentDetail.data
.slice(0, 8)
.map((item) => {
// set the project according to current project id
if (item.project_id === currentProjectId) {
return {
avatarUrl: item.avatar_url,
createdTime: item.created_time,
dealAmount: item.deal_amount,
dealStatus: item.deal_status,
investorId: item.investor_id,
username: item.username,
};
}
return undefined;
})
.filter((item) => item !== undefined) as {
avatarUrl: string;
createdTime: Date;
dealAmount: number;
dealStatus: string;
investorId: string;
username: string;
}[]
);
console.table(latestInvestment)
}
};
fetchLatestInvestment();
setTopLatestInvestment();
}, [supabase, investmentDetail]);
useEffect(() => {
const fetchProjects = async () => {
@ -88,7 +101,7 @@ export default function Dashboard() {
// console.table(latestInvestment);
return (
<>
<div className="container max-w-screen-xl">
<Loader isSuccess={isSuccess} />
<div className="md:hidden">
<Image
@ -265,22 +278,18 @@ export default function Dashboard() {
<CardTitle>Recent Funds</CardTitle>
</CardHeader>
<CardContent>
<RecentFunds
data={latestInvestment
.map((item) => {
if (item.projectId === currentProjectId) {
return {
name: item.name,
amount: item.amount,
avatar: item.logo_url,
date: item.date,
status: item.status,
};
}
return undefined;
})
.filter((item) => item !== undefined)}
/>
<RecentFunds
data={latestInvestment.map((item) => {
return {
name: item.username,
amount: item.dealAmount,
avatar: item.avatarUrl,
date: new Date(item.createdTime),
status: item.dealStatus,
profile_url: `/profile/${item.investorId}`,
};
})}
/>
</CardContent>
</Card>
</div>
@ -289,6 +298,6 @@ export default function Dashboard() {
</Tabs>
</div>
</div>
</>
</div>
);
}

View File

@ -0,0 +1 @@

View File

@ -26,7 +26,7 @@ function getTotalInvestment(deals: { deal_amount: number }[]) {
}
async function getLatestInvestment(
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 count = 8;

View File

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

View File

@ -1,4 +1,5 @@
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import Link from "next/link";
export type RecentDealData = {
created_time: Date;
@ -11,42 +12,122 @@ export type RecentDealData = {
};
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) {
const content = (
<div>
</div>
)
return (
<div className="space-y-8">
{(props?.data || []).map((deal, index) => (
<div className="flex items-center" key={index}>
<Avatar className="h-9 w-9">
<AvatarImage src={deal.logo_url} 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}
</p>
<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">
<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}
</p>
</div>
)}
</div>
)}
</div>
<div className="ml-auto font-medium">+${deal.amount}</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}
</p>
</div>
)}
</div>
<div className="ml-auto font-medium">+${deal.amount}</div>
</div>
)}
</div>
))}
</div>
);
}

View File

@ -16,14 +16,21 @@ export const getInvestmentByProjectsIds = (client: SupabaseClient, projectIds: s
.select(
`
id,
deal_status:deal_status_id(value),
...deal_status_id(
deal_status:value
),
project_id,
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) => {