1
1
'use client' ;
2
2
3
+ import { FileIcon } from "@/components/ui/fileIcon" ;
3
4
import { Repository , SearchResultFile } from "@/lib/types" ;
4
5
import { cn , getRepoCodeHostInfo } from "@/lib/utils" ;
5
- import { SetStateAction , useCallback , useEffect , useState } from "react" ;
6
+ import { LaptopIcon } from "@radix-ui/react-icons" ;
7
+ import Image from "next/image" ;
8
+ import { useRouter , useSearchParams } from "next/navigation" ;
9
+ import { useEffect , useMemo } from "react" ;
6
10
import { Entry } from "./entry" ;
7
11
import { Filter } from "./filter" ;
8
- import Image from "next/image" ;
9
- import { LaptopIcon } from "@radix-ui/react-icons" ;
10
- import { FileIcon } from "@/components/ui/fileIcon" ;
11
- import { useSearchParams } from "next/navigation" ;
12
- import { useRouter } from "next/navigation" ;
13
12
14
13
interface FilePanelProps {
15
14
matches : SearchResultFile [ ] ;
@@ -34,7 +33,7 @@ export const FilterPanel = ({
34
33
return value ? new Set ( value . split ( ',' ) ) : new Set ( ) ;
35
34
} ;
36
35
37
- const [ repos , setRepos ] = useState < Record < string , Entry > > ( ( ) => {
36
+ const repos = useMemo ( ( ) => {
38
37
const selectedRepos = getSelectedFromQuery ( REPOS_QUERY_PARAM ) ;
39
38
return aggregateMatches (
40
39
"Repository" ,
@@ -60,10 +59,10 @@ export const FilterPanel = ({
60
59
Icon,
61
60
} ;
62
61
}
63
- ) ;
64
- } ) ;
62
+ )
63
+ } , [ searchParams ] ) ;
65
64
66
- const [ languages , setLanguages ] = useState < Record < string , Entry > > ( ( ) => {
65
+ const languages = useMemo ( ( ) => {
67
66
const selectedLanguages = getSelectedFromQuery ( LANGUAGES_QUERY_PARAM ) ;
68
67
return aggregateMatches (
69
68
"Language" ,
@@ -82,20 +81,7 @@ export const FilterPanel = ({
82
81
} satisfies Entry ;
83
82
}
84
83
) ;
85
- } ) ;
86
-
87
- const onEntryClicked = useCallback ( (
88
- key : string ,
89
- setter : ( value : SetStateAction < Record < string , Entry > > ) => void ,
90
- ) => {
91
- setter ( ( values ) => ( {
92
- ...values ,
93
- [ key ] : {
94
- ...values [ key ] ,
95
- isSelected : ! values [ key ] . isSelected ,
96
- } ,
97
- } ) ) ;
98
- } , [ ] ) ;
84
+ } , [ searchParams ] ) ;
99
85
100
86
// Calls `onFilterChanged` with the filtered list of matches
101
87
// whenever the filter state changes.
@@ -113,47 +99,53 @@ export const FilterPanel = ({
113
99
114
100
} , [ matches , repos , languages , onFilterChanged , searchParams , router ] ) ;
115
101
116
- // Updates the query params when the filter state changes
117
- useEffect ( ( ) => {
118
- const selectedRepos = Object . keys ( repos ) . filter ( ( key ) => repos [ key ] . isSelected ) ;
119
- const selectedLanguages = Object . keys ( languages ) . filter ( ( key ) => languages [ key ] . isSelected ) ;
120
-
121
- const newParams = new URLSearchParams ( searchParams . toString ( ) ) ;
122
-
123
- if ( selectedRepos . length > 0 ) {
124
- newParams . set ( REPOS_QUERY_PARAM , selectedRepos . join ( ',' ) ) ;
125
- } else {
126
- newParams . delete ( REPOS_QUERY_PARAM ) ;
127
- }
128
-
129
- if ( selectedLanguages . length > 0 ) {
130
- newParams . set ( LANGUAGES_QUERY_PARAM , selectedLanguages . join ( ',' ) ) ;
131
- } else {
132
- newParams . delete ( LANGUAGES_QUERY_PARAM ) ;
133
- }
134
-
135
- // Only push if params actually changed
136
- if ( newParams . toString ( ) !== searchParams . toString ( ) ) {
137
- router . replace ( `?${ newParams . toString ( ) } ` , { scroll : false } ) ;
138
- }
139
- } , [ repos , languages , searchParams , router ] ) ;
140
-
141
- const numRepos = Object . keys ( repos ) . length > 100 ? '100+' : Object . keys ( repos ) . length ;
142
- const numLanguages = Object . keys ( languages ) . length > 100 ? '100+' : Object . keys ( languages ) . length ;
102
+ const numRepos = useMemo ( ( ) => Object . keys ( repos ) . length > 100 ? '100+' : Object . keys ( repos ) . length , [ repos ] ) ;
103
+ const numLanguages = useMemo ( ( ) => Object . keys ( languages ) . length > 100 ? '100+' : Object . keys ( languages ) . length , [ languages ] ) ;
104
+
143
105
return (
144
106
< div className = "p-3 flex flex-col gap-3 h-full" >
145
107
< Filter
146
108
title = "Filter By Repository"
147
109
searchPlaceholder = { `Filter ${ numRepos } repositories` }
148
110
entries = { Object . values ( repos ) }
149
- onEntryClicked = { ( key ) => onEntryClicked ( key , setRepos ) }
111
+ onEntryClicked = { ( key ) => {
112
+ const newRepos = { ...repos } ;
113
+ newRepos [ key ] . isSelected = ! newRepos [ key ] . isSelected ;
114
+ const selectedRepos = Object . keys ( newRepos ) . filter ( ( key ) => newRepos [ key ] . isSelected ) ;
115
+ const newParams = new URLSearchParams ( searchParams . toString ( ) ) ;
116
+
117
+ if ( selectedRepos . length > 0 ) {
118
+ newParams . set ( REPOS_QUERY_PARAM , selectedRepos . join ( ',' ) ) ;
119
+ } else {
120
+ newParams . delete ( REPOS_QUERY_PARAM ) ;
121
+ }
122
+
123
+ if ( newParams . toString ( ) !== searchParams . toString ( ) ) {
124
+ router . replace ( `?${ newParams . toString ( ) } ` , { scroll : false } ) ;
125
+ }
126
+ } }
150
127
className = "max-h-[50%]"
151
128
/>
152
129
< Filter
153
130
title = "Filter By Language"
154
131
searchPlaceholder = { `Filter ${ numLanguages } languages` }
155
132
entries = { Object . values ( languages ) }
156
- onEntryClicked = { ( key ) => onEntryClicked ( key , setLanguages ) }
133
+ onEntryClicked = { ( key ) => {
134
+ const newLanguages = { ...languages } ;
135
+ newLanguages [ key ] . isSelected = ! newLanguages [ key ] . isSelected ;
136
+ const selectedLanguages = Object . keys ( newLanguages ) . filter ( ( key ) => newLanguages [ key ] . isSelected ) ;
137
+ const newParams = new URLSearchParams ( searchParams . toString ( ) ) ;
138
+
139
+ if ( selectedLanguages . length > 0 ) {
140
+ newParams . set ( LANGUAGES_QUERY_PARAM , selectedLanguages . join ( ',' ) ) ;
141
+ } else {
142
+ newParams . delete ( LANGUAGES_QUERY_PARAM ) ;
143
+ }
144
+
145
+ if ( newParams . toString ( ) !== searchParams . toString ( ) ) {
146
+ router . replace ( `?${ newParams . toString ( ) } ` , { scroll : false } ) ;
147
+ }
148
+ } }
157
149
className = "overflow-auto"
158
150
/>
159
151
</ div >
0 commit comments