From 22e1de748fd41e02771d31ff3d0152f49ead4ee5 Mon Sep 17 00:00:00 2001 From: jeafreezy Date: Thu, 5 Dec 2024 17:05:28 +0100 Subject: [PATCH] feat: added users models page --- frontend/src/app/router.tsx | 4 +- frontend/src/app/routes/account/models.tsx | 174 ++++++++++++- .../src/app/routes/models/models-list.tsx | 242 +----------------- frontend/src/contents/index.ts | 2 + frontend/src/contents/models.ts | 5 + frontend/src/enums/models.ts | 4 + frontend/src/features/models/api/factory.ts | 6 +- .../src/features/models/api/get-models.ts | 2 + .../components/filters/clear-filters.tsx | 33 +++ .../models/components/filters/index.ts | 2 + .../components/filters/mobile-filter.tsx | 22 ++ .../src/features/models/components/header.tsx | 6 +- .../src/features/models/components/index.ts | 2 + .../models/components/layout-toggle.tsx | 42 +++ .../features/models/components/map-toggle.tsx | 38 +++ .../src/features/models/hooks/use-models.ts | 134 +++++++++- 16 files changed, 476 insertions(+), 242 deletions(-) create mode 100644 frontend/src/contents/models.ts create mode 100644 frontend/src/enums/models.ts create mode 100644 frontend/src/features/models/components/filters/clear-filters.tsx create mode 100644 frontend/src/features/models/components/filters/mobile-filter.tsx create mode 100644 frontend/src/features/models/components/layout-toggle.tsx create mode 100644 frontend/src/features/models/components/map-toggle.tsx diff --git a/frontend/src/app/router.tsx b/frontend/src/app/router.tsx index 7978e7dd..84351905 100644 --- a/frontend/src/app/router.tsx +++ b/frontend/src/app/router.tsx @@ -315,11 +315,11 @@ const router = createBrowserRouter([ { path: APPLICATION_ROUTES.ACCOUNT_MODELS, lazy: async () => { - const { UserAccountModelsPage } = await import( + const { UserModelsPage } = await import( "@/app/routes/account/models" ); return { - Component: () => , + Component: () => , }; }, }, diff --git a/frontend/src/app/routes/account/models.tsx b/frontend/src/app/routes/account/models.tsx index 8b81868c..2ab974db 100644 --- a/frontend/src/app/routes/account/models.tsx +++ b/frontend/src/app/routes/account/models.tsx @@ -1,5 +1,173 @@ -import { PageUnderConstruction } from "@/components/errors"; +import Pagination, { PAGE_LIMIT } from "@/components/pagination"; +import { Head } from "@/components/seo"; +import { APPLICATION_CONTENTS } from "@/contents"; +import { LayoutView } from "@/enums/models"; +import { LayoutToggle, PageHeader } from "@/features/models/components"; +import { MobileModelFiltersDialog } from "@/features/models/components/dialogs"; +import { CategoryFilter, ClearFilters, DateRangeFilter, MobileFilter, OrderingFilter, SearchFilter } from "@/features/models/components/filters"; +import { useModelsListFilters } from "@/features/models/hooks/use-models"; +import { ModelListGridLayout, ModelListTableLayout } from "@/features/models/layouts"; +import { useDialog } from "@/hooks/use-dialog"; +import { APP_CONTENT } from "@/utils"; +import { useMemo } from "react"; +import ModelNotFound from "@/features/models/components/model-not-found"; +import { SEARCH_PARAMS } from "@/app/routes/models/models-list"; +import { useAuth } from "@/app/providers/auth-provider"; -export const UserAccountModelsPage = () => { - return ; + +export const UserModelsPage = () => { + + const { isOpened, openDialog, closeDialog } = useDialog(); + const { user } = useAuth(); + + const { clearAllFilters, data, isError, isPending, isPlaceholderData, query, updateQuery } = useModelsListFilters(user.osm_id) + + // Since it's just a static filter, it's better to memoize it. + const memoizedCategoryFilter = useMemo( + () => , + [isPending], + ); + + + const renderContent = () => { + if (data?.count === 0) { + return ( +
+ +
+ ); + } + + if (query[SEARCH_PARAMS.layout] === LayoutView.LIST) { + return ( +
+ +
+ ); + } + return ( + + ); + }; + + return ( + <> + + +
+ + {/* Filters */} +
+
+
+
+ + {memoizedCategoryFilter} + {/* Mobile filters */} +
+ + +
+ + {/* Desktop */} + +
+
+ {/* Desktop */} + +
+
+ {/* Mobile */} +
+ +
+
+ {isPending ? ( +
+ ) : ( +
+
+

+ {data?.count}{" "} + { + APP_CONTENT.models.modelsList.sortingAndPaginationSection + .modelCountSuffix + } +

+
+
+ +
+ +
+
+
+ )} +
+ +
+ {renderContent()} +
+ {/* mobile pagination */} +
+ +
+
+ + ) }; diff --git a/frontend/src/app/routes/models/models-list.tsx b/frontend/src/app/routes/models/models-list.tsx index 3b04d733..c427c872 100644 --- a/frontend/src/app/routes/models/models-list.tsx +++ b/frontend/src/app/routes/models/models-list.tsx @@ -1,39 +1,31 @@ import { - useModels, + useModelsListFilters, useModelsMapData, } from "@/features/models/hooks/use-models"; -import { useCallback, useEffect, useMemo, useState } from "react"; -import { useSearchParams } from "react-router-dom"; -import { Button } from "@/components/ui/button"; -import { CategoryIcon, FilterIcon, ListIcon } from "@/components/ui/icons"; -import { Switch } from "@/components/ui/form"; +import { useMemo, } from "react"; import { ModelListGridLayout, ModelListTableLayout, } from "@/features/models/layouts"; -import { ModelsMap } from "@/features/models/components"; +import { LayoutToggle, ModelMapToggle, ModelsMap } from "@/features/models/components"; import { CategoryFilter, + ClearFilters, DateRangeFilter, + MobileFilter, OrderingFilter, SearchFilter, } from "@/features/models/components/filters"; import Pagination, { PAGE_LIMIT } from "@/components/pagination"; -import { APP_CONTENT, buildDateFilterQueryString } from "@/utils"; +import { APP_CONTENT, } from "@/utils"; import { PageHeader } from "@/features/models/components/"; -import { dateFilters } from "@/features/models/components/filters/date-range-filter"; -import { ORDERING_FIELDS } from "@/features/models/components/filters/ordering-filter"; -import { FeatureCollection, TQueryParams } from "@/types"; +import { FeatureCollection, } from "@/types"; import ModelNotFound from "@/features/models/components/model-not-found"; -import useDebounce from "@/hooks/use-debounce"; import { useDialog } from "@/hooks/use-dialog"; import { MobileModelFiltersDialog } from "@/features/models/components/dialogs"; import { Head } from "@/components/seo"; +import { LayoutView } from "@/enums/models"; -export enum LayoutView { - LIST = "list", - GRID = "grid", -} export const SEARCH_PARAMS = { startDate: "start_date", @@ -47,209 +39,14 @@ export const SEARCH_PARAMS = { id: "id", }; -const ClearFilters = ({ - query, - clearAllFilters, - isMobile, -}: { - clearAllFilters: (event: React.ChangeEvent) => void; - query: TQueryParams; - isMobile?: boolean; -}) => { - const canClearAllFilters = Boolean( - query[SEARCH_PARAMS.searchQuery] || - query[SEARCH_PARAMS.startDate] || - query[SEARCH_PARAMS.endDate] || - query[SEARCH_PARAMS.id], - ); - return ( -
- {canClearAllFilters ? ( - // @ts-expect-error bad type definition - - ) : null} -
- ); -}; -const SetMapToggle = ({ - query, - updateQuery, - isMobile, -}: { - updateQuery: (params: TQueryParams) => void; - query: TQueryParams; - isMobile?: boolean; -}) => { - return ( -
-

- {APP_CONTENT.models.modelsList.filtersSection.mapViewToggleText} -

- { - updateQuery({ - [SEARCH_PARAMS.mapIsActive]: !query[SEARCH_PARAMS.mapIsActive], - }); - }} - /> -
- ); -}; - -const LayoutToggle = ({ - query, - updateQuery, - isMobile, - disabled = false, -}: { - updateQuery: (params: TQueryParams) => void; - query: TQueryParams; - isMobile?: boolean; - disabled?: boolean; -}) => { - const activeLayout = query[SEARCH_PARAMS.layout]; - return ( - - ); -}; - -const MobileFilter = ({ - openMobileFilterModal, -}: { - openMobileFilterModal: () => void; - isMobile?: boolean; -}) => { - return ( -
- {} -
- ); -}; export const ModelsPage = () => { - const [searchParams, setSearchParams] = useSearchParams(); - - const defaultQueries = { - [SEARCH_PARAMS.offset]: 0, - [SEARCH_PARAMS.searchQuery]: - searchParams.get(SEARCH_PARAMS.searchQuery) || "", - [SEARCH_PARAMS.ordering]: - searchParams.get(SEARCH_PARAMS.ordering) || - (ORDERING_FIELDS[1].apiValue as string), - [SEARCH_PARAMS.mapIsActive]: - searchParams.get(SEARCH_PARAMS.mapIsActive) || false, - [SEARCH_PARAMS.startDate]: searchParams.get(SEARCH_PARAMS.startDate) || "", - [SEARCH_PARAMS.endDate]: searchParams.get(SEARCH_PARAMS.endDate) || "", - [SEARCH_PARAMS.dateFilter]: - searchParams.get(SEARCH_PARAMS.dateFilter) || dateFilters[0].searchParams, - [SEARCH_PARAMS.layout]: - searchParams.get(SEARCH_PARAMS.layout) || LayoutView.GRID, - [SEARCH_PARAMS.id]: searchParams.get(SEARCH_PARAMS.id) || "", - }; - - const [query, setQuery] = useState(defaultQueries); const { isOpened, openDialog, closeDialog } = useDialog(); - const debouncedSearchText = useDebounce( - query[SEARCH_PARAMS.searchQuery] as string, - 300, - ); - - const { data, isPending, isPlaceholderData, isError } = useModels({ - searchQuery: debouncedSearchText, - limit: PAGE_LIMIT, - offset: query[SEARCH_PARAMS.offset] as number, - orderBy: query[SEARCH_PARAMS.ordering] as string, - id: query[SEARCH_PARAMS.id] as number, - dateFilters: buildDateFilterQueryString( - dateFilters.find( - (filter) => filter.searchParams === query[SEARCH_PARAMS.dateFilter], - ), - query[SEARCH_PARAMS.startDate] as string, - query[SEARCH_PARAMS.endDate] as string, - ), - }); - - const updateQuery = useCallback( - (newParams: TQueryParams) => { - setQuery((prevQuery) => ({ - ...prevQuery, - ...newParams, - })); - const updatedParams = new URLSearchParams(searchParams); - - Object.entries(newParams).forEach(([key, value]) => { - if (value) { - updatedParams.set(key, String(value)); - } else { - updatedParams.delete(key); - } - }); - - setSearchParams(updatedParams, { replace: true }); - }, - [searchParams, setSearchParams], - ); - - //reset offset back to 0 when searching or when ID filtering is applied from the map. - useEffect(() => { - if ( - (query[SEARCH_PARAMS.searchQuery] !== "" || - query[SEARCH_PARAMS.id] !== "") && - (query[SEARCH_PARAMS.offset] as number) > 0 - ) { - updateQuery({ [SEARCH_PARAMS.offset]: 0 }); - } - }, [query]); - - useEffect(() => { - const newQuery = { - [SEARCH_PARAMS.offset]: defaultQueries[SEARCH_PARAMS.offset], - [SEARCH_PARAMS.ordering]: defaultQueries[SEARCH_PARAMS.ordering], - [SEARCH_PARAMS.mapIsActive]: defaultQueries[SEARCH_PARAMS.mapIsActive], - [SEARCH_PARAMS.startDate]: defaultQueries[SEARCH_PARAMS.startDate], - [SEARCH_PARAMS.endDate]: defaultQueries[SEARCH_PARAMS.endDate], - [SEARCH_PARAMS.dateFilter]: defaultQueries[SEARCH_PARAMS.dateFilter], - [SEARCH_PARAMS.layout]: defaultQueries[SEARCH_PARAMS.layout], - [SEARCH_PARAMS.searchQuery]: defaultQueries[SEARCH_PARAMS.searchQuery], - [SEARCH_PARAMS.id]: defaultQueries[SEARCH_PARAMS.id], - }; - setQuery(newQuery); - }, []); + const { clearAllFilters, data, isError, isPending, isPlaceholderData, query, updateQuery, mapViewIsActive } = useModelsListFilters() const { data: mapData, @@ -263,24 +60,7 @@ export const ModelsPage = () => { [isPending], ); - const mapViewIsActive = useMemo( - () => query[SEARCH_PARAMS.mapIsActive], - [query], - ); - const clearAllFilters = useCallback(() => { - const resetParams = new URLSearchParams(); - setSearchParams(resetParams); - setQuery((prev) => ({ - // Preserve existing query params - ...prev, - // Clear only the filter fields - [SEARCH_PARAMS.searchQuery]: "", - [SEARCH_PARAMS.startDate]: "", - [SEARCH_PARAMS.endDate]: "", - [SEARCH_PARAMS.id]: "", - })); - }, []); const renderContent = () => { if (data?.count === 0) { @@ -376,7 +156,7 @@ export const ModelsPage = () => {
{/* Desktop */} - + { .modelCountSuffix }

- ; status: number; id: number; + userId?: number }; export const getModelsQueryOptions = ({ @@ -34,14 +35,15 @@ export const getModelsQueryOptions = ({ orderBy, dateFilters, id, + userId }: TModelQueryOptions) => { return queryOptions({ queryKey: [ "models", - { status, searchQuery, offset, orderBy, dateFilters, id }, + { status, searchQuery, offset, orderBy, dateFilters, id, userId }, ], queryFn: () => - getModels(limit, offset, orderBy, status, searchQuery, dateFilters, id), + getModels(limit, offset, orderBy, status, searchQuery, dateFilters, id, userId), placeholderData: keepPreviousData, }); }; diff --git a/frontend/src/features/models/api/get-models.ts b/frontend/src/features/models/api/get-models.ts index efbc361e..e556cc54 100644 --- a/frontend/src/features/models/api/get-models.ts +++ b/frontend/src/features/models/api/get-models.ts @@ -9,6 +9,7 @@ export const getModels = async ( searchQuery: string, dateFilters: Record, id: number, + userId?: number ): Promise => { const res = await apiClient.get(API_ENDPOINTS.GET_MODELS, { params: { @@ -18,6 +19,7 @@ export const getModels = async ( offset, ordering: orderBy, id: id, + user: userId, ...dateFilters, }, }); diff --git a/frontend/src/features/models/components/filters/clear-filters.tsx b/frontend/src/features/models/components/filters/clear-filters.tsx new file mode 100644 index 00000000..08742450 --- /dev/null +++ b/frontend/src/features/models/components/filters/clear-filters.tsx @@ -0,0 +1,33 @@ +import { SEARCH_PARAMS } from "@/app/routes/models/models-list"; +import { Button } from "@/components/ui/button"; +import { TQueryParams } from "@/types"; + +const ClearFilters = ({ + query, + clearAllFilters, + isMobile, +}: { + clearAllFilters: (event: React.ChangeEvent) => void; + query: TQueryParams; + isMobile?: boolean; +}) => { + const canClearAllFilters = Boolean( + query[SEARCH_PARAMS.searchQuery] || + query[SEARCH_PARAMS.startDate] || + query[SEARCH_PARAMS.endDate] || + query[SEARCH_PARAMS.id], + ); + + return ( +
+ {canClearAllFilters ? ( + // @ts-expect-error bad type definition + + ) : null} +
+ ); +}; + +export default ClearFilters \ No newline at end of file diff --git a/frontend/src/features/models/components/filters/index.ts b/frontend/src/features/models/components/filters/index.ts index 88d16056..ae7cf1b0 100644 --- a/frontend/src/features/models/components/filters/index.ts +++ b/frontend/src/features/models/components/filters/index.ts @@ -2,3 +2,5 @@ export { default as OrderingFilter } from "./ordering-filter"; export { default as DateRangeFilter } from "./date-range-filter"; export { default as CategoryFilter } from "./category-filter"; export { default as SearchFilter } from "./search-filter"; +export { default as ClearFilters } from './clear-filters' +export { default as MobileFilter } from './mobile-filter' \ No newline at end of file diff --git a/frontend/src/features/models/components/filters/mobile-filter.tsx b/frontend/src/features/models/components/filters/mobile-filter.tsx new file mode 100644 index 00000000..28554b48 --- /dev/null +++ b/frontend/src/features/models/components/filters/mobile-filter.tsx @@ -0,0 +1,22 @@ +import { FilterIcon } from "@/components/ui/icons"; + +const MobileFilter = ({ + openMobileFilterModal, +}: { + openMobileFilterModal: () => void; + isMobile?: boolean; +}) => { + return ( +
+ {} +
+ ); +}; + +export default MobileFilter diff --git a/frontend/src/features/models/components/header.tsx b/frontend/src/features/models/components/header.tsx index 12340f0d..ec96d7d2 100644 --- a/frontend/src/features/models/components/header.tsx +++ b/frontend/src/features/models/components/header.tsx @@ -3,7 +3,7 @@ import { AddIcon } from "@/components/ui/icons"; import { APP_CONTENT, APPLICATION_ROUTES } from "@/utils"; import { useNavigate } from "react-router-dom"; -const PageHeader = () => { +const PageHeader = ({ title, description }: { title?: string, description?: string }) => { const navigate = useNavigate(); const handleClick = () => { navigate(APPLICATION_ROUTES.CREATE_NEW_MODEL); @@ -13,12 +13,12 @@ const PageHeader = () => {

- {APP_CONTENT.models.modelsList.pageTitle} + {title ?? APP_CONTENT.models.modelsList.pageTitle}

- {APP_CONTENT.models.modelsList.description} + {description ?? APP_CONTENT.models.modelsList.description}

void; + query: TQueryParams; + isMobile?: boolean; + disabled?: boolean; +}) => { + const activeLayout = query[SEARCH_PARAMS.layout]; + return ( + + ); +}; + + +export default LayoutToggle \ No newline at end of file diff --git a/frontend/src/features/models/components/map-toggle.tsx b/frontend/src/features/models/components/map-toggle.tsx new file mode 100644 index 00000000..287a1afd --- /dev/null +++ b/frontend/src/features/models/components/map-toggle.tsx @@ -0,0 +1,38 @@ +import { SEARCH_PARAMS } from "@/app/routes/models/models-list"; +import { Switch } from "@/components/ui/form"; +import { LayoutView } from "@/enums/models"; +import { TQueryParams } from "@/types"; +import { APP_CONTENT } from "@/utils"; + +const ModelMapToggle = ({ + query, + updateQuery, + isMobile, +}: { + updateQuery: (params: TQueryParams) => void; + query: TQueryParams; + isMobile?: boolean; +}) => { + return ( +
+

+ {APP_CONTENT.models.modelsList.filtersSection.mapViewToggleText} +

+ { + updateQuery({ + [SEARCH_PARAMS.mapIsActive]: !query[SEARCH_PARAMS.mapIsActive], + }); + }} + /> +
+ ); +}; + + +export default ModelMapToggle \ No newline at end of file diff --git a/frontend/src/features/models/hooks/use-models.ts b/frontend/src/features/models/hooks/use-models.ts index 576670a5..e48fb63a 100644 --- a/frontend/src/features/models/hooks/use-models.ts +++ b/frontend/src/features/models/hooks/use-models.ts @@ -3,7 +3,17 @@ import { getModelsQueryOptions, getModelDetailsQueryOptions, getModelsMapDataQueryOptions, -} from "../api/factory"; +} from "@/features/models/api/factory"; +import { useSearchParams } from "react-router-dom"; +import { SEARCH_PARAMS } from "@/app/routes/models/models-list"; +import { ORDERING_FIELDS } from "@/features/models/components/filters/ordering-filter"; +import { TQueryParams } from "@/types"; +import { useCallback, useEffect, useMemo, useState } from "react"; +import { buildDateFilterQueryString } from "@/utils"; +import { PAGE_LIMIT } from "@/components/pagination"; +import { dateFilters } from "@/features/models/components/filters/date-range-filter"; +import useDebounce from "@/hooks/use-debounce"; +import { LayoutView } from "@/enums/models"; type UseModelsOptions = { limit: number; @@ -13,6 +23,7 @@ type UseModelsOptions = { dateFilters: Record; status?: number; id: number; + userId?: number }; export const useModels = ({ @@ -23,6 +34,7 @@ export const useModels = ({ searchQuery, dateFilters, id, + userId }: UseModelsOptions) => { return useQuery({ ...getModelsQueryOptions({ @@ -33,6 +45,7 @@ export const useModels = ({ searchQuery, dateFilters, id, + userId }), //@ts-expect-error bad type definition throwOnError: (error) => error.response?.status >= 500, @@ -64,3 +77,122 @@ export const useModelsMapData = () => { throwOnError: (error) => error.response?.status >= 500, }); }; + + + +export const useModelsListFilters = (userId?: number) => { + const [searchParams, setSearchParams] = useSearchParams(); + + const defaultQueries = { + [SEARCH_PARAMS.offset]: 0, + [SEARCH_PARAMS.searchQuery]: + searchParams.get(SEARCH_PARAMS.searchQuery) || "", + [SEARCH_PARAMS.ordering]: + searchParams.get(SEARCH_PARAMS.ordering) || + (ORDERING_FIELDS[1].apiValue as string), + [SEARCH_PARAMS.mapIsActive]: + searchParams.get(SEARCH_PARAMS.mapIsActive) || false, + [SEARCH_PARAMS.startDate]: searchParams.get(SEARCH_PARAMS.startDate) || "", + [SEARCH_PARAMS.endDate]: searchParams.get(SEARCH_PARAMS.endDate) || "", + [SEARCH_PARAMS.dateFilter]: + searchParams.get(SEARCH_PARAMS.dateFilter) || dateFilters[0].searchParams, + [SEARCH_PARAMS.layout]: + searchParams.get(SEARCH_PARAMS.layout) || LayoutView.GRID, + [SEARCH_PARAMS.id]: searchParams.get(SEARCH_PARAMS.id) || "", + }; + const [query, setQuery] = useState(defaultQueries); + + + const debouncedSearchText = useDebounce( + query[SEARCH_PARAMS.searchQuery] as string, + 300, + ); + + const { data, isPending, isPlaceholderData, isError } = useModels({ + searchQuery: debouncedSearchText, + limit: PAGE_LIMIT, + offset: query[SEARCH_PARAMS.offset] as number, + orderBy: query[SEARCH_PARAMS.ordering] as string, + id: query[SEARCH_PARAMS.id] as number, + dateFilters: buildDateFilterQueryString( + dateFilters.find( + (filter) => filter.searchParams === query[SEARCH_PARAMS.dateFilter], + ), + query[SEARCH_PARAMS.startDate] as string, + query[SEARCH_PARAMS.endDate] as string, + ), + userId: userId + }); + + const updateQuery = useCallback( + (newParams: TQueryParams) => { + setQuery((prevQuery) => ({ + ...prevQuery, + ...newParams, + })); + const updatedParams = new URLSearchParams(searchParams); + + Object.entries(newParams).forEach(([key, value]) => { + if (value) { + updatedParams.set(key, String(value)); + } else { + updatedParams.delete(key); + } + }); + + setSearchParams(updatedParams, { replace: true }); + }, + [searchParams, setSearchParams], + ); + + //reset offset back to 0 when searching or when ID filtering is applied from the map. + useEffect(() => { + if ( + (query[SEARCH_PARAMS.searchQuery] !== "" || + query[SEARCH_PARAMS.id] !== "") && + (query[SEARCH_PARAMS.offset] as number) > 0 + ) { + updateQuery({ [SEARCH_PARAMS.offset]: 0 }); + } + }, [query]); + + + + useEffect(() => { + const newQuery = { + [SEARCH_PARAMS.offset]: defaultQueries[SEARCH_PARAMS.offset], + [SEARCH_PARAMS.ordering]: defaultQueries[SEARCH_PARAMS.ordering], + [SEARCH_PARAMS.mapIsActive]: defaultQueries[SEARCH_PARAMS.mapIsActive], + [SEARCH_PARAMS.startDate]: defaultQueries[SEARCH_PARAMS.startDate], + [SEARCH_PARAMS.endDate]: defaultQueries[SEARCH_PARAMS.endDate], + [SEARCH_PARAMS.dateFilter]: defaultQueries[SEARCH_PARAMS.dateFilter], + [SEARCH_PARAMS.layout]: defaultQueries[SEARCH_PARAMS.layout], + [SEARCH_PARAMS.searchQuery]: defaultQueries[SEARCH_PARAMS.searchQuery], + [SEARCH_PARAMS.id]: defaultQueries[SEARCH_PARAMS.id], + }; + setQuery(newQuery); + }, []); + + const mapViewIsActive = useMemo( + () => query[SEARCH_PARAMS.mapIsActive], + [query], + ); + + const clearAllFilters = useCallback(() => { + const resetParams = new URLSearchParams(); + setSearchParams(resetParams); + setQuery((prev) => ({ + // Preserve existing query params + ...prev, + // Clear only the filter fields + [SEARCH_PARAMS.searchQuery]: "", + [SEARCH_PARAMS.startDate]: "", + [SEARCH_PARAMS.endDate]: "", + [SEARCH_PARAMS.id]: "", + })); + }, []); + + + return { query, data, isPending, isPlaceholderData, isError, updateQuery, mapViewIsActive, clearAllFilters } + +} \ No newline at end of file