@@ -10,6 +10,7 @@ import {
1010 TrashIcon ,
1111} from "lucide-react" ;
1212import Link from "next/link" ;
13+ import { useRouter } from "next/router" ;
1314import { useEffect , useMemo , useState } from "react" ;
1415import { toast } from "sonner" ;
1516import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar" ;
@@ -54,16 +55,23 @@ import {
5455} from "@/components/ui/select" ;
5556import { TimeBadge } from "@/components/ui/time-badge" ;
5657import { api } from "@/utils/api" ;
58+ import { useDebounce } from "@/utils/hooks/use-debounce" ;
5759import { HandleProject } from "./handle-project" ;
5860import { ProjectEnvironment } from "./project-environment" ;
5961
6062export const ShowProjects = ( ) => {
6163 const utils = api . useUtils ( ) ;
64+ const router = useRouter ( ) ;
6265 const { data : isCloud } = api . settings . isCloud . useQuery ( ) ;
6366 const { data, isLoading } = api . project . all . useQuery ( ) ;
6467 const { data : auth } = api . user . get . useQuery ( ) ;
6568 const { mutateAsync } = api . project . remove . useMutation ( ) ;
66- const [ searchQuery , setSearchQuery ] = useState ( "" ) ;
69+
70+ const [ searchQuery , setSearchQuery ] = useState (
71+ router . isReady && typeof router . query . q === "string" ? router . query . q : "" ,
72+ ) ;
73+ const debouncedSearchQuery = useDebounce ( searchQuery , 500 ) ;
74+
6775 const [ sortBy , setSortBy ] = useState < string > ( ( ) => {
6876 if ( typeof window !== "undefined" ) {
6977 return localStorage . getItem ( "projectsSort" ) || "createdAt-desc" ;
@@ -75,14 +83,41 @@ export const ShowProjects = () => {
7583 localStorage . setItem ( "projectsSort" , sortBy ) ;
7684 } , [ sortBy ] ) ;
7785
86+ useEffect ( ( ) => {
87+ if ( ! router . isReady ) return ;
88+ const urlQuery = typeof router . query . q === "string" ? router . query . q : "" ;
89+ if ( urlQuery !== searchQuery ) {
90+ setSearchQuery ( urlQuery ) ;
91+ }
92+ } , [ router . isReady , router . query . q ] ) ;
93+
94+ useEffect ( ( ) => {
95+ if ( ! router . isReady ) return ;
96+ const urlQuery = typeof router . query . q === "string" ? router . query . q : "" ;
97+ if ( debouncedSearchQuery === urlQuery ) return ;
98+
99+ const newQuery = { ...router . query } ;
100+ if ( debouncedSearchQuery ) {
101+ newQuery . q = debouncedSearchQuery ;
102+ } else {
103+ delete newQuery . q ;
104+ }
105+ router . replace ( { pathname : router . pathname , query : newQuery } , undefined , {
106+ shallow : true ,
107+ } ) ;
108+ } , [ debouncedSearchQuery ] ) ;
109+
78110 const filteredProjects = useMemo ( ( ) => {
79111 if ( ! data ) return [ ] ;
80112
81- // First filter by search query
82113 const filtered = data . filter (
83114 ( project ) =>
84- project . name . toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) ||
85- project . description ?. toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) ,
115+ project . name
116+ . toLowerCase ( )
117+ . includes ( debouncedSearchQuery . toLowerCase ( ) ) ||
118+ project . description
119+ ?. toLowerCase ( )
120+ . includes ( debouncedSearchQuery . toLowerCase ( ) ) ,
86121 ) ;
87122
88123 // Then sort the filtered results
@@ -130,7 +165,7 @@ export const ShowProjects = () => {
130165 }
131166 return direction === "asc" ? comparison : - comparison ;
132167 } ) ;
133- } , [ data , searchQuery , sortBy ] ) ;
168+ } , [ data , debouncedSearchQuery , sortBy ] ) ;
134169
135170 return (
136171 < >
0 commit comments