From 676fb240949a3eb70ede2732c9ae8ef2162230f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Z=C3=ADpek?= Date: Mon, 1 Apr 2024 09:25:21 +0200 Subject: [PATCH] Save filters into query string (non-reactive way) --- client/src/pages/Router.tsx | 6 +-- .../dashboard/contexts/DashboardContext.tsx | 41 ++++++++++++++++-- client/src/utils/hooks/useHashLocation.ts | 10 ++++- client/src/utils/hooks/useQueryString.ts | 43 +++++++++++++++++++ 4 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 client/src/utils/hooks/useQueryString.ts diff --git a/client/src/pages/Router.tsx b/client/src/pages/Router.tsx index 086aa51..81c3fc8 100644 --- a/client/src/pages/Router.tsx +++ b/client/src/pages/Router.tsx @@ -1,10 +1,10 @@ import { useAppContext } from '@/contexts/AppContext' -import { useHashLocation } from '@/utils/hooks/useHashLocation' +import { useHashRouterLocation } from '@/utils/hooks/useHashLocation' import { Route, Router as Wouter } from 'wouter' +import { AlertsPage } from './alerts/AlertsPage' import { NewDashboardPage } from './dashboard/NewDashboardPage' import { LoginPage } from './login/LoginPage' import { SensorsPage } from './sensors/SensorsPage' -import { AlertsPage } from './alerts/AlertsPage' export const Router = () => { const { loggedIn } = useAppContext() @@ -12,7 +12,7 @@ export const Router = () => { return ( <> {loggedIn && ( - + diff --git a/client/src/pages/dashboard/contexts/DashboardContext.tsx b/client/src/pages/dashboard/contexts/DashboardContext.tsx index 5c2a8a8..24d30ec 100644 --- a/client/src/pages/dashboard/contexts/DashboardContext.tsx +++ b/client/src/pages/dashboard/contexts/DashboardContext.tsx @@ -18,8 +18,12 @@ import { useState, } from 'preact/hooks' import { useQuery } from 'react-query' -import { FilterValue } from '../components/DashboardHeader/components/DashboardFilters' +import { + FilterInterval, + FilterValue, +} from '../components/DashboardHeader/components/DashboardFilters' import { BoxDefinition } from '../types' +import { useQueryString } from '@/utils/hooks/useQueryString' type DashboardContextType = { filter: FilterValue @@ -48,6 +52,8 @@ export const DashboardContextProvider = ({ const dashboards = useQuery(['/dashboards'], getDashboards) + const { getValues: getQuery, setValues: setQuery } = useQueryString() + const dashboard = useQuery( ['/dashboards', dashboardId], () => getDashboard(dashboardId), @@ -98,11 +104,40 @@ export const DashboardContextProvider = ({ }, [dashboards.data, isDashboardSelected, dashboards.isFetching]) const [filter, setFilter] = useState(() => { - const range = intervalToRange('week', new Date(), new Date()) + const query = getQuery() + const queryFilter = query.get('interval') + const queryFilterFrom = query.get('from') + const queryFilterTo = query.get('to') - return { interval: 'week', customFrom: range[0], customTo: range[1] } + const presetInterval = + queryFilter && + ['hour', 'day', 'week', 'month', 'year', 'custom'].includes(queryFilter) + ? (queryFilter as FilterInterval) + : 'week' + + const customFrom = queryFilterFrom ? new Date(queryFilterFrom) : new Date() + const customTo = queryFilterTo ? new Date(queryFilterTo) : new Date() + + const range = intervalToRange(presetInterval, customFrom, customTo) + console.log({ presetInterval, range }) + + return { + interval: presetInterval, + customFrom: range[0], + customTo: range[1], + } }) + useEffect(() => { + setQuery({ + interval: filter.interval, + ...(filter.interval === 'custom' && { + from: filter.customFrom.toISOString(), + to: filter.customTo.toISOString(), + }), + }) + }, [filter]) + const verticalMode = viewport.width < 800 const value = useMemo( diff --git a/client/src/utils/hooks/useHashLocation.ts b/client/src/utils/hooks/useHashLocation.ts index b068dda..8288537 100644 --- a/client/src/utils/hooks/useHashLocation.ts +++ b/client/src/utils/hooks/useHashLocation.ts @@ -21,5 +21,13 @@ export const useHashLocation = () => { return () => window.removeEventListener('hashchange', handler) }, []) - return [loc, navigate] + return [loc, navigate] as const +} + +export const useHashRouterLocation = () => { + const [location, setLocation] = useHashLocation() + + const locationWithoutQueryString = location.split('?')[0] + + return [locationWithoutQueryString, setLocation] as const } diff --git a/client/src/utils/hooks/useQueryString.ts b/client/src/utils/hooks/useQueryString.ts new file mode 100644 index 0000000..decc02f --- /dev/null +++ b/client/src/utils/hooks/useQueryString.ts @@ -0,0 +1,43 @@ +import { useCallback, useMemo, useRef } from 'preact/hooks' +import { useHashLocation } from './useHashLocation' + +export const useQueryString = () => { + const [location, setLocation] = useHashLocation() + + const values = useMemo(() => { + const queryIndex = location.indexOf('?') + + if (queryIndex === -1) { + return [location, new URLSearchParams()] as const + } + + const search = location.slice(queryIndex + 1) + + console.log('search', search) + + return [location.slice(0, queryIndex), new URLSearchParams(search)] as const + }, [location]) + + const valuesRef = useRef(values) + valuesRef.current = values + + const getValues = useCallback(() => { + const [, searchParams] = valuesRef.current + + return searchParams + }, []) + + const setValues = useCallback((values: Record) => { + const [baseLocation] = valuesRef.current + + const newParams = new URLSearchParams(values) + setLocation(`${baseLocation}?${newParams}`) + }, []) + + const hookData = useMemo( + () => ({ getValues, setValues }), + [getValues, setValues] + ) + + return hookData +}