import jalaali from "jalaali-js"; import { Book, CheckCircle } from "lucide-react"; import { useEffect, useState } from "react"; import toast from "react-hot-toast"; import { Label, PolarGrid, PolarRadiusAxis, RadialBar, RadialBarChart, } from "recharts"; import { BaseCard } from "~/components/ui/base-card"; import { Button } from "~/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card"; import { ChartContainer } from "~/components/ui/chart"; import { MetricCard } from "~/components/ui/metric-card"; import { Progress } from "~/components/ui/progress"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs"; import apiService from "~/lib/api"; import { EventBus, formatNumber } from "~/lib/utils"; import type { CalendarDate } from "~/types/util.type"; import { D3ImageInfo } from "./d3-image-info"; import { DashboardCustomBarChart } from "./dashboard-custom-bar-chart"; import { InteractiveBarChart } from "./interactive-bar-chart"; import { DashboardLayout } from "./layout"; export function DashboardHome() { const { jy } = jalaali.toJalaali(new Date()); const [dashboardData, setDashboardData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // Chart and schematic data from select API const [companyChartData, setCompanyChartData] = useState< { category: string; capacity: number; revenue: number; cost: number; costI: number; capacityI: number; revenueI: number; }[] >([]); const [date, setDate] = useState({ start: `${jy}/01/01`, end: `${jy}/12/30`, }); useEffect(() => { EventBus.on("dateSelected", (date: CalendarDate) => { if (date) setDate(date); }); }, []); useEffect(() => { fetchDashboardData(); }, [date]); const fetchDashboardData = async () => { try { setLoading(true); setError(null); // First authenticate if needed const token = localStorage.getItem("auth_token"); if (!token) { await apiService.login("inogen_admin", "123456"); } // Fetch top cards data const topCardsResponse = await apiService.call({ main_page_first_function: { start_date: date.start || null, end_date: date.end || null, }, }); // Fetch left section data const leftCardsResponse = await apiService.call({ main_page_second_function: { start_date: date.start || null, end_date: date.end || null, }, }); const topCardsResponseData = JSON.parse(topCardsResponse?.data); const leftCardsResponseData = JSON.parse(leftCardsResponse?.data); console.log("API Responses:", { topCardsResponseData, leftCardsResponseData, }); // Use real API data structure with English keys const topData = topCardsResponseData || {}; const leftData = leftCardsResponseData || {}; const realData = { topData: topData, leftData: leftData, chartData: leftCardsResponseData?.chartData || [], }; setDashboardData(realData); // Fetch company aggregates for chart and schematic (select API) const selectPayload = { ProcessName: "project", OutputFields: [ "related_company", "sum(pre_innovation_fee)", "sum(innovation_cost_reduction)", "sum(pre_project_production_capacity)", "sum(increased_capacity_after_innovation)", "sum(pre_project_income)", "sum(increased_income_after_innovation)", ], Conditions: [ ["start_date", ">=", date.start || null, "and"], ["start_date", "<=", date.end || null], ], GroupBy: ["related_company"], }; const selectResp = await apiService.select(selectPayload); const selectDataRaw = ((): any => { try { return typeof selectResp?.data === "string" ? JSON.parse(selectResp.data) : selectResp?.data; } catch { return []; } })(); const rows: any[] = Array.isArray(selectDataRaw) ? selectDataRaw : []; let incCapacityTotal = 0; const chartRows = rows.map((r) => { const rel = r?.related_company ?? "-"; const preFee = Number(r?.pre_innovation_fee_sum ?? 0) >= 0 ? r?.pre_innovation_fee_sum : 0; const costRed = Number(r?.innovation_cost_reduction_sum ?? 0) >= 0 ? r?.innovation_cost_reduction_sum : 0; const preCap = Number(r?.pre_project_production_capacity_sum ?? 0) >= 0 ? r?.pre_project_production_capacity_sum : 0; const incCap = Number(r?.increased_capacity_after_innovation_sum ?? 0) >= 0 ? r?.increased_capacity_after_innovation_sum : 0; const preInc = Number(r?.pre_project_income_sum ?? 0) >= 0 ? r?.pre_project_income_sum : 0; const incInc = Number(r?.increased_income_after_innovation_sum ?? 0) >= 0 ? r?.increased_income_after_innovation_sum : 0; incCapacityTotal += incCap; const capacityPct = preCap >= 0 ? (incCap / preCap) * 100 : 0; const revenuePct = preInc >= 0 ? (incInc / preInc) * 100 : 0; const costPct = preFee >= 0 ? (costRed / preFee) * 100 : 0; return { category: rel, capacity: isFinite(capacityPct) ? capacityPct : 0, revenue: isFinite(revenuePct) ? revenuePct : 0, cost: isFinite(costPct) ? costPct : 0, costI: costRed, capacityI: incCap, revenueI: incInc, }; }); setCompanyChartData(chartRows); // setTotalIncreasedCapacity(incCapacityTotal); } catch (error) { console.error("Error fetching dashboard data:", error); const errorMessage = error instanceof Error ? error.message : "خطای نامشخص"; setError(`خطا در بارگذاری داده‌ها: ${errorMessage}`); toast.error(`خطا در بارگذاری داده‌ها: ${errorMessage}`); } finally { setLoading(false); } }; // RadialBarChart data for ideas visualization // const getIdeasChartData = () => { // if (!dashboardData?.topData) // return [{ browser: "safari", visitors: 0, fill: "var(--color-safari)" }]; // const registered = parseFloat( // dashboardData.topData.registered_innovation_technology_idea || "0" // ); // const ongoing = parseFloat( // dashboardData.topData.ongoing_innovation_technology_ideas || "0" // ); // const percentage = registered > 0 ? (ongoing / registered) * 100 : 0; // return [ // { browser: "safari", visitors: percentage, fill: "var(--color-safari)" }, // ]; // }; // const chartData = getIdeasChartData(); const chartConfig = { visitors: { label: "Ideas Progress", }, safari: { label: "Safari", color: "var(--chart-2)", }, }; // Skeleton component for cards const SkeletonCard = ({ className = "" }) => (
); // Skeleton for the chart const SkeletonChart = () => (
{[...Array(12)].map((_, i) => (
))}
{[...Array(6)].map((_, i) => (
))}
); if (loading) { return (
{/* Top Cards Row */}
{/* Middle Section */}
{/* Chart Section */}
{/* Right Sidebar */}
); } if (error || !dashboardData) { return (

خطا در بارگذاری داده‌ها

{error || "خطای نامشخص در بارگذاری داده‌های داشبورد رخ داده است"}

); } return (
{/* Top Cards Row - Redesigned to match other components */}
{/* Ideas Card */}
0 ? Math.round( (parseFloat( dashboardData.topData ?.ongoing_innovation_technology_ideas || "0" ) / parseFloat( dashboardData.topData ?.registered_innovation_technology_idea || "1" )) * 100 ) : 0, fill: "var(--color-green)", }, ]} startAngle={90} endAngle={ 90 + ((parseFloat( dashboardData.topData ?.registered_innovation_technology_idea || "0" ) > 0 ? Math.round( (parseFloat( dashboardData.topData ?.ongoing_innovation_technology_ideas || "0" ) / parseFloat( dashboardData.topData ?.registered_innovation_technology_idea || "1" )) * 100 ) : 0) / 100) * 360 } innerRadius={35} outerRadius={55} >
ثبت شده :
{formatNumber( dashboardData.topData ?.registered_innovation_technology_idea || "0" )}
در حال اجرا :
{formatNumber( dashboardData.topData ?.ongoing_innovation_technology_ideas || "0" )}
{/* Revenue Card */} {/* Cost Reduction Card */} {/* Budget Ratio Card */}
مصوب :
{formatNumber( Math.round( parseFloat( dashboardData.topData?.approved_innovation_budget_achievement_ratio?.replace( /,/g, "" ) || "0" ) ) )}
جذب شده :
{formatNumber( Math.round( parseFloat( dashboardData.topData?.allocated_innovation_budget_achievement_ratio?.replace( /,/g, "" ) || "0" ) ) )}
{/* Main Content with Tabs */}

تحقق ارزش ها

شماتیک مقایسه ای
{ const imageMap: Record = { بسپاران: "/besparan.png", خوارزمی: "/khwarazmi.png", "فراورش 1": "/faravash1.png", "فراورش 2": "/faravash2.png", کیمیا: "/kimia.png", "آب نیرو": "/abniro.png", }; return { id: item.category, name: item.category, imageUrl: imageMap[item.category] || "/placeholder.png", cost: item?.costI || 0, capacity: item?.capacityI || 0, revenue: item?.revenueI || 0, }; })} />
{/* Left Section - Status Cards */}
{/* Technology Intensity */}
شدت فناوری
{/* Program Status */} {/* Publications */} انتشارات فناوری و نوآوری
کتاب:
{formatNumber( dashboardData.leftData?.printed_books_count || "0" )}
پتنت:
{formatNumber( dashboardData.leftData?.registered_patents_count || "0" )}
گزارش:
{formatNumber( dashboardData.leftData?.published_reports_count || "0" )}
مقاله:
{formatNumber( dashboardData.leftData?.printed_articles_count || "0" )}
{/* Promotion */} ترویج فناوری و نوآوری
کنفرانس:
{formatNumber( dashboardData.leftData?.attended_conferences_count || "0" )}
شرکت در رویداد:
{formatNumber( dashboardData.leftData?.attended_events_count || "0" )}
نمایشگاه:
{formatNumber( dashboardData.leftData?.attended_exhibitions_count || "0" )}
برگزاری رویداد:
{formatNumber( dashboardData.leftData?.organized_events_count || "0" )}
); } export default DashboardHome;