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 <[email protected]>
This commit is contained in:
Denozordec
2026-09-11 09:38:31 +07:00
co-authored by Cursor
parent 5aef419582
commit 2ef6f833c2
3 changed files with 42 additions and 14 deletions
+14 -6
View File
@@ -1,7 +1,7 @@
"use client" "use client"
import { useCallback, useEffect, useMemo, useState } from "react" import { Suspense, useCallback, useEffect, useMemo, useState } from "react"
import { useRouter, useSearchParams } from "next/navigation" import { useSearchParams } from "next/navigation"
import { import {
ActivityIcon, ActivityIcon,
DatabaseIcon, DatabaseIcon,
@@ -254,8 +254,7 @@ function chipList(slices: CubeSlices): { key: string; label: string }[] {
return chips return chips
} }
export default function StatisticsPage() { function StatisticsPageInner() {
const router = useRouter()
const searchParams = useSearchParams() const searchParams = useSearchParams()
const { mode, backendUrl, prefsHydrated } = useDataSource() const { mode, backendUrl, prefsHydrated } = useDataSource()
const isLive = mode === "live" const isLive = mode === "live"
@@ -282,9 +281,10 @@ export default function StatisticsPage() {
else sp.delete(k) else sp.delete(k)
} }
const qs = sp.toString() 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( const setRange = useCallback(
@@ -548,3 +548,11 @@ export default function StatisticsPage() {
</div> </div>
) )
} }
export default function StatisticsPage() {
return (
<Suspense fallback={null}>
<StatisticsPageInner />
</Suspense>
)
}
+13 -8
View File
@@ -1,6 +1,6 @@
"use client" "use client"
import { useMemo } from "react" import { useCallback, useMemo, useState } from "react"
import { format } from "date-fns" import { format } from "date-fns"
import { ru } from "date-fns/locale" import { ru } from "date-fns/locale"
import { CalendarIcon } from "lucide-react" import { CalendarIcon } from "lucide-react"
@@ -130,14 +130,19 @@ export function PeriodSelector({
range: DateRangeYmd range: DateRangeYmd
onChange: (next: DateRangeYmd) => void onChange: (next: DateRangeYmd) => void
}) { }) {
const [open, setOpen] = useState(false)
const selectorValue = useMemo(() => rangeToSelector(range), [range]) const selectorValue = useMemo(() => rangeToSelector(range), [range])
function handleSelectorChange(value: DateSelectorValue) { const handleSelectorChange = useCallback(
const next = dateSelectorToRange(value) (value: DateSelectorValue) => {
if (!next) return const next = dateSelectorToRange(value)
if (next.from === range.from && next.to === range.to) return if (!next) return
onChange(next) 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 activePreset = PRESETS.find((p) => {
const r = rangeForPreset(p.id) const r = rangeForPreset(p.id)
@@ -157,7 +162,7 @@ export function PeriodSelector({
{p.label} {p.label}
</Button> </Button>
))} ))}
<Popover> <Popover open={open} onOpenChange={setOpen} modal={false}>
<PopoverTrigger <PopoverTrigger
render={ render={
<Button type="button" variant="outline" size="sm" className="min-w-40 justify-between" /> <Button type="button" variant="outline" size="sm" className="min-w-40 justify-between" />
+15
View File
@@ -14875,6 +14875,21 @@
"dependencies": { "dependencies": {
"zod": "^4.4.1" "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"
}
} }
} }
} }