* Add ecosystem page with network graph and company info panel Co-authored-by: sd.eed1381 <sd.eed1381@gmail.com> * Add unpaid company highlighting to network graph with toggle Co-authored-by: sd.eed1381 <sd.eed1381@gmail.com> * fix id something * remove the useless files * update the graph * update the graph,fix the api ,also add some style and filters * Refactor process impacts chart to use new CustomBarChart component (#3) Co-authored-by: Cursor Agent <cursoragent@cursor.com> * fix somestyle , add charts in ecosystem --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
170 lines
6.0 KiB
TypeScript
170 lines
6.0 KiB
TypeScript
"use client";
|
||
|
||
import React, { useEffect, useState } from "react";
|
||
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
|
||
import {
|
||
Area,
|
||
AreaChart,
|
||
Bar,
|
||
CartesianGrid,
|
||
ResponsiveContainer,
|
||
Tooltip,
|
||
XAxis,
|
||
YAxis,
|
||
} from "recharts";
|
||
import { CustomBarChart } from "~/components/ui/custom-bar-chart";
|
||
import apiService from "~/lib/api";
|
||
|
||
export interface InfoPanelProps {
|
||
selectedCompany: { id: string; label?: string } | null;
|
||
}
|
||
|
||
interface EcosystemCounts {
|
||
knowledge_based_count: string;
|
||
consultant_count: string;
|
||
startup_count: string;
|
||
innovation_center_count: string;
|
||
accelerator_count: string;
|
||
university_count: string;
|
||
fund_count: string;
|
||
company_count: string;
|
||
actor_count: string;
|
||
mou_count: string;
|
||
}
|
||
|
||
export function InfoPanel({ selectedCompany }: InfoPanelProps) {
|
||
const [counts, setCounts] = useState<EcosystemCounts | null>(null);
|
||
const [isLoading, setIsLoading] = useState(true);
|
||
|
||
useEffect(() => {
|
||
const fetchCounts = async () => {
|
||
setIsLoading(true);
|
||
try {
|
||
const res = await apiService.callInnovationProcess<EcosystemCounts>({
|
||
ecosystem_counts_function: {},
|
||
});
|
||
setCounts(res.data);
|
||
} catch (err) {
|
||
console.error("Failed to fetch ecosystem counts:", err);
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
};
|
||
fetchCounts();
|
||
}, []);
|
||
|
||
const title = selectedCompany?.label || "نمای کلی";
|
||
const subTitle = selectedCompany ? `شناسه: ${selectedCompany.id}` : "انتخابی انجام نشده است";
|
||
|
||
// Transform counts into chart-friendly data
|
||
const barData =
|
||
counts && !selectedCompany
|
||
? [
|
||
{ name: "دانش بنیان", value: +counts.knowledge_based_count },
|
||
{ name: "مشاور", value: +counts.consultant_count },
|
||
{ name: "استارتاپ", value: +counts.startup_count },
|
||
{ name: "مرکز نوآوری", value: +counts.innovation_center_count },
|
||
{ name: "شتابدهنده", value: +counts.accelerator_count },
|
||
{ name: "دانشگاه", value: +counts.university_count },
|
||
{ name: "صندوق", value: +counts.fund_count },
|
||
{ name: "شرکت", value: +counts.company_count },
|
||
]
|
||
: [];
|
||
|
||
const lineData = [
|
||
{ month: "01", value: 3 },
|
||
{ month: "02", value: 6 },
|
||
{ month: "03", value: 4 },
|
||
{ month: "04", value: 9 },
|
||
{ month: "05", value: 7 },
|
||
{ month: "06", value: 11 },
|
||
];
|
||
|
||
return (
|
||
<div className="space-y-4 min-h-full">
|
||
<Card className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)]">
|
||
<CardHeader className="pb-2">
|
||
<CardTitle className="font-persian text-base">{title}</CardTitle>
|
||
<div className="text-xs text-gray-400 font-persian">{subTitle}</div>
|
||
</CardHeader>
|
||
|
||
<CardContent>
|
||
{isLoading ? (
|
||
<div className="text-sm text-gray-300 font-persian">در حال بارگذاری...</div>
|
||
) : selectedCompany ? (
|
||
<div className="text-sm text-gray-300 font-persian">
|
||
این یک باکس اطلاعات نمونه است. پس از دریافت API، جزئیات شرکت نمایش داده میشود.
|
||
</div>
|
||
) : counts ? (
|
||
<div className="space-y-4 text-sm text-gray-300 font-persian">
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div>
|
||
<span className="font-bold">تعداد بازیگران اکوسیستم: </span>
|
||
{counts.actor_count}
|
||
</div>
|
||
<div>
|
||
<span className="font-bold">تعداد تفاهم نامه ها: </span>
|
||
{counts.mou_count}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Grid for categories */}
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div>دانش بنیان: {counts.knowledge_based_count}</div>
|
||
<div>مشاور: {counts.consultant_count}</div>
|
||
<div>استارتاپ: {counts.startup_count}</div>
|
||
<div>مرکز نوآوری: {counts.innovation_center_count}</div>
|
||
<div>شتابدهنده: {counts.accelerator_count}</div>
|
||
<div>دانشگاه: {counts.university_count}</div>
|
||
<div>صندوق: {counts.fund_count}</div>
|
||
<div>شرکت: {counts.company_count}</div>
|
||
</div>
|
||
</div>
|
||
) : (
|
||
<div className="text-sm text-gray-300 font-persian">خطا در بارگذاری دادهها.</div>
|
||
)}
|
||
</CardContent>
|
||
|
||
{/* Bar Chart Section */}
|
||
<div className="h-56">
|
||
<CardHeader className="pb-0">
|
||
<CardTitle className="font-persian text-sm">
|
||
{selectedCompany ? "نمودار میلهای" : "نمودار تعداد بر اساس دستهبندی"}
|
||
</CardTitle>
|
||
</CardHeader>
|
||
<CardContent className="h-[180px]">
|
||
{barData.length > 0 && (
|
||
<CustomBarChart data={barData} dataKey="value" labelKey="name" />
|
||
)}
|
||
</CardContent>
|
||
</div>
|
||
|
||
{/* Line/Area Chart Section */}
|
||
<div className="h-56">
|
||
<CardHeader className="pb-0">
|
||
<CardTitle className="font-persian text-sm">روند نمونه</CardTitle>
|
||
</CardHeader>
|
||
<CardContent className="h-[180px]">
|
||
<ResponsiveContainer width="100%" height="100%">
|
||
<AreaChart data={lineData}>
|
||
<CartesianGrid strokeDasharray="3 3" stroke="rgba(255,255,255,0.1)" />
|
||
<XAxis dataKey="month" />
|
||
<YAxis />
|
||
<Tooltip />
|
||
<Area
|
||
type="monotone"
|
||
dataKey="value"
|
||
stroke="#34d399"
|
||
fill="rgba(52, 211, 153, 0.25)"
|
||
/>
|
||
</AreaChart>
|
||
</ResponsiveContainer>
|
||
</CardContent>
|
||
</div>
|
||
</Card>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default InfoPanel;
|