Skip to content

Commit 3c38dc1

Browse files
committed
feat: add search param sync in apps route (#200)
1 parent b1a8ef3 commit 3c38dc1

2 files changed

Lines changed: 59 additions & 11 deletions

File tree

src/features/apps/index.tsx

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { useState } from 'react'
1+
import { type ChangeEvent, useState } from 'react'
2+
import { getRouteApi } from '@tanstack/react-router'
23
import { SlidersHorizontal, ArrowUpAZ, ArrowDownAZ } from 'lucide-react'
34
import { Button } from '@/components/ui/button'
45
import { Input } from '@/components/ui/input'
@@ -17,20 +18,31 @@ import { Search } from '@/components/search'
1718
import { ThemeSwitch } from '@/components/theme-switch'
1819
import { apps } from './data/apps'
1920

20-
const appText = new Map<string, string>([
21+
const route = getRouteApi('/_authenticated/apps/')
22+
23+
type AppType = 'all' | 'connected' | 'notConnected'
24+
25+
const appText = new Map<AppType, string>([
2126
['all', 'All Apps'],
2227
['connected', 'Connected'],
2328
['notConnected', 'Not Connected'],
2429
])
2530

2631
export function Apps() {
27-
const [sort, setSort] = useState('ascending')
28-
const [appType, setAppType] = useState('all')
29-
const [searchTerm, setSearchTerm] = useState('')
32+
const {
33+
filter = '',
34+
type = 'all',
35+
sort: initSort = 'asc',
36+
} = route.useSearch()
37+
const navigate = route.useNavigate()
38+
39+
const [sort, setSort] = useState(initSort)
40+
const [appType, setAppType] = useState(type)
41+
const [searchTerm, setSearchTerm] = useState(filter)
3042

3143
const filteredApps = apps
3244
.sort((a, b) =>
33-
sort === 'ascending'
45+
sort === 'asc'
3446
? a.name.localeCompare(b.name)
3547
: b.name.localeCompare(a.name)
3648
)
@@ -43,6 +55,31 @@ export function Apps() {
4355
)
4456
.filter((app) => app.name.toLowerCase().includes(searchTerm.toLowerCase()))
4557

58+
const handleSearch = (e: ChangeEvent<HTMLInputElement>) => {
59+
setSearchTerm(e.target.value)
60+
navigate({
61+
search: (prev) => ({
62+
...prev,
63+
filter: e.target.value || undefined,
64+
}),
65+
})
66+
}
67+
68+
const handleTypeChange = (value: AppType) => {
69+
setAppType(value)
70+
navigate({
71+
search: (prev) => ({
72+
...prev,
73+
type: value === 'all' ? undefined : value,
74+
}),
75+
})
76+
}
77+
78+
const handleSortChange = (sort: 'asc' | 'desc') => {
79+
setSort(sort)
80+
navigate({ search: (prev) => ({ ...prev, sort }) })
81+
}
82+
4683
return (
4784
<>
4885
{/* ===== Top Heading ===== */}
@@ -70,9 +107,9 @@ export function Apps() {
70107
placeholder='Filter apps...'
71108
className='h-9 w-40 lg:w-[250px]'
72109
value={searchTerm}
73-
onChange={(e) => setSearchTerm(e.target.value)}
110+
onChange={handleSearch}
74111
/>
75-
<Select value={appType} onValueChange={setAppType}>
112+
<Select value={appType} onValueChange={handleTypeChange}>
76113
<SelectTrigger className='w-36'>
77114
<SelectValue>{appText.get(appType)}</SelectValue>
78115
</SelectTrigger>
@@ -84,20 +121,20 @@ export function Apps() {
84121
</Select>
85122
</div>
86123

87-
<Select value={sort} onValueChange={setSort}>
124+
<Select value={sort} onValueChange={handleSortChange}>
88125
<SelectTrigger className='w-16'>
89126
<SelectValue>
90127
<SlidersHorizontal size={18} />
91128
</SelectValue>
92129
</SelectTrigger>
93130
<SelectContent align='end'>
94-
<SelectItem value='ascending'>
131+
<SelectItem value='asc'>
95132
<div className='flex items-center gap-4'>
96133
<ArrowUpAZ size={16} />
97134
<span>Ascending</span>
98135
</div>
99136
</SelectItem>
100-
<SelectItem value='descending'>
137+
<SelectItem value='desc'>
101138
<div className='flex items-center gap-4'>
102139
<ArrowDownAZ size={16} />
103140
<span>Descending</span>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1+
import z from 'zod'
12
import { createFileRoute } from '@tanstack/react-router'
23
import { Apps } from '@/features/apps'
34

5+
const appsSearchSchema = z.object({
6+
type: z
7+
.enum(['all', 'connected', 'notConnected'])
8+
.optional()
9+
.catch(undefined),
10+
filter: z.string().optional().catch(''),
11+
sort: z.enum(['asc', 'desc']).optional().catch(undefined),
12+
})
13+
414
export const Route = createFileRoute('/_authenticated/apps/')({
15+
validateSearch: appsSearchSchema,
516
component: Apps,
617
})

0 commit comments

Comments
 (0)