diff --git a/app/components/dashboard/project-management/digital-innovation-page.tsx b/app/components/dashboard/project-management/digital-innovation-page.tsx index c5ebd2f..1b5b35b 100644 --- a/app/components/dashboard/project-management/digital-innovation-page.tsx +++ b/app/components/dashboard/project-management/digital-innovation-page.tsx @@ -548,7 +548,7 @@ export function DigitalInnovationPage() { index: greenBoxes + 1, style: `linear-gradient( to right, - oklch(76.5% 0.177 163.223) 0%, + oklch(76.5% 0.177 163.223) 0%, oklch(76.5% 0.177 163.223) ${partialPercent * 100}%, oklch(55.1% 0.027 264.364) ${partialPercent * 100}%, oklch(55.1% 0.027 264.364) 100% diff --git a/app/components/dashboard/project-management/mange-ideas-tech-page.tsx b/app/components/dashboard/project-management/mange-ideas-tech-page.tsx index aef763f..12aba32 100644 --- a/app/components/dashboard/project-management/mange-ideas-tech-page.tsx +++ b/app/components/dashboard/project-management/mange-ideas-tech-page.tsx @@ -1,4 +1,4 @@ -import { ChevronDown, ChevronUp, RefreshCw, Eye, Star } from "lucide-react"; +import { ChevronDown, ChevronUp, RefreshCw, Eye, Star, TrendingUp, Hexagon, Download } from "lucide-react"; import { useCallback, useEffect, useRef, useState, useMemo } from "react"; import toast from "react-hot-toast"; import { Badge } from "~/components/ui/badge"; @@ -21,6 +21,18 @@ import { import apiService from "~/lib/api"; import { formatCurrency, formatNumber } from "~/lib/utils"; import { DashboardLayout } from "../layout"; +import { + ChartContainer, + ChartTooltip, + ChartTooltipContent, + type ChartConfig, +} from "~/components/ui/chart"; +import { BarChart, Bar, XAxis, YAxis, ResponsiveContainer, CartesianGrid, LabelList, Cell, RadialBarChart, PolarGrid, RadialBar, PolarRadiusAxis } from "recharts"; +import { BaseCard } from "~/components/ui/base-card"; +import { Label } from "~/components/ui/label"; +import { MetricCard } from "~/components/ui/metric-card"; + + interface IdeaData { idea_title: string; @@ -48,6 +60,18 @@ interface PersonRanking { stars: number; } +interface IdeaStatusData { + idea_status: string; + idea_status_count: number; +} + +interface IdeaStatsData { + registered_innovation_technology_idea: string; + ongoing_innovation_technology_ideas: string; + increased_revenue_from_ideas: string; + increased_revenue_from_ideas_percent: string; +} + interface SortConfig { field: string; direction: "asc" | "desc"; @@ -88,6 +112,14 @@ export function ManageIdeasTechPage() { const [peopleRanking, setPeopleRanking] = useState([]); const [loadingPeople, setLoadingPeople] = useState(false); + // Chart state + const [chartData, setChartData] = useState([]); + const [loadingChart, setLoadingChart] = useState(false); + + // Stats state + const [statsData, setStatsData] = useState(null); + const [loadingStats, setLoadingStats] = useState(false); + const observerRef = useRef(null); const fetchingRef = useRef(false); const scrollTimeoutRef = useRef(null); @@ -204,6 +236,8 @@ export function ManageIdeasTechPage() { fetchIdeas(true); fetchTotalCount(); fetchPeopleRanking(); + fetchChartData(); + fetchStatsData(); }, [sortConfig]); useEffect(() => { @@ -350,6 +384,68 @@ export function ManageIdeasTechPage() { } }; + const fetchChartData = async () => { + try { + setLoadingChart(true); + + const response = await apiService.select({ + ProcessName: "idea", + OutputFields: ["idea_status", "count(idea_status)"], + GroupBy: ["idea_status"], + }); + + if (response.state === 0) { + const dataString = response.data; + if (dataString && typeof dataString === "string") { + try { + const parsedData: IdeaStatusData[] = JSON.parse(dataString); + if (Array.isArray(parsedData)) { + setChartData(parsedData?.reverse()); + } + } catch (parseError) { + console.error("Error parsing chart data:", parseError); + } + } + } else { + toast.error(response.message || "خطا در دریافت اطلاعات نمودار"); + } + } catch (error) { + console.error("Error fetching chart data:", error); + toast.error("خطا در دریافت اطلاعات نمودار"); + } finally { + setLoadingChart(false); + } + }; + + const fetchStatsData = async () => { + try { + setLoadingStats(true); + + const response = await apiService.call({ + idea_page_function: {} + }); + + if (response.state === 0) { + const dataString = response.data; + if (dataString && typeof dataString === "string") { + try { + const parsedData: IdeaStatsData = JSON.parse(dataString); + setStatsData(parsedData); + } catch (parseError) { + console.error("Error parsing stats data:", parseError); + } + } + } else { + toast.error(response.message || "خطا در دریافت آمار ایده‌ها"); + } + } catch (error) { + console.error("Error fetching stats data:", error); + toast.error("خطا در دریافت آمار ایده‌ها"); + } finally { + setLoadingStats(false); + } + }; + const toPersianDigits = (input: string | number): string => { const str = String(input); const map: Record = { @@ -395,7 +491,30 @@ export function ManageIdeasTechPage() { } }; + // Chart configuration for shadcn/ui + const chartConfig: ChartConfig = { + count: { + label: "تعداد", + }, + }; + // Color palette for idea status + // Specific colors for idea statuses + const getChartStatusColor = (status: string) => { + switch (status) { + case "اجرا شده": + return "#69C8EA"; + case "تایید شده": + return "#3AEA83"; + case "در حال بررسی": + return "#EAD069"; + case "رد شده": + return "#F76276"; + default: + return "#6B7280"; + } + }; + const statusColorPalette = ["#3AEA83", "#69C8EA", "#F76276", "#FFD700", "#A757FF", "#E884CE", "#C3BF8B", "#FB7185"]; // Build a mapping of status value -> color based on loaded ideas @@ -469,7 +588,7 @@ export function ManageIdeasTechPage() { variant="ghost" size="sm" onClick={() => handleShowDetails(item)} - className="underline text-pr-green underline-offset-4 text-sm hover:bg-emerald-500/20" + className="underline text-pr-green underline-offset-4 text-sm hover:bg-pr-green/20" > جزئیات بیشتر ); @@ -482,9 +601,104 @@ export function ManageIdeasTechPage() { } }; + // Custom Vertical Bar Chart Component using shadcn/ui + const VerticalBarChart = () => { + if (loadingChart) { + return ( +
+
+
+
+ ); + } + + if (!chartData.length) { + return ( +
+

وضعیت ایده ها

+

هیچ داده‌ای یافت نشد

+
+ ); + } + + // Prepare data for recharts + const rechartData = chartData.map((item) => ({ + status: item.idea_status, + count: item.idea_status_count, + fill: getChartStatusColor(item.idea_status), + })); + + return ( + + + + + + toPersianDigits(value)} + label={{ +value: "تعداد برنامه ها" , +angle: -90, +position: "insideLeft", +fill: "#94a3b8", +fontSize: 11, +offset: 0, +dy: 0, +style: { textAnchor: "middle" }, +}} + /> + + `${formatNumber(Math.round(v))}`} + /> + + + + + ); + }; + return (
+
{/* People Ranking Table */}
@@ -588,7 +802,7 @@ export function ManageIdeasTechPage() {
@@ -701,127 +915,354 @@ export function ManageIdeasTechPage() { + {/* Chart Section */} + + + +
+ +
+ + 0 + ? Math.round( + (parseFloat( + statsData?.registered_innovation_technology_idea || "0", + ) / + parseFloat( + statsData + ?.registered_innovation_technology_idea || + "1", + )) * + 100, + ) + : 0, + fill: "var(--color-green)", + }, + ]} + startAngle={90} + endAngle={ + 90 + + ((parseFloat( + statsData + ?.registered_innovation_technology_idea || "0", + ) > 0 + ? Math.round( + (parseFloat( + statsData + ?.ongoing_innovation_technology_ideas || "0", + ) / + parseFloat( + statsData + ?.registered_innovation_technology_idea || + "1", + )) * + 100, + ) + : 0) / + 100) * + 360 + } + innerRadius={35} + outerRadius={55} + > + + + + + + +
+
+ +
ثبت شده :
+ {formatNumber( + statsData + ?.registered_innovation_technology_idea || "0", + )} +
+ +
در حال اجرا :
+ {formatNumber( + statsData + ?.ongoing_innovation_technology_ideas || "0", + )} +
+
+
+
+
+ + +
{/* Details Dialog */} - - - - جزئیات ایده: {selectedIdea?.idea_title} + + + + عنوان ایده: میکروکاتالیزورهای دما بالا - {selectedIdea && ( -
-
-
-
- -

{selectedIdea.full_name || "-"}

+ {selectedIdea &&
+
+ {/* مشخصات ایده پردازان Section */} +
+

+ مشخصات ایده پردازان +

+
+
+
+ + نام ایده پرداز: +
+ {selectedIdea.full_name || "-"}
- -
- -

{toPersianDigits(selectedIdea.personnel_number) || "-"}

+
+
+ + شماره پرسنلی: +
+ {toPersianDigits(selectedIdea.personnel_number) || "۱۳۰۶۵۸۰۶"}
- -
- -

{selectedIdea.management || "-"}

+
+
+ + مدیریت: +
+ {selectedIdea.management || "مدیریت توسعه"}
- -
- -

{selectedIdea.deputy || "-"}

+
+
+ + معاونت: +
+ {selectedIdea.deputy || "توسعه"}
- -
- -

{selectedIdea.innovation_type || "-"}

-
- -
- -

{selectedIdea.idea_originality || "-"}

-
- -
- -

{selectedIdea.idea_axis || "-"}

+
+
+ + اعضای تیم: +
+ + {selectedIdea.innovator_team_members || "رضا حسین پور, محمد رضا شیاطی, محمد مددی"} +
+
-
-
- -

{selectedIdea.innovator_team_members || "-"}

+ {/* مشخصات ایده Section */} +
+

+ مشخصات ایده +

+
+
+
+ + تاریخ ثبت ایده: +
+ {formatDate(selectedIdea.idea_registration_date) || "-"}
- -
- -

- {selectedIdea.idea_description || "-"} -

+
+
+ + نوع نوآوری: +
+ {selectedIdea.innovation_type || "-"}
- -
- -

- {selectedIdea.idea_current_status_description || "-"} -

+
+
+ + اصالت ایده: +
+ {selectedIdea.idea_originality || "-"}
- -
- -

- {selectedIdea.idea_execution_benefits || "-"} -

+
+
+ + محور ایده: +
+ {selectedIdea.idea_axis || "-"}
+
+
+ {/* نتایج و خروجی ها Section */} +
+

+ نتایج و خروجی ها +

+
+
+
+ + درآمد حاصل: +
+ {formatNumber(selectedIdea.increased_revenue) || "-"} + + میلیون ریال -
- -

- {selectedIdea.process_improvements || "-"} -

+ +
+
+
+ + مقاله چاپ شده: +
+ + -
- -

- {formatCurrency(selectedIdea.increased_revenue)} -

+ دانلود + +
+
+
+ + پتنت ثبت شده: +
+ + + دانلود +
- )} +
+ + {/* شرح ایده Section */} +
+

+ شرح ایده +

+
+

+ {selectedIdea.idea_description || + "-" + } +

+
+
+ + {/* شرح وضعیت موجود ایده Section */} +
+

+ شرح وضعیت موجود ایده +

+
+

+ {selectedIdea.idea_current_status_description || + "-" + } +

+
+
+ + {/* منافع حاصل از ایده Section */} +
+

+ منافع حاصل از ایده +

+
+

+ {selectedIdea.idea_execution_benefits || + "-" + } +

+
+
+ + {/* بهبود های فرآیندی ایده Section */} +
+

+ بهبود های فرآیندی ایده +

+
+

+ {selectedIdea.process_improvements || + "-" + } +

+
+
+ +
+
}
diff --git a/app/components/dashboard/project-management/product-innovation-page.tsx b/app/components/dashboard/project-management/product-innovation-page.tsx index 092e091..c1c8679 100644 --- a/app/components/dashboard/project-management/product-innovation-page.tsx +++ b/app/components/dashboard/project-management/product-innovation-page.tsx @@ -616,22 +616,22 @@ export function ProductInnovationPage() { size="sm" onClick={() => { handleProjectDetails(item)}} - className="text-emerald-400 underline underline-offset-4 font-ligth text-base hover:bg-emerald-500/20 p-2 h-auto" + className="text-emerald-400 underline underline-offset-4 font-ligth text-sm hover:bg-emerald-500/20 p-2 h-auto" > جزئیات بیشتر ); case "project_no": return ( - + {String(value)} ); case "title": - return {String(value)}; + return {String(value)}; case "project_status": return ( -
+
); default: - return {String(value) || "-"}; + return {String(value) || "-"}; } };