From 911df127fd16bf07d7e814473a72e723fbe1beb7 Mon Sep 17 00:00:00 2001 From: MehrdadAdabi <126083584+mehrdadAdabi@users.noreply.github.com> Date: Fri, 22 Aug 2025 20:50:39 +0330 Subject: [PATCH 1/5] feat: create page and component --- .../digital-innovation-page.tsx | 1034 +++ .../process-innovation-page.tsx | 135 +- app/components/dashboard/sidebar.tsx | 20 +- app/components/ui/custom-bar-chart.tsx | 51 +- app/routes.ts | 9 +- app/routes/digital-innovation-page.tsx | 17 + app/routes/project-management.tsx | 2 +- package-lock.json | 6859 +++++++++++++++++ package.json | 2 +- 9 files changed, 8022 insertions(+), 107 deletions(-) create mode 100644 app/components/dashboard/project-management/digital-innovation-page.tsx create mode 100644 app/routes/digital-innovation-page.tsx create mode 100644 package-lock.json diff --git a/app/components/dashboard/project-management/digital-innovation-page.tsx b/app/components/dashboard/project-management/digital-innovation-page.tsx new file mode 100644 index 0000000..fd43216 --- /dev/null +++ b/app/components/dashboard/project-management/digital-innovation-page.tsx @@ -0,0 +1,1034 @@ +import { useState, useEffect, useCallback, useRef } from "react"; +import { DashboardLayout } from "../layout"; +import { Card, CardContent } from "~/components/ui/card"; +import { Button } from "~/components/ui/button"; +import { Badge } from "~/components/ui/badge"; +import { Checkbox } from "~/components/ui/checkbox"; +import moment from "moment-jalaali"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "~/components/ui/table"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from "~/components/ui/dialog"; +import { + ChevronUp, + ChevronDown, + RefreshCw, + Building2, + PickaxeIcon, + UserIcon, + UsersIcon, +} from "lucide-react"; +import apiService from "~/lib/api"; +import toast from "react-hot-toast"; +import { + Database, + Zap, + TrendingDown, + TrendingUp, + Key, + Sprout, + BrainCircuit, + LoaderCircle, +} from "lucide-react"; +import { CustomBarChart } from "~/components/ui/custom-bar-chart"; + +moment.loadPersian({ usePersianDigits: true }); + +interface SortConfig { + field: string; + direction: "asc" | "desc"; +} + +interface StatsCard { + id: string; + title: string; + value: string; + description?: string; + icon: React.ReactNode; + color: string; +} + +// Raw API response interface for digital innovation metrics +interface DigitalInnovationMetrics { + count_innovation_digital_projects: string; + increased_revenue: string; + increased_revenue_percent: string; + reduce_costs: string; + reduce_costs_percent: string; + reduce_energy_consumption: string; + reduce_energy_consumption_percent: string; + resource_productivity: string; + resource_productivity_percent: string; +} + +// Normalized interface for digital innovation stats +interface DigitalInnovationStats { + totalDigitalProjects: number; + increasedRevenue: number; + increasedRevenuePercent: number; + reduceCosts: number; + reduceCostsPercent: number; + reduceEnergyConsumption: number; + reduceEnergyConsumptionPercent: number; + resourceProductivity: number; + resourceProductivityPercent: number; +} + +enum DigitalCardLabel { + decreasCost = "کاهش هزینه‌ها", + increaseRevenue = "افزایش درآمد", + performance = "بهره‌وری منابع", + decreaseEnergy = "کاهش مصرف انرژی", +} + +interface ProcessInnovationData { + project_no: string; + title: string; + project_status: string; + project_rating: string; + project_description: string; +} + +const columns = [ + // { key: "select", label: "", sortable: false, width: "50px" }, + { key: "project_no", label: "شماره پروژه", sortable: true, width: "140px" }, + { key: "title", label: "عنوان پروژه", sortable: true, width: "400px" }, + { + key: "project_status", + label: "وضعیت پروژه", + sortable: true, + width: "140px", + }, + { + key: "project_rating", + label: "امتیاز پروژه", + sortable: true, + width: "140px", + }, +]; + +export function DigitalInnovationPage() { + const [projects, setProjects] = useState([]); + const [loading, setLoading] = useState(false); + const [loadingMore, setLoadingMore] = useState(false); + const [currentPage, setCurrentPage] = useState(1); + const [pageSize] = useState(20); + const [hasMore, setHasMore] = useState(true); + const [totalCount, setTotalCount] = useState(0); + const [actualTotalCount, setActualTotalCount] = useState(0); + const [statsLoading, setStatsLoading] = useState(false); + const [stats, setStats] = useState({ + totalDigitalProjects: 0, + increasedRevenue: 0, + increasedRevenuePercent: 0, + reduceCosts: 0, + reduceCostsPercent: 0, + reduceEnergyConsumption: 0, + reduceEnergyConsumptionPercent: 0, + resourceProductivity: 0, + resourceProductivityPercent: 0, + }); + const [sortConfig, setSortConfig] = useState({ + field: "start_date", + direction: "asc", + }); + const [selectedProjects, setSelectedProjects] = useState>( + new Set() + ); + const [detailsDialogOpen, setDetailsDialogOpen] = useState(false); + // const [selectedProjectDetails, setSelectedProjectDetails] = + // useState(null); + const observerRef = useRef(null); + const fetchingRef = useRef(false); + + // Selection handlers + const handleSelectAll = () => { + if (selectedProjects.size === projects.length) { + setSelectedProjects(new Set()); + } else { + setSelectedProjects(new Set(projects.map((p: any) => p.project_no))); + } + }; + + // const handleSelectProject = (projectNo: string) => { + // const newSelected = new Set(selectedProjects); + // if (newSelected.has(projectNo)) { + // newSelected.delete(projectNo); + // } else { + // newSelected.add(projectNo); + // } + // setSelectedProjects(newSelected); + // }; + + // const handleProjectDetails = (project: ProcessInnovationData) => { + // console.log(project); + // // setSelectedProjectDetails(project); + // setDetailsDialogOpen(true); + // }; + + const formatNumber = (value: string | number) => { + if (!value) return "0"; + const numericValue = typeof value === "string" ? parseFloat(value) : value; + if (isNaN(numericValue)) return "0"; + return new Intl.NumberFormat("fa-IR").format(numericValue); + }; + + // Stats cards data - computed from projects data + const statsCards: StatsCard[] = [ + { + id: "production-stops-prevention", + title: DigitalCardLabel.decreasCost, + value: formatNumber(stats.reduceCosts.toFixed?.(1) ?? stats.reduceCosts), + description: "میلیون ریال کاهش یافته", + icon: , + color: "text-emerald-400", + }, + { + id: "bottleneck-removal", + title: DigitalCardLabel.increaseRevenue, + value: formatNumber(stats.increasedRevenue), + description: "میلیون ریال افزایش یافته", + icon: , + color: "text-emerald-400", + }, + + { + id: "currency-reduction", + title: DigitalCardLabel.performance, + value: formatNumber( + stats.resourceProductivity.toFixed?.(0) ?? stats.resourceProductivity + ), + description: "هزار تن صرفه جوریی شده", + icon: , + color: "text-emerald-400", + }, + { + id: "frequent-failures-reduction", + title: DigitalCardLabel.decreaseEnergy, + value: formatNumber( + stats.reduceEnergyConsumption.toFixed?.(1) ?? + stats.reduceEnergyConsumption + ), + description: "مگاوات کاهش یافته", + icon: , + color: "text-emerald-400", + }, + ]; + + const fetchTable = async (reset = false) => { + if (fetchingRef.current) { + return; + } + + try { + fetchingRef.current = true; + + if (reset) { + setLoading(true); + setCurrentPage(1); + } else { + setLoadingMore(true); + } + + const pageToFetch = reset ? 1 : currentPage; + + const response = await apiService.select({ + ProcessName: "project", + OutputFields: [ + "project_no", + "title", + "project_description", + "project_status", + "project_rating", + ], + Sorts: [["start_date", "asc"]], + Conditions: [["type_of_innovation", "=", "نوآوری دیجیتال"]], + Pagination: { PageNumber: pageToFetch, PageSize: pageSize }, + }); + + // console.log(JSON.parse(response.data)); + if (response.state === 0) { + const dataString = response.data; + if (dataString && typeof dataString === "string") { + try { + const parsedData = JSON.parse(dataString); + if (Array.isArray(parsedData)) { + if (reset) { + setProjects(parsedData); + setTotalCount(parsedData.length); + } else { + setProjects((prev) => [...prev, ...parsedData]); + setTotalCount((prev) => prev + parsedData.length); + } + setHasMore(parsedData.length === pageSize); + } else { + if (reset) { + setProjects([]); + setTotalCount(0); + } + setHasMore(false); + } + } catch (parseError) { + console.error("Error parsing project data:", parseError); + if (reset) { + setProjects([]); + setTotalCount(0); + } + setHasMore(false); + } + } else { + if (reset) { + setProjects([]); + setTotalCount(0); + } + setHasMore(false); + } + } else { + toast.error(response.message || "خطا در دریافت اطلاعات پروژه‌ها"); + if (reset) { + setProjects([]); + setTotalCount(0); + } + setHasMore(false); + } + } catch (error) { + console.error("Error fetching projects:", error); + toast.error("خطا در دریافت اطلاعات پروژه‌ها"); + if (reset) { + setProjects([]); + setTotalCount(0); + } + setHasMore(false); + } finally { + setLoading(false); + setLoadingMore(false); + fetchingRef.current = false; + } + }; + + const loadMore = useCallback(() => { + if (!loadingMore && hasMore && !loading) { + setCurrentPage((prev) => prev + 1); + } + }, [loadingMore, hasMore, loading]); + + useEffect(() => { + fetchTable(true); + fetchTotalCount(); + fetchStats(); + }, [sortConfig]); + + useEffect(() => { + if (currentPage > 1) { + fetchTable(false); + } + }, [currentPage]); + + useEffect(() => { + const scrollContainer = document.querySelector(".overflow-auto"); + + const handleScroll = () => { + if (!scrollContainer || !hasMore || loadingMore) return; + + const { scrollTop, scrollHeight, clientHeight } = scrollContainer; + const scrollPercentage = (scrollTop + clientHeight) / scrollHeight; + + if (scrollPercentage >= 0.9) { + loadMore(); + } + }; + + if (scrollContainer) { + scrollContainer.addEventListener("scroll", handleScroll); + } + + return () => { + if (scrollContainer) { + scrollContainer.removeEventListener("scroll", handleScroll); + } + }; + }, [loadMore, hasMore, loadingMore]); + + const handleSort = (field: string) => { + fetchingRef.current = false; + setSortConfig((prev) => ({ + field, + direction: + prev.field === field && prev.direction === "asc" ? "desc" : "asc", + })); + setCurrentPage(1); + setProjects([]); + setHasMore(true); + }; + + const fetchTotalCount = async () => { + try { + const response = await apiService.select({ + ProcessName: "project", + OutputFields: ["count(project_no)"], + Conditions: [["type_of_innovation", "=", "نوآوری در فرآیند"]], + }); + + if (response.state === 0) { + const dataString = response.data; + if (dataString && typeof dataString === "string") { + try { + const parsedData = JSON.parse(dataString); + if (Array.isArray(parsedData) && parsedData[0]) { + const count = parsedData[0].project_no_count || 0; + setActualTotalCount(count); + // Keep stats in sync if backend stats not yet loaded + setStats((prev) => ({ ...prev, totalProjects: count })); + } + } catch (parseError) { + console.error("Error parsing count data:", parseError); + } + } + } + } catch (error) { + console.error("Error fetching total count:", error); + } + }; + + // Fetch aggregated stats from backend call API (innovation_process_function) + const fetchStats = async () => { + try { + setStatsLoading(true); + const raw = await apiService.callInnovationProcess({ + innovation_digital_function: {}, + }); + + let payload: DigitalInnovationMetrics = raw?.data; + if (typeof payload === "string") { + try { + payload = JSON.parse(payload); + } catch {} + } + + const parseNum = (v: unknown): number => { + if (v == null) return 0; + if (typeof v === "number") return v; + if (typeof v === "string") { + const cleaned = v.replace(/,/g, "").trim(); + const n = parseFloat(cleaned); + return isNaN(n) ? 0 : n; + } + return 0; + }; + + const normalized: DigitalInnovationStats = { + totalDigitalProjects: parseNum( + payload?.count_innovation_digital_projects + ), + increasedRevenue: parseNum(payload?.increased_revenue), + increasedRevenuePercent: parseNum(payload?.increased_revenue_percent), + reduceCosts: parseNum(payload?.reduce_costs), + reduceCostsPercent: parseNum(payload?.reduce_costs_percent), + reduceEnergyConsumption: parseNum(payload?.reduce_energy_consumption), + reduceEnergyConsumptionPercent: parseNum( + payload?.reduce_energy_consumption_percent + ), + resourceProductivity: parseNum(payload?.resource_productivity), + resourceProductivityPercent: parseNum( + payload?.resource_productivity_percent + ), + }; + + setStats(normalized); + } catch (error) { + console.error("Error fetching stats:", error); + } finally { + setStatsLoading(false); + } + }; + + const handleRefresh = () => { + fetchingRef.current = false; + setCurrentPage(1); + setProjects([]); + setHasMore(true); + fetchTable(true); + fetchTotalCount(); + fetchStats(); + }; + + const formatCurrency = (amount: string | number) => { + if (!amount) return "0 ریال"; + const numericAmount = + typeof amount === "string" + ? parseFloat(amount.replace(/,/g, "")) + : amount; + if (isNaN(numericAmount)) return "0 ریال"; + return new Intl.NumberFormat("fa-IR").format(numericAmount) + " ریال"; + }; + + const formatPercentage = (value: string | number) => { + if (!value) return "0%"; + const numericValue = typeof value === "string" ? parseFloat(value) : value; + if (isNaN(numericValue)) return "0%"; + return `${numericValue.toFixed(1)}%`; + }; + + const getStatusColor = (status: string) => { + switch (status?.toLowerCase()) { + case "فعال": + return "#3AEA83"; + case "متوقف": + return "#F76276"; + case "تکمیل شده": + return "#32CD32"; + default: + return "#6B7280"; + } + }; + + const getRatingColor = (rating: string) => { + const ratingNum = parseFloat(rating); + if (isNaN(ratingNum)) return "#6B7280"; + + if (ratingNum >= 8) return "#3AEA83"; + if (ratingNum >= 6) return "#69C8EA"; + if (ratingNum >= 4) return "#FFD700"; + return "#F76276"; + }; + + const renderCellContent = (item: any, column: any) => { + const value = item[column.key as keyof ProcessInnovationData]; + + switch (column.key) { + case "select": + return ( + handleSelectProject(item.project_no)} + className="data-[state=checked]:bg-emerald-600 data-[state=checked]:border-emerald-600" + /> + ); + case "details": + return ( + + ); + case "amount_currency_reduction": + return ( + + {formatCurrency(String(value))} + + ); + case "project_no": + return ( + + {String(value)} + + ); + case "title": + return {String(value)}; + case "project_status": + return ( + + {String(value)} + + ); + case "project_rating": + return ( + + {formatNumber(String(value))} + + ); + case "reduce_prevention_production_stops": + case "throat_removal": + case "Reduce_rate_failure": + return ( + + {formatNumber(String(value))} + + ); + default: + return {String(value) || "-"}; + } + }; + + return ( + +
+ {/* Stats Cards */} +
+
+ {/* Stats Grid */} +
+ {loading || statsLoading + ? // Loading skeleton for stats cards - matching new design + Array.from({ length: 4 }).map((_, index) => ( + + +
+
+
+
+
+
+
+
+
+
+
+
+ + + )) + : statsCards.map((card) => ( + setDetailsDialogOpen(true)} + key={card.id} + className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm border-gray-700/50" + > + +
+
+

+ {card.title} +

+
+ {card.icon} +
+
+
+

+ {card.value} +

+

+ {card.description} +

+
+
+
+
+ ))} +
+
+ + {/* Process Impacts Chart */} + + {/* */} + + {/* */} + +
+ + {/* Data Table */} + + +
+ + + + {columns.map((column) => ( + + {column.key === "select" ? ( +
+ 0 + } + onCheckedChange={handleSelectAll} + className="data-[state=checked]:bg-emerald-600 data-[state=checked]:border-emerald-600" + /> +
+ ) : column.sortable ? ( + + ) : ( + column.label + )} +
+ ))} +
+
+ + {loading ? ( + // Skeleton loading rows (compact) + Array.from({ length: 10 }).map((_, index) => ( + + {columns.map((column) => ( + +
+
+
+
+ + ))} + + )) + ) : projects.length === 0 ? ( + + + + هیچ پروژه‌ای یافت نشد + + + + ) : ( + projects.map((project, index) => ( + + {columns.map((column) => ( + + {renderCellContent(project, column)} + + ))} + + )) + )} + +
+
+ + {/* Infinite scroll trigger */} +
+ {loadingMore && ( +
+
+ + +
+
+ )} +
+
+ + {/* Footer */} +
+
+
+
+ {" "} + کل پروژه ها :{" "} + {formatNumber(stats.totalDigitalProjects || actualTotalCount)} +
+
+ {/* Project number column - empty */} +
+ {/* Title column - empty */} +
+ {/* Project status column - empty */} +
+ + + + +
+ {/* Project rating column - show average */} +
+
+ میانگین امتیاز :‌ +
+
+ {formatNumber( + ((stats.averageScore ?? 0) as number).toFixed?.(1) ?? + stats.averageScore ?? + 0 + )} +
+
+
+
+
+
+ + {/* Project Details Dialog */} + + + + + شرح پروژه + + +
+
+ + توسعه فناوری جدید در تولید پلی‌اتیلن + +

+ در این پروژه، هدف اصلی طراحی یک نقشه راه جامع برای تحول دیجیتال + در صنعت پتروشیمی بوده است. با توجه به روند سریع تغییرات + تکنولوژیکی و رقابت فزاینده در بازار، این پروژه به شناسایی و + پیاده‌سازی استراتژی‌های دیجیتال برای بهینه‌سازی فرآیندهای تولید، + مدیریت منابع، و ارتقاء بهره‌وری در واحدهای مختلف پتروشیمی + پرداخته است. در این پروژه، هدف اصلی طراحی یک نقشه راه جامع برای + تحول دیجیتال در صنعت پتروشیمی بوده است. با توجه به روند سریع + تغییرات تکنولوژیکی و رقابت فزاینده در بازار، این پروژه به + شناسایی و پیاده‌سازی استراتژی‌های دیجیتال برای بهینه‌سازی + فرآیندهای تولید، مدیریت منابع، و ارتقاء بهره‌وری در واحدهای + مختلف پتروشیمی پرداخته است. +

+
+ ویژگی های اصلی پروژه: +
+
+
+ + + شایستگی دیجیتال: + +
+ + شایستگی­ های کلیدی محدود + +
+
+
+ + + اصالت راهکار دیجیتال: + +
+ + بدون تغییر کپی شده + +
+
+
+ + + المان های بلوغ دیجیتال: + +
+ + دیجیتال کردن ارائه اطلاعات + +
+
+
+
+
+
+ + توسعه قابلیت های دیجیتال:{" "} + +
+
+ + قابلیت شماره یک +
+
+ + قابلیت شماره یک +
+
+ + قابلیت شماره یک +
+
+
+ +
+ + توسعه قابلیت های دیجیتال:{" "} + +
+
+ + قابلیت شماره یک +
+
+ + قابلیت شماره یک +
+
+ + قابلیت شماره یک +
+
+
+
+ + توسعه قابلیت های دیجیتال:{" "} + +
+
+ + قابلیت شماره یک +
+
+ + قابلیت شماره یک +
+
+ + قابلیت شماره یک +
+
+
+
+
+
+
+ + کاهش هزینه ها + + +
+
+ + 10% + + + درصد به کل هزینه ها + +
+ +
+ + ۱۰,۲۳۰ + + + میلیون ریال + +
+
+
+
+
+
+
+
+
+ + ); +} + +export default DigitalInnovationPage; diff --git a/app/components/dashboard/project-management/process-innovation-page.tsx b/app/components/dashboard/project-management/process-innovation-page.tsx index 0190f3b..36e9d59 100644 --- a/app/components/dashboard/project-management/process-innovation-page.tsx +++ b/app/components/dashboard/project-management/process-innovation-page.tsx @@ -34,7 +34,6 @@ import { import apiService from "~/lib/api"; import toast from "react-hot-toast"; import { Funnel, Wrench, CirclePause, DollarSign } from "lucide-react"; -import ProjectDetail from "../projects/project-detail"; moment.loadPersian({ usePersianDigits: true }); interface ProcessInnovationData { @@ -169,7 +168,7 @@ export function ProcessInnovationPage() { title: "جلوگیری از توقفات تولید", value: formatNumber( stats.productionStopsPreventionSum.toFixed?.(1) ?? - stats.productionStopsPreventionSum, + stats.productionStopsPreventionSum, ), description: "ظرفیت افزایش یافته", icon: , @@ -199,7 +198,7 @@ export function ProcessInnovationPage() { title: "کاهش خرابیهای پرتکرار", value: formatNumber( stats.frequentFailuresReductionSum.toFixed?.(1) ?? - stats.frequentFailuresReductionSum, + stats.frequentFailuresReductionSum, ), description: "مجموع درصد کاهش خرابی", icon: , @@ -402,7 +401,7 @@ export function ProcessInnovationPage() { if (typeof payload === "string") { try { payload = JSON.parse(payload); - } catch {} + } catch { } } const parseNum = (v: unknown): number => { @@ -575,67 +574,67 @@ export function ProcessInnovationPage() {
{loading || statsLoading ? // Loading skeleton for stats cards - matching new design - Array.from({ length: 4 }).map((_, index) => ( - - -
-
-
-
-
-
-
-
-
-
+ Array.from({ length: 4 }).map((_, index) => ( + + +
+
+
+
+
- - - )) +
+
+
+
+
+ + + )) : statsCards.map((card) => ( - - -
-
-

- {card.title} -

-
- {card.icon} -
-
-
-

- {card.value} -

-

- {card.description} -

+ + +
+
+

+ {card.title} +

+
+ {card.icon}
- - - ))} +
+

+ {card.value} +

+

+ {card.description} +

+
+
+
+
+ ))}
@@ -842,8 +841,8 @@ export function ProcessInnovationPage() {
{formatNumber( ((stats.averageScore ?? 0) as number).toFixed?.(1) ?? - stats.averageScore ?? - 0, + stats.averageScore ?? + 0, )}
@@ -883,9 +882,9 @@ export function ProcessInnovationPage() { {selectedProjectDetails?.start_date ? moment( - selectedProjectDetails?.start_date, - "YYYY-MM-DD", - ).format("YYYY/MM/DD") + selectedProjectDetails?.start_date, + "YYYY-MM-DD", + ).format("YYYY/MM/DD") : "-"}
@@ -898,9 +897,9 @@ export function ProcessInnovationPage() { {selectedProjectDetails?.done_date ? moment( - selectedProjectDetails?.done_date, - "YYYY-MM-DD", - ).format("YYYY/MM/DD") + selectedProjectDetails?.done_date, + "YYYY-MM-DD", + ).format("YYYY/MM/DD") : "-"}
diff --git a/app/components/dashboard/sidebar.tsx b/app/components/dashboard/sidebar.tsx index 44e887b..9585803 100644 --- a/app/components/dashboard/sidebar.tsx +++ b/app/components/dashboard/sidebar.tsx @@ -149,7 +149,7 @@ export function Sidebar({ React.useEffect(() => { const autoExpandParents = () => { const newExpandedItems: string[] = []; - + menuItems.forEach((item) => { if (item.children) { const hasActiveChild = item.children.some( @@ -160,10 +160,10 @@ export function Sidebar({ } } }); - + setExpandedItems(newExpandedItems); }; - + autoExpandParents(); }, [location.pathname]); @@ -200,8 +200,8 @@ export function Sidebar({ const renderMenuItem = (item: MenuItem, level = 0) => { const isActive = isActiveRoute(item.href, item.children); - const isExpanded = expandedItems.includes(item.id) || - (item.children && item.children.some(child => + const isExpanded = expandedItems.includes(item.id) || + (item.children && item.children.some(child => child.href && location.pathname === child.href )); const hasChildren = item.children && item.children.length > 0; @@ -265,14 +265,14 @@ export function Sidebar({
) : ( - @@ -554,15 +595,16 @@ export function DigitalInnovationPage() { return {String(value)}; case "project_status": return ( - +
+ {String(value)} - +
); case "project_rating": return ( @@ -583,6 +625,14 @@ export function DigitalInnovationPage() { } }; + const calculateAverage = (data: Array) => { + let number = 0; + data.map( + (item: ProcessInnovationData) => (number = number + +item.project_rating) + ); + setAvarage(number / data.length); + }; + return (
@@ -700,7 +750,7 @@ export function DigitalInnovationPage() {
- +
{columns.map((column) => ( @@ -837,11 +887,7 @@ export function DigitalInnovationPage() { میانگین امتیاز :‌
- {formatNumber( - ((stats.averageScore ?? 0) as number).toFixed?.(1) ?? - stats.averageScore ?? - 0 - )} + {formatNumber(((avarage ?? 0) as number).toFixed?.(1) ?? 0)}
@@ -876,7 +922,7 @@ export function DigitalInnovationPage() { - شایستگی­ های کلیدی محدود + {dialogInfo?.digital_capability}
@@ -887,7 +933,7 @@ export function DigitalInnovationPage() {
- بدون تغییر کپی شده + {dialogInfo?.digital_competence}
@@ -901,15 +947,15 @@ export function DigitalInnovationPage() {
- دیجیتال کردن ارائه اطلاعات + {dialogInfo?.digital_puberty_elements} -
+
- + توسعه قابلیت های دیجیتال:{" "}
@@ -918,28 +964,16 @@ export function DigitalInnovationPage() { size={"1.2rem"} className="text-emerald-400" /> - قابلیت شماره یک -
-
- - قابلیت شماره یک -
-
- - قابلیت شماره یک + + {dialogInfo?.digital_capability} +
- - توسعه قابلیت های دیجیتال:{" "} + + برنامه های عملیاتی مرتبط:
@@ -947,27 +981,15 @@ export function DigitalInnovationPage() { size={"1.2rem"} className="text-emerald-400" /> - قابلیت شماره یک -
-
- - قابلیت شماره یک -
-
- - قابلیت شماره یک + + {dialogInfo?.operational_plan} +
- - توسعه قابلیت های دیجیتال:{" "} + + استراتژی های مورد نظر:
@@ -975,22 +997,24 @@ export function DigitalInnovationPage() { size={"1.2rem"} className="text-emerald-400" /> - قابلیت شماره یک + + {dialogInfo?.desired_strategy} +
-
+ {/*
قابلیت شماره یک -
-
+
*/} + {/*
قابلیت شماره یک -
+
*/}
@@ -1004,7 +1028,14 @@ export function DigitalInnovationPage() {
- 10% + %{" "} + {formatNumber( + ( + Math.round( + dialogInfo?.reduce_costs_percent! * 100 + ) / 100 + ).toFixed(2) + )} درصد به کل هزینه ها @@ -1013,7 +1044,7 @@ export function DigitalInnovationPage() {
- ۱۰,۲۳۰ + {formatNumber(+dialogInfo?.innovation_cost_reduction!)} میلیون ریال diff --git a/app/components/ui/table.tsx b/app/components/ui/table.tsx index 6ba984a..d5eae2e 100644 --- a/app/components/ui/table.tsx +++ b/app/components/ui/table.tsx @@ -11,7 +11,7 @@ const Table = React.forwardRef(
-- 2.46.0.windows.1