mirror of
https://github.com/Sosokker/B2D-Ventures.git
synced 2025-12-20 14:34:05 +01:00
feat: update dashboard to enhance investment data handling and display
This commit is contained in:
parent
0933f86faf
commit
804de94cbe
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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 = "/";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user