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;