Просмотр исходного кода

feat: add search param sync in apps route (#200)

Sat Naing 11 месяцев назад
Родитель
Сommit
3c38dc125f
2 измененных файлов с 59 добавлено и 11 удалено
  1. 48 11
      src/features/apps/index.tsx
  2. 11 0
      src/routes/_authenticated/apps/index.tsx

+ 48 - 11
src/features/apps/index.tsx

@@ -1,4 +1,5 @@
-import { useState } from 'react'
+import { type ChangeEvent, useState } from 'react'
+import { getRouteApi } from '@tanstack/react-router'
 import { SlidersHorizontal, ArrowUpAZ, ArrowDownAZ } from 'lucide-react'
 import { SlidersHorizontal, ArrowUpAZ, ArrowDownAZ } from 'lucide-react'
 import { Button } from '@/components/ui/button'
 import { Button } from '@/components/ui/button'
 import { Input } from '@/components/ui/input'
 import { Input } from '@/components/ui/input'
@@ -17,20 +18,31 @@ import { Search } from '@/components/search'
 import { ThemeSwitch } from '@/components/theme-switch'
 import { ThemeSwitch } from '@/components/theme-switch'
 import { apps } from './data/apps'
 import { apps } from './data/apps'
 
 
-const appText = new Map<string, string>([
+const route = getRouteApi('/_authenticated/apps/')
+
+type AppType = 'all' | 'connected' | 'notConnected'
+
+const appText = new Map<AppType, string>([
   ['all', 'All Apps'],
   ['all', 'All Apps'],
   ['connected', 'Connected'],
   ['connected', 'Connected'],
   ['notConnected', 'Not Connected'],
   ['notConnected', 'Not Connected'],
 ])
 ])
 
 
 export function Apps() {
 export function Apps() {
-  const [sort, setSort] = useState('ascending')
-  const [appType, setAppType] = useState('all')
-  const [searchTerm, setSearchTerm] = useState('')
+  const {
+    filter = '',
+    type = 'all',
+    sort: initSort = 'asc',
+  } = route.useSearch()
+  const navigate = route.useNavigate()
+
+  const [sort, setSort] = useState(initSort)
+  const [appType, setAppType] = useState(type)
+  const [searchTerm, setSearchTerm] = useState(filter)
 
 
   const filteredApps = apps
   const filteredApps = apps
     .sort((a, b) =>
     .sort((a, b) =>
-      sort === 'ascending'
+      sort === 'asc'
         ? a.name.localeCompare(b.name)
         ? a.name.localeCompare(b.name)
         : b.name.localeCompare(a.name)
         : b.name.localeCompare(a.name)
     )
     )
@@ -43,6 +55,31 @@ export function Apps() {
     )
     )
     .filter((app) => app.name.toLowerCase().includes(searchTerm.toLowerCase()))
     .filter((app) => app.name.toLowerCase().includes(searchTerm.toLowerCase()))
 
 
+  const handleSearch = (e: ChangeEvent<HTMLInputElement>) => {
+    setSearchTerm(e.target.value)
+    navigate({
+      search: (prev) => ({
+        ...prev,
+        filter: e.target.value || undefined,
+      }),
+    })
+  }
+
+  const handleTypeChange = (value: AppType) => {
+    setAppType(value)
+    navigate({
+      search: (prev) => ({
+        ...prev,
+        type: value === 'all' ? undefined : value,
+      }),
+    })
+  }
+
+  const handleSortChange = (sort: 'asc' | 'desc') => {
+    setSort(sort)
+    navigate({ search: (prev) => ({ ...prev, sort }) })
+  }
+
   return (
   return (
     <>
     <>
       {/* ===== Top Heading ===== */}
       {/* ===== Top Heading ===== */}
@@ -70,9 +107,9 @@ export function Apps() {
               placeholder='Filter apps...'
               placeholder='Filter apps...'
               className='h-9 w-40 lg:w-[250px]'
               className='h-9 w-40 lg:w-[250px]'
               value={searchTerm}
               value={searchTerm}
-              onChange={(e) => setSearchTerm(e.target.value)}
+              onChange={handleSearch}
             />
             />
-            <Select value={appType} onValueChange={setAppType}>
+            <Select value={appType} onValueChange={handleTypeChange}>
               <SelectTrigger className='w-36'>
               <SelectTrigger className='w-36'>
                 <SelectValue>{appText.get(appType)}</SelectValue>
                 <SelectValue>{appText.get(appType)}</SelectValue>
               </SelectTrigger>
               </SelectTrigger>
@@ -84,20 +121,20 @@ export function Apps() {
             </Select>
             </Select>
           </div>
           </div>
 
 
-          <Select value={sort} onValueChange={setSort}>
+          <Select value={sort} onValueChange={handleSortChange}>
             <SelectTrigger className='w-16'>
             <SelectTrigger className='w-16'>
               <SelectValue>
               <SelectValue>
                 <SlidersHorizontal size={18} />
                 <SlidersHorizontal size={18} />
               </SelectValue>
               </SelectValue>
             </SelectTrigger>
             </SelectTrigger>
             <SelectContent align='end'>
             <SelectContent align='end'>
-              <SelectItem value='ascending'>
+              <SelectItem value='asc'>
                 <div className='flex items-center gap-4'>
                 <div className='flex items-center gap-4'>
                   <ArrowUpAZ size={16} />
                   <ArrowUpAZ size={16} />
                   <span>Ascending</span>
                   <span>Ascending</span>
                 </div>
                 </div>
               </SelectItem>
               </SelectItem>
-              <SelectItem value='descending'>
+              <SelectItem value='desc'>
                 <div className='flex items-center gap-4'>
                 <div className='flex items-center gap-4'>
                   <ArrowDownAZ size={16} />
                   <ArrowDownAZ size={16} />
                   <span>Descending</span>
                   <span>Descending</span>

+ 11 - 0
src/routes/_authenticated/apps/index.tsx

@@ -1,6 +1,17 @@
+import z from 'zod'
 import { createFileRoute } from '@tanstack/react-router'
 import { createFileRoute } from '@tanstack/react-router'
 import { Apps } from '@/features/apps'
 import { Apps } from '@/features/apps'
 
 
+const appsSearchSchema = z.object({
+  type: z
+    .enum(['all', 'connected', 'notConnected'])
+    .optional()
+    .catch(undefined),
+  filter: z.string().optional().catch(''),
+  sort: z.enum(['asc', 'desc']).optional().catch(undefined),
+})
+
 export const Route = createFileRoute('/_authenticated/apps/')({
 export const Route = createFileRoute('/_authenticated/apps/')({
+  validateSearch: appsSearchSchema,
   component: Apps,
   component: Apps,
 })
 })