fix: change date-picker logic

This commit is contained in:
MehrdadAdabi 2025-10-14 16:39:29 +03:30
parent 7603703fa5
commit b1db9e8685
15 changed files with 194 additions and 132 deletions

View File

@ -1,4 +1,3 @@
import jalaali from "jalaali-js";
import { Book, CheckCircle } from "lucide-react"; import { Book, CheckCircle } from "lucide-react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
@ -16,6 +15,7 @@ import { ChartContainer } from "~/components/ui/chart";
import { MetricCard } from "~/components/ui/metric-card"; import { MetricCard } from "~/components/ui/metric-card";
import { Progress } from "~/components/ui/progress"; import { Progress } from "~/components/ui/progress";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs";
import { useStoredDate } from "~/hooks/useStoredDate";
import apiService from "~/lib/api"; import apiService from "~/lib/api";
import { EventBus, formatNumber } from "~/lib/utils"; import { EventBus, formatNumber } from "~/lib/utils";
import type { CalendarDate } from "~/types/util.type"; import type { CalendarDate } from "~/types/util.type";
@ -25,7 +25,6 @@ import { InteractiveBarChart } from "./interactive-bar-chart";
import { DashboardLayout } from "./layout"; import { DashboardLayout } from "./layout";
export function DashboardHome() { export function DashboardHome() {
const { jy } = jalaali.toJalaali(new Date());
const [dashboardData, setDashboardData] = useState<any | null>(null); const [dashboardData, setDashboardData] = useState<any | null>(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
@ -42,10 +41,7 @@ export function DashboardHome() {
}[] }[]
>([]); >([]);
const [date, setDate] = useState<CalendarDate>({ const [date, setDate] = useStoredDate();
start: `${jy}/01/01`,
end: `${jy}/12/30`,
});
useEffect(() => { useEffect(() => {
EventBus.on("dateSelected", (date: CalendarDate) => { EventBus.on("dateSelected", (date: CalendarDate) => {
@ -54,7 +50,7 @@ export function DashboardHome() {
}, []); }, []);
useEffect(() => { useEffect(() => {
fetchDashboardData(); if (date?.end && date?.start) fetchDashboardData();
}, [date]); }, [date]);
const fetchDashboardData = async () => { const fetchDashboardData = async () => {

View File

@ -65,7 +65,7 @@ const monthList: Array<MonthItem> = [
id: "month-4", id: "month-4",
label: "زمستان", label: "زمستان",
start: "10/01", start: "10/01",
end: "12/29", end: "12/30",
}, },
]; ];
@ -87,12 +87,34 @@ export function Header({
until: jy, until: jy,
}); });
const [selectedDate, setSelectedDate] = useState<CurrentDay>({ const [selectedDate, setSelectedDate] = useState<CurrentDay>({});
sinceMonth: "بهار",
fromMonth: "زمستان", useEffect(() => {
start: `${currentYear.since}/01/01`, const storedDate = localStorage.getItem("dateSelected");
end: `${currentYear.until}/12/30`, if (storedDate) {
}); const parsedDate = JSON.parse(storedDate);
setSelectedDate(parsedDate);
const sinceYear = parsedDate.start
? parseInt(parsedDate.start.split("/")[0], 10)
: jy;
const untilYear = parsedDate.end
? parseInt(parsedDate.end.split("/")[0], 10)
: jy;
setCurrentYear({ since: sinceYear, until: untilYear });
} else {
const defaultDate = {
sinceMonth: "بهار",
fromMonth: "زمستان",
start: `${jy}/01/01`,
end: `${jy}/12/30`,
};
setSelectedDate(defaultDate);
localStorage.setItem("dateSelected", JSON.stringify(defaultDate));
setCurrentYear({ since: jy, until: jy });
}
}, []);
const redirectHandler = async () => { const redirectHandler = async () => {
try { try {
@ -119,6 +141,7 @@ export function Header({
start: `${newSince}/${selectedDate.start?.split("/").slice(1).join("/")}`, start: `${newSince}/${selectedDate.start?.split("/").slice(1).join("/")}`,
}; };
setSelectedDate(updatedDate); setSelectedDate(updatedDate);
localStorage.setItem("dateSelected", JSON.stringify(updatedDate));
EventBus.emit("dateSelected", updatedDate); EventBus.emit("dateSelected", updatedDate);
}; };
@ -132,6 +155,7 @@ export function Header({
sinceMonth: val.label, sinceMonth: val.label,
}; };
setSelectedDate(data); setSelectedDate(data);
localStorage.setItem("dateSelected", JSON.stringify(data));
EventBus.emit("dateSelected", data); EventBus.emit("dateSelected", data);
}; };
@ -150,6 +174,7 @@ export function Header({
end: `${newUntil}/${selectedDate.end?.split("/").slice(1).join("/")}`, end: `${newUntil}/${selectedDate.end?.split("/").slice(1).join("/")}`,
}; };
setSelectedDate(updatedDate); setSelectedDate(updatedDate);
localStorage.setItem("dateSelected", JSON.stringify(updatedDate));
EventBus.emit("dateSelected", updatedDate); EventBus.emit("dateSelected", updatedDate);
}; };
@ -163,6 +188,7 @@ export function Header({
fromMonth: val.label, fromMonth: val.label,
}; };
setSelectedDate(data); setSelectedDate(data);
localStorage.setItem("dateSelected", JSON.stringify(data));
EventBus.emit("dateSelected", data); EventBus.emit("dateSelected", data);
toggleCalendar(); toggleCalendar();
}; };

View File

@ -1,4 +1,3 @@
import jalaali from "jalaali-js";
import { import {
BrainCircuit, BrainCircuit,
ChevronDown, ChevronDown,
@ -34,6 +33,7 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "~/components/ui/table"; } from "~/components/ui/table";
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";
import type { CalendarDate } from "~/types/util.type"; import type { CalendarDate } from "~/types/util.type";
@ -148,18 +148,13 @@ const columns = [
]; ];
export function DigitalInnovationPage() { export function DigitalInnovationPage() {
const { jy } = jalaali.toJalaali(new Date());
const [projects, setProjects] = useState<DigitalInnovationMetrics[]>([]); const [projects, setProjects] = useState<DigitalInnovationMetrics[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [loadingMore, setLoadingMore] = useState(false); const [loadingMore, setLoadingMore] = useState(false);
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [pageSize] = useState(20); const [pageSize] = useState(20);
const [hasMore, setHasMore] = useState(true); const [hasMore, setHasMore] = useState(true);
// const [totalCount, setTotalCount] = useState(0); const [date, setDate] = useStoredDate();
const [date, setDate] = useState<CalendarDate>({
start: `${jy}/01/01`,
end: `${jy}/12/30`,
});
const [actualTotalCount, setActualTotalCount] = useState(0); const [actualTotalCount, setActualTotalCount] = useState(0);
const [statsLoading, setStatsLoading] = useState(false); const [statsLoading, setStatsLoading] = useState(false);
const [rating, setRating] = useState<ListItem[]>([]); const [rating, setRating] = useState<ListItem[]>([]);
@ -363,10 +358,25 @@ export function DigitalInnovationPage() {
} }
}, [hasMore, loading, loadingMore]); }, [hasMore, loading, loadingMore]);
// useEffect(() => {
// const storedDate = localStorage.getItem("dateSelected");
// if (storedDate) {
// setDate(JSON.parse(storedDate));
// } else {
// setDate({
// start: `${jy}/01/01`,
// end: `${jy}/12/30`,
// });
// }
// }, []);
useEffect(() => { useEffect(() => {
fetchTable(true); if (date?.start && date?.end) {
fetchTotalCount(); fetchTable(true);
fetchStats(); fetchTotalCount();
fetchStats();
}
}, [sortConfig, date]); }, [sortConfig, date]);
useEffect(() => { useEffect(() => {
@ -378,7 +388,7 @@ export function DigitalInnovationPage() {
}, []); }, []);
useEffect(() => { useEffect(() => {
if (currentPage > 1) { if (currentPage > 1 && date?.start && date?.end) {
fetchTable(false); fetchTable(false);
} }
}, [currentPage]); }, [currentPage]);

View File

@ -1,4 +1,3 @@
// import moment from "moment-jalaali";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { import {
Bar, Bar,
@ -28,7 +27,6 @@ import {
} from "~/components/ui/table"; } from "~/components/ui/table";
import { EventBus, formatNumber } from "~/lib/utils"; import { EventBus, formatNumber } from "~/lib/utils";
import jalaali from "jalaali-js";
import { import {
Building2, Building2,
ChevronDown, ChevronDown,
@ -44,13 +42,16 @@ import {
UsersIcon, UsersIcon,
Zap, Zap,
} from "lucide-react"; } from "lucide-react";
import moment from "moment-jalaali";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
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";
import type { CalendarDate } from "~/types/util.type"; import type { CalendarDate } from "~/types/util.type";
import DashboardLayout from "../layout"; import DashboardLayout from "../layout";
// moment.loadPersian({ usePersianDigits: true }); moment.loadPersian({ usePersianDigits: true });
interface GreenInnovationData { interface GreenInnovationData {
WorkflowID: string; WorkflowID: string;
approved_budget: string; approved_budget: string;
@ -159,7 +160,6 @@ const columns = [
]; ];
export function GreenInnovationPage() { export function GreenInnovationPage() {
const { jy } = jalaali.toJalaali(new Date());
const [projects, setProjects] = useState<GreenInnovationData[]>([]); const [projects, setProjects] = useState<GreenInnovationData[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [loadingMore, setLoadingMore] = useState(false); const [loadingMore, setLoadingMore] = useState(false);
@ -169,10 +169,8 @@ export function GreenInnovationPage() {
const [totalCount, setTotalCount] = useState(0); const [totalCount, setTotalCount] = useState(0);
const [actualTotalCount, setActualTotalCount] = useState(0); const [actualTotalCount, setActualTotalCount] = useState(0);
const [statsLoading, setStatsLoading] = useState(false); const [statsLoading, setStatsLoading] = useState(false);
const [date, setDate] = useState<CalendarDate>({ const [date, setDate] = useStoredDate();
start: `${jy}/01/01`,
end: `${jy}/12/30`,
});
const [stats, setStats] = useState<stateCounter>(); const [stats, setStats] = useState<stateCounter>();
const [sortConfig, setSortConfig] = useState<SortConfig>({ const [sortConfig, setSortConfig] = useState<SortConfig>({
field: "start_date", field: "start_date",
@ -376,12 +374,14 @@ export function GreenInnovationPage() {
}, [hasMore, loading]); }, [hasMore, loading]);
useEffect(() => { useEffect(() => {
fetchProjects(true); if (date.end && date.start) {
fetchTotalCount(); fetchProjects(true);
fetchTotalCount();
}
}, [sortConfig, date]); }, [sortConfig, date]);
useEffect(() => { useEffect(() => {
fetchStats(); if (date.end && date.start) fetchStats();
}, [selectedProjects, date]); }, [selectedProjects, date]);
useEffect(() => { useEffect(() => {

View File

@ -19,7 +19,6 @@ import {
TableRow, TableRow,
} from "~/components/ui/table"; } from "~/components/ui/table";
import jalaali from "jalaali-js";
import { import {
ChevronDown, ChevronDown,
ChevronUp, ChevronUp,
@ -40,6 +39,7 @@ import {
ResponsiveContainer, ResponsiveContainer,
XAxis, XAxis,
} from "recharts"; } from "recharts";
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";
import type { CalendarDate } from "~/types/util.type"; import type { CalendarDate } from "~/types/util.type";
@ -179,7 +179,6 @@ const dialogChartData = [
]; ];
export function InnovationBuiltInsidePage() { export function InnovationBuiltInsidePage() {
const { jy } = jalaali.toJalaali(new Date());
const [projects, setProjects] = useState<innovationBuiltInDate[]>([]); const [projects, setProjects] = useState<innovationBuiltInDate[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [loadingMore, setLoadingMore] = useState(false); const [loadingMore, setLoadingMore] = useState(false);
@ -194,10 +193,8 @@ export function InnovationBuiltInsidePage() {
field: "start_date", field: "start_date",
direction: "asc", direction: "asc",
}); });
const [date, setDate] = useState<CalendarDate>({
start: `${jy}/01/01`, const [date, setDate] = useStoredDate();
end: `${jy}/12/30`,
});
const [tblAvarage, setTblAvarage] = useState<number>(0); const [tblAvarage, setTblAvarage] = useState<number>(0);
const [selectedProjects, setSelectedProjects] = const [selectedProjects, setSelectedProjects] =
useState<Set<string | number>>(); useState<Set<string | number>>();
@ -436,11 +433,11 @@ export function InnovationBuiltInsidePage() {
}, []); }, []);
useEffect(() => { useEffect(() => {
fetchProjects(true); if (date.start && date.end) fetchProjects(true);
}, [sortConfig, date]); }, [sortConfig, date]);
useEffect(() => { useEffect(() => {
fetchStats(); if (date.end && date.start) fetchStats();
}, [selectedProjects, date]); }, [selectedProjects, date]);
useEffect(() => { useEffect(() => {
@ -724,7 +721,7 @@ export function InnovationBuiltInsidePage() {
return ( return (
<DashboardLayout title="نوآوری ساخت داخل"> <DashboardLayout title="نوآوری ساخت داخل">
<div className="space-y-4 justify-between gap-8 grid pl-3.5 sm:grid-cols-1 xl:grid-cols-[35%_65%]"> <div className="space-y-4 justify-between gap-8 grid pl-6 sm:grid-cols-1 xl:grid-cols-[35%_65%]">
{/* Stats Cards */} {/* Stats Cards */}
<div className="flex w-full mb-0"> <div className="flex w-full mb-0">
<div className="flex flex-col w-full justify-between gap-2"> <div className="flex flex-col w-full justify-between gap-2">

View File

@ -1,4 +1,3 @@
import jalaali from "jalaali-js";
import { import {
ChevronDown, ChevronDown,
ChevronUp, ChevronUp,
@ -43,6 +42,7 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "~/components/ui/table"; } from "~/components/ui/table";
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";
import type { CalendarDate } from "~/types/util.type"; import type { CalendarDate } from "~/types/util.type";
@ -261,7 +261,6 @@ const VerticalBarChart = memo<{
const MemoizedVerticalBarChart = VerticalBarChart; const MemoizedVerticalBarChart = VerticalBarChart;
export function ManageIdeasTechPage() { export function ManageIdeasTechPage() {
const { jy } = jalaali.toJalaali(new Date());
const [ideas, setIdeas] = useState<IdeaData[]>([]); const [ideas, setIdeas] = useState<IdeaData[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [loadingMore, setLoadingMore] = useState(false); const [loadingMore, setLoadingMore] = useState(false);
@ -276,10 +275,7 @@ export function ManageIdeasTechPage() {
field: "idea_title", field: "idea_title",
direction: "asc", direction: "asc",
}); });
const [date, setDate] = useState<CalendarDate>({ const [date, setDate] = useStoredDate();
start: `${jy}/01/01`,
end: `${jy}/12/30`,
});
// People ranking state // People ranking state
const [peopleRanking, setPeopleRanking] = useState<PersonRanking[]>([]); const [peopleRanking, setPeopleRanking] = useState<PersonRanking[]>([]);
@ -417,11 +413,13 @@ export function ManageIdeasTechPage() {
}, []); }, []);
useEffect(() => { useEffect(() => {
fetchIdeas(true); if (date.end && date.start) {
fetchTotalCount(); fetchIdeas(true);
fetchPeopleRanking(); fetchTotalCount();
fetchChartData(); fetchPeopleRanking();
fetchStatsData(); fetchChartData();
fetchStatsData();
}
}, [sortConfig, date]); }, [sortConfig, date]);
useEffect(() => { useEffect(() => {

View File

@ -1,4 +1,3 @@
import jalaali from "jalaali-js";
import { import {
Building2, Building2,
ChevronDown, ChevronDown,
@ -35,6 +34,7 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "~/components/ui/table"; } from "~/components/ui/table";
import { useStoredDate } from "~/hooks/useStoredDate";
import apiService from "~/lib/api"; import apiService from "~/lib/api";
import { EventBus, formatNumber } from "~/lib/utils"; import { EventBus, formatNumber } from "~/lib/utils";
import type { CalendarDate } from "~/types/util.type"; import type { CalendarDate } from "~/types/util.type";
@ -119,18 +119,13 @@ const columns = [
]; ];
export function ProcessInnovationPage() { export function ProcessInnovationPage() {
const { jy } = jalaali.toJalaali(new Date());
const [projects, setProjects] = useState<ProcessInnovationData[]>([]); const [projects, setProjects] = useState<ProcessInnovationData[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [loadingMore, setLoadingMore] = useState(false); const [loadingMore, setLoadingMore] = useState(false);
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [pageSize] = useState(20); const [pageSize] = useState(20);
const [hasMore, setHasMore] = useState(true); const [hasMore, setHasMore] = useState(true);
// const [totalCount, setTotalCount] = useState(0); const [date, setDate] = useStoredDate();
const [date, setDate] = useState<CalendarDate>({
start: `${jy}/01/01`,
end: `${jy}/12/30`,
});
const [actualTotalCount, setActualTotalCount] = useState(0); const [actualTotalCount, setActualTotalCount] = useState(0);
const [statsLoading, setStatsLoading] = useState(false); const [statsLoading, setStatsLoading] = useState(false);
const [stats, setStats] = useState<InnovationStats>({ const [stats, setStats] = useState<InnovationStats>({
@ -345,12 +340,14 @@ export function ProcessInnovationPage() {
}, []); }, []);
useEffect(() => { useEffect(() => {
fetchProjects(true); if (date?.start && date?.end) {
fetchTotalCount(); fetchProjects(true);
fetchTotalCount();
}
}, [sortConfig, date]); }, [sortConfig, date]);
useEffect(() => { useEffect(() => {
fetchStats(); if (date?.start && date?.end) fetchStats();
}, [selectedProjects, date]); }, [selectedProjects, date]);
useEffect(() => { useEffect(() => {

View File

@ -14,7 +14,6 @@ import {
PopoverTrigger, PopoverTrigger,
} from "~/components/ui/popover"; } from "~/components/ui/popover";
import jalaali from "jalaali-js";
import { import {
CartesianGrid, CartesianGrid,
Legend, Legend,
@ -42,6 +41,7 @@ import {
TableRow, TableRow,
} from "~/components/ui/table"; } from "~/components/ui/table";
import { Tooltip as TooltipSh, TooltipTrigger } from "~/components/ui/tooltip"; import { Tooltip as TooltipSh, TooltipTrigger } from "~/components/ui/tooltip";
import { useStoredDate } from "~/hooks/useStoredDate";
import apiService from "~/lib/api"; import apiService from "~/lib/api";
import { EventBus, formatNumber, handleDataValue } from "~/lib/utils"; import { EventBus, formatNumber, handleDataValue } from "~/lib/utils";
import type { CalendarDate } from "~/types/util.type"; import type { CalendarDate } from "~/types/util.type";
@ -199,7 +199,6 @@ export default function Timeline(valueTimeLine: string) {
export function ProductInnovationPage() { export function ProductInnovationPage() {
// const [showPopup, setShowPopup] = useState(false); // const [showPopup, setShowPopup] = useState(false);
const { jy } = jalaali.toJalaali(new Date());
const [projects, setProjects] = useState<ProductInnovationData[]>([]); const [projects, setProjects] = useState<ProductInnovationData[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [loadingMore, setLoadingMore] = useState(false); const [loadingMore, setLoadingMore] = useState(false);
@ -264,10 +263,8 @@ export function ProductInnovationPage() {
}, },
}); });
const [date, setDate] = useState<CalendarDate>({ const [date, setDate] = useStoredDate();
start: `${jy}/01/01`,
end: `${jy}/12/30`,
});
const observerRef = useRef<HTMLDivElement>(null); const observerRef = useRef<HTMLDivElement>(null);
const fetchingRef = useRef(false); const fetchingRef = useRef(false);
@ -520,11 +517,11 @@ export function ProductInnovationPage() {
}, []); }, []);
useEffect(() => { useEffect(() => {
fetchProjects(true); if (date.end && date.start) fetchProjects(true);
}, [sortConfig, date]); }, [sortConfig, date]);
useEffect(() => { useEffect(() => {
fetchStats(); if (date.end && date.start) fetchStats();
}, [date]); }, [date]);
useEffect(() => { useEffect(() => {

View File

@ -1,4 +1,3 @@
import jalaali from "jalaali-js";
import { ChevronDown, ChevronUp, RefreshCw } from "lucide-react"; import { ChevronDown, ChevronUp, RefreshCw } from "lucide-react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
@ -13,6 +12,7 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "~/components/ui/table"; } from "~/components/ui/table";
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";
import type { CalendarDate } from "~/types/util.type"; import type { CalendarDate } from "~/types/util.type";
@ -154,7 +154,6 @@ const columns: ColumnDef[] = [
]; ];
export function ProjectManagementPage() { export function ProjectManagementPage() {
const { jy } = jalaali.toJalaali(new Date());
const [projects, setProjects] = useState<ProjectData[]>([]); const [projects, setProjects] = useState<ProjectData[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [loadingMore, setLoadingMore] = useState(false); const [loadingMore, setLoadingMore] = useState(false);
@ -171,10 +170,12 @@ export function ProjectManagementPage() {
const fetchingRef = useRef(false); const fetchingRef = useRef(false);
const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null); const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const scrollContainerRef = useRef<HTMLDivElement>(null); const scrollContainerRef = useRef<HTMLDivElement>(null);
const [date, setDate] = useState<CalendarDate>({ // const [date, setDate] = useState<CalendarDate>({
start: `${jy}/01/01`, // start: `${jy}/01/01`,
end: `${jy}/12/30`, // end: `${jy}/12/30`,
}); // });
const [date, setDate] = useStoredDate();
const fetchProjects = async (reset = false) => { const fetchProjects = async (reset = false) => {
// Prevent concurrent API calls // Prevent concurrent API calls
@ -288,8 +289,10 @@ export function ProjectManagementPage() {
}, [hasMore, loading, loadingMore]); }, [hasMore, loading, loadingMore]);
useEffect(() => { useEffect(() => {
fetchProjects(true); if (date.end && date.start) {
fetchTotalCount(); fetchProjects(true);
fetchTotalCount();
}
}, [sortConfig, date]); }, [sortConfig, date]);
useEffect(() => { useEffect(() => {

View File

@ -1,4 +1,3 @@
import jalaali from "jalaali-js";
import { useEffect, useReducer, useRef, useState } from "react"; import { useEffect, useReducer, useRef, useState } from "react";
import { import {
Bar, Bar,
@ -12,6 +11,7 @@ import {
} from "recharts"; } from "recharts";
import { Dialog, DialogContent, DialogHeader } from "~/components/ui/dialog"; import { Dialog, DialogContent, DialogHeader } from "~/components/ui/dialog";
import { Skeleton } from "~/components/ui/skeleton"; import { Skeleton } from "~/components/ui/skeleton";
import { useStoredDate } from "~/hooks/useStoredDate";
import apiService from "~/lib/api"; import apiService from "~/lib/api";
import { EventBus, formatNumber } from "~/lib/utils"; import { EventBus, formatNumber } from "~/lib/utils";
import type { CalendarDate } from "~/types/util.type"; import type { CalendarDate } from "~/types/util.type";
@ -118,7 +118,6 @@ export function StrategicAlignmentPopup({
open, open,
onOpenChange, onOpenChange,
}: StrategicAlignmentPopupProps) { }: StrategicAlignmentPopupProps) {
const { jy } = jalaali.toJalaali(new Date());
const [data, setData] = useState<StrategicAlignmentData[]>([]); const [data, setData] = useState<StrategicAlignmentData[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const contentRef = useRef<HTMLDivElement | null>(null); const contentRef = useRef<HTMLDivElement | null>(null);
@ -128,10 +127,8 @@ export function StrategicAlignmentPopup({
dropDownItems: [], dropDownItems: [],
}); });
const [date, setDate] = useState<CalendarDate>({ const [date, setDate] = useStoredDate();
start: `${jy}/01/01`,
end: `${jy}/12/30`,
});
useEffect(() => { useEffect(() => {
if (open) { if (open) {
fetchData(); fetchData();

View File

@ -12,6 +12,7 @@ import {
} from "recharts"; } from "recharts";
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
import { CustomBarChart } from "~/components/ui/custom-bar-chart"; import { CustomBarChart } from "~/components/ui/custom-bar-chart";
import { useStoredDate } from "~/hooks/useStoredDate";
import apiService from "~/lib/api"; import apiService from "~/lib/api";
import { EventBus, formatNumber } from "~/lib/utils"; import { EventBus, formatNumber } from "~/lib/utils";
import type { CalendarDate } from "~/types/util.type"; import type { CalendarDate } from "~/types/util.type";
@ -63,7 +64,9 @@ export function InfoPanel({ selectedCompany }: InfoPanelProps) {
const [counts, setCounts] = useState<EcosystemCounts | null>(null); const [counts, setCounts] = useState<EcosystemCounts | null>(null);
const [processData, setProcessData] = useState<ProcessActorsData[]>([]); const [processData, setProcessData] = useState<ProcessActorsData[]>([]);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [date, setDate] = useState<CalendarDate>(); // const [date, setDate] = useState<CalendarDate>();
const [date, setDate] = useStoredDate();
useEffect(() => { useEffect(() => {
EventBus.on("dateSelected", (date: CalendarDate) => { EventBus.on("dateSelected", (date: CalendarDate) => {
if (date) { if (date) {
@ -73,7 +76,7 @@ export function InfoPanel({ selectedCompany }: InfoPanelProps) {
}, []); }, []);
useEffect(() => { useEffect(() => {
fetchCounts(); if (date.end && date.start) fetchCounts();
}, [date]); }, [date]);
const fetchCounts = async () => { const fetchCounts = async () => {

View File

@ -1,5 +1,6 @@
import * as d3 from "d3"; import * as d3 from "d3";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { useStoredDate } from "~/hooks/useStoredDate";
import { EventBus } from "~/lib/utils"; import { EventBus } from "~/lib/utils";
import type { CalendarDate } from "~/types/util.type"; import type { CalendarDate } from "~/types/util.type";
import { useAuth } from "../../contexts/auth-context"; import { useAuth } from "../../contexts/auth-context";
@ -73,7 +74,9 @@ export function NetworkGraph({
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const { token } = useAuth(); const { token } = useAuth();
const [date, setDate] = useState<CalendarDate>(); // const [date, setDate] = useState<CalendarDate>();
const [date, setDate] = useStoredDate();
useEffect(() => { useEffect(() => {
EventBus.on("dateSelected", (date: CalendarDate) => { EventBus.on("dateSelected", (date: CalendarDate) => {
if (date) { if (date) {
@ -120,7 +123,10 @@ export function NetworkGraph({
setIsLoading(true); setIsLoading(true);
try { try {
const res = await apiService.call<any[]>({ const res = await apiService.call<any[]>({
graph_production_function: {}, graph_production_function: {
start_date: date.start || null,
end_date: date.end || null,
},
}); });
if (aborted) return; if (aborted) return;
@ -484,35 +490,37 @@ export function NetworkGraph({
onLoadingChange?.(true); onLoadingChange?.(true);
try { try {
const res = await callAPI(d.stageid); if (date.start && date.end) {
const responseData = JSON.parse(res.data); const res = await callAPI(d.stageid);
const fieldValues = const responseData = JSON.parse(res.data);
JSON.parse(responseData?.getvalue)?.[0]?.FieldValues || []; const fieldValues =
JSON.parse(responseData?.getvalue)?.[0]?.FieldValues || [];
const filteredFields = fieldValues.filter( const filteredFields = fieldValues.filter(
(field: any) => (field: any) =>
!["image", "img", "full_name", "about_collaboration"].includes( !["image", "img", "full_name", "about_collaboration"].includes(
field.F.toLowerCase() 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("about_collaboration") || field.F.toLowerCase().includes("about_collaboration") ||
field.F.toLowerCase().includes("about") field.F.toLowerCase().includes("about")
); );
const companyDetails: CompanyDetails = { const companyDetails: CompanyDetails = {
id: d.id, id: d.id,
label: d.label, label: d.label,
category: d.category, category: d.category,
stageid: d.stageid, stageid: d.stageid,
fields: filteredFields, fields: filteredFields,
description: descriptionField?.V || undefined, description: descriptionField?.V || undefined,
}; };
onNodeClick(companyDetails); onNodeClick(companyDetails);
}
} catch (error) { } catch (error) {
console.error("Failed to fetch company details:", error); console.error("Failed to fetch company details:", error);
// Keep the basic details already shown // Keep the basic details already shown
@ -541,7 +549,7 @@ export function NetworkGraph({
return () => { return () => {
simulation.stop(); simulation.stop();
}; };
}, [nodes, links, isLoading, isMounted, onNodeClick, callAPI]); }, [nodes, links, isLoading, isMounted, onNodeClick, callAPI, date]);
if (error) { if (error) {
return ( return (

View File

@ -0,0 +1,27 @@
import jalaali from "jalaali-js";
import { useEffect, useState } from "react";
import type { CalendarDate } from "~/types/util.type";
const { jy } = jalaali.toJalaali(new Date());
export function useStoredDate(): [
CalendarDate,
React.Dispatch<React.SetStateAction<CalendarDate>>,
] {
const [date, setDate] = useState<CalendarDate>({});
useEffect(() => {
const storedDate = localStorage.getItem("dateSelected");
if (storedDate) {
setDate(JSON.parse(storedDate));
} else {
setDate({
start: `${jy}/01/01`,
end: `${jy}/12/30`,
});
}
}, [jy]);
return [date, setDate];
}

View File

@ -1,28 +1,26 @@
import type { Route } from "./+types/ecosystem"; import moment from "moment-jalaali";
import React from "react"; import React from "react";
import { ProtectedRoute } from "~/components/auth/protected-route"; import { ProtectedRoute } from "~/components/auth/protected-route";
import { DashboardLayout } from "~/components/dashboard/layout"; import { DashboardLayout } from "~/components/dashboard/layout";
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card"; import { InfoPanel } from "~/components/ecosystem/info-panel";
import { NetworkGraph } from "~/components/ecosystem/network-graph";
import { Card, CardContent } from "~/components/ui/card";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
DialogDescription,
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from "~/components/ui/dialog"; } from "~/components/ui/dialog";
import { NetworkGraph } from "~/components/ecosystem/network-graph";
import { InfoPanel } from "~/components/ecosystem/info-panel";
import { useAuth } from "~/contexts/auth-context"; import { useAuth } from "~/contexts/auth-context";
import moment from "moment-jalaali"; import type { Route } from "./+types/ecosystem";
// Get API base URL at module level to avoid process.env access in browser // Get API base URL at module level to avoid process.env access in browser
const API_BASE_URL = const API_BASE_URL =
import.meta.env.VITE_API_URL || "https://inogen-back.pelekan.org/api"; import.meta.env.VITE_API_URL || "https://inogen-back.pelekan.org/api";
// Import the CompanyDetails type // Import the CompanyDetails type
import type { CompanyDetails } from "~/components/ecosystem/network-graph";
import { formatNumber } from "~/lib/utils";
import { Hexagon } from "lucide-react"; import { Hexagon } from "lucide-react";
import type { CompanyDetails } from "~/components/ecosystem/network-graph";
export function meta({}: Route.MetaArgs) { export function meta({}: Route.MetaArgs) {
return [ return [
@ -89,7 +87,10 @@ export default function EcosystemPage() {
<div className="lg:col-span-8 h-full"> <div className="lg:col-span-8 h-full">
<Card className="h-full overflow-hidden bg-transparent border-[#3F415A]"> <Card className="h-full overflow-hidden bg-transparent border-[#3F415A]">
<CardContent className="p-0 h-full bg-transparent"> <CardContent className="p-0 h-full bg-transparent">
<NetworkGraph onNodeClick={handleNodeClick} onLoadingChange={handleLoadingChange} /> <NetworkGraph
onNodeClick={handleNodeClick}
onLoadingChange={handleLoadingChange}
/>
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
@ -224,9 +225,11 @@ export default function EcosystemPage() {
</span> </span>
<span className="text-right min-w-1/3"> <span className="text-right min-w-1/3">
<span className="font-persian text-sm font-normal text-right"> <span className="font-persian text-sm font-normal text-right">
{handleValue(field.V)} {handleValue(field.V)}
{field.U && <span className="mr-1">({field.U})</span>} {field.U && (
</span> <span className="mr-1">({field.U})</span>
)}
</span>
</span> </span>
</div> </div>
))} ))}

View File

@ -1,6 +1,6 @@
export interface CalendarDate { export interface CalendarDate {
start: string; start?: string;
end: string; end?: string;
sinceMonth?: string; sinceMonth?: string;
untilMonth?: string; untilMonth?: string;
} }