Commit f67145f3 authored by tom's avatar tom

save search term and category in the url

parent 621f86f5
import { useQuery } from '@tanstack/react-query';
import _pickBy from 'lodash/pickBy';
import _unique from 'lodash/uniq';
import React, { useCallback, useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import React from 'react';
import type { MarketplaceAppOverview } from 'types/client/marketplace';
import { MarketplaceCategory } from 'types/client/marketplace';
......@@ -9,6 +11,7 @@ import appConfig from 'configs/app/config';
import type { ResourceError } from 'lib/api/resources';
import useDebounce from 'lib/hooks/useDebounce';
import useApiFetch from 'lib/hooks/useFetch';
import getQueryParamString from 'lib/router/getQueryParamString';
const favoriteAppsLocalStorageKey = 'favoriteApps';
......@@ -31,10 +34,14 @@ function isAppCategoryMatches(category: string, app: MarketplaceAppOverview, fav
}
export default function useMarketplace() {
const [ selectedAppId, setSelectedAppId ] = useState<string | null>(null);
const [ selectedCategoryId, setSelectedCategoryId ] = useState<string>(MarketplaceCategory.ALL);
const [ filterQuery, setFilterQuery ] = useState('');
const [ favoriteApps, setFavoriteApps ] = useState<Array<string>>([]);
const router = useRouter();
const defaultCategoryId = getQueryParamString(router.query.category);
const defaultFilterQuery = getQueryParamString(router.query.filter);
const [ selectedAppId, setSelectedAppId ] = React.useState<string | null>(null);
const [ selectedCategoryId, setSelectedCategoryId ] = React.useState<string>(MarketplaceCategory.ALL);
const [ filterQuery, setFilterQuery ] = React.useState(defaultFilterQuery);
const [ favoriteApps, setFavoriteApps ] = React.useState<Array<string>>([]);
const apiFetch = useApiFetch();
const { isLoading, isError, error, data } = useQuery<unknown, ResourceError<unknown>, Array<MarketplaceAppOverview>>(
......@@ -42,9 +49,10 @@ export default function useMarketplace() {
async() => apiFetch(appConfig.marketplaceConfigUrl || ''),
{
select: (data) => (data as Array<MarketplaceAppOverview>).sort((a, b) => a.title.localeCompare(b.title)),
staleTime: Infinity,
});
const handleFavoriteClick = useCallback((id: string, isFavorite: boolean) => {
const handleFavoriteClick = React.useCallback((id: string, isFavorite: boolean) => {
const favoriteApps = getFavoriteApps();
if (isFavorite) {
......@@ -58,14 +66,14 @@ export default function useMarketplace() {
}
}, [ ]);
const showAppInfo = useCallback((id: string) => {
const showAppInfo = React.useCallback((id: string) => {
setSelectedAppId(id);
}, []);
const debouncedFilterQuery = useDebounce(filterQuery, 500);
const clearSelectedAppId = useCallback(() => setSelectedAppId(null), []);
const clearSelectedAppId = React.useCallback(() => setSelectedAppId(null), []);
const handleCategoryChange = useCallback((newCategory: string) => {
const handleCategoryChange = React.useCallback((newCategory: string) => {
setSelectedCategoryId(newCategory);
}, []);
......@@ -77,13 +85,38 @@ export default function useMarketplace() {
return _unique(data?.map(app => app.categories).flat()) || [];
}, [ data ]);
useEffect(() => {
React.useEffect(() => {
setFavoriteApps(getFavoriteApps());
}, [ ]);
React.useEffect(() => {
if (!isLoading && !isError) {
const isValidDefaultCategory = categories.includes(defaultCategoryId);
isValidDefaultCategory && setSelectedCategoryId(defaultCategoryId);
}
// run only when data is loaded
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ isLoading ]);
React.useEffect(() => {
const query = _pickBy({
category: selectedCategoryId === MarketplaceCategory.ALL ? undefined : selectedCategoryId,
filter: debouncedFilterQuery,
}, Boolean);
router.replace(
{ pathname: '/apps', query },
undefined,
{ shallow: true },
);
// omit router in the deps because router.push() somehow modifies it
// and we get infinite re-renders then
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ debouncedFilterQuery, selectedCategoryId ]);
return React.useMemo(() => ({
selectedCategoryId,
onCategoryChange: handleCategoryChange,
filterQuery: debouncedFilterQuery,
onSearchInputChange: setFilterQuery,
isLoading,
isError,
......@@ -108,5 +141,6 @@ export default function useMarketplace() {
isError,
isLoading,
showAppInfo,
debouncedFilterQuery,
]);
}
......@@ -19,6 +19,7 @@ const Marketplace = () => {
selectedCategoryId,
categories,
onCategoryChange,
filterQuery,
onSearchInputChange,
showAppInfo,
displayedApps,
......@@ -46,7 +47,12 @@ const Marketplace = () => {
onSelect={ onCategoryChange }
/>
<FilterInput onChange={ onSearchInputChange } marginBottom={{ base: '4', lg: '6' }} placeholder="Find app"/>
<FilterInput
initialValue={ filterQuery }
onChange={ onSearchInputChange }
marginBottom={{ base: '4', lg: '6' }}
placeholder="Find app"
/>
</Box>
{ isLoading ? <MarketplaceListSkeleton/> : (
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment