Skip to content

Commit 7abbec4

Browse files
authored
Merge pull request #1 from offbeatjs/patch-2
Patch 2
2 parents f823b02 + 6cc47ae commit 7abbec4

File tree

4 files changed

+76
-83
lines changed

4 files changed

+76
-83
lines changed

src/app/(public)/repos/_components/pagination.tsx

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,30 @@
22

33
import { Button } from '@/app/(public)/_components/button';
44
import { ArrowLeft, ArrowRight, Loader2 } from 'lucide-react';
5-
import { useRouter } from 'next/navigation';
65
import { useTransition } from 'react';
7-
import type { SearchParams } from '@/types';
6+
import { useQueryState } from 'nuqs';
87

98
const MAX_PER_PAGE = 21;
109
interface PaginationProps {
1110
page: number;
1211
totalCount: number;
13-
searchParams: SearchParams;
1412
}
1513

1614
export function Pagination({
1715
page,
18-
totalCount,
19-
searchParams
16+
totalCount
2017
}: PaginationProps) {
21-
const router = useRouter();
18+
const [, setPageParam] = useQueryState('p', {
19+
defaultValue: '1',
20+
parse: (value: string) => value,
21+
serialize: (value: string) => value
22+
});
2223
const [isPending, startTransition] = useTransition();
2324

2425
function changePage(delta: number) {
25-
const params = new URLSearchParams(
26-
Object.entries(searchParams).map(([k, v]) => [k, String(v)])
27-
);
28-
params.set('p', String(page + delta));
29-
26+
const newPage = page + delta;
3027
startTransition(() => {
31-
router.push(`?${params.toString()}`);
28+
void setPageParam(String(newPage));
3229
});
3330
}
3431

src/app/(public)/repos/_components/sorter.tsx

Lines changed: 47 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import { Button } from '@/app/(public)/_components/button';
44
import { ArrowUpAZ, Code } from 'lucide-react';
55
import Link from 'next/link';
66
import languages from '@/assets/languages.json';
7-
import { usePathname, useSearchParams } from 'next/navigation';
7+
import { usePathname } from 'next/navigation';
88
import { sortByName } from '@/lib/utils';
9+
import { useQueryStates, useQueryState } from 'nuqs';
910

1011
const { mainLanguages } = languages;
1112

@@ -23,88 +24,74 @@ enum SortTypes {
2324
type Pathname = '/repos' | `/repos/${string}`;
2425

2526
export function Sorter() {
26-
const searchParams = useSearchParams();
2727
const pathname = usePathname() as Pathname;
28+
const [sortField] = useQueryState('s', { defaultValue: '' });
29+
const [sortOrder] = useQueryState('o', { defaultValue: 'desc' });
30+
const [languages_] = useQueryState('l', { parse: (value: string) => value.split(',').filter(Boolean), serialize: (value: string[]) => value.join(',') });
2831

2932
const navigationItems = [
3033
{
3134
name: 'Best match',
32-
onSelect(sp: URLSearchParams) {
33-
sp.delete('o');
34-
sp.delete('s');
35-
return sp;
35+
onSelect(): { s: string | null; o: string | null } {
36+
return { s: null, o: null };
3637
}
3738
},
3839
{
3940
name: 'Most stars',
40-
onSelect(sp: URLSearchParams) {
41-
sp.set('s', 'stars');
42-
sp.set('o', 'desc');
43-
return sp;
41+
onSelect() {
42+
return { s: 'stars', o: 'desc' };
4443
}
4544
},
4645
{
4746
name: 'Fewest stars',
48-
onSelect(sp: URLSearchParams) {
49-
sp.set('s', 'stars');
50-
sp.set('o', 'asc');
51-
return sp;
47+
onSelect() {
48+
return { s: 'stars', o: 'asc' };
5249
}
5350
},
5451
{
5552
name: 'Most forks',
56-
onSelect(sp: URLSearchParams) {
57-
sp.set('s', 'forks');
58-
sp.set('o', 'desc');
59-
return sp;
53+
onSelect() {
54+
return { s: 'forks', o: 'desc' };
6055
}
6156
},
6257
{
6358
name: 'Fewest forks',
64-
onSelect(sp: URLSearchParams) {
65-
sp.set('s', 'forks');
66-
sp.set('o', 'asc');
67-
return sp;
59+
onSelect() {
60+
return { s: 'forks', o: 'asc' };
6861
}
6962
},
7063
{
7164
name: 'Most help wanted issues',
72-
onSelect(sp: URLSearchParams) {
73-
sp.set('s', 'help-wanted-issues');
74-
sp.set('o', 'desc');
75-
return sp;
65+
onSelect() {
66+
return { s: 'help-wanted-issues', o: 'desc' };
7667
}
7768
},
7869
{
7970
name: 'Recently updated',
80-
onSelect(sp: URLSearchParams) {
81-
sp.set('s', 'updated');
82-
sp.set('o', 'desc');
83-
return sp;
71+
onSelect() {
72+
return { s: 'updated', o: 'desc' };
8473
}
8574
},
8675
{
8776
name: 'Least recently updated',
88-
onSelect(sp: URLSearchParams) {
89-
sp.set('s', 'updated');
90-
sp.set('o', 'asc');
91-
return sp;
77+
onSelect() {
78+
return { s: 'updated', o: 'asc' };
9279
}
9380
}
9481
];
9582

9683
function selectedSort(): SortTypes {
97-
if (searchParams.get('o') === 'asc') {
98-
if (searchParams.get('s') === 'stars') return SortTypes.FewestStars;
99-
if (searchParams.get('s') === 'forks') return SortTypes.FewestForks;
100-
if (searchParams.get('s') === 'updated')
84+
if (sortOrder === 'asc') {
85+
if (sortField === 'stars') return SortTypes.FewestStars;
86+
if (sortField === 'forks') return SortTypes.FewestForks;
87+
if (sortField === 'updated')
10188
return SortTypes.LeastRecentlyUpdated;
10289
return SortTypes.BestMatch;
103-
} else if (searchParams.get('o') === 'desc') {
104-
if (searchParams.get('s') === 'stars') return SortTypes.MostStars;
105-
if (searchParams.get('s') === 'forks') return SortTypes.MostForks;
106-
if (searchParams.get('s') === 'updated') return SortTypes.RecentlyUpdated;
107-
if (searchParams.get('s') === 'help-wanted-issues')
90+
} else if (sortOrder === 'desc') {
91+
if (sortField === 'stars') return SortTypes.MostStars;
92+
if (sortField === 'forks') return SortTypes.MostForks;
93+
if (sortField === 'updated') return SortTypes.RecentlyUpdated;
94+
if (sortField === 'help-wanted-issues')
10895
return SortTypes.MostHelpWantedIssues;
10996
return SortTypes.BestMatch;
11097
} else {
@@ -127,12 +114,17 @@ export function Sorter() {
127114
<div className="z-[9999] h-64 p-2 overflow-y-auto shadow-lg dropdown-content hidden group-hover:block bg-white/95 backdrop-blur-sm rounded-xl w-60 border border-gray-200/50">
128115
<ul tabIndex={0} className="menu menu-vertical">
129116
{mainLanguages.sort(sortByName).map(language => {
130-
const sp = new URLSearchParams(searchParams);
131-
sp.delete('p');
117+
const languageParams = `l=${language.toLowerCase()}`;
118+
const currentParams = new URLSearchParams();
119+
if (sortField) currentParams.set('s', sortField);
120+
if (sortOrder) currentParams.set('o', sortOrder);
121+
const queryString = currentParams.toString();
122+
const fullQuery = queryString ? `${languageParams}&${queryString}` : languageParams;
123+
132124
return (
133125
<li key={language} onClick={handleClick}>
134126
<Link
135-
href={`/repos/${language.toLowerCase()}?${sp.toString()}`}
127+
href={`/repos/${language.toLowerCase()}?${fullQuery}`}
136128
className="text-gray-700 hover:text-white hover:bg-hacktoberfest-light-blue rounded-lg transition-colors duration-200 px-3 py-2"
137129
>
138130
{language}
@@ -151,16 +143,19 @@ export function Sorter() {
151143
<div className="z-[9999] h-64 p-2 overflow-y-auto shadow-lg dropdown-content hidden group-hover:block -ml-16 bg-white/95 backdrop-blur-sm rounded-xl w-60 border border-gray-200/50">
152144
<ul tabIndex={0} className="menu menu-vertical">
153145
{navigationItems.map((item, index) => {
154-
const sp = item.onSelect(new URLSearchParams(searchParams));
155-
sp.delete('p');
156-
if (item.name === SortTypes.BestMatch) {
157-
sp.delete('o');
158-
sp.delete('s');
146+
const { s, o } = item.onSelect();
147+
const currentParams = new URLSearchParams();
148+
if (s) currentParams.set('s', s);
149+
if (o) currentParams.set('o', o);
150+
if (languages_ && languages_.length > 0) {
151+
currentParams.set('l', languages_.join(','));
159152
}
153+
const queryString = currentParams.toString();
154+
160155
return (
161156
<li key={index} onClick={handleClick}>
162157
<Link
163-
href={`${pathname}?${sp.toString()}`}
158+
href={`${pathname}?${queryString}`}
164159
className="text-gray-700 hover:text-white hover:bg-hacktoberfest-light-blue rounded-lg transition-colors duration-200 px-3 py-2"
165160
>
166161
{item.name}

src/app/(public)/repos/_components/stars-filter.tsx

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
import {
44
useParams,
5-
usePathname,
6-
useRouter,
7-
useSearchParams
5+
usePathname
86
} from 'next/navigation';
97
import { useEffect } from 'react';
108
import { Controller, useForm } from 'react-hook-form';
9+
import { useQueryStates } from 'nuqs';
1110

1211
interface FormValues {
1312
startStars: number | '';
@@ -17,40 +16,43 @@ interface FormValues {
1716
type Pathname = '/repos' | `/repos/${string}`;
1817

1918
export function StarsFilter() {
20-
const router = useRouter();
2119
const pathname = usePathname() as Pathname;
22-
const searchParams = useSearchParams();
2320
const params = useParams();
21+
const [{ startStars, endStars, p }, setStarsParams] = useQueryStates({
22+
startStars: { parse: (value: string) => (value ? +value : ''), serialize: (value: number | '') => value === '' ? '' : String(value) },
23+
endStars: { parse: (value: string) => (value ? +value : ''), serialize: (value: number | '') => value === '' ? '' : String(value) },
24+
p: { parse: (value: string) => (value ? +value : 1), serialize: (value: number) => String(value) }
25+
});
26+
2427
const { handleSubmit, control, reset } = useForm<FormValues>({
2528
defaultValues: {
26-
startStars: !searchParams.get('startStars')
27-
? ''
28-
: +(searchParams.get('startStars') as string),
29-
endStars: !searchParams.get('endStars')
30-
? ''
31-
: +(searchParams.get('endStars') as string)
29+
startStars: startStars === '' ? '' : startStars || '',
30+
endStars: endStars === '' ? '' : endStars || ''
3231
}
3332
});
3433

3534
// eslint-disable-next-line react-hooks/exhaustive-deps
3635
useEffect(() => reset(), [params.language]);
3736

3837
function onSubmit({ startStars, endStars }: FormValues) {
39-
const sp = new URLSearchParams(searchParams);
4038
if (
4139
typeof endStars === 'number' &&
4240
typeof startStars === 'number' &&
4341
endStars < startStars
4442
) {
4543
reset({ startStars, endStars: '' });
46-
sp.delete('endStars');
47-
sp.set('startStars', startStars.toString());
44+
void setStarsParams({
45+
startStars,
46+
endStars: '',
47+
p: 1
48+
});
4849
} else {
49-
sp.set('startStars', startStars.toString());
50-
sp.set('endStars', endStars.toString());
50+
void setStarsParams({
51+
startStars: typeof startStars === 'number' ? startStars : '',
52+
endStars: typeof endStars === 'number' ? endStars : '',
53+
p: 1
54+
});
5155
}
52-
sp.delete('p');
53-
router.push(`${pathname}?${sp.toString()}`);
5456
}
5557

5658
return (

src/app/(public)/repos/page.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ export default async function ReposPage({
6464
<Pagination
6565
page={page}
6666
totalCount={repos.total_count}
67-
searchParams={sp}
6867
/>
6968
</div>
7069
</div>

0 commit comments

Comments
 (0)