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 { ChangeEvent, useContext, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { Context } from '..'; import { useDebounce } from '../hooks/useDebounce'; 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 MainFiltersRightSide from '../widgets/sidebars/MainFiltersRightSide'; import { SideBarContext } from '../widgets/sidebars/SideBarContext'; import RetryErrorPage from './RetryErrorPage'; import CameraCard from '../widgets/card/CameraCard'; import { useInView } from 'react-intersection-observer'; export const mainPageParams = { hostId: 'hostId', selectedTags: 'selectedTags', searchQuery: 'searchQuery', } const MainPage = () => { const { t } = useTranslation() const navigate = useNavigate() const { mainStore } = useContext(Context) const [searchParams] = useSearchParams() const { setRightChildren } = useContext(SideBarContext) const { hostId: selectedHostId, selectedTags, searchQuery } = mainStore.filters const [filteredCameras, setFilteredCameras] = useState([]) const { ref, inView } = useInView({ threshold: 0.5 }) const [visibleCameras, setVisibleCameras] = useState([]) const realmUser = useRealmUser() if (!isProduction) console.log('Realmuser:', realmUser) const { data: cameras, isPending, isError, refetch } = useQuery({ queryKey: [frigateQueryKeys.getCamerasWHost, selectedHostId, searchQuery, selectedTags], queryFn: () => frigateApi.getCamerasWHost({ name: searchQuery, // filter by camera name frigateHostId: selectedHostId, // filter by host id tagIds: selectedTags, // filter by tag id(s) // offset and limit can be added later for pagination }), }) useEffect(() => { setFilteredCameras(cameras || []); setVisibleCameras([]); // reset visible cameras for pagination }, [cameras]); useEffect(() => { const pageSize = 20; if (inView && filteredCameras.length > visibleCameras.length) { const nextBatch = filteredCameras.slice(visibleCameras.length, visibleCameras.length + pageSize); setVisibleCameras(prev => [...prev, ...nextBatch]); } }, [inView, filteredCameras, visibleCameras]); useEffect(() => { const hostId = searchParams.get(mainPageParams.hostId) || '' const searchQuery = searchParams.get(mainPageParams.searchQuery) || '' const selectedTags = mainStore.getArrayParam(mainPageParams.selectedTags) mainStore.setHostId(hostId, navigate) mainStore.setSearchQuery(searchQuery, navigate) mainStore.setSelectedTags(selectedTags, navigate) }, [searchParams]) useEffect(() => { const deSerializedTags = mainStore.getArrayParam(mainPageParams.selectedTags) mainStore.loadFiltersFromPage({ hostId: searchParams.get(mainPageParams.hostId) || undefined, searchQuery: searchParams.get(mainPageParams.searchQuery) || undefined, selectedTags: deSerializedTags, }) setRightChildren(); return () => setRightChildren(null); }, []); const debouncedHandleSearchQuery = useDebounce((value: string) => { mainStore.setSearchQuery(value, navigate); }, 600); const onInputChange = (event: ChangeEvent) => { debouncedHandleSearchQuery(event.currentTarget.value) } if (isPending) return if (isError) return if (!isProduction) console.log('MainPage rendered') return ( } value={searchQuery || undefined} onChange={onInputChange} /> {visibleCameras.map(camera => ( ))}
{/* trigger point */} ); } export default observer(MainPage);