@@ -12,7 +12,7 @@ const LocationPage = () => {
1212 const [ loadingListings , setLoadingListings ] = useState ( true ) ;
1313 const [ location , setLocation ] = useState < any | null > ( null ) ;
1414 const [ cachedName , setCachedName ] = useState < string | null > ( null ) ;
15- const [ categoryFilter , setCategoryFilter ] = useState < string > ( "" ) ;
15+ const [ tagFilter , setTagFilter ] = useState < string > ( "" ) ;
1616
1717 const refreshDelay = process . env . NEXT_PUBLIC_REFRESH_DELAY ? Number ( process . env . NEXT_PUBLIC_REFRESH_DELAY ) : 4000 ;
1818 // Future: we could store geo/radius for map previews
@@ -113,7 +113,6 @@ const LocationPage = () => {
113113 priceWei
114114 tokenSymbol
115115 tokenDecimals
116- category
117116 }
118117 }
119118 }` ,
@@ -142,7 +141,6 @@ const LocationPage = () => {
142141 priceWei : it ?. priceWei ?? null ,
143142 tokenSymbol : it ?. tokenSymbol ?? null ,
144143 tokenDecimals : it ?. tokenDecimals ?? null ,
145- category : it ?. category ?? null ,
146144 } ;
147145 } ) ;
148146 setListings ( items ) ;
@@ -193,16 +191,33 @@ const LocationPage = () => {
193191 return ( ) => clearTimeout ( timeout ) ;
194192 } , [ fetchListings , params ?. id , refreshDelay ] ) ;
195193
194+ const availableTags = useMemo ( ( ) => {
195+ const tagSet = listings . reduce ( ( acc : Set < string > , listing ) => {
196+ if ( Array . isArray ( listing . tags ) ) {
197+ listing . tags . forEach ( ( tag : string ) => {
198+ if ( tag && typeof tag === "string" ) {
199+ acc . add ( tag . toLowerCase ( ) ) ;
200+ }
201+ } ) ;
202+ }
203+ return acc ;
204+ } , new Set < string > ( ) ) ;
205+ return Array . from ( tagSet ) . sort ( ) ;
206+ } , [ listings ] ) ;
207+
196208 const filtered = useMemo ( ( ) => {
197209 const q = ( query || "" ) . toLowerCase ( ) ;
198- const cat = ( categoryFilter || "" ) . toLowerCase ( ) ;
210+ const selectedTag = ( tagFilter || "" ) . toLowerCase ( ) ;
199211
200212 return listings . filter ( l => {
201213 if ( q && ! ( l . title || "" ) . toLowerCase ( ) . includes ( q ) ) return false ;
202- if ( cat && String ( l . category || "" ) . toLowerCase ( ) !== cat ) return false ;
214+ if ( selectedTag ) {
215+ const listingTags = Array . isArray ( l . tags ) ? l . tags . map ( ( t : string ) => String ( t ) . toLowerCase ( ) ) : [ ] ;
216+ if ( ! listingTags . includes ( selectedTag ) ) return false ;
217+ }
203218 return true ;
204219 } ) ;
205- } , [ listings , query , categoryFilter ] ) ;
220+ } , [ listings , query , tagFilter ] ) ;
206221
207222 return (
208223 < div className = "p-4 space-y-4" >
@@ -222,56 +237,39 @@ const LocationPage = () => {
222237 < details className = "dropdown" >
223238 < summary className = "btn btn-sm relative" >
224239 Filters
225- { categoryFilter ? < span className = "absolute -top-1 -right-1 h-2 w-2 rounded-full bg-red-500" /> : null }
240+ { tagFilter ? < span className = "absolute -top-1 -right-1 h-2 w-2 rounded-full bg-red-500" /> : null }
226241 </ summary >
227242 < div className = "menu dropdown-content bg-base-100 rounded-box shadow p-3 mt-2 w-80 space-y-2" >
228243 < div className = "space-y-1" >
229- < div className = "text-sm opacity-80" > Category</ div >
230- < select
231- className = "select select-bordered w-full"
232- value = { categoryFilter }
233- onChange = { e => {
234- setCategoryFilter ( e . target . value ) ;
235- try {
236- const parent = ( e . target as HTMLSelectElement ) . closest ( "details" ) as HTMLDetailsElement | null ;
237- if ( parent ) parent . open = false ; // auto close
238- } catch { }
239- } }
240- >
241- < option value = "" > All categories</ option >
242- < option value = "vehicles" > Vehicles</ option >
243- < option value = "housing" > Housing & Rooms </ option >
244- < option value = "furniture" > Furniture</ option >
245- < option value = "appliances" > Appliances</ option >
246- < option value = "electronics" > Electronics</ option >
247- < option value = "tools" > Tools & Equipment </ option >
248- < option value = "garden_outdoor" > Garden & Outdoor </ option >
249- < option value = "home_improvement" > Home Improvement</ option >
250- < option value = "clothing_accessories" > Clothing & Accessories </ option >
251- < option value = "baby_kids" > Baby & Kids </ option >
252- < option value = "sports_fitness" > Sports & Fitness </ option >
253- < option value = "bikes" > Bikes</ option >
254- < option value = "pets" > Pets & Supplies </ option >
255- < option value = "farm_garden" > Farm & Garden </ option >
256- < option value = "business_industrial" > Business & Industrial </ option >
257- < option value = "services" > Services</ option >
258- < option value = "jobs" > Jobs</ option >
259- < option value = "classes" > Classes & Lessons </ option >
260- < option value = "events" > Local Events</ option >
261- < option value = "free_stuff" > Free Stuff</ option >
262- < option value = "lost_found" > Lost & Found </ option >
263- < option value = "community" > Community</ option >
264- < option value = "garage_sales" > Garage & Yard Sales </ option >
265- < option value = "rideshare" > Rideshare & Carpool </ option >
266- < option value = "experiences" > Experiences</ option >
267- < option value = "other" > Other</ option >
268- </ select >
244+ < div className = "text-sm opacity-80" > Tag</ div >
245+ { availableTags . length > 0 ? (
246+ < select
247+ className = "select select-bordered w-full"
248+ value = { tagFilter }
249+ onChange = { e => {
250+ setTagFilter ( e . target . value ) ;
251+ try {
252+ const parent = ( e . target as HTMLSelectElement ) . closest ( "details" ) as HTMLDetailsElement | null ;
253+ if ( parent ) parent . open = false ; // auto close
254+ } catch { }
255+ } }
256+ >
257+ < option value = "" > All tags</ option >
258+ { availableTags . map ( tag => (
259+ < option key = { tag } value = { tag } >
260+ { tag }
261+ </ option >
262+ ) ) }
263+ </ select >
264+ ) : (
265+ < div className = "text-sm opacity-60 py-2" > No tags available</ div >
266+ ) }
269267 < div className = "flex justify-end pt-1" >
270268 < button
271269 className = "btn btn-ghost btn-sm"
272270 onClick = { e => {
273271 e . preventDefault ( ) ;
274- setCategoryFilter ( "" ) ;
272+ setTagFilter ( "" ) ;
275273 try {
276274 const parent = ( e . currentTarget as HTMLButtonElement ) . closest (
277275 "details" ,
0 commit comments