From ab3bf6f16251548594a4274656a350a46444c872 Mon Sep 17 00:00:00 2001 From: NlightN22 Date: Sat, 30 Nov 2024 17:58:27 +0700 Subject: [PATCH] add host and tags params to main page --- src/pages/EventsPage.tsx | 19 +++--- src/pages/MainPage.tsx | 26 +++++-- src/shared/stores/events.store.ts | 26 ++----- src/shared/stores/main.store.ts | 67 ++++++++++++++----- src/widgets/sidebars/MainFiltersRightSide.tsx | 17 +++-- 5 files changed, 93 insertions(+), 62 deletions(-) diff --git a/src/pages/EventsPage.tsx b/src/pages/EventsPage.tsx index cd2d313..24e3202 100644 --- a/src/pages/EventsPage.tsx +++ b/src/pages/EventsPage.tsx @@ -3,13 +3,13 @@ import { notifications } from '@mantine/notifications'; import { IconAlertCircle } from '@tabler/icons-react'; import { t } from 'i18next'; import { observer } from 'mobx-react-lite'; -import { useContext, useEffect, useMemo } from 'react'; +import { useContext, useEffect } from 'react'; +import { useSearchParams } from 'react-router-dom'; import { Context } from '..'; import { isStartBiggerThanEndTime } from '../shared/utils/dateUtil'; import EventsBody from '../widgets/EventsBody'; import EventsRightFilters from '../widgets/sidebars/EventsRightFilters'; import { SideBarContext } from '../widgets/sidebars/SideBarContext'; -import { useLocation, useSearchParams } from 'react-router-dom'; export const eventsQueryParams = { hostId: 'hostId', @@ -28,6 +28,13 @@ const EventsPage = () => { useEffect(() => { setRightChildren() + const paramHostId = searchParams.get(eventsQueryParams.hostId) || undefined + const paramCameraId = searchParams.get(eventsQueryParams.cameraId) || undefined + const paramStartDate = searchParams.get(eventsQueryParams.startDate) || undefined + const paramEndDate = searchParams.get(eventsQueryParams.endDate) || undefined + const paramStartTime = searchParams.get(eventsQueryParams.startTime) || undefined + const paramEndTime = searchParams.get(eventsQueryParams.endTime) || undefined + eventsStore.loadFiltersFromPage(paramHostId, paramCameraId, paramStartDate, paramEndDate, paramStartTime, paramEndTime) return () => setRightChildren(null) }, []) @@ -37,13 +44,7 @@ const EventsPage = () => { const { hostId, cameraId, period, startTime, endTime } = eventsStore.filters useEffect(() => { - const paramHostId = searchParams.get(eventsQueryParams.hostId) || undefined - const paramCameraId = searchParams.get(eventsQueryParams.cameraId) || undefined - const paramStartDate = searchParams.get(eventsQueryParams.startDate) || undefined - const paramEndDate = searchParams.get(eventsQueryParams.endDate) || undefined - const paramStartTime = searchParams.get(eventsQueryParams.startTime) || undefined - const paramEndTime = searchParams.get(eventsQueryParams.endTime) || undefined - eventsStore.loadFiltersFromPage(paramHostId, paramCameraId, paramStartDate, paramEndDate, paramStartTime, paramEndTime) + }, [searchParams]) useEffect(() => { diff --git a/src/pages/MainPage.tsx b/src/pages/MainPage.tsx index f47ac38..afd27d9 100644 --- a/src/pages/MainPage.tsx +++ b/src/pages/MainPage.tsx @@ -1,4 +1,5 @@ import { Flex, Grid } from '@mantine/core'; +import { IconSearch } from '@tabler/icons-react'; import { useQuery } from '@tanstack/react-query'; import { observer } from 'mobx-react-lite'; import { useContext, useEffect, useMemo, useState } from 'react'; @@ -7,24 +8,30 @@ import { Context } from '..'; import { useRealmUser } from '../hooks/useRealmUser'; import { frigateApi, frigateQueryKeys } from '../services/frigate.proxy/frigate.api'; import { GetCameraWHostWConfig } from '../services/frigate.proxy/frigate.schema'; +import ClearableTextInput from '../shared/components/inputs/ClearableTextInput'; import CenterLoader from '../shared/components/loaders/CenterLoader'; import { isProduction } from '../shared/env.const'; import CameraCard from '../widgets/CameraCard'; import MainFiltersRightSide from '../widgets/sidebars/MainFiltersRightSide'; import { SideBarContext } from '../widgets/sidebars/SideBarContext'; import RetryErrorPage from './RetryErrorPage'; -import { IconSearch } from '@tabler/icons-react'; -import ClearableTextInput from '../shared/components/inputs/ClearableTextInput'; -import { CameraTag } from '../types/tags'; +import { useSearchParams } from 'react-router-dom'; + +export const mainPageParams = { + hostId: 'hostId', + selectedTags: 'selectedTags', + searchQuery: 'searchQuery', +} const MainPage = () => { const { t } = useTranslation() const { mainStore } = useContext(Context) + const [searchParams] = useSearchParams() + const { setRightChildren } = useContext(SideBarContext) - const { selectedHostId, selectedTags } = mainStore + const { hostId: selectedHostId, selectedTags } = mainStore.filters const [searchQuery, setSearchQuery] = useState() const [filteredCameras, setFilteredCameras] = useState() - const [filteredTags, setFilteredTags] = useState() const realmUser = useRealmUser() if (!isProduction) console.log('Realmuser:', realmUser) @@ -36,6 +43,13 @@ const MainPage = () => { useEffect(() => { setRightChildren(); + const serializedTags = searchParams.get(mainPageParams.selectedTags) + const deSerializedTags = serializedTags ? mainStore.getArrayParam(serializedTags) : [] + mainStore.loadFiltersFromPage({ + hostId: searchParams.get(mainPageParams.hostId) || undefined, + searchQuery: searchParams.get(mainPageParams.searchQuery) || undefined, + selectedTags: deSerializedTags, + }) return () => setRightChildren(null); }, []); @@ -48,7 +62,7 @@ const MainPage = () => { const filterCameras = (camera: GetCameraWHostWConfig) => { const matchesHostId = selectedHostId ? camera.frigateHost?.id === selectedHostId : true const matchesSearchQuery = searchQuery ? camera.name.toLowerCase().includes(searchQuery.toLowerCase()) : true - const matchesTags = selectedTags.length === 0 || camera.tags.some( tag => selectedTags.includes(tag.id)) + const matchesTags = selectedTags.length === 0 || camera.tags.some( tag => selectedTags.includes(tag.id)) return matchesHostId && matchesSearchQuery && matchesTags } diff --git a/src/shared/stores/events.store.ts b/src/shared/stores/events.store.ts index 35f4515..1a8c30a 100644 --- a/src/shared/stores/events.store.ts +++ b/src/shared/stores/events.store.ts @@ -15,20 +15,6 @@ export class EventsStore { constructor() { makeAutoObservable(this); - // this.loadFiltersFromURL(); - } - - loadFiltersFromURL() { - const params = new URLSearchParams(window.location.search); - this.filters.hostId = params.get(eventsQueryParams.hostId) || undefined; - this.filters.cameraId = params.get(eventsQueryParams.cameraId) || undefined; - const startDate = params.get(eventsQueryParams.startDate); - const endDate = params.get(eventsQueryParams.endDate); - if (startDate && endDate) { - this.filters.period = [new Date(startDate), new Date(endDate)] - } - this.filters.startTime = params.get(eventsQueryParams.startTime) || undefined - this.filters.endTime = params.get(eventsQueryParams.endTime) || undefined } loadFiltersFromPage( @@ -74,20 +60,20 @@ export class EventsStore { updateURL(navigate: (path: string, options?: NavigateOptions) => void) { const params = new URLSearchParams(); - if (this.filters.hostId) params.set('hostId', this.filters.hostId); - if (this.filters.cameraId) params.set('cameraId', this.filters.cameraId); + if (this.filters.hostId) params.set(eventsQueryParams.hostId, this.filters.hostId); + if (this.filters.cameraId) params.set(eventsQueryParams.cameraId, this.filters.cameraId); if (this.filters.period) { const [startDate, endDate] = this.filters.period; if (startDate instanceof Date && !isNaN(startDate.getTime())) { - params.set('startDate', startDate.toISOString()); + params.set(eventsQueryParams.startDate, startDate.toISOString()); } if (endDate instanceof Date && !isNaN(endDate.getTime())) { - params.set('endDate', endDate.toISOString()); + params.set(eventsQueryParams.endDate, endDate.toISOString()); } } - if (this.filters.startTime) params.set('startTime', this.filters.startTime) - if (this.filters.endTime) params.set('endTime', this.filters.endTime) + if (this.filters.startTime) params.set(eventsQueryParams.startTime, this.filters.startTime) + if (this.filters.endTime) params.set(eventsQueryParams.endTime, this.filters.endTime) navigate(`?${params.toString()}`, { replace: true }); } diff --git a/src/shared/stores/main.store.ts b/src/shared/stores/main.store.ts index ae20fe2..7dc1785 100644 --- a/src/shared/stores/main.store.ts +++ b/src/shared/stores/main.store.ts @@ -1,26 +1,57 @@ import { makeAutoObservable } from "mobx"; -import { CameraTag } from "../../types/tags"; +import { NavigateOptions } from "react-router-dom"; +import { mainPageParams } from "../../pages/MainPage"; +import { isProduction } from "../env.const"; + + +interface Filters { + hostId?: string | null + searchQuery?: string | null + selectedTags: string[] +} export class MainStore { - - private _selectedHostId: string | undefined - public get selectedHostId(): string | undefined { - return this._selectedHostId; - } - public set selectedHostId(value: string | undefined) { - this._selectedHostId = value; - } - - - private _selectedTags: string[] = []; - public get selectedTags(): string[] { - return this._selectedTags; - } - public set selectedTags(value: string[]) { - this._selectedTags = value; - } + filters: Filters = { selectedTags: []} constructor() { makeAutoObservable(this) } + + loadFiltersFromPage(filters: Filters) { + if (!isProduction) console.log('MainPage load filters') + this.filters = filters + } + + updateURL(navigate: (path: string, options?: NavigateOptions) => void) { + const params = new URLSearchParams(); + if (this.filters.hostId) params.set(mainPageParams.hostId, this.filters.hostId); + if (this.filters.searchQuery) params.set(mainPageParams.searchQuery, this.filters.searchQuery); + if (this.filters.selectedTags) { + const serializedTags = this.filters.selectedTags.join(",") + params.set(mainPageParams.selectedTags, serializedTags); + } + navigate(`?${params.toString()}`, { replace: true }); + } + + setHostId(hostId: string, navigate: (path: string, options?: NavigateOptions) => void) { + this.filters.hostId = hostId; + this.updateURL(navigate) + } + + setSearchQuery(searchQuery: string, navigate: (path: string, options?: NavigateOptions) => void) { + this.filters.searchQuery = searchQuery; + this.updateURL(navigate) + } + + setSelectedTags(selectedTags: string[], navigate: (path: string, options?: NavigateOptions) => void) { + if (!isProduction) console.log('MainPage set filters.selectedTags ', selectedTags) + this.filters.selectedTags = selectedTags ? selectedTags : [] + this.updateURL(navigate) + } + + getArrayParam = (key: string): string[] => { + const searchParams = new URLSearchParams(window.location.search); + const paramValue = searchParams.get(key); + return paramValue ? paramValue.split(",") : []; + } } \ No newline at end of file diff --git a/src/widgets/sidebars/MainFiltersRightSide.tsx b/src/widgets/sidebars/MainFiltersRightSide.tsx index 51d2b99..67b9d7d 100644 --- a/src/widgets/sidebars/MainFiltersRightSide.tsx +++ b/src/widgets/sidebars/MainFiltersRightSide.tsx @@ -5,37 +5,36 @@ import { Context } from '../..'; import HostSelect from '../../shared/components/filters/HostSelect'; import UserTagsFilter from '../../shared/components/filters/UserTagsFilter'; import { isProduction } from '../../shared/env.const'; - - - +import { useNavigate } from 'react-router-dom'; const MainFiltersRightSide = () => { const { t } = useTranslation() + const navigate = useNavigate() const { mainStore } = useContext(Context) - const { selectedHostId } = mainStore + const { hostId } = mainStore.filters const handleSelectHost = (value: string) => { if (!isProduction) console.log('handleSelectHost value', value) - mainStore.selectedHostId = value + mainStore.setHostId(value, navigate) } const handleSelectTags = (tags: string[]) => { if (!isProduction) console.log('handleSelectTags value', tags) - mainStore.selectedTags = tags + mainStore.setSelectedTags(tags, navigate) } return ( <> -