add popup for innvation ,also fix the zoom initial in graph popup
This commit is contained in:
parent
a51f8b3105
commit
ba7a2499f1
|
|
@ -5,6 +5,7 @@ import { Button } from "~/components/ui/button";
|
||||||
import { Badge } from "~/components/ui/badge";
|
import { Badge } from "~/components/ui/badge";
|
||||||
import { Checkbox } from "~/components/ui/checkbox";
|
import { Checkbox } from "~/components/ui/checkbox";
|
||||||
import { CustomBarChart } from "~/components/ui/custom-bar-chart";
|
import { CustomBarChart } from "~/components/ui/custom-bar-chart";
|
||||||
|
import moment from "moment-jalaali";
|
||||||
import type { BarChartData } from "~/components/ui/custom-bar-chart";
|
import type { BarChartData } from "~/components/ui/custom-bar-chart";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
|
|
@ -25,11 +26,17 @@ import {
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
RefreshCw,
|
RefreshCw,
|
||||||
ExternalLink,
|
ExternalLink,
|
||||||
|
Building2,
|
||||||
|
PickaxeIcon,
|
||||||
|
UserIcon,
|
||||||
|
UsersIcon,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import apiService from "~/lib/api";
|
import apiService from "~/lib/api";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import {Funnel, Wrench , CirclePause , DollarSign} from "lucide-react"
|
import { Funnel, Wrench, CirclePause, DollarSign } from "lucide-react";
|
||||||
|
import ProjectDetail from "../projects/project-detail";
|
||||||
|
|
||||||
|
moment.loadPersian({ usePersianDigits: true });
|
||||||
interface ProcessInnovationData {
|
interface ProcessInnovationData {
|
||||||
project_no: string;
|
project_no: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
|
@ -39,6 +46,7 @@ interface ProcessInnovationData {
|
||||||
throat_removal: string;
|
throat_removal: string;
|
||||||
amount_currency_reduction: string;
|
amount_currency_reduction: string;
|
||||||
Reduce_rate_failure: string;
|
Reduce_rate_failure: string;
|
||||||
|
observer: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SortConfig {
|
interface SortConfig {
|
||||||
|
|
@ -72,9 +80,19 @@ const columns = [
|
||||||
{ key: "select", label: "", sortable: false, width: "50px" },
|
{ key: "select", label: "", sortable: false, width: "50px" },
|
||||||
{ key: "project_no", label: "شماره پروژه", sortable: true, width: "140px" },
|
{ key: "project_no", label: "شماره پروژه", sortable: true, width: "140px" },
|
||||||
{ key: "title", label: "عنوان پروژه", sortable: true, width: "400px" },
|
{ key: "title", label: "عنوان پروژه", sortable: true, width: "400px" },
|
||||||
{ key: "project_status", label: "وضعیت پروژه", sortable: true, width: "140px" },
|
{
|
||||||
{ key: "project_rating", label: "امتیاز پروژه", sortable: true, width: "140px" },
|
key: "project_status",
|
||||||
{ key: "details", label: "جزئیات پروژه", sortable: false, width: "140px" }
|
label: "وضعیت پروژه",
|
||||||
|
sortable: true,
|
||||||
|
width: "140px",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "project_rating",
|
||||||
|
label: "امتیاز پروژه",
|
||||||
|
sortable: true,
|
||||||
|
width: "140px",
|
||||||
|
},
|
||||||
|
{ key: "details", label: "جزئیات پروژه", sortable: false, width: "140px" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export function ProcessInnovationPage() {
|
export function ProcessInnovationPage() {
|
||||||
|
|
@ -103,9 +121,12 @@ export function ProcessInnovationPage() {
|
||||||
field: "start_date",
|
field: "start_date",
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
});
|
});
|
||||||
const [selectedProjects, setSelectedProjects] = useState<Set<string>>(new Set());
|
const [selectedProjects, setSelectedProjects] = useState<Set<string>>(
|
||||||
|
new Set(),
|
||||||
|
);
|
||||||
const [detailsDialogOpen, setDetailsDialogOpen] = useState(false);
|
const [detailsDialogOpen, setDetailsDialogOpen] = useState(false);
|
||||||
const [selectedProjectDetails, setSelectedProjectDetails] = useState<ProcessInnovationData | null>(null);
|
const [selectedProjectDetails, setSelectedProjectDetails] =
|
||||||
|
useState<ProcessInnovationData | null>(null);
|
||||||
const observerRef = useRef<HTMLDivElement>(null);
|
const observerRef = useRef<HTMLDivElement>(null);
|
||||||
const fetchingRef = useRef(false);
|
const fetchingRef = useRef(false);
|
||||||
|
|
||||||
|
|
@ -114,7 +135,7 @@ export function ProcessInnovationPage() {
|
||||||
if (selectedProjects.size === projects.length) {
|
if (selectedProjects.size === projects.length) {
|
||||||
setSelectedProjects(new Set());
|
setSelectedProjects(new Set());
|
||||||
} else {
|
} else {
|
||||||
setSelectedProjects(new Set(projects.map(p => p.project_no)));
|
setSelectedProjects(new Set(projects.map((p) => p.project_no)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -129,6 +150,7 @@ export function ProcessInnovationPage() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleProjectDetails = (project: ProcessInnovationData) => {
|
const handleProjectDetails = (project: ProcessInnovationData) => {
|
||||||
|
console.log(project);
|
||||||
setSelectedProjectDetails(project);
|
setSelectedProjectDetails(project);
|
||||||
setDetailsDialogOpen(true);
|
setDetailsDialogOpen(true);
|
||||||
};
|
};
|
||||||
|
|
@ -145,9 +167,12 @@ export function ProcessInnovationPage() {
|
||||||
{
|
{
|
||||||
id: "production-stops-prevention",
|
id: "production-stops-prevention",
|
||||||
title: "جلوگیری از توقفات تولید",
|
title: "جلوگیری از توقفات تولید",
|
||||||
value: formatNumber(stats.productionStopsPreventionSum.toFixed?.(1) ?? stats.productionStopsPreventionSum),
|
value: formatNumber(
|
||||||
|
stats.productionStopsPreventionSum.toFixed?.(1) ??
|
||||||
|
stats.productionStopsPreventionSum,
|
||||||
|
),
|
||||||
description: "ظرفیت افزایش یافته",
|
description: "ظرفیت افزایش یافته",
|
||||||
icon: <CirclePause/>,
|
icon: <CirclePause />,
|
||||||
color: "text-emerald-400",
|
color: "text-emerald-400",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -156,25 +181,30 @@ export function ProcessInnovationPage() {
|
||||||
value: formatNumber(stats.bottleneckRemovalCount),
|
value: formatNumber(stats.bottleneckRemovalCount),
|
||||||
description: "تعداد رفع گلوگاه",
|
description: "تعداد رفع گلوگاه",
|
||||||
icon: <Funnel />,
|
icon: <Funnel />,
|
||||||
color: "text-emerald-400"
|
color: "text-emerald-400",
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: "currency-reduction",
|
id: "currency-reduction",
|
||||||
title: "کاهش ارز بری",
|
title: "کاهش ارز بری",
|
||||||
value: formatNumber(stats.currencyReductionSum.toFixed?.(0) ?? stats.currencyReductionSum),
|
value: formatNumber(
|
||||||
|
stats.currencyReductionSum.toFixed?.(0) ?? stats.currencyReductionSum,
|
||||||
|
),
|
||||||
description: "دلار کاهش یافته",
|
description: "دلار کاهش یافته",
|
||||||
icon: <DollarSign/>,
|
icon: <DollarSign />,
|
||||||
color: "text-emerald-400",
|
color: "text-emerald-400",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "frequent-failures-reduction",
|
id: "frequent-failures-reduction",
|
||||||
title: "کاهش خرابیهای پرتکرار",
|
title: "کاهش خرابیهای پرتکرار",
|
||||||
value: formatNumber(stats.frequentFailuresReductionSum.toFixed?.(1) ?? stats.frequentFailuresReductionSum),
|
value: formatNumber(
|
||||||
|
stats.frequentFailuresReductionSum.toFixed?.(1) ??
|
||||||
|
stats.frequentFailuresReductionSum,
|
||||||
|
),
|
||||||
description: "مجموع درصد کاهش خرابی",
|
description: "مجموع درصد کاهش خرابی",
|
||||||
icon: <Wrench/>,
|
icon: <Wrench />,
|
||||||
color: "text-emerald-400",
|
color: "text-emerald-400",
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const fetchProjects = async (reset = false) => {
|
const fetchProjects = async (reset = false) => {
|
||||||
|
|
@ -201,16 +231,22 @@ export function ProcessInnovationPage() {
|
||||||
"title",
|
"title",
|
||||||
"project_status",
|
"project_status",
|
||||||
"project_rating",
|
"project_rating",
|
||||||
"reduce_prevention_production_stops",
|
|
||||||
"throat_removal",
|
"throat_removal",
|
||||||
|
"reduce_prevention_production_stops",
|
||||||
"amount_currency_reduction",
|
"amount_currency_reduction",
|
||||||
"Reduce_rate_failure",
|
"Reduce_rate_failure",
|
||||||
|
"project_description",
|
||||||
|
"start_date",
|
||||||
|
"done_date",
|
||||||
|
"approved_budget",
|
||||||
|
"observer",
|
||||||
],
|
],
|
||||||
Pagination: { PageNumber: pageToFetch, PageSize: pageSize },
|
Sorts: [["start_date", "asc"]],
|
||||||
Sorts: [[sortConfig.field, sortConfig.direction]],
|
|
||||||
Conditions: [["type_of_innovation", "=", "نوآوری در فرآیند"]],
|
Conditions: [["type_of_innovation", "=", "نوآوری در فرآیند"]],
|
||||||
|
Pagination: { PageNumber: pageToFetch, PageSize: pageSize },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(JSON.parse(response.data));
|
||||||
if (response.state === 0) {
|
if (response.state === 0) {
|
||||||
const dataString = response.data;
|
const dataString = response.data;
|
||||||
if (dataString && typeof dataString === "string") {
|
if (dataString && typeof dataString === "string") {
|
||||||
|
|
@ -289,7 +325,7 @@ export function ProcessInnovationPage() {
|
||||||
}, [currentPage]);
|
}, [currentPage]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const scrollContainer = document.querySelector('.overflow-auto');
|
const scrollContainer = document.querySelector(".overflow-auto");
|
||||||
|
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
if (!scrollContainer || !hasMore || loadingMore) return;
|
if (!scrollContainer || !hasMore || loadingMore) return;
|
||||||
|
|
@ -303,12 +339,12 @@ export function ProcessInnovationPage() {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (scrollContainer) {
|
if (scrollContainer) {
|
||||||
scrollContainer.addEventListener('scroll', handleScroll);
|
scrollContainer.addEventListener("scroll", handleScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (scrollContainer) {
|
if (scrollContainer) {
|
||||||
scrollContainer.removeEventListener('scroll', handleScroll);
|
scrollContainer.removeEventListener("scroll", handleScroll);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [loadMore, hasMore, loadingMore]);
|
}, [loadMore, hasMore, loadingMore]);
|
||||||
|
|
@ -359,13 +395,14 @@ export function ProcessInnovationPage() {
|
||||||
try {
|
try {
|
||||||
setStatsLoading(true);
|
setStatsLoading(true);
|
||||||
const raw = await apiService.callInnovationProcess<any>({
|
const raw = await apiService.callInnovationProcess<any>({
|
||||||
innovation_process_function: {
|
innovation_process_function: {},
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let payload: any = raw?.data;
|
let payload: any = raw?.data;
|
||||||
if (typeof payload === "string") {
|
if (typeof payload === "string") {
|
||||||
try { payload = JSON.parse(payload); } catch {}
|
try {
|
||||||
|
payload = JSON.parse(payload);
|
||||||
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseNum = (v: unknown): number => {
|
const parseNum = (v: unknown): number => {
|
||||||
|
|
@ -382,14 +419,24 @@ export function ProcessInnovationPage() {
|
||||||
const normalized: InnovationStats = {
|
const normalized: InnovationStats = {
|
||||||
totalProjects: parseNum(payload?.count_innovation_process_projects),
|
totalProjects: parseNum(payload?.count_innovation_process_projects),
|
||||||
averageScore: parseNum(payload?.average_project_score),
|
averageScore: parseNum(payload?.average_project_score),
|
||||||
productionStopsPreventionSum: parseNum(payload?.sum_stopping_production),
|
productionStopsPreventionSum: parseNum(
|
||||||
|
payload?.sum_stopping_production,
|
||||||
|
),
|
||||||
bottleneckRemovalCount: parseNum(payload?.count_throat_removal),
|
bottleneckRemovalCount: parseNum(payload?.count_throat_removal),
|
||||||
currencyReductionSum: parseNum(payload?.sum_reduction_value_currency),
|
currencyReductionSum: parseNum(payload?.sum_reduction_value_currency),
|
||||||
frequentFailuresReductionSum: parseNum(payload?.sum_reducing_breakdowns),
|
frequentFailuresReductionSum: parseNum(
|
||||||
percentProductionStops: parseNum(payload?.percent_sum_stopping_production),
|
payload?.sum_reducing_breakdowns,
|
||||||
|
),
|
||||||
|
percentProductionStops: parseNum(
|
||||||
|
payload?.percent_sum_stopping_production,
|
||||||
|
),
|
||||||
percentBottleneckRemoval: parseNum(payload?.percent_throat_removal),
|
percentBottleneckRemoval: parseNum(payload?.percent_throat_removal),
|
||||||
percentCurrencyReduction: parseNum(payload?.percent_reduction_value_currency),
|
percentCurrencyReduction: parseNum(
|
||||||
percentFailuresReduction: parseNum(payload?.percent_reducing_breakdowns),
|
payload?.percent_reduction_value_currency,
|
||||||
|
),
|
||||||
|
percentFailuresReduction: parseNum(
|
||||||
|
payload?.percent_reducing_breakdowns,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
setStats(normalized);
|
setStats(normalized);
|
||||||
|
|
@ -481,10 +528,7 @@ export function ProcessInnovationPage() {
|
||||||
);
|
);
|
||||||
case "project_no":
|
case "project_no":
|
||||||
return (
|
return (
|
||||||
<Badge
|
<Badge variant="outline" className="font-mono">
|
||||||
variant="outline"
|
|
||||||
className="font-mono"
|
|
||||||
>
|
|
||||||
{String(value)}
|
{String(value)}
|
||||||
</Badge>
|
</Badge>
|
||||||
);
|
);
|
||||||
|
|
@ -496,7 +540,7 @@ export function ProcessInnovationPage() {
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="font-medium border-2"
|
className="font-medium border-2"
|
||||||
style={{
|
style={{
|
||||||
border:"none",
|
border: "none",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{String(value)}
|
{String(value)}
|
||||||
|
|
@ -504,10 +548,7 @@ export function ProcessInnovationPage() {
|
||||||
);
|
);
|
||||||
case "project_rating":
|
case "project_rating":
|
||||||
return (
|
return (
|
||||||
<Badge
|
<Badge variant="outline" className="text-lg text-center border-none">
|
||||||
variant="outline"
|
|
||||||
className="text-lg text-center border-none"
|
|
||||||
>
|
|
||||||
{formatNumber(String(value))}
|
{formatNumber(String(value))}
|
||||||
</Badge>
|
</Badge>
|
||||||
);
|
);
|
||||||
|
|
@ -529,187 +570,215 @@ export function ProcessInnovationPage() {
|
||||||
<div className="p-6 space-y-4">
|
<div className="p-6 space-y-4">
|
||||||
{/* Stats Cards */}
|
{/* Stats Cards */}
|
||||||
<div className="flex gap-6">
|
<div className="flex gap-6">
|
||||||
<div className="space-y-6 w-full">
|
<div className="space-y-6 w-full">
|
||||||
{/* Stats Grid */}
|
{/* Stats Grid */}
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
{loading || statsLoading ? (
|
{loading || statsLoading
|
||||||
// Loading skeleton for stats cards - matching new design
|
? // Loading skeleton for stats cards - matching new design
|
||||||
Array.from({ length: 4 }).map((_, index) => (
|
Array.from({ length: 4 }).map((_, index) => (
|
||||||
<Card key={`skeleton-${index}`} className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm rounded-2xl overflow-hidden">
|
<Card
|
||||||
<CardContent className="p-2">
|
key={`skeleton-${index}`}
|
||||||
<div className="flex flex-col justify-between gap-2">
|
className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm rounded-2xl overflow-hidden"
|
||||||
<div className="flex justify-between items-center border-b-2 mx-4 border-gray-500/20">
|
>
|
||||||
<div className="h-6 bg-gray-600 rounded animate-pulse" style={{ width: '60%' }} />
|
<CardContent className="p-2">
|
||||||
<div className="p-3 bg-emerald-500/20 rounded-full w-fit">
|
<div className="flex flex-col justify-between gap-2">
|
||||||
<div className="w-6 h-6 bg-gray-600 rounded animate-pulse" />
|
<div className="flex justify-between items-center border-b-2 mx-4 border-gray-500/20">
|
||||||
|
<div
|
||||||
|
className="h-6 bg-gray-600 rounded animate-pulse"
|
||||||
|
style={{ width: "60%" }}
|
||||||
|
/>
|
||||||
|
<div className="p-3 bg-emerald-500/20 rounded-full w-fit">
|
||||||
|
<div className="w-6 h-6 bg-gray-600 rounded animate-pulse" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-center flex-col p-1">
|
||||||
|
<div
|
||||||
|
className="h-8 bg-gray-600 rounded mb-1 animate-pulse"
|
||||||
|
style={{ width: "40%" }}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="h-4 bg-gray-600 rounded animate-pulse"
|
||||||
|
style={{ width: "80%" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</CardContent>
|
||||||
<div className="flex items-center justify-center flex-col p-1">
|
</Card>
|
||||||
<div className="h-8 bg-gray-600 rounded mb-1 animate-pulse" style={{ width: '40%' }} />
|
))
|
||||||
<div className="h-4 bg-gray-600 rounded animate-pulse" style={{ width: '80%' }} />
|
: statsCards.map((card) => (
|
||||||
</div>
|
<Card
|
||||||
</div>
|
key={card.id}
|
||||||
</CardContent>
|
className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm border-gray-700/50"
|
||||||
</Card>
|
>
|
||||||
))
|
<CardContent className="p-2">
|
||||||
) : (
|
<div className="flex flex-col justify-between gap-2">
|
||||||
statsCards.map((card) => (
|
<div className="flex justify-between items-center border-b-2 mx-4 border-gray-500/20">
|
||||||
<Card key={card.id} className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm border-gray-700/50">
|
<h3 className="text-lg font-bold text-white font-persian">
|
||||||
<CardContent className="p-2">
|
{card.title}
|
||||||
<div className="flex flex-col justify-between gap-2">
|
</h3>
|
||||||
<div className="flex justify-between items-center border-b-2 mx-4 border-gray-500/20">
|
<div
|
||||||
<h3 className="text-lg font-bold text-white font-persian">
|
className={`p-3 gird placeitems-center rounded-full w-fit `}
|
||||||
{card.title}
|
>
|
||||||
</h3>
|
{card.icon}
|
||||||
<div className={`p-3 gird placeitems-center rounded-full w-fit `}>
|
</div>
|
||||||
{card.icon}
|
</div>
|
||||||
|
<div className="flex items-center justify-center flex-col p-1">
|
||||||
|
<p
|
||||||
|
className={`text-3xl font-bold ${card.color} mb-1`}
|
||||||
|
>
|
||||||
|
{card.value}
|
||||||
|
</p>
|
||||||
|
<p className="text-sm text-gray-300 font-persian">
|
||||||
|
{card.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</CardContent>
|
||||||
<div className="flex items-center justify-center flex-col p-1">
|
</Card>
|
||||||
<p className={`text-3xl font-bold ${card.color} mb-1`}>
|
))}
|
||||||
{card.value}
|
</div>
|
||||||
</p>
|
|
||||||
<p className="text-sm text-gray-300 font-persian">
|
|
||||||
{card.description}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Process Impacts Chart */}
|
{/* Process Impacts Chart */}
|
||||||
<Card className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm rounded-2xl w-full overflow-hidden">
|
<Card className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm rounded-2xl w-full overflow-hidden">
|
||||||
<CardContent className="p-4">
|
<CardContent className="p-4">
|
||||||
<CustomBarChart
|
<CustomBarChart
|
||||||
title="تاثیرات فرآیندی به صورت درصد مقایسه ای"
|
title="تاثیرات فرآیندی به صورت درصد مقایسه ای"
|
||||||
loading={statsLoading}
|
loading={statsLoading}
|
||||||
data={[
|
data={[
|
||||||
{
|
{
|
||||||
label: "کاهش توقفات تولید",
|
label: "کاهش توقفات تولید",
|
||||||
value: stats.percentProductionStops || 0,
|
value: stats.percentProductionStops || 0,
|
||||||
color: "bg-emerald-400",
|
color: "bg-emerald-400",
|
||||||
labelColor: "text-white"
|
labelColor: "text-white",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "رفع گلوگاه تولید",
|
label: "رفع گلوگاه تولید",
|
||||||
value: stats.percentBottleneckRemoval || 0,
|
value: stats.percentBottleneckRemoval || 0,
|
||||||
color: "bg-emerald-400",
|
color: "bg-emerald-400",
|
||||||
labelColor: "text-white"
|
labelColor: "text-white",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "کاهش ارز بری",
|
label: "کاهش ارز بری",
|
||||||
value: stats.percentCurrencyReduction || 0,
|
value: stats.percentCurrencyReduction || 0,
|
||||||
color: "bg-emerald-400",
|
color: "bg-emerald-400",
|
||||||
labelColor: "text-white"
|
labelColor: "text-white",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "کاهش خرابی پر تکرار",
|
label: "کاهش خرابی پر تکرار",
|
||||||
value: stats.percentFailuresReduction || 0,
|
value: stats.percentFailuresReduction || 0,
|
||||||
color: "bg-emerald-400",
|
color: "bg-emerald-400",
|
||||||
labelColor: "text-white"
|
labelColor: "text-white",
|
||||||
}
|
},
|
||||||
]}
|
]}
|
||||||
barHeight="h-5"
|
barHeight="h-5"
|
||||||
showAxisLabels={true}
|
showAxisLabels={true}
|
||||||
/>
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Data Table */}
|
{/* Data Table */}
|
||||||
<Card className="bg-transparent backdrop-blur-sm rounded-2xl overflow-hidden">
|
<Card className="bg-transparent backdrop-blur-sm rounded-2xl overflow-hidden">
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Table containerClassName="overflow-auto custom-scrollbar max-h-[calc(90vh-400px)]">
|
<Table containerClassName="overflow-auto custom-scrollbar max-h-[calc(90vh-400px)]">
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow className="bg-[#3F415A]">
|
<TableRow className="bg-[#3F415A]">
|
||||||
{columns.map((column) => (
|
{columns.map((column) => (
|
||||||
<TableHead
|
<TableHead
|
||||||
key={column.key}
|
key={column.key}
|
||||||
className="text-right font-persian whitespace-nowrap text-gray-200 font-medium sticky top-0 z-20 bg-[#3F415A]"
|
className="text-right font-persian whitespace-nowrap text-gray-200 font-medium sticky top-0 z-20 bg-[#3F415A]"
|
||||||
style={{ width: column.width }}
|
style={{ width: column.width }}
|
||||||
>
|
>
|
||||||
{column.key === "select" ? (
|
{column.key === "select" ? (
|
||||||
<div className="flex items-center justify-center">
|
<div className="flex items-center justify-center">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={selectedProjects.size === projects.length && projects.length > 0}
|
checked={
|
||||||
onCheckedChange={handleSelectAll}
|
selectedProjects.size === projects.length &&
|
||||||
className="data-[state=checked]:bg-emerald-600 data-[state=checked]:border-emerald-600"
|
projects.length > 0
|
||||||
|
}
|
||||||
|
onCheckedChange={handleSelectAll}
|
||||||
|
className="data-[state=checked]:bg-emerald-600 data-[state=checked]:border-emerald-600"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : column.sortable ? (
|
||||||
|
<button
|
||||||
|
onClick={() => handleSort(column.key)}
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span>{column.label}</span>
|
||||||
|
{sortConfig.field === column.key ? (
|
||||||
|
sortConfig.direction === "asc" ? (
|
||||||
|
<ChevronUp className="w-4 h-4" />
|
||||||
|
) : (
|
||||||
|
<ChevronDown className="w-4 h-4" />
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<div className="w-4 h-4" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
column.label
|
||||||
|
)}
|
||||||
|
</TableHead>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{loading ? (
|
||||||
|
// Skeleton loading rows (compact)
|
||||||
|
Array.from({ length: 10 }).map((_, index) => (
|
||||||
|
<TableRow
|
||||||
|
key={`skeleton-${index}`}
|
||||||
|
className="text-sm leading-tight h-8"
|
||||||
|
>
|
||||||
|
{columns.map((column) => (
|
||||||
|
<TableCell
|
||||||
|
key={column.key}
|
||||||
|
className="text-right whitespace-nowrap border-emerald-500/20 py-1 px-2"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="w-2.5 h-2.5 bg-gray-600 rounded-full animate-pulse" />
|
||||||
|
<div
|
||||||
|
className="h-2.5 bg-gray-600 rounded animate-pulse"
|
||||||
|
style={{ width: `${Math.random() * 60 + 40}%` }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : column.sortable ? (
|
</TableCell>
|
||||||
<button
|
))}
|
||||||
onClick={() => handleSort(column.key)}
|
|
||||||
className="flex items-center gap-2"
|
|
||||||
>
|
|
||||||
<span>{column.label}</span>
|
|
||||||
{sortConfig.field === column.key ? (
|
|
||||||
sortConfig.direction === "asc" ? (
|
|
||||||
<ChevronUp className="w-4 h-4" />
|
|
||||||
) : (
|
|
||||||
<ChevronDown className="w-4 h-4" />
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<div className="w-4 h-4" />
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
) : (
|
|
||||||
column.label
|
|
||||||
)}
|
|
||||||
</TableHead>
|
|
||||||
))}
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{loading ? (
|
|
||||||
// Skeleton loading rows (compact)
|
|
||||||
Array.from({ length: 10 }).map((_, index) => (
|
|
||||||
<TableRow key={`skeleton-${index}`} className="text-sm leading-tight h-8">
|
|
||||||
{columns.map((column) => (
|
|
||||||
<TableCell
|
|
||||||
key={column.key}
|
|
||||||
className="text-right whitespace-nowrap border-emerald-500/20 py-1 px-2"
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<div className="w-2.5 h-2.5 bg-gray-600 rounded-full animate-pulse" />
|
|
||||||
<div className="h-2.5 bg-gray-600 rounded animate-pulse" style={{ width: `${Math.random() * 60 + 40}%` }} />
|
|
||||||
</div>
|
|
||||||
</TableCell>
|
|
||||||
))}
|
|
||||||
</TableRow>
|
|
||||||
))
|
|
||||||
) : projects.length === 0 ? (
|
|
||||||
<TableRow>
|
|
||||||
<TableCell
|
|
||||||
colSpan={columns.length}
|
|
||||||
className="text-center py-8"
|
|
||||||
>
|
|
||||||
<span className="text-gray-400 font-persian">
|
|
||||||
هیچ پروژهای یافت نشد
|
|
||||||
</span>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : (
|
))
|
||||||
projects.map((project, index) => (
|
) : projects.length === 0 ? (
|
||||||
<TableRow key={`${project.project_no}-${index}`} className="text-sm leading-tight h-8">
|
<TableRow>
|
||||||
{columns.map((column) => (
|
<TableCell
|
||||||
<TableCell
|
colSpan={columns.length}
|
||||||
key={column.key}
|
className="text-center py-8"
|
||||||
className={`text-right whitespace-nowrap border-emerald-500/20 py-1 px-2 ${column.key==="select" ? "flex justify-center items-center" :""}`}
|
>
|
||||||
>
|
<span className="text-gray-400 font-persian">
|
||||||
{renderCellContent(project, column)}
|
هیچ پروژهای یافت نشد
|
||||||
</TableCell>
|
</span>
|
||||||
))}
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
) : (
|
||||||
)}
|
projects.map((project, index) => (
|
||||||
</TableBody>
|
<TableRow
|
||||||
</Table>
|
key={`${project.project_no}-${index}`}
|
||||||
|
className="text-sm leading-tight h-8"
|
||||||
|
>
|
||||||
|
{columns.map((column) => (
|
||||||
|
<TableCell
|
||||||
|
key={column.key}
|
||||||
|
className={`text-right whitespace-nowrap border-emerald-500/20 py-1 px-2 ${column.key === "select" ? "flex justify-center items-center" : ""}`}
|
||||||
|
>
|
||||||
|
{renderCellContent(project, column)}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Infinite scroll trigger */}
|
{/* Infinite scroll trigger */}
|
||||||
|
|
@ -718,8 +787,7 @@ export function ProcessInnovationPage() {
|
||||||
<div className="flex items-center justify-center py-1">
|
<div className="flex items-center justify-center py-1">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<RefreshCw className="w-4 h-4 animate-spin text-emerald-400" />
|
<RefreshCw className="w-4 h-4 animate-spin text-emerald-400" />
|
||||||
<span className="font-persian text-gray-300 text-xs">
|
<span className="font-persian text-gray-300 text-xs"></span>
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -752,8 +820,12 @@ export function ProcessInnovationPage() {
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<div className="p-2 px-4 bg-gray-700/50">
|
<div className="p-2 px-4 bg-gray-700/50">
|
||||||
<div className="grid grid-cols-6 gap-4 text-sm text-gray-300 font-persian">
|
<div className="grid grid-cols-6 gap-4 text-sm text-gray-300 font-persian">
|
||||||
<div className="text-center gap-2 items-center flex">
|
<div className="text-center gap-2 items-center flex">
|
||||||
<div className="text-base text-gray-401 mb-1"> کل پروژه ها : {formatNumber(stats.totalProjects || actualTotalCount)}</div>
|
<div className="text-base text-gray-401 mb-1">
|
||||||
|
{" "}
|
||||||
|
کل پروژه ها :{" "}
|
||||||
|
{formatNumber(stats.totalProjects || actualTotalCount)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Project number column - empty */}
|
{/* Project number column - empty */}
|
||||||
<div></div>
|
<div></div>
|
||||||
|
|
@ -763,126 +835,103 @@ export function ProcessInnovationPage() {
|
||||||
<div></div>
|
<div></div>
|
||||||
{/* Project rating column - show average */}
|
{/* Project rating column - show average */}
|
||||||
<div className="flex justify-center items-center gap-2">
|
<div className="flex justify-center items-center gap-2">
|
||||||
<div className="text-base text-gray-400 mb-1"> میانگین امتیاز :</div>
|
<div className="text-base text-gray-400 mb-1">
|
||||||
|
{" "}
|
||||||
|
میانگین امتیاز :
|
||||||
|
</div>
|
||||||
<div className="font-bold">
|
<div className="font-bold">
|
||||||
{formatNumber(((stats.averageScore ?? 0) as number).toFixed?.(1) ?? (stats.averageScore ?? 0))}
|
{formatNumber(
|
||||||
|
((stats.averageScore ?? 0) as number).toFixed?.(1) ??
|
||||||
|
stats.averageScore ??
|
||||||
|
0,
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Details column - show total count */}
|
{/* Details column - show total count */}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Project Details Dialog */}
|
{/* Project Details Dialog */}
|
||||||
<Dialog open={detailsDialogOpen} onOpenChange={setDetailsDialogOpen}>
|
<Dialog open={detailsDialogOpen} onOpenChange={setDetailsDialogOpen}>
|
||||||
<DialogContent className="bg-[#2A2D3E] border-gray-700 max-w-2xl max-h-[80vh] overflow-y-auto">
|
<DialogContent className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] max-w-4xl max-h-[80vh] overflow-y-auto">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className="text-white font-persian text-right">
|
<DialogTitle className="text-white mr-4 border-b-2 border-gray-600 pb-4 font-persian text-right">
|
||||||
جزئیات پروژه
|
شرح پروژه
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
<div className="space-y-4 flex justify-between text-right px-6">
|
||||||
|
{/* Project Description */}
|
||||||
|
<div className="flex-[4] border-l-2 border-gray-600">
|
||||||
|
<h2 className="font-bold">{selectedProjectDetails?.title}</h2>
|
||||||
|
<p className="text-gray-300 font-persian px-2 mt-2">
|
||||||
|
{selectedProjectDetails?.project_description || "-"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{selectedProjectDetails && (
|
{/* Project Details */}
|
||||||
<div className="space-y-6 text-right">
|
<div className="flex flex-[3] gap-2 flex-col px-4">
|
||||||
{/* Project Header */}
|
<div className="font-bold text-right ">جزئیات پروژه</div>
|
||||||
<div className="bg-gray-700/30 rounded-lg p-4">
|
|
||||||
<h3 className="text-lg font-bold text-white font-persian mb-2">
|
<div className="flex items-center justify-between">
|
||||||
{selectedProjectDetails.title}
|
<h4 className="font-medium text-gray-300 font-persian mb-2 flex items-center gap-1">
|
||||||
</h3>
|
<Building2 className="h-4 text-green-500" />
|
||||||
<div className="flex items-center gap-4">
|
زمان شروع:
|
||||||
<Badge
|
</h4>
|
||||||
variant="outline"
|
<span className="text-white font-bold font-persian">
|
||||||
className="font-mono text-emerald-400 border-emerald-500/50"
|
{selectedProjectDetails?.start_date
|
||||||
>
|
? moment(
|
||||||
{selectedProjectDetails.project_no}
|
selectedProjectDetails?.start_date,
|
||||||
</Badge>
|
"YYYY-MM-DD",
|
||||||
<Badge
|
).format("YYYY/MM/DD")
|
||||||
variant="outline"
|
: "-"}
|
||||||
className="font-medium border-2"
|
</span>
|
||||||
style={{
|
|
||||||
color: getStatusColor(selectedProjectDetails.project_status),
|
|
||||||
borderColor: getStatusColor(selectedProjectDetails.project_status),
|
|
||||||
backgroundColor: `${getStatusColor(selectedProjectDetails.project_status)}20`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{selectedProjectDetails.project_status}
|
|
||||||
</Badge>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Project Metrics */}
|
<div className="flex items-center justify-between">
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<h4 className="font-medium text-gray-300 font-persian mb-2 flex items-center gap-1">
|
||||||
<div className="bg-gray-700/20 rounded-lg p-4">
|
<PickaxeIcon className="h-4 text-green-500" />
|
||||||
<h4 className="text-sm font-medium text-gray-300 font-persian mb-2">
|
زمان پایان:
|
||||||
امتیاز پروژه
|
</h4>
|
||||||
</h4>
|
<span className="text-white font-bold font-persian">
|
||||||
<Badge
|
{selectedProjectDetails?.done_date
|
||||||
variant="outline"
|
? moment(
|
||||||
className="text-lg font-bold border-2"
|
selectedProjectDetails?.done_date,
|
||||||
style={{
|
"YYYY-MM-DD",
|
||||||
color: getRatingColor(selectedProjectDetails.project_rating),
|
).format("YYYY/MM/DD")
|
||||||
borderColor: getRatingColor(selectedProjectDetails.project_rating),
|
: "-"}
|
||||||
backgroundColor: `${getRatingColor(selectedProjectDetails.project_rating)}20`,
|
</span>
|
||||||
}}
|
|
||||||
>
|
|
||||||
{formatNumber(selectedProjectDetails.project_rating)}
|
|
||||||
</Badge>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="bg-gray-700/20 rounded-lg p-4">
|
|
||||||
<h4 className="text-sm font-medium text-gray-300 font-persian mb-2">
|
|
||||||
کاهش توقفات تولید
|
|
||||||
</h4>
|
|
||||||
<span className="text-lg font-bold text-blue-400">
|
|
||||||
{formatNumber(selectedProjectDetails.reduce_prevention_production_stops)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="bg-gray-700/20 rounded-lg p-4">
|
|
||||||
<h4 className="text-sm font-medium text-gray-300 font-persian mb-2">
|
|
||||||
رفع گلوگاه تولید
|
|
||||||
</h4>
|
|
||||||
<span className="text-lg font-bold text-blue-400">
|
|
||||||
{formatNumber(selectedProjectDetails.throat_removal)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="bg-gray-700/20 rounded-lg p-4">
|
|
||||||
<h4 className="text-sm font-medium text-gray-300 font-persian mb-2">
|
|
||||||
کاهش ارز بری
|
|
||||||
</h4>
|
|
||||||
<span className="text-lg font-bold text-emerald-400">
|
|
||||||
{formatCurrency(selectedProjectDetails.amount_currency_reduction)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="bg-gray-700/20 rounded-lg p-4 col-span-2">
|
|
||||||
<h4 className="text-sm font-medium text-gray-300 font-persian mb-2">
|
|
||||||
کاهش خرابی پر تکرار
|
|
||||||
</h4>
|
|
||||||
<span className="text-lg font-bold text-blue-400">
|
|
||||||
{formatNumber(selectedProjectDetails.Reduce_rate_failure)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Action Buttons */}
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex justify-end gap-3 pt-4 border-t border-gray-700">
|
<h4 className="font-medium text-gray-300 font-persian mb-2 flex items-center gap-1">
|
||||||
<Button
|
<UsersIcon className="h-4 text-green-500" />
|
||||||
variant="outline"
|
هزینه برآورد شده:
|
||||||
onClick={() => setDetailsDialogOpen(false)}
|
</h4>
|
||||||
className="border-gray-600 text-gray-300 hover:bg-gray-700"
|
<span className="text-white font-bold font-persian">
|
||||||
>
|
{formatNumber(
|
||||||
بستن
|
Number(
|
||||||
</Button>
|
selectedProjectDetails?.approved_budget.replaceAll(
|
||||||
|
",",
|
||||||
|
"",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) || "-"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<h4 className="font-medium text-gray-300 font-persian mb-2 flex items-center gap-1">
|
||||||
|
<UserIcon className="h-4 text-green-500" />
|
||||||
|
نفر مرتبط:
|
||||||
|
</h4>
|
||||||
|
<span className="text-white font-bold font-persian">
|
||||||
|
{selectedProjectDetails?.observer || "-"}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</DashboardLayout>
|
</DashboardLayout>
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,7 @@ export function NetworkGraph({ onNodeClick }: NetworkGraphProps) {
|
||||||
// Create zoom behavior
|
// Create zoom behavior
|
||||||
const zoom = d3
|
const zoom = d3
|
||||||
.zoom<SVGSVGElement, unknown>()
|
.zoom<SVGSVGElement, unknown>()
|
||||||
.scaleExtent([1, 2.5]) // Limit zoom out to 1x, zoom in to 2.5x
|
.scaleExtent([0.8, 2.5]) // Limit zoom out to 1x, zoom in to 2.5x
|
||||||
.on("zoom", (event) => {
|
.on("zoom", (event) => {
|
||||||
container.attr("transform", event.transform);
|
container.attr("transform", event.transform);
|
||||||
});
|
});
|
||||||
|
|
@ -240,6 +240,18 @@ export function NetworkGraph({ onNodeClick }: NetworkGraphProps) {
|
||||||
d3.forceCollide().radius((d) => (d.isCenter ? 40 : 30)),
|
d3.forceCollide().radius((d) => (d.isCenter ? 40 : 30)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const initialScale = 0.85;
|
||||||
|
const initialTranslate = [
|
||||||
|
width / 2 - (width / 2) * initialScale,
|
||||||
|
height / 2 - (height / 2) * initialScale,
|
||||||
|
];
|
||||||
|
svg.call(
|
||||||
|
zoom.transform,
|
||||||
|
d3.zoomIdentity
|
||||||
|
.translate(initialTranslate[0], initialTranslate[1])
|
||||||
|
.scale(initialScale),
|
||||||
|
);
|
||||||
|
|
||||||
// Fix center node position
|
// Fix center node position
|
||||||
const centerNode = nodes.find((n) => n.isCenter);
|
const centerNode = nodes.find((n) => n.isCenter);
|
||||||
if (centerNode) {
|
if (centerNode) {
|
||||||
|
|
@ -424,19 +436,13 @@ export function NetworkGraph({ onNodeClick }: NetworkGraphProps) {
|
||||||
// Filter out image fields and find description
|
// Filter out image fields and find description
|
||||||
const filteredFields = fieldValues.filter(
|
const filteredFields = fieldValues.filter(
|
||||||
(field: any) =>
|
(field: any) =>
|
||||||
![
|
!["image", "img", "full_name"].includes(field.F.toLowerCase()),
|
||||||
"image",
|
|
||||||
"img",
|
|
||||||
"des",
|
|
||||||
"dec",
|
|
||||||
"description",
|
|
||||||
"collaboration",
|
|
||||||
].includes(field.F.toLowerCase()),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const descriptionField = fieldValues.find(
|
const descriptionField = fieldValues.find(
|
||||||
(field: any) =>
|
(field: any) =>
|
||||||
field.F.toLowerCase().includes("description") ||
|
field.F.toLowerCase().includes("description") ||
|
||||||
|
field.F.toLowerCase().includes("collaboration") ||
|
||||||
field.F.toLowerCase().includes("about"),
|
field.F.toLowerCase().includes("about"),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
"@radix-ui/react-slot": "^1.0.2",
|
"@radix-ui/react-slot": "^1.0.2",
|
||||||
"@react-router/node": "^7.7.0",
|
"@react-router/node": "^7.7.0",
|
||||||
"@react-router/serve": "^7.7.1",
|
"@react-router/serve": "^7.7.1",
|
||||||
"@sigma/node-image": "^3.0.0",
|
|
||||||
"@types/d3": "^7.4.3",
|
"@types/d3": "^7.4.3",
|
||||||
"chart.js": "^4.5.0",
|
"chart.js": "^4.5.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
|
|
@ -32,7 +31,6 @@
|
||||||
"react-hot-toast": "^2.5.2",
|
"react-hot-toast": "^2.5.2",
|
||||||
"react-router": "^7.7.0",
|
"react-router": "^7.7.0",
|
||||||
"recharts": "^3.1.2",
|
"recharts": "^3.1.2",
|
||||||
"sigma": "^3.0.2",
|
|
||||||
"tailwind-merge": "^3.3.1"
|
"tailwind-merge": "^3.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,6 @@ importers:
|
||||||
'@react-router/serve':
|
'@react-router/serve':
|
||||||
specifier: ^7.7.1
|
specifier: ^7.7.1
|
||||||
version: 7.8.0(react-router@7.7.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(typescript@5.8.3)
|
version: 7.8.0(react-router@7.7.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(typescript@5.8.3)
|
||||||
'@sigma/node-image':
|
|
||||||
specifier: ^3.0.0
|
|
||||||
version: 3.0.0(sigma@3.0.2(graphology-types@0.24.8))
|
|
||||||
'@types/d3':
|
'@types/d3':
|
||||||
specifier: ^7.4.3
|
specifier: ^7.4.3
|
||||||
version: 7.4.3
|
version: 7.4.3
|
||||||
|
|
@ -77,9 +74,6 @@ importers:
|
||||||
recharts:
|
recharts:
|
||||||
specifier: ^3.1.2
|
specifier: ^3.1.2
|
||||||
version: 3.1.2(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react-is@19.1.1)(react@19.1.0)(redux@5.0.1)
|
version: 3.1.2(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react-is@19.1.1)(react@19.1.0)(redux@5.0.1)
|
||||||
sigma:
|
|
||||||
specifier: ^3.0.2
|
|
||||||
version: 3.0.2(graphology-types@0.24.8)
|
|
||||||
tailwind-merge:
|
tailwind-merge:
|
||||||
specifier: ^3.3.1
|
specifier: ^3.3.1
|
||||||
version: 3.3.1
|
version: 3.3.1
|
||||||
|
|
@ -974,11 +968,6 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@sigma/node-image@3.0.0':
|
|
||||||
resolution: {integrity: sha512-i4WLNPugDY4jgQEZtNSiSVj4HHXOraciXLtlgdygeUxMVEhH8PJ/+Q1vQ9f/SlKFnZQ+7vH3HnsSDW6FD9aP+g==}
|
|
||||||
peerDependencies:
|
|
||||||
sigma: '>=3.0.0-beta.10'
|
|
||||||
|
|
||||||
'@standard-schema/spec@1.0.0':
|
'@standard-schema/spec@1.0.0':
|
||||||
resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==}
|
resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==}
|
||||||
|
|
||||||
|
|
@ -1659,11 +1648,6 @@ packages:
|
||||||
graphology-types@0.24.8:
|
graphology-types@0.24.8:
|
||||||
resolution: {integrity: sha512-hDRKYXa8TsoZHjgEaysSRyPdT6uB78Ci8WnjgbStlQysz7xR52PInxNsmnB7IBOM1BhikxkNyCVEFgmPKnpx3Q==}
|
resolution: {integrity: sha512-hDRKYXa8TsoZHjgEaysSRyPdT6uB78Ci8WnjgbStlQysz7xR52PInxNsmnB7IBOM1BhikxkNyCVEFgmPKnpx3Q==}
|
||||||
|
|
||||||
graphology-utils@2.5.2:
|
|
||||||
resolution: {integrity: sha512-ckHg8MXrXJkOARk56ZaSCM1g1Wihe2d6iTmz1enGOz4W/l831MBCKSayeFQfowgF8wd+PQ4rlch/56Vs/VZLDQ==}
|
|
||||||
peerDependencies:
|
|
||||||
graphology-types: '>=0.23.0'
|
|
||||||
|
|
||||||
graphology@0.26.0:
|
graphology@0.26.0:
|
||||||
resolution: {integrity: sha512-8SSImzgUUYC89Z042s+0r/vMibY7GX/Emz4LDO5e7jYXhuoWfHISPFJYjpRLUSJGq6UQ6xlenvX1p/hJdfXuXg==}
|
resolution: {integrity: sha512-8SSImzgUUYC89Z042s+0r/vMibY7GX/Emz4LDO5e7jYXhuoWfHISPFJYjpRLUSJGq6UQ6xlenvX1p/hJdfXuXg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
@ -2198,9 +2182,6 @@ packages:
|
||||||
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
|
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
sigma@3.0.2:
|
|
||||||
resolution: {integrity: sha512-/BUbeOwPGruiBOm0YQQ6ZMcLIZ6tf/W+Jcm7dxZyAX0tK3WP9/sq7/NAWBxPIxVahdGjCJoGwej0Gdrv0DxlQQ==}
|
|
||||||
|
|
||||||
signal-exit@4.1.0:
|
signal-exit@4.1.0:
|
||||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
|
@ -3282,10 +3263,6 @@ snapshots:
|
||||||
'@rollup/rollup-win32-x64-msvc@4.45.1':
|
'@rollup/rollup-win32-x64-msvc@4.45.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@sigma/node-image@3.0.0(sigma@3.0.2(graphology-types@0.24.8))':
|
|
||||||
dependencies:
|
|
||||||
sigma: 3.0.2(graphology-types@0.24.8)
|
|
||||||
|
|
||||||
'@standard-schema/spec@1.0.0': {}
|
'@standard-schema/spec@1.0.0': {}
|
||||||
|
|
||||||
'@standard-schema/utils@0.3.0': {}
|
'@standard-schema/utils@0.3.0': {}
|
||||||
|
|
@ -4009,10 +3986,6 @@ snapshots:
|
||||||
|
|
||||||
graphology-types@0.24.8: {}
|
graphology-types@0.24.8: {}
|
||||||
|
|
||||||
graphology-utils@2.5.2(graphology-types@0.24.8):
|
|
||||||
dependencies:
|
|
||||||
graphology-types: 0.24.8
|
|
||||||
|
|
||||||
graphology@0.26.0(graphology-types@0.24.8):
|
graphology@0.26.0(graphology-types@0.24.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
events: 3.3.0
|
events: 3.3.0
|
||||||
|
|
@ -4503,13 +4476,6 @@ snapshots:
|
||||||
side-channel-map: 1.0.1
|
side-channel-map: 1.0.1
|
||||||
side-channel-weakmap: 1.0.2
|
side-channel-weakmap: 1.0.2
|
||||||
|
|
||||||
sigma@3.0.2(graphology-types@0.24.8):
|
|
||||||
dependencies:
|
|
||||||
events: 3.3.0
|
|
||||||
graphology-utils: 2.5.2(graphology-types@0.24.8)
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- graphology-types
|
|
||||||
|
|
||||||
signal-exit@4.1.0: {}
|
signal-exit@4.1.0: {}
|
||||||
|
|
||||||
source-map-js@1.2.1: {}
|
source-map-js@1.2.1: {}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user