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 e451903..f3a94e7 100644
--- a/app/components/dashboard/project-management/mange-ideas-tech-page.tsx
+++ b/app/components/dashboard/project-management/mange-ideas-tech-page.tsx
@@ -1,5 +1,5 @@
import { ChevronDown, ChevronUp, RefreshCw, Eye, Star, TrendingUp, Hexagon, Download } from "lucide-react";
-import { useCallback, useEffect, useRef, useState, useMemo } from "react";
+import { useCallback, useEffect, useRef, useState, useMemo, memo } from "react";
import toast from "react-hot-toast";
import { Badge } from "~/components/ui/badge";
import { Button } from "~/components/ui/button";
@@ -92,6 +92,135 @@ const columns: ColumnDef[] = [
{ key: "details", label: "جزئیات بیشتر", sortable: false, width: "120px" },
];
+// Memoized Vertical Bar Chart Component
+const VerticalBarChart = memo<{
+ chartData: IdeaStatusData[];
+ loadingChart: boolean;
+ chartConfig: ChartConfig;
+ getChartStatusColor: (status: string) => string;
+ toPersianDigits: (input: string | number) => string;
+ formatNumber: (value: number) => string;
+}>(({ chartData, loadingChart, chartConfig, getChartStatusColor, toPersianDigits, formatNumber }) => {
+ if (loadingChart) {
+ return (
+
+ {/* Chart title skeleton */}
+
+
+ {/* Chart area skeleton */}
+
+ {/* Y-axis labels */}
+
+ {Array.from({ length: 4 }).map((_, i) => (
+
+ ))}
+
+
+ {/* Bars skeleton */}
+
+ {Array.from({ length: 4 }).map((_, i) => (
+
+ {/* Bar */}
+
+ {/* X-axis label */}
+
+
+ ))}
+
+
+
+ );
+ }
+
+ if (!chartData.length) {
+ return (
+
+
وضعیت ایده ها
+
هیچ دادهای یافت نشد
+
+ );
+ }
+
+ // Prepare data for recharts
+ const rechartData = useMemo(() => chartData.map((item) => ({
+ status: item.idea_status,
+ count: item.idea_status_count,
+ fill: getChartStatusColor(item.idea_status),
+ })), [chartData, getChartStatusColor]);
+
+ return (
+
+
+
+
+
+ toPersianDigits(value)}
+ label={{
+ value: "تعداد برنامه ها",
+ angle: -90,
+ position: "insideLeft",
+ fill: "#94a3b8",
+ fontSize: 11,
+ offset: 0,
+ dy: 0,
+ style: { textAnchor: "middle" },
+ }}
+ />
+
+ `${formatNumber(Math.round(v))}`}
+ />
+
+
+
+
+ );
+});
+
+const MemoizedVerticalBarChart = VerticalBarChart;
+
export function ManageIdeasTechPage() {
const [ideas, setIdeas] = useState([]);
const [loading, setLoading] = useState(false);
@@ -446,7 +575,7 @@ export function ManageIdeasTechPage() {
}
};
- const toPersianDigits = (input: string | number): string => {
+ const toPersianDigits = useCallback((input: string | number): string => {
const str = String(input);
const map: Record = {
"0": "۰",
@@ -461,7 +590,7 @@ export function ManageIdeasTechPage() {
"9": "۹",
};
return str.replace(/[0-9]/g, (d) => map[d] ?? d);
- };
+ }, []);
const formatDate = (dateString: string | null) => {
if (!dateString || dateString === "null" || dateString.trim() === "") {
@@ -492,15 +621,15 @@ export function ManageIdeasTechPage() {
};
// Chart configuration for shadcn/ui
- const chartConfig: ChartConfig = {
+ const chartConfig: ChartConfig = useMemo(() => ({
count: {
label: "تعداد",
},
- };
+ }), []);
// Color palette for idea status
// Specific colors for idea statuses
- const getChartStatusColor = (status: string) => {
+ const getChartStatusColor = useCallback((status: string) => {
switch (status) {
case "اجرا شده":
return "#69C8EA";
@@ -513,7 +642,7 @@ export function ManageIdeasTechPage() {
default:
return "#6B7280";
}
- };
+ }, []);
const statusColorPalette = ["#3AEA83", "#69C8EA", "#F76276", "#FFD700", "#A757FF", "#E884CE", "#C3BF8B", "#FB7185"];
@@ -601,124 +730,7 @@ export function ManageIdeasTechPage() {
}
};
- // Custom Vertical Bar Chart Component using shadcn/ui
- const VerticalBarChart = () => {
- if (loadingChart) {
- return (
-
- {/* Chart title skeleton */}
-
- {/* Chart area skeleton */}
-
- {/* Y-axis labels */}
-
- {Array.from({ length: 4 }).map((_, i) => (
-
- ))}
-
-
- {/* Bars skeleton */}
-
- {Array.from({ length: 4 }).map((_, i) => (
-
- {/* Bar */}
-
- {/* X-axis label */}
-
-
- ))}
-
-
-
- );
- }
-
- 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 (
@@ -727,7 +739,7 @@ style: { textAnchor: "middle" },
{/* People Ranking Table */}
-
+
رتبه بندی نوآوران
@@ -819,7 +831,7 @@ style: { textAnchor: "middle" },
{/* Main Ideas Table */}
-
+
لیست ایده ها
@@ -827,7 +839,7 @@ style: { textAnchor: "middle" },
@@ -941,10 +953,17 @@ style: { textAnchor: "middle" },
{/* Chart Section */}
-
-
+
+
-
+
{loadingStats ? (
diff --git a/app/components/dashboard/project-management/product-innovation-page.tsx b/app/components/dashboard/project-management/product-innovation-page.tsx
index c1c8679..7d1aa1b 100644
--- a/app/components/dashboard/project-management/product-innovation-page.tsx
+++ b/app/components/dashboard/project-management/product-innovation-page.tsx
@@ -672,9 +672,9 @@ export function ProductInnovationPage() {
return (
-
+
{/* Stats Cards */}
-
+
{/* Stats Grid */}
@@ -793,7 +793,7 @@ export function ProductInnovationPage() {
{/* Data Table */}
-
+