From 380c0f43aa354d2e5be66244d782838bf06602c0 Mon Sep 17 00:00:00 2001 From: saeed0920 Date: Thu, 18 Sep 2025 10:29:45 +0330 Subject: [PATCH] refactor and fix the styles in ecosystem and process-innovation --- app/app.css | 1 + .../process-innovation-page.tsx | 246 +++++++++--------- app/components/ecosystem/info-panel.tsx | 132 +++++----- app/components/ecosystem/network-graph.tsx | 6 +- app/components/ui/base-card.tsx | 9 +- app/components/ui/custom-bar-chart.tsx | 50 ++-- app/routes/ecosystem.tsx | 19 +- 7 files changed, 230 insertions(+), 233 deletions(-) diff --git a/app/app.css b/app/app.css index 0c8c204..9202430 100644 --- a/app/app.css +++ b/app/app.css @@ -37,6 +37,7 @@ --color-pr-green : #3AEA83; --color-pr-blue : #69C8EA; --color-pr-red : #F76276; + --color-pr-gray : #3F415A; } html, diff --git a/app/components/dashboard/project-management/process-innovation-page.tsx b/app/components/dashboard/project-management/process-innovation-page.tsx index 83d5ca3..b7a3748 100644 --- a/app/components/dashboard/project-management/process-innovation-page.tsx +++ b/app/components/dashboard/project-management/process-innovation-page.tsx @@ -16,7 +16,7 @@ import { useCallback, useEffect, useRef, useState } from "react"; import toast from "react-hot-toast"; import { Badge } from "~/components/ui/badge"; import { Button } from "~/components/ui/button"; -import { Card, CardContent } from "~/components/ui/card"; +import { BaseCard } from "~/components/ui/base-card"; import { Checkbox } from "~/components/ui/checkbox"; import { CustomBarChart } from "~/components/ui/custom-bar-chart"; import { @@ -36,6 +36,7 @@ import { import apiService from "~/lib/api"; import { formatNumber } from "~/lib/utils"; import { DashboardLayout } from "../layout"; +import { Card , CardContent} from "~/components/ui/card"; moment.loadPersian({ usePersianDigits: true }); interface ProcessInnovationData { @@ -49,6 +50,11 @@ interface ProcessInnovationData { amount_currency_reduction: string; Reduce_rate_failure: string; observer: string; + // optional detailed fields returned by API + project_description?: string; + start_date?: string; + done_date?: string; + approved_budget?: string; } interface ProjectStats { @@ -152,7 +158,7 @@ export function ProcessInnovationPage() { stats.productionStopsPreventionSum ), description: "تن افزایش یافته", - icon: , + icon: CirclePause, color: "text-emerald-400", }, bottleneckremoval: { @@ -160,7 +166,7 @@ export function ProcessInnovationPage() { title: "رفع گلوگاه", value: formatNumber(stats.bottleneckRemovalCount), description: "تعداد رفع گلوگاه", - icon: , + icon: Funnel, color: "text-emerald-400", }, currencyreduction: { @@ -170,7 +176,7 @@ export function ProcessInnovationPage() { stats.currencyReductionSum.toFixed?.(0) ?? stats.currencyReductionSum ), description: "دلار کاهش یافته", - icon: , + icon: DollarSign , color: "text-emerald-400", }, frequentfailuresreduction: { @@ -181,7 +187,7 @@ export function ProcessInnovationPage() { stats.frequentFailuresReductionSum ), description: "مجموع درصد کاهش خرابی", - icon: , + icon: Wrench, color: "text-emerald-400", }, }); @@ -528,7 +534,7 @@ export function ProcessInnovationPage() { variant="ghost" size="sm" onClick={() => handleProjectDetails(item)} - className="text-emerald-400 hover:text-emerald-300 hover:bg-emerald-500/20 p-2 h-auto" + className="text-pr-green hover:text-emerald-300 underline-offset-4 underline font-normal hover:bg-emerald-500/20 p-2 h-auto" > جزئیات بیشتر @@ -541,18 +547,18 @@ export function ProcessInnovationPage() { ); case "project_no": return ( - + {String(value)} ); case "title": - return {String(value)}; + return {String(value)}; case "project_status": return (
+ {formatNumber(String(value))} ); @@ -590,106 +596,96 @@ export function ProcessInnovationPage() { {loading || statsLoading ? // Loading skeleton for stats cards - matching new design Array.from({ length: 4 }).map((_, index) => ( - - -
-
-
-
-
-
-
-
-
-
+ +
+
+
+
+
- - +
+
+
+
+
+ )) - : Object.entries(stateCard).map(([key, card]) => ( - - -
-
-

- {card.title} -

-
- {card.icon} + : Object.entries(stateCard).map(([key, card]) => { + // map percent values for each card key + const percentMap: Record = { + productionstopsprevention: stats.percentProductionStops, + bottleneckremoval: stats.percentBottleneckRemoval, + currencyreduction: stats.percentCurrencyReduction, + frequentfailuresreduction: stats.percentFailuresReduction, + }; + const percentValue = percentMap[key]; + + return ( + +
+
+
+

+ {(card.value)} +

+
+ {card.description} +
-
-

- {card.value} -

-

- {card.description} -

-
- - - ))} +
+ ); + })}
{/* Process Impacts Chart */} - - - - - + + +
{/* Data Table */} @@ -810,7 +806,7 @@ export function ProcessInnovationPage() { {/* Footer */} -
+
@@ -841,15 +837,15 @@ export function ProcessInnovationPage() { - + شرح پروژه
{/* Project Description */}
-

{selectedProjectDetails?.title}

-

+

{selectedProjectDetails?.title}

+

{selectedProjectDetails?.project_description || "-"}

@@ -859,11 +855,11 @@ export function ProcessInnovationPage() {
جزئیات پروژه
-

- +

+ زمان شروع:

- + {selectedProjectDetails?.start_date ? moment( selectedProjectDetails?.start_date, @@ -874,11 +870,11 @@ export function ProcessInnovationPage() {

-

- +

+ زمان پایان:

- + {selectedProjectDetails?.done_date ? moment( selectedProjectDetails?.done_date, @@ -889,27 +885,29 @@ export function ProcessInnovationPage() {

-

- +

+ هزینه برآورد شده:

- - {formatNumber( - Number( - selectedProjectDetails?.approved_budget.replaceAll( - ",", - "" + + {selectedProjectDetails?.approved_budget + ? formatNumber( + Number( + selectedProjectDetails.approved_budget.replaceAll( + ",", + "" + ) + ) ) - ) - ) || "-"} + : "-"}

-

- +

+ نفر مرتبط:

- + {selectedProjectDetails?.observer || "-"}

diff --git a/app/components/ecosystem/info-panel.tsx b/app/components/ecosystem/info-panel.tsx index d373924..4e5e1c8 100644 --- a/app/components/ecosystem/info-panel.tsx +++ b/app/components/ecosystem/info-panel.tsx @@ -401,21 +401,13 @@ export function InfoPanel({ selectedCompany }: InfoPanelProps) {
- + وضعیت زیست‌بوم فناوری و نوآوری - {/* Footer - MOU Count */} - {/* -
- تعداد تفاهم نامه ها - {formatNumber(counts.mou_count)} -
-
*/} - - + تعداد تفاهم نامه ها {formatNumber(counts.mou_count)} @@ -424,7 +416,7 @@ export function InfoPanel({ selectedCompany }: InfoPanelProps) { - + تعداد بازیگران {formatNumber(counts.actor_count)} @@ -433,7 +425,7 @@ export function InfoPanel({ selectedCompany }: InfoPanelProps) { {/* Actor Count Display */} - + تنوع بازیگران {/* Middle - Bar Chart */} @@ -454,58 +446,78 @@ export function InfoPanel({ selectedCompany }: InfoPanelProps) { {/* Area Chart Section */} - -
- + +
+ روند ایجاد بازیگران در طول سال‌ها
-
+
{processData.length > 0 ? ( - - - - - formatNumber(value)} - /> - - `سال ${formatPersianYear(value.toString())}` - } - formatter={(value) => [ - formatNumber(value), - "تعداد بازیگران", - ]} - /> - - - + + + + + + + + + + + + formatNumber(value)} + /> + } /> + + {/* ✅ Use gradient for fill */} + ( + + {/* Small circle */} + + {/* Year label above point */} + + {formatPersianYear(payload.year)} + + + )} + /> + + + ) : (
داده‌ای برای نمایش وجود ندارد diff --git a/app/components/ecosystem/network-graph.tsx b/app/components/ecosystem/network-graph.tsx index aa133d2..9c05b67 100644 --- a/app/components/ecosystem/network-graph.tsx +++ b/app/components/ecosystem/network-graph.tsx @@ -508,7 +508,7 @@ export function NetworkGraph({ onNodeClick }: NetworkGraphProps) { // Don't render on server side if (!isMounted) { return ( -
+
در حال بارگذاری...
@@ -518,7 +518,7 @@ export function NetworkGraph({ onNodeClick }: NetworkGraphProps) { if (isLoading) { return ( -
+
{/* Skeleton Graph Container */}
{/* Center Node Skeleton */} @@ -579,7 +579,7 @@ export function NetworkGraph({ onNodeClick }: NetworkGraphProps) { } return ( -
+
); diff --git a/app/components/ui/base-card.tsx b/app/components/ui/base-card.tsx index 0aacd39..bb06dc5 100644 --- a/app/components/ui/base-card.tsx +++ b/app/components/ui/base-card.tsx @@ -7,6 +7,7 @@ interface BaseCardProps { headerClassName?: string; contentClassName?: string; children: React.ReactNode; + icon ?: React.ComponentType<{ className?: string }>; withHeader?: boolean; } @@ -17,6 +18,7 @@ export function BaseCard({ contentClassName, children, withHeader = false, + icon : Icon, }: BaseCardProps) { return ( - {withHeader && title ? ( + {Icon && title ? ( + + {title} {} + + ) : + withHeader && title ? ( {title} diff --git a/app/components/ui/custom-bar-chart.tsx b/app/components/ui/custom-bar-chart.tsx index dfc053d..7d09269 100644 --- a/app/components/ui/custom-bar-chart.tsx +++ b/app/components/ui/custom-bar-chart.tsx @@ -67,76 +67,56 @@ export function CustomBarChart({ return (
-
- {title && ( -

+ {title &&
+ +

{title}

- )} -
+

}
{data.map((item, index) => { const percentage = globalMaxValue > 0 ? (item.value / globalMaxValue) * 100 : 0; const displayValue: any = item.value; - return (
- {/* Label */} {item.label} - - {/* Bar Container */}
- {/* Add a subtle gradient effect for better visual appeal */} -
+
-
- - {/* Value Label */} {item.valuePrefix || ""} - {formatNumber(parseFloat(displayValue))}% + {formatNumber(parseFloat(displayValue))} {item.valueSuffix || ""} +
); })} {/* Axis Labels */} {showAxisLabels && globalMaxValue > 0 && ( -
- +
+
{formatNumber(0)} @@ -152,7 +132,7 @@ export function CustomBarChart({ {formatNumber(Math.round(globalMaxValue))}
- +
)}
diff --git a/app/routes/ecosystem.tsx b/app/routes/ecosystem.tsx index 866c5fa..5fda44b 100644 --- a/app/routes/ecosystem.tsx +++ b/app/routes/ecosystem.tsx @@ -76,8 +76,8 @@ export default function EcosystemPage() {
- - + + @@ -92,11 +92,10 @@ export default function EcosystemPage() { > - + معرفی {selectedCompany?.category} -
@@ -109,7 +108,7 @@ export default function EcosystemPage() { {selectedCompany?.label { // Hide image and show fallback on error e.currentTarget.style.display = "none"; @@ -147,7 +146,7 @@ export default function EcosystemPage() {
{selectedCompany?.description ? (
-

+

{selectedCompany.description}

@@ -159,22 +158,22 @@ export default function EcosystemPage() {
{/* Left Column - Company Fields */}
-

+

اطلاعات {selectedCompany?.category}

{selectedCompany?.fields && selectedCompany.fields.length > 0 ? ( -
+
{selectedCompany.fields.map((field, index) => (
- + {field.N}: - + {handleValue(field.V)} {field.U && ({field.U})}