Skip to content

Commit 42b7b8f

Browse files
committed
feat: filter synced as query param
1 parent 815cfbf commit 42b7b8f

1 file changed

Lines changed: 53 additions & 27 deletions

File tree

frontend/src/app/[locale]/blog/blog.tsx

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11

22
'use client';
33

4+
import { useRouter, useSearchParams } from 'next/navigation';
45
import { useTranslations } from 'next-intl';
56
import { Title, BaseCardsBlock, Pagination, SearchInput, Filter, Button } from '@/components';
67
import { BlogsPageMeta, BlogsPageData } from './page';
7-
import { useState, useMemo } from 'react';
8+
import { useState, useMemo, useCallback } from 'react';
89
import { getPressReleaseLink } from '@/lib/utils';
10+
import { usePagination } from '@/hooks/usePagination';
911
import clsx from 'clsx';
1012

1113

@@ -114,21 +116,29 @@ function transformBlogsData(resources: NonNullable<BlogsPageData>): TransformedR
114116
});
115117
}
116118

119+
function getSearchParamValues(params: URLSearchParams, key: string): string[] {
120+
const val = params.get(key);
121+
return val ? val.split(',').filter(Boolean) : [];
122+
}
123+
117124
type BlogsPageProps = {
118125
data: BlogsPageData
119126
pagination: BlogsPageMeta
120127
}
121128

122129
export default function BlogPage({data, pagination: _pagination}: BlogsPageProps) {
123130
const t = useTranslations('blog');
131+
const router = useRouter();
132+
const searchParams = useSearchParams();
124133
const allResources = useMemo(() => transformBlogsData(data), [data]);
125134

126-
const [searchQuery, setSearchQuery] = useState('');
127-
const [activeYears, setActiveYears] = useState<string[]>([]);
128-
const [activeTypes, setActiveTypes] = useState<string[]>([]);
129-
const [activeNewsletters, setActiveNewsletters] = useState<string[]>([]);
135+
const [searchQuery, setSearchQuery] = useState(searchParams.get('search') ?? '');
136+
const [activeYears, setActiveYears] = useState<string[]>(() => getSearchParamValues(searchParams, 'years'));
137+
const [activeTypes, setActiveTypes] = useState<string[]>(() => getSearchParamValues(searchParams, 'types'));
138+
const [activeNewsletters, setActiveNewsletters] = useState<string[]>(() => getSearchParamValues(searchParams, 'newsletters'));
130139
const [hideFilters, setHideFilters] = useState(true);
131-
const [currentPage, setCurrentPage] = useState(1);
140+
141+
const { currentPage, handlePageChange } = usePagination(1);
132142

133143
const pageSize = 12;
134144

@@ -163,37 +173,53 @@ export default function BlogPage({data, pagination: _pagination}: BlogsPageProps
163173

164174
const pageCount = Math.ceil(filteredResources.length / pageSize);
165175

176+
const syncFiltersToUrl = useCallback((years: string[], types: string[], newsletters: string[], search: string, page: number) => {
177+
const params = new URLSearchParams(searchParams.toString());
178+
if (years.length > 0) params.set('years', years.join(','));
179+
else params.delete('years');
180+
if (types.length > 0) params.set('types', types.join(','));
181+
else params.delete('types');
182+
if (newsletters.length > 0) params.set('newsletters', newsletters.join(','));
183+
else params.delete('newsletters');
184+
if (search) params.set('search', search);
185+
else params.delete('search');
186+
if (page > 1) params.set('page', String(page));
187+
else params.delete('page');
188+
router.push(`?${params.toString()}`, { scroll: false });
189+
}, [router, searchParams]);
190+
166191
const handleSearchChange = (e: any) => {
167-
if (searchQuery !== e.value) {
168-
setSearchQuery(e.value);
169-
setCurrentPage(1);
170-
}
192+
const query = e.value ?? '';
193+
setSearchQuery(query);
194+
syncFiltersToUrl(activeYears, activeTypes, activeNewsletters, query, 1);
171195
};
172196

173197
const handleFilterClick = (e: any) => {
174198
const filterValue = e.value as string;
175199
const filterType = e.getAttribute('data-type');
176200

201+
let newYears = activeYears;
202+
let newTypes = activeTypes;
203+
let newNewsletters = activeNewsletters;
204+
177205
if (filterType === 'year') {
178-
setActiveYears(prev =>
179-
prev.includes(filterValue)
180-
? prev.filter(v => v !== filterValue)
181-
: [...prev, filterValue]
182-
);
206+
newYears = activeYears.includes(filterValue)
207+
? activeYears.filter(v => v !== filterValue)
208+
: [...activeYears, filterValue];
209+
setActiveYears(newYears);
183210
} else if (filterType === 'type') {
184-
setActiveTypes(prev =>
185-
prev.includes(filterValue)
186-
? prev.filter(v => v !== filterValue)
187-
: [...prev, filterValue]
188-
);
211+
newTypes = activeTypes.includes(filterValue)
212+
? activeTypes.filter(v => v !== filterValue)
213+
: [...activeTypes, filterValue];
214+
setActiveTypes(newTypes);
189215
} else if (filterType === 'newsletter') {
190-
setActiveNewsletters(prev =>
191-
prev.includes(filterValue)
192-
? prev.filter(v => v !== filterValue)
193-
: [...prev, filterValue]
194-
);
216+
newNewsletters = activeNewsletters.includes(filterValue)
217+
? activeNewsletters.filter(v => v !== filterValue)
218+
: [...activeNewsletters, filterValue];
219+
setActiveNewsletters(newNewsletters);
195220
}
196-
setCurrentPage(1);
221+
222+
syncFiltersToUrl(newYears, newTypes, newNewsletters, searchQuery, 1);
197223
};
198224

199225
const yearFilters = [
@@ -295,7 +321,7 @@ export default function BlogPage({data, pagination: _pagination}: BlogsPageProps
295321
<Pagination
296322
pageCount={pageCount}
297323
currentPage={currentPage}
298-
setCurrentPage={setCurrentPage}
324+
setCurrentPage={handlePageChange}
299325
className="mt-sm mb-lg mx-auto max-w-max"
300326
color="black"
301327
/>

0 commit comments

Comments
 (0)