From 3c42c114f5200b0d36eb82164e32ce15adf3df0f Mon Sep 17 00:00:00 2001 From: Denozordec Date: Fri, 11 Sep 2026 09:38:31 +0700 Subject: [PATCH] refactor(statistics): improve component structure and enhance state management - Introduced Suspense for lazy loading in StatisticsPage to optimize rendering. - Refactored StatisticsPage to separate inner logic into StatisticsPageInner for better readability. - Updated PeriodSelector to utilize useCallback for handling state changes, improving performance and clarity. Co-authored-by: Cursor --- app/(main)/statistics/page.tsx | 20 ++++++++++++++------ components/statistics/period-selector.tsx | 21 +++++++++++++-------- package-lock.json | 15 +++++++++++++++ 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/app/(main)/statistics/page.tsx b/app/(main)/statistics/page.tsx index 864fa88..36ba0e1 100644 --- a/app/(main)/statistics/page.tsx +++ b/app/(main)/statistics/page.tsx @@ -1,7 +1,7 @@ "use client" -import { useCallback, useEffect, useMemo, useState } from "react" -import { useRouter, useSearchParams } from "next/navigation" +import { Suspense, useCallback, useEffect, useMemo, useState } from "react" +import { useSearchParams } from "next/navigation" import { ActivityIcon, DatabaseIcon, @@ -254,8 +254,7 @@ function chipList(slices: CubeSlices): { key: string; label: string }[] { return chips } -export default function StatisticsPage() { - const router = useRouter() +function StatisticsPageInner() { const searchParams = useSearchParams() const { mode, backendUrl, prefsHydrated } = useDataSource() const isLive = mode === "live" @@ -282,9 +281,10 @@ export default function StatisticsPage() { else sp.delete(k) } const qs = sp.toString() - router.replace(qs ? `/statistics?${qs}` : "/statistics") + if (qs === searchParams.toString()) return + window.history.replaceState(null, "", qs ? `/statistics?${qs}` : "/statistics") }, - [router, searchParams], + [searchParams], ) const setRange = useCallback( @@ -548,3 +548,11 @@ export default function StatisticsPage() { ) } + +export default function StatisticsPage() { + return ( + + + + ) +} diff --git a/components/statistics/period-selector.tsx b/components/statistics/period-selector.tsx index 4a54f86..fc3f5d2 100644 --- a/components/statistics/period-selector.tsx +++ b/components/statistics/period-selector.tsx @@ -1,6 +1,6 @@ "use client" -import { useMemo } from "react" +import { useCallback, useMemo, useState } from "react" import { format } from "date-fns" import { ru } from "date-fns/locale" import { CalendarIcon } from "lucide-react" @@ -130,14 +130,19 @@ export function PeriodSelector({ range: DateRangeYmd onChange: (next: DateRangeYmd) => void }) { + const [open, setOpen] = useState(false) const selectorValue = useMemo(() => rangeToSelector(range), [range]) - function handleSelectorChange(value: DateSelectorValue) { - const next = dateSelectorToRange(value) - if (!next) return - if (next.from === range.from && next.to === range.to) return - onChange(next) - } + const handleSelectorChange = useCallback( + (value: DateSelectorValue) => { + const next = dateSelectorToRange(value) + if (!next) return + if (next.from === range.from && next.to === range.to) return + onChange(next) + setOpen(false) + }, + [onChange, range.from, range.to], + ) const activePreset = PRESETS.find((p) => { const r = rangeForPreset(p.id) @@ -157,7 +162,7 @@ export function PeriodSelector({ {p.label} ))} - + diff --git a/package-lock.json b/package-lock.json index b19640e..e9eb672 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14875,6 +14875,21 @@ "dependencies": { "zod": "^4.4.1" } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.4.tgz", + "integrity": "sha512-kMVGgsqhO5YTYODD9IPGGhA6iprWidQckK3LmPeW08PIFENRmgfb4MjXHO+p//d+ts2rpjvK5gXWzXSMrPl9cw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } }