fix: bugs and chnage some logic
This commit is contained in:
parent
c31eba3c19
commit
ac1081cdd2
|
|
@ -15,6 +15,7 @@ import moment from "moment-jalaali";
|
||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { Badge } from "~/components/ui/badge";
|
import { Badge } from "~/components/ui/badge";
|
||||||
|
import { BaseCard } from "~/components/ui/base-card";
|
||||||
import { Button } from "~/components/ui/button";
|
import { Button } from "~/components/ui/button";
|
||||||
import { Card, CardContent } from "~/components/ui/card";
|
import { Card, CardContent } from "~/components/ui/card";
|
||||||
import { Checkbox } from "~/components/ui/checkbox";
|
import { Checkbox } from "~/components/ui/checkbox";
|
||||||
|
|
@ -763,12 +764,12 @@ export function DigitalInnovationPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Process Impacts Chart */}
|
{/* Process Impacts Chart */}
|
||||||
<Card className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm rounded-lg w-full overflow-hidden h-[18rem]">
|
<BaseCard className="rounded-xl w-full overflow-hidden">
|
||||||
{/* <CardContent > */}
|
{/* <CardContent > */}
|
||||||
<CustomBarChart
|
<CustomBarChart
|
||||||
title="تاثیرات نوآوری دیجیتال به صورت درصد مقایسه ای"
|
title="تاثیرات نوآوری دیجیتال به صورت درصد مقایسه ای"
|
||||||
loading={statsLoading}
|
loading={statsLoading}
|
||||||
height="100%"
|
// height="100%"
|
||||||
data={[
|
data={[
|
||||||
{
|
{
|
||||||
label: DigitalCardLabel.decreasCost,
|
label: DigitalCardLabel.decreasCost,
|
||||||
|
|
@ -798,8 +799,7 @@ export function DigitalInnovationPage() {
|
||||||
barHeight="h-5"
|
barHeight="h-5"
|
||||||
showAxisLabels={true}
|
showAxisLabels={true}
|
||||||
/>
|
/>
|
||||||
{/* </CardContent> */}
|
</BaseCard>
|
||||||
</Card>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Data Table */}
|
{/* Data Table */}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ import {
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import moment from "moment-jalaali";
|
import moment from "moment-jalaali";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
|
import { MetricCard } from "~/components/ui/metric-card";
|
||||||
import { useStoredDate } from "~/hooks/useStoredDate";
|
import { useStoredDate } from "~/hooks/useStoredDate";
|
||||||
import apiService from "~/lib/api";
|
import apiService from "~/lib/api";
|
||||||
import { formatCurrency } from "~/lib/utils";
|
import { formatCurrency } from "~/lib/utils";
|
||||||
|
|
@ -519,13 +520,13 @@ export function GreenInnovationPage() {
|
||||||
},
|
},
|
||||||
|
|
||||||
pollution: {
|
pollution: {
|
||||||
value: formatNumber(parseNum(stats.pollution_reduction)),
|
value: parseNum(stats.pollution_reduction),
|
||||||
percent: formatNumber(parseNum(stats.pollution_reduction_percent)),
|
percent: parseNum(stats.pollution_reduction_percent),
|
||||||
},
|
},
|
||||||
|
|
||||||
waste: {
|
waste: {
|
||||||
value: formatNumber(parseNum(stats.waste_reduction)),
|
value: parseNum(stats.waste_reduction),
|
||||||
percent: formatNumber(parseNum(stats.waste_reductionn_percent)),
|
percent: parseNum(stats.waste_reductionn_percent),
|
||||||
},
|
},
|
||||||
avarage: stats.average_project_score,
|
avarage: stats.average_project_score,
|
||||||
countInnovationGreenProjects: stats.count_innovation_green_projects,
|
countInnovationGreenProjects: stats.count_innovation_green_projects,
|
||||||
|
|
@ -543,7 +544,6 @@ export function GreenInnovationPage() {
|
||||||
setStatsLoading(false);
|
setStatsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const setPageData = (normalized: any) => {
|
const setPageData = (normalized: any) => {
|
||||||
setSustainabilityStats((prev) => ({
|
setSustainabilityStats((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
|
|
@ -747,39 +747,14 @@ export function GreenInnovationPage() {
|
||||||
</Card>
|
</Card>
|
||||||
))
|
))
|
||||||
: Object.entries(sustainabilityStats).map(([key, value]) => (
|
: Object.entries(sustainabilityStats).map(([key, value]) => (
|
||||||
<Card
|
<MetricCard
|
||||||
key={key}
|
key={key}
|
||||||
className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] rounded-lg backdrop-blur-sm border-gray-700/50"
|
title={value.title}
|
||||||
>
|
value={Math.round(value.total.value || 0)}
|
||||||
<CardContent className="p-0 h-full">
|
valueLabel={value.total?.description}
|
||||||
<div className="flex flex-col justify-between gap-2 h-full">
|
percentValue={value.percent?.value || 0}
|
||||||
<div className="flex justify-between items-center border-b-2 border-gray-500/20 ">
|
percentLabel={value.percent?.description}
|
||||||
<h3 className="text-lg font-bold text-white font-persian p-4">
|
/>
|
||||||
{value.title}
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center justify-between p-6 flex-row-reverse">
|
|
||||||
<div className="flex flex-col">
|
|
||||||
<span className="text-3xl font-bold text-pr-green mb-1 font-persian">
|
|
||||||
% {value.percent?.value}
|
|
||||||
</span>
|
|
||||||
<span className="text-sm text-gray-400 font-persian">
|
|
||||||
{value.percent?.description}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<b className="block w-0.5 h-8 bg-gray-600 rotate-45" />
|
|
||||||
<div className="flex flex-col">
|
|
||||||
<span className="text-3xl font-bold text-pr-green mb-1 font-persian">
|
|
||||||
{value.total?.value}
|
|
||||||
</span>
|
|
||||||
<span className="text-sm text-gray-400 font-persian">
|
|
||||||
{value.total?.description}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import {
|
||||||
ResponsiveContainer,
|
ResponsiveContainer,
|
||||||
XAxis,
|
XAxis,
|
||||||
} from "recharts";
|
} from "recharts";
|
||||||
|
import { MetricCard } from "~/components/ui/metric-card";
|
||||||
import { useStoredDate } from "~/hooks/useStoredDate";
|
import { useStoredDate } from "~/hooks/useStoredDate";
|
||||||
import apiService from "~/lib/api";
|
import apiService from "~/lib/api";
|
||||||
import { EventBus, formatCurrency, formatNumber } from "~/lib/utils";
|
import { EventBus, formatCurrency, formatNumber } from "~/lib/utils";
|
||||||
|
|
@ -523,15 +524,13 @@ export function InnovationBuiltInsidePage() {
|
||||||
const stats = data[0];
|
const stats = data[0];
|
||||||
const normalized: any = {
|
const normalized: any = {
|
||||||
currencySaving: {
|
currencySaving: {
|
||||||
value: formatNumber(parseNum(stats?.foreign_currency_saving)),
|
value: parseNum(stats?.foreign_currency_saving),
|
||||||
percent: formatNumber(
|
percent: parseNum(stats?.foreign_currency_saving_percent),
|
||||||
parseNum(stats?.foreign_currency_saving_percent)
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
investmentAmount: {
|
investmentAmount: {
|
||||||
value: formatNumber(parseNum(stats?.investment_amount)),
|
value: parseNum(stats?.investment_amount),
|
||||||
percent: formatNumber(parseNum(stats?.investment_amount_percent)),
|
percent: parseNum(stats?.investment_amount_percent),
|
||||||
},
|
},
|
||||||
|
|
||||||
technology: {
|
technology: {
|
||||||
|
|
@ -755,39 +754,47 @@ export function InnovationBuiltInsidePage() {
|
||||||
</Card>
|
</Card>
|
||||||
))
|
))
|
||||||
: Object.entries(sustainabilityStats).map(([key, value]) => (
|
: Object.entries(sustainabilityStats).map(([key, value]) => (
|
||||||
<Card
|
<MetricCard
|
||||||
key={key}
|
key={key}
|
||||||
className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] rounded-lg backdrop-blur-sm border-gray-700/50"
|
title={value.title}
|
||||||
>
|
value={Math.round(value.total.value || 0)}
|
||||||
<CardContent className="p-0 h-full">
|
valueLabel={value.total?.description}
|
||||||
<div className="flex flex-col justify-between gap-2 h-full">
|
percentValue={value.percent?.value || 0}
|
||||||
<div className="flex justify-between items-center border-b-2 border-gray-500/20 ">
|
percentLabel={value.percent?.description}
|
||||||
<h3 className="text-lg font-semibold text-white p-4">
|
/>
|
||||||
{value.title}
|
// <Card
|
||||||
</h3>
|
// key={key}
|
||||||
</div>
|
// className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] rounded-lg backdrop-blur-sm border-gray-700/50"
|
||||||
<div className="flex items-center justify-between p-6 flex-row-reverse">
|
// >
|
||||||
<div className="flex flex-col">
|
// <CardContent className="p-0 h-full">
|
||||||
<span className="text-3xl font-bold text-pr-green mb-1 font-persian">
|
// <div className="flex flex-col justify-between gap-2 h-full">
|
||||||
% {value.percent?.value}
|
// <div className="flex justify-between items-center border-b-2 border-gray-500/20 ">
|
||||||
</span>
|
// <h3 className="text-lg font-semibold text-white p-4">
|
||||||
<span className="text-sm text-gray-400 font-persian">
|
// {value.title}
|
||||||
{value.percent?.description}
|
// </h3>
|
||||||
</span>
|
// </div>
|
||||||
</div>
|
// <div className="flex items-center justify-between p-6 flex-row-reverse">
|
||||||
<b className="block w-0.5 h-8 bg-gray-600 rotate-45" />
|
// <div className="flex flex-col">
|
||||||
<div className="flex flex-col">
|
// <span className="text-3xl font-bold text-pr-green mb-1 font-persian">
|
||||||
<span className="text-3xl font-bold text-pr-green mb-1 font-persian">
|
// % {value.percent?.value}
|
||||||
{value.total?.value}
|
// </span>
|
||||||
</span>
|
// <span className="text-sm text-gray-400 font-persian">
|
||||||
<span className="text-sm text-gray-400 font-persian">
|
// {value.percent?.description}
|
||||||
{value.total?.description}
|
// </span>
|
||||||
</span>
|
// </div>
|
||||||
</div>
|
// <b className="block w-0.5 h-8 bg-gray-600 rotate-45" />
|
||||||
</div>
|
// <div className="flex flex-col">
|
||||||
</div>
|
// <span className="text-3xl font-bold text-pr-green mb-1 font-persian">
|
||||||
</CardContent>
|
// {value.total?.value}
|
||||||
</Card>
|
// </span>
|
||||||
|
// <span className="text-sm text-gray-400 font-persian">
|
||||||
|
// {value.total?.description}
|
||||||
|
// </span>
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
// </CardContent>
|
||||||
|
// </Card>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{statsLoading ? (
|
{statsLoading ? (
|
||||||
|
|
|
||||||
|
|
@ -187,11 +187,12 @@ export function ProcessInnovationPage() {
|
||||||
icon: DollarSign,
|
icon: DollarSign,
|
||||||
color: "text-pr-green",
|
color: "text-pr-green",
|
||||||
},
|
},
|
||||||
currencyreduction1: {
|
decreaseCurrencyOperation: {
|
||||||
id: "currencyreduction1",
|
id: "decreaseCurrencyOperation",
|
||||||
title: "کاهش هزینه عملیاتی",
|
title: "کاهش هزینه عملیاتی",
|
||||||
value: formatNumber(
|
value: formatNumber(
|
||||||
stats.reductionCostOprationSum.toFixed?.(0) ?? stats.reductionCostOprationSum
|
stats.reductionCostOprationSum.toFixed?.(0) ??
|
||||||
|
stats.reductionCostOprationSum
|
||||||
),
|
),
|
||||||
description: "میلیون ریال یافته",
|
description: "میلیون ریال یافته",
|
||||||
icon: DollarSign,
|
icon: DollarSign,
|
||||||
|
|
@ -213,15 +214,6 @@ export function ProcessInnovationPage() {
|
||||||
const observerRef = useRef<HTMLDivElement>(null);
|
const observerRef = useRef<HTMLDivElement>(null);
|
||||||
const fetchingRef = useRef(false);
|
const fetchingRef = useRef(false);
|
||||||
|
|
||||||
// Selection handlers
|
|
||||||
// const handleSelectAll = () => {
|
|
||||||
// if (selectedProjects.size === projects.length) {
|
|
||||||
// setSelectedProjects(new Set());
|
|
||||||
// } else {
|
|
||||||
// setSelectedProjects(new Set(projects.map((p) => p.project_no)));
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
const handleSelectProject = (projectNo: string) => {
|
const handleSelectProject = (projectNo: string) => {
|
||||||
const newSelected = new Set(selectedProjects);
|
const newSelected = new Set(selectedProjects);
|
||||||
if (newSelected.has(projectNo)) {
|
if (newSelected.has(projectNo)) {
|
||||||
|
|
@ -489,7 +481,8 @@ export function ProcessInnovationPage() {
|
||||||
currencyReductionSum: parseNum(stats?.sum_reduction_value_currency),
|
currencyReductionSum: parseNum(stats?.sum_reduction_value_currency),
|
||||||
frequentFailuresReductionSum: parseNum(stats?.sum_reducing_breakdowns),
|
frequentFailuresReductionSum: parseNum(stats?.sum_reducing_breakdowns),
|
||||||
percentProductionStops: stats?.percent_sum_stopping_production,
|
percentProductionStops: stats?.percent_sum_stopping_production,
|
||||||
percentOperatingCostBeforeInnovation: stats?.percent_operating_cost_before_innovation,
|
percentOperatingCostBeforeInnovation:
|
||||||
|
stats?.percent_operating_cost_before_innovation,
|
||||||
percentBottleneckRemoval: stats?.percent_throat_removal,
|
percentBottleneckRemoval: stats?.percent_throat_removal,
|
||||||
percentCurrencyReduction: stats?.percent_reduction_value_currency,
|
percentCurrencyReduction: stats?.percent_reduction_value_currency,
|
||||||
percentFailuresReduction: stats?.percent_reducing_breakdowns,
|
percentFailuresReduction: stats?.percent_reducing_breakdowns,
|
||||||
|
|
@ -512,6 +505,10 @@ export function ProcessInnovationPage() {
|
||||||
...prev.currencyreduction,
|
...prev.currencyreduction,
|
||||||
value: formatNumber(normalized.currencyReductionSum),
|
value: formatNumber(normalized.currencyReductionSum),
|
||||||
},
|
},
|
||||||
|
decreaseCurrencyOperation: {
|
||||||
|
...prev.decreaseCurrencyOperation,
|
||||||
|
value: formatNumber(normalized.reductionCostOprationSum),
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
setStats(normalized);
|
setStats(normalized);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -638,13 +635,14 @@ export function ProcessInnovationPage() {
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<div className="space-y-4 w-full">
|
<div className="space-y-4 w-full">
|
||||||
{/* Stats Grid */}
|
{/* Stats Grid */}
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="h-full">
|
||||||
{loading || statsLoading
|
{loading || statsLoading ? (
|
||||||
? // Loading skeleton for stats cards - matching new design
|
// Skeleton cards
|
||||||
Array.from({ length: 4 }).map((_, index) => (
|
<div className="flex flex-wrap justify-between gap-3">
|
||||||
|
{Array.from({ length: 6 }).map((_, index) => (
|
||||||
<BaseCard
|
<BaseCard
|
||||||
key={`skeleton-${index}`}
|
key={`skeleton-${index}`}
|
||||||
className="rounded-2xl overflow-hidden"
|
className="rounded-2xl overflow-hidden w-full sm:w-[48%] md:w-[30%]"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col justify-between gap-2">
|
<div className="flex flex-col justify-between gap-2">
|
||||||
<div className="flex justify-between items-center border-b-2 mx-4 border-gray-500/20">
|
<div className="flex justify-between items-center border-b-2 mx-4 border-gray-500/20">
|
||||||
|
|
@ -652,7 +650,7 @@ export function ProcessInnovationPage() {
|
||||||
className="h-6 bg-gray-600 rounded animate-pulse"
|
className="h-6 bg-gray-600 rounded animate-pulse"
|
||||||
style={{ width: "60%" }}
|
style={{ width: "60%" }}
|
||||||
/>
|
/>
|
||||||
<div className="p-3 rounded-full w-fit">
|
<div className="p-3 rounded-full w-fit">
|
||||||
<div className="w-6 h-6 bg-gray-600 rounded animate-pulse" />
|
<div className="w-6 h-6 bg-gray-600 rounded animate-pulse" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -668,42 +666,112 @@ export function ProcessInnovationPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</BaseCard>
|
</BaseCard>
|
||||||
))
|
))}
|
||||||
: Object.entries(stateCard).map(([key, card]) => {
|
</div>
|
||||||
// map percent values for each card key
|
) : (
|
||||||
const percentMap: Record<
|
<div className="flex flex-col h-full gap-5">
|
||||||
string,
|
<div className="flex flex-row gap-4 h-full">
|
||||||
number | string | undefined
|
<BaseCard
|
||||||
> = {
|
key={stateCard.bottleneckremoval.id}
|
||||||
productionstopsprevention: stats.percentProductionStops,
|
title={stateCard.bottleneckremoval.title}
|
||||||
bottleneckremoval: stats.percentBottleneckRemoval,
|
className="border-gray-700/50 w-full"
|
||||||
currencyreduction: stats.percentCurrencyReduction,
|
icon={stateCard.bottleneckremoval.icon}
|
||||||
frequentfailuresreduction: stats.percentFailuresReduction,
|
>
|
||||||
};
|
<div className="flex items-center justify-center flex-col">
|
||||||
const percentValue = percentMap[key];
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="text-center">
|
||||||
return (
|
<p className="text-3xl text-pr-green font-bold mb-1">
|
||||||
<BaseCard
|
{stateCard.bottleneckremoval.value}
|
||||||
key={card.id}
|
</p>
|
||||||
title={card.title}
|
<div className="text-[11px] text-[#ACACAC] font-light font-persian">
|
||||||
className="border-gray-700/50"
|
{stateCard.bottleneckremoval.description}
|
||||||
icon={card.icon}
|
|
||||||
>
|
|
||||||
<div className="flex items-center justify-center flex-col">
|
|
||||||
<div className="flex items-center gap-4">
|
|
||||||
<div className="text-center">
|
|
||||||
<p className="text-3xl text-pr-green font-bold mb-1">
|
|
||||||
{card.value}
|
|
||||||
</p>
|
|
||||||
<div className="text-[11px] text-[#ACACAC] font-light font-persian">
|
|
||||||
{card.description}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</BaseCard>
|
</div>
|
||||||
);
|
</BaseCard>
|
||||||
})}
|
|
||||||
|
<BaseCard
|
||||||
|
key={stateCard.currencyreduction.id}
|
||||||
|
title={stateCard.currencyreduction.title}
|
||||||
|
className="border-gray-700/50 w-full"
|
||||||
|
icon={stateCard.currencyreduction.icon}
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-center flex-col">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="text-center">
|
||||||
|
<p className="text-3xl text-pr-green font-bold mb-1">
|
||||||
|
{stateCard.currencyreduction.value}
|
||||||
|
</p>
|
||||||
|
<div className="text-[11px] text-[#ACACAC] font-light font-persian">
|
||||||
|
{stateCard.currencyreduction.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BaseCard>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row gap-4 h-full">
|
||||||
|
<BaseCard
|
||||||
|
key={stateCard.frequentfailuresreduction.id}
|
||||||
|
title={stateCard.frequentfailuresreduction.title}
|
||||||
|
className="border-gray-700/50 w-full"
|
||||||
|
icon={stateCard.frequentfailuresreduction.icon}
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-center flex-col">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="text-center">
|
||||||
|
<p className="text-3xl text-pr-green font-bold mb-1">
|
||||||
|
{stateCard.frequentfailuresreduction.value}
|
||||||
|
</p>
|
||||||
|
<div className="text-[11px] text-[#ACACAC] font-light font-persian">
|
||||||
|
{stateCard.frequentfailuresreduction.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BaseCard>
|
||||||
|
<BaseCard
|
||||||
|
key={stateCard.decreaseCurrencyOperation.id}
|
||||||
|
title={stateCard.decreaseCurrencyOperation.title}
|
||||||
|
className="border-gray-700/50 w-full"
|
||||||
|
icon={stateCard.decreaseCurrencyOperation.icon}
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-center flex-col">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="text-center">
|
||||||
|
<p className="text-3xl text-pr-green font-bold mb-1">
|
||||||
|
{stateCard.decreaseCurrencyOperation.value}
|
||||||
|
</p>
|
||||||
|
<div className="text-[11px] text-[#ACACAC] font-light font-persian">
|
||||||
|
{stateCard.decreaseCurrencyOperation.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BaseCard>
|
||||||
|
<BaseCard
|
||||||
|
key={stateCard.productionstopsprevention.id}
|
||||||
|
title={stateCard.productionstopsprevention.title}
|
||||||
|
className="border-gray-700/50 w-full"
|
||||||
|
icon={stateCard.productionstopsprevention.icon}
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-center flex-col">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="text-center">
|
||||||
|
<p className="text-3xl text-pr-green font-bold mb-1">
|
||||||
|
{stateCard.productionstopsprevention.value}
|
||||||
|
</p>
|
||||||
|
<div className="text-[11px] text-[#ACACAC] font-light font-persian">
|
||||||
|
{stateCard.productionstopsprevention.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BaseCard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -736,7 +804,8 @@ export function ProcessInnovationPage() {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "کاهش هزینه عملیاتی",
|
label: "کاهش هزینه عملیاتی",
|
||||||
value: Number(stats.percentOperatingCostBeforeInnovation) || 0,
|
value:
|
||||||
|
Number(stats.percentOperatingCostBeforeInnovation) || 0,
|
||||||
labelColor: "text-white",
|
labelColor: "text-white",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -745,7 +814,7 @@ export function ProcessInnovationPage() {
|
||||||
labelColor: "text-white",
|
labelColor: "text-white",
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
barHeight="h-6"
|
barHeight="h-5"
|
||||||
showAxisLabels={true}
|
showAxisLabels={true}
|
||||||
/>
|
/>
|
||||||
</BaseCard>
|
</BaseCard>
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,8 @@ export function NetworkGraph({
|
||||||
return await apiService.call<any>({
|
return await apiService.call<any>({
|
||||||
get_values_workflow_function: {
|
get_values_workflow_function: {
|
||||||
stage_id: stage_id,
|
stage_id: stage_id,
|
||||||
start_date: date?.start || null,
|
// start_date: date?.start || null,
|
||||||
end_date: date?.end || null,
|
// end_date: date?.end || null,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -194,7 +194,7 @@ export function NetworkGraph({
|
||||||
aborted = true;
|
aborted = true;
|
||||||
controller.abort();
|
controller.abort();
|
||||||
};
|
};
|
||||||
}, [isMounted, token, getImageUrl]);
|
}, [isMounted, token, getImageUrl, date]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isMounted || !svgRef.current || isLoading || nodes.length === 0)
|
if (!isMounted || !svgRef.current || isLoading || nodes.length === 0)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ interface BaseCardProps {
|
||||||
headerClassName?: string;
|
headerClassName?: string;
|
||||||
contentClassName?: string;
|
contentClassName?: string;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
icon ?: React.ComponentType<{ className?: string }>;
|
icon?: React.ComponentType<{ className?: string }>;
|
||||||
withHeader?: boolean;
|
withHeader?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -18,32 +18,44 @@ export function BaseCard({
|
||||||
contentClassName,
|
contentClassName,
|
||||||
children,
|
children,
|
||||||
withHeader = false,
|
withHeader = false,
|
||||||
icon : Icon,
|
icon: Icon,
|
||||||
}: BaseCardProps) {
|
}: BaseCardProps) {
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm py-4 grid items-center",
|
"bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm py-2 pb-0 grid items-center",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{Icon && title ? (
|
{Icon && title ? (
|
||||||
<CardHeader className={cn("border-b-2 border-gray-500/20 py-2 px-0 pb-4", headerClassName)}>
|
<CardHeader
|
||||||
<CardTitle className="text-white text-sm text-right font-persian px-4 my-auto items-center flex w-full justify-between">{title} {<Icon />} </CardTitle>
|
className={cn(
|
||||||
|
"border-b-2 border-gray-500/20 py-2 px-0 pb-4",
|
||||||
|
headerClassName
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<CardTitle className="text-white text-sm text-right font-persian px-4 my-auto items-center flex w-full justify-between">
|
||||||
|
{title} {<Icon />}{" "}
|
||||||
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
) :
|
) : withHeader && title ? (
|
||||||
withHeader && title ? (
|
<CardHeader
|
||||||
<CardHeader className={cn("pb-2 border-b-2 border-gray-500/20", headerClassName)}>
|
className={cn("pb-2 border-b-2 border-gray-500/20", headerClassName)}
|
||||||
<CardTitle className="text-white text-sm text-right font-persian px-4">{title}</CardTitle>
|
>
|
||||||
|
<CardTitle className="text-white text-sm text-right font-persian px-4">
|
||||||
|
{title}
|
||||||
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
) : title ? (
|
) : title ? (
|
||||||
<div className="border-b-2 border-gray-500/20 pb-2">
|
<div className="border-b-2 border-gray-500/20 pb-2">
|
||||||
<h3 className="text-sm font-bold text-white text-right font-persian px-4">{title}</h3>
|
<h3 className="text-sm font-bold text-white text-right font-persian px-4">
|
||||||
|
{title}
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<CardContent className={cn("py-2 px-4", contentClassName)}>
|
<CardContent className={cn("py-2 px-4 ", contentClassName)}>
|
||||||
{children}
|
{children}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ const Card = React.forwardRef<
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-lg border bg-card text-card-foreground shadow-sm ",
|
"rounded-lg border bg-card text-card-foreground shadow-sm",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ export function CustomBarChart({
|
||||||
// Loading skeleton
|
// Loading skeleton
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className={`space-y-6 p-4 ${className}`} style={{ height }}>
|
<div className={`space-y-6 p-4 pt-0 ${className}`} style={{ height }}>
|
||||||
{title && (
|
{title && (
|
||||||
<div className="h-7 bg-gray-600 rounded animate-pulse mb-4 w-1/2"></div>
|
<div className="h-7 bg-gray-600 rounded animate-pulse mb-4 w-1/2"></div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -71,7 +71,7 @@ export function CustomBarChart({
|
||||||
<div className={`space-y-6 ${className}`} style={{ height }}>
|
<div className={`space-y-6 ${className}`} style={{ height }}>
|
||||||
{title && (
|
{title && (
|
||||||
<div className="border-b-[#3F415A] border-b-2">
|
<div className="border-b-[#3F415A] border-b-2">
|
||||||
<h3 className="text-sm font-semibold text-white font-persian text-right p-4">
|
<h3 className="text-sm font-semibold text-white font-persian text-right px-4 pb-3">
|
||||||
{title}
|
{title}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -17,32 +17,32 @@ export function MetricCard({
|
||||||
percentLabel = "درصد به کل",
|
percentLabel = "درصد به کل",
|
||||||
}: MetricCardProps) {
|
}: MetricCardProps) {
|
||||||
return (
|
return (
|
||||||
<BaseCard title={title}>
|
<BaseCard title={title} className="h-full">
|
||||||
<div className="flex items-center justify-center flex-col">
|
<div className="flex items-center justify-center flex-col">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4 h-full">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<p className="text-3xl font-bold text-green-400">
|
<p className="text-3xl font-bold text-green-400">
|
||||||
{formatNumber(value)}
|
{formatNumber(value)}
|
||||||
</p>
|
</p>
|
||||||
<div className="text-xs text-gray-400 font-persian">
|
<div className="text-xs text-gray-400 font-persian">
|
||||||
{valueLabel}
|
{valueLabel}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{percentValue !== undefined && (
|
|
||||||
<>
|
|
||||||
<span className="text-5xl font-thin text-gray-600">/</span>
|
|
||||||
<div className="text-center">
|
|
||||||
<p className="text-3xl font-bold text-green-400">
|
|
||||||
{formatNumber(percentValue)}%
|
|
||||||
</p>
|
|
||||||
<div className="text-xs text-gray-400 font-persian">
|
|
||||||
{percentLabel}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</BaseCard>
|
{percentValue !== undefined && (
|
||||||
|
<>
|
||||||
|
<span className="text-5xl font-thin text-gray-600">/</span>
|
||||||
|
<div className="text-center">
|
||||||
|
<p className="text-3xl font-bold text-green-400">
|
||||||
|
{formatNumber(percentValue)}%
|
||||||
|
</p>
|
||||||
|
<div className="text-xs text-gray-400 font-persian">
|
||||||
|
{percentLabel}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BaseCard>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5140
package-lock.json
generated
Normal file
5140
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user