From e5c49d475ef96250b99e1bda05c8bbb91455c88a Mon Sep 17 00:00:00 2001 From: Lucy Joy Ameh Date: Fri, 25 Apr 2025 10:46:21 +0100 Subject: [PATCH 1/2] feat: implement marketplace filters UI --- .../components/home/featured-products.tsx | 2 +- .../marketplace/MarketplaceFilters.tsx | 441 ++++++++++++++++++ .../components/products/product-list.tsx | 3 + apps/frontend/locales/en.ts | 39 ++ apps/frontend/locales/es.ts | 38 ++ 5 files changed, 522 insertions(+), 1 deletion(-) create mode 100644 apps/frontend/components/marketplace/MarketplaceFilters.tsx diff --git a/apps/frontend/components/home/featured-products.tsx b/apps/frontend/components/home/featured-products.tsx index 9a5865ca..5ee044e5 100644 --- a/apps/frontend/components/home/featured-products.tsx +++ b/apps/frontend/components/home/featured-products.tsx @@ -29,7 +29,7 @@ export function FeaturedProducts() {

- {t("common.featuredProductsTitle.title")} + {t("common.featuredProductsTitle.title")}

void; +} + +export default function MarketplaceFilters({ + onFilterChange, +}: MarketplaceFiltersProps) { + const t = useTranslations(); + const [showFilters, setShowFilters] = useState(true); + const [activeFilters, setActiveFilters] = useState([]); + + // Filter states + const [categoryFilter, setCategoryFilter] = useState("electronics"); + const [priceRange, setPriceRange] = useState<[number, number]>([970, 5000]); + const [conditionFilter, setConditionFilter] = useState(["new"]); + const [sellerRatingFilter, setSellerRatingFilter] = useState("4"); + const [postedWithinFilter, setPostedWithinFilter] = useState("24h"); + const [sortByFilter, setSortByFilter] = useState("price_low_high"); + + // Update active filters whenever any filter changes + useEffect(() => { + updateActiveFilters(); + if (onFilterChange) { + onFilterChange({ + category: categoryFilter, + priceRange, + condition: conditionFilter, + sellerRating: sellerRatingFilter, + postedWithin: postedWithinFilter, + sortBy: sortByFilter, + }); + } + }, [ + categoryFilter, + priceRange, + conditionFilter, + sellerRatingFilter, + postedWithinFilter, + sortByFilter, + ]); + + // Update active filters display + const updateActiveFilters = () => { + const newActiveFilters = []; + if (categoryFilter) + newActiveFilters.push( + `Category: ${t(`commonMarketPlaceFilter.categories.${categoryFilter}`)}` + ); + if (priceRange[0] > 0 || priceRange[1] < 5000) { + newActiveFilters.push(`Price: $${priceRange[0]}-$${priceRange[1]}`); + } + if (conditionFilter.includes("new")) newActiveFilters.push("New: Yes"); + if (sellerRatingFilter) + newActiveFilters.push(`Seller Rating: ${sellerRatingFilter}★ & Up`); + if (postedWithinFilter === "24h") + newActiveFilters.push("Posted Within: Last 24 Hours"); + if (sortByFilter === "price_low_high") + newActiveFilters.push("Sort By: Price: Low to High"); + + setActiveFilters(newActiveFilters); + }; + + // Toggle filter visibility + const toggleFilters = () => { + setShowFilters(!showFilters); + }; + + // Clear all filters + const clearAllFilters = () => { + setCategoryFilter(""); + setPriceRange([0, 5000]); + setConditionFilter([]); + setSellerRatingFilter(""); + setPostedWithinFilter(""); + setSortByFilter(""); + }; + + // Remove a specific filter + const removeFilter = (filterType: string) => { + switch (filterType) { + case "Category": + setCategoryFilter(""); + break; + case "Price": + setPriceRange([0, 5000]); + break; + case "New": + setConditionFilter(conditionFilter.filter((c) => c !== "new")); + break; + case "Seller Rating": + setSellerRatingFilter(""); + break; + case "Posted Within": + setPostedWithinFilter(""); + break; + case "Sort By": + setSortByFilter(""); + break; + } + }; + + return ( +
+ {/* Filters Card */} + +
+
+

+ {t("commonMarketPlaceFilter.filters")} + {activeFilters.length > 0 && ( + + {activeFilters.length} + + )} +

+
+ +
+ + {showFilters && ( +
+ {/* Category Filter */} +
+ + +
+ + {/* Price Range Filter */} +
+ +
+ + setPriceRange([values[0], values[1]]) + } + /> +
+
+ + {/* Condition Filter */} +
+ +
+
+ { + if (checked) { + setConditionFilter([...conditionFilter, "new"]); + } else { + setConditionFilter( + conditionFilter.filter((c) => c !== "new") + ); + } + }} + /> + +
+
+ { + if (checked) { + setConditionFilter([...conditionFilter, "like-new"]); + } else { + setConditionFilter( + conditionFilter.filter((c) => c !== "like-new") + ); + } + }} + /> + +
+
+ { + if (checked) { + setConditionFilter([...conditionFilter, "good"]); + } else { + setConditionFilter( + conditionFilter.filter((c) => c !== "good") + ); + } + }} + /> + +
+
+ { + if (checked) { + setConditionFilter([...conditionFilter, "fair"]); + } else { + setConditionFilter( + conditionFilter.filter((c) => c !== "fair") + ); + } + }} + /> + +
+
+
+ + {/* Seller Rating Filter */} +
+ + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + {/* Posted Within Filter */} +
+ + +
+ + {/* Sort By Filter */} +
+ + +
+
+ )} +
+ {/* Active Filters - Now outside the Card */} + {activeFilters.length > 0 && ( +
+
+ + {t("commonMarketPlaceFilter.activeFilters")}: + + + {activeFilters.map((filter, index) => ( + + {filter} + removeFilter(filter.split(":")[0].trim())} + /> + + ))} + + +
+
+ )} +
+ ); +} \ No newline at end of file diff --git a/apps/frontend/components/products/product-list.tsx b/apps/frontend/components/products/product-list.tsx index 0212e437..281e375f 100644 --- a/apps/frontend/components/products/product-list.tsx +++ b/apps/frontend/components/products/product-list.tsx @@ -17,6 +17,7 @@ import type { ProductImagesData, ProductsData, } from "@/lib/types/product"; +import MarketplaceFilters from "../marketplace/MarketplaceFilters"; export default function ProductList() { const t = useTranslations(); @@ -83,7 +84,9 @@ export default function ProductList() { <>

Marketplace

+ Showing 8 of 100 products
+
{loading ? ( diff --git a/apps/frontend/locales/en.ts b/apps/frontend/locales/en.ts index f58a4abf..b3b48705 100644 --- a/apps/frontend/locales/en.ts +++ b/apps/frontend/locales/en.ts @@ -635,6 +635,45 @@ export const en = { save: "Save changes", successMessage: "Your profile has been successfully updated.", }, + commonMarketPlaceFilter: { + // Filter UI elements + filters: "Filters", + hideFilters: "Hide Filters", + showFilters: "Show Filters", + category: "Category", + selectCategory: "Select category...", + priceRange: "Price Range ($${min} - $${max})", + condition: "Condition", + sellerRating: "Seller Rating", + postedWithin: "Posted Within", + anyTime: "Any Time", + last24Hours: "Last 24 Hours", + last7Days: "Last 7 Days", + last30Days: "Last 30 Days", + sortBy: "Sort By", + mostRecent: "Most Recent", + priceLowHigh: "Price: Low to High", + priceHighLow: "Price: High to Low", + bestRating: "Best Rating", + activeFilters: "Active filters", + clearAll: "Clear all", + applyFilters: "Apply Filters", + + // Condition options + conditions: { + new: "New", + likeNew: "Like New", + good: "Good", + fair: "Fair" + }, + categories: { + electronics: "Electronics", + clothing: "Clothing", + homeAndGarden: "Home & Garden", + sports: "Sports & Outdoors" + }, + } + // Add more sections as needed }; diff --git a/apps/frontend/locales/es.ts b/apps/frontend/locales/es.ts index e0644326..42ee5cb3 100644 --- a/apps/frontend/locales/es.ts +++ b/apps/frontend/locales/es.ts @@ -640,6 +640,44 @@ export const es = { save: "Guardar cambios", successMessage: "Su perfil se ha actualizado correctamente.", }, + commonMarketPlaceFilter: { + // Filter UI elements + filters: "Filtros", + hideFilters: "Ocultar Filtros", + showFilters: "Mostrar Filtros", + category: "Categoría", + selectCategory: "Seleccionar categoría...", + priceRange: "Rango de Precio ($${min} - $${max})", + condition: "Condición", + sellerRating: "Calificación del Vendedor", + postedWithin: "Publicado Dentro", + anyTime: "Cualquier Tiempo", + last24Hours: "Últimas 24 Horas", + last7Days: "Últimos 7 Días", + last30Days: "Últimos 30 Días", + sortBy: "Ordenar Por", + mostRecent: "Más Reciente", + priceLowHigh: "Precio: Bajo a Alto", + priceHighLow: "Precio: Alto a Bajo", + bestRating: "Mejor Calificación", + activeFilters: "Filtros activos", + clearAll: "Borrar todo", + applyFilters: "Aplicar Filtros", + + // Condition options + conditions: { + new: "Nuevo", + likeNew: "Como Nuevo", + good: "Bueno", + fair: "Regular" + }, + categories: { + electronics: "Electrónica", + clothing: "Ropa", + homeAndGarden: "Hogar y Jardín", + sports: "Deportes y Aire Libre" + } + } // Add more sections as needed }; From 36e534eedd707f854d93bdbd77f3a63bc11e60a9 Mon Sep 17 00:00:00 2001 From: Lucy Joy Ameh Date: Sat, 26 Apr 2025 06:27:40 +0100 Subject: [PATCH 2/2] fix: resolve linting issues in marketplace filters - replace any type and fix useEffect dependencies --- .../marketplace/MarketplaceFilters.tsx | 441 ----------------- .../marketplace/marketplace-filters.tsx | 446 ++++++++++++++++++ .../components/products/product-list.tsx | 2 +- apps/frontend/locales/en.ts | 20 +- apps/frontend/locales/es.ts | 18 +- 5 files changed, 466 insertions(+), 461 deletions(-) delete mode 100644 apps/frontend/components/marketplace/MarketplaceFilters.tsx create mode 100644 apps/frontend/components/marketplace/marketplace-filters.tsx diff --git a/apps/frontend/components/marketplace/MarketplaceFilters.tsx b/apps/frontend/components/marketplace/MarketplaceFilters.tsx deleted file mode 100644 index 6012a9bf..00000000 --- a/apps/frontend/components/marketplace/MarketplaceFilters.tsx +++ /dev/null @@ -1,441 +0,0 @@ -// components/marketplace/MarketplaceFilters.tsx -"use client"; - -import { useState, useEffect } from "react"; -import { useTranslations } from "next-intl"; -import { X, ChevronUp, ChevronDown } from "lucide-react"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { Card } from "@/components/ui/card"; -import { Checkbox } from "@/components/ui/checkbox"; -import { Slider } from "@/components/ui/slider"; -import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; -import { - Select, - SelectContent, - SelectGroup, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { Label } from "@/components/ui/label"; - -interface MarketplaceFiltersProps { - onFilterChange?: (filters: any) => void; -} - -export default function MarketplaceFilters({ - onFilterChange, -}: MarketplaceFiltersProps) { - const t = useTranslations(); - const [showFilters, setShowFilters] = useState(true); - const [activeFilters, setActiveFilters] = useState([]); - - // Filter states - const [categoryFilter, setCategoryFilter] = useState("electronics"); - const [priceRange, setPriceRange] = useState<[number, number]>([970, 5000]); - const [conditionFilter, setConditionFilter] = useState(["new"]); - const [sellerRatingFilter, setSellerRatingFilter] = useState("4"); - const [postedWithinFilter, setPostedWithinFilter] = useState("24h"); - const [sortByFilter, setSortByFilter] = useState("price_low_high"); - - // Update active filters whenever any filter changes - useEffect(() => { - updateActiveFilters(); - if (onFilterChange) { - onFilterChange({ - category: categoryFilter, - priceRange, - condition: conditionFilter, - sellerRating: sellerRatingFilter, - postedWithin: postedWithinFilter, - sortBy: sortByFilter, - }); - } - }, [ - categoryFilter, - priceRange, - conditionFilter, - sellerRatingFilter, - postedWithinFilter, - sortByFilter, - ]); - - // Update active filters display - const updateActiveFilters = () => { - const newActiveFilters = []; - if (categoryFilter) - newActiveFilters.push( - `Category: ${t(`commonMarketPlaceFilter.categories.${categoryFilter}`)}` - ); - if (priceRange[0] > 0 || priceRange[1] < 5000) { - newActiveFilters.push(`Price: $${priceRange[0]}-$${priceRange[1]}`); - } - if (conditionFilter.includes("new")) newActiveFilters.push("New: Yes"); - if (sellerRatingFilter) - newActiveFilters.push(`Seller Rating: ${sellerRatingFilter}★ & Up`); - if (postedWithinFilter === "24h") - newActiveFilters.push("Posted Within: Last 24 Hours"); - if (sortByFilter === "price_low_high") - newActiveFilters.push("Sort By: Price: Low to High"); - - setActiveFilters(newActiveFilters); - }; - - // Toggle filter visibility - const toggleFilters = () => { - setShowFilters(!showFilters); - }; - - // Clear all filters - const clearAllFilters = () => { - setCategoryFilter(""); - setPriceRange([0, 5000]); - setConditionFilter([]); - setSellerRatingFilter(""); - setPostedWithinFilter(""); - setSortByFilter(""); - }; - - // Remove a specific filter - const removeFilter = (filterType: string) => { - switch (filterType) { - case "Category": - setCategoryFilter(""); - break; - case "Price": - setPriceRange([0, 5000]); - break; - case "New": - setConditionFilter(conditionFilter.filter((c) => c !== "new")); - break; - case "Seller Rating": - setSellerRatingFilter(""); - break; - case "Posted Within": - setPostedWithinFilter(""); - break; - case "Sort By": - setSortByFilter(""); - break; - } - }; - - return ( -
- {/* Filters Card */} - -
-
-

- {t("commonMarketPlaceFilter.filters")} - {activeFilters.length > 0 && ( - - {activeFilters.length} - - )} -

-
- -
- - {showFilters && ( -
- {/* Category Filter */} -
- - -
- - {/* Price Range Filter */} -
- -
- - setPriceRange([values[0], values[1]]) - } - /> -
-
- - {/* Condition Filter */} -
- -
-
- { - if (checked) { - setConditionFilter([...conditionFilter, "new"]); - } else { - setConditionFilter( - conditionFilter.filter((c) => c !== "new") - ); - } - }} - /> - -
-
- { - if (checked) { - setConditionFilter([...conditionFilter, "like-new"]); - } else { - setConditionFilter( - conditionFilter.filter((c) => c !== "like-new") - ); - } - }} - /> - -
-
- { - if (checked) { - setConditionFilter([...conditionFilter, "good"]); - } else { - setConditionFilter( - conditionFilter.filter((c) => c !== "good") - ); - } - }} - /> - -
-
- { - if (checked) { - setConditionFilter([...conditionFilter, "fair"]); - } else { - setConditionFilter( - conditionFilter.filter((c) => c !== "fair") - ); - } - }} - /> - -
-
-
- - {/* Seller Rating Filter */} -
- - -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- - {/* Posted Within Filter */} -
- - -
- - {/* Sort By Filter */} -
- - -
-
- )} -
- {/* Active Filters - Now outside the Card */} - {activeFilters.length > 0 && ( -
-
- - {t("commonMarketPlaceFilter.activeFilters")}: - - - {activeFilters.map((filter, index) => ( - - {filter} - removeFilter(filter.split(":")[0].trim())} - /> - - ))} - - -
-
- )} -
- ); -} \ No newline at end of file diff --git a/apps/frontend/components/marketplace/marketplace-filters.tsx b/apps/frontend/components/marketplace/marketplace-filters.tsx new file mode 100644 index 00000000..21e6393b --- /dev/null +++ b/apps/frontend/components/marketplace/marketplace-filters.tsx @@ -0,0 +1,446 @@ +"use client"; + +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Label } from "@/components/ui/label"; +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Slider } from "@/components/ui/slider"; +import { ChevronDown, ChevronUp, X } from "lucide-react"; +import { useTranslations } from "next-intl"; +import { useCallback, useEffect, useState } from "react"; + +interface FilterParams { + category?: string; + priceRange: [number, number]; + condition?: string[]; + sellerRating?: string; + postedWithin?: string; + sortBy?: string; +} + +interface MarketplaceFiltersProps { + onFilterChange?: (filters: FilterParams) => void; +} + +export default function MarketplaceFilters({ + onFilterChange, +}: MarketplaceFiltersProps) { + const t = useTranslations(); + const [showFilters, setShowFilters] = useState(true); + const [activeFilters, setActiveFilters] = useState([]); + + const [categoryFilter, setCategoryFilter] = useState("electronics"); + const [priceRange, setPriceRange] = useState<[number, number]>([970, 5000]); + const [conditionFilter, setConditionFilter] = useState(["new"]); + const [sellerRatingFilter, setSellerRatingFilter] = useState("4"); + const [postedWithinFilter, setPostedWithinFilter] = useState("24h"); + const [sortByFilter, setSortByFilter] = useState("price_low_high"); + + const updateActiveFilters = useCallback(() => { + const newActiveFilters = []; + if (categoryFilter) + newActiveFilters.push( + `Category: ${t(`commonMarketPlaceFilter.categories.${categoryFilter}`)}`, + ); + if (priceRange[0] > 0 || priceRange[1] < 5000) { + newActiveFilters.push(`Price: $${priceRange[0]}-$${priceRange[1]}`); + } + if (conditionFilter.includes("new")) newActiveFilters.push("New: Yes"); + if (sellerRatingFilter) + newActiveFilters.push(`Seller Rating: ${sellerRatingFilter}★ & Up`); + if (postedWithinFilter === "24h") + newActiveFilters.push("Posted Within: Last 24 Hours"); + if (sortByFilter === "price_low_high") + newActiveFilters.push("Sort By: Price: Low to High"); + + setActiveFilters(newActiveFilters); + }, [ + categoryFilter, + conditionFilter, + priceRange, + postedWithinFilter, + sellerRatingFilter, + sortByFilter, + t, + ]); + + useEffect(() => { + updateActiveFilters(); + if (onFilterChange) { + onFilterChange({ + category: categoryFilter, + priceRange, + condition: conditionFilter, + sellerRating: sellerRatingFilter, + postedWithin: postedWithinFilter, + sortBy: sortByFilter, + }); + } + }, [ + updateActiveFilters, + onFilterChange, + categoryFilter, + priceRange, + conditionFilter, + sellerRatingFilter, + postedWithinFilter, + sortByFilter, + ]); + + const toggleFilters = () => { + setShowFilters(!showFilters); + }; + + const clearAllFilters = () => { + setCategoryFilter(""); + setPriceRange([0, 5000]); + setConditionFilter([]); + setSellerRatingFilter(""); + setPostedWithinFilter(""); + setSortByFilter(""); + }; + + // Remove a specific filter + const removeFilter = (filterType: string) => { + switch (filterType) { + case "Category": + setCategoryFilter(""); + break; + case "Price": + setPriceRange([0, 5000]); + break; + case "New": + setConditionFilter(conditionFilter.filter((c) => c !== "new")); + break; + case "Seller Rating": + setSellerRatingFilter(""); + break; + case "Posted Within": + setPostedWithinFilter(""); + break; + case "Sort By": + setSortByFilter(""); + break; + } + }; + + return ( +
+ +
+
+

+ {t("commonMarketPlaceFilter.filters")} + {activeFilters.length > 0 && ( + + {activeFilters.length} + + )} +

+
+ +
+ + {showFilters && ( +
+
+ + +
+ +
+ +
+ + setPriceRange([values[0], values[1]]) + } + /> +
+
+ +
+ +
+
+ { + if (checked) { + setConditionFilter([...conditionFilter, "new"]); + } else { + setConditionFilter( + conditionFilter.filter((c) => c !== "new"), + ); + } + }} + /> + +
+
+ { + if (checked) { + setConditionFilter([...conditionFilter, "like-new"]); + } else { + setConditionFilter( + conditionFilter.filter((c) => c !== "like-new"), + ); + } + }} + /> + +
+
+ { + if (checked) { + setConditionFilter([...conditionFilter, "good"]); + } else { + setConditionFilter( + conditionFilter.filter((c) => c !== "good"), + ); + } + }} + /> + +
+
+ { + if (checked) { + setConditionFilter([...conditionFilter, "fair"]); + } else { + setConditionFilter( + conditionFilter.filter((c) => c !== "fair"), + ); + } + }} + /> + +
+
+
+ +
+ + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ + +
+ +
+ + +
+
+ )} +
+ {activeFilters.length > 0 && ( +
+
+ + {t("commonMarketPlaceFilter.activeFilters")}: + + + {activeFilters.map((filter, index) => ( + + {filter} + removeFilter(filter.split(":")[0].trim())} + /> + + ))} + + +
+
+ )} +
+ ); +} diff --git a/apps/frontend/components/products/product-list.tsx b/apps/frontend/components/products/product-list.tsx index 281e375f..d2396be3 100644 --- a/apps/frontend/components/products/product-list.tsx +++ b/apps/frontend/components/products/product-list.tsx @@ -17,7 +17,7 @@ import type { ProductImagesData, ProductsData, } from "@/lib/types/product"; -import MarketplaceFilters from "../marketplace/MarketplaceFilters"; +import MarketplaceFilters from "../marketplace/marketplace-filters"; export default function ProductList() { const t = useTranslations(); diff --git a/apps/frontend/locales/en.ts b/apps/frontend/locales/en.ts index b3b48705..ec7f78aa 100644 --- a/apps/frontend/locales/en.ts +++ b/apps/frontend/locales/en.ts @@ -642,7 +642,7 @@ export const en = { showFilters: "Show Filters", category: "Category", selectCategory: "Select category...", - priceRange: "Price Range ($${min} - $${max})", + priceRange: "Price Range (${min} - ${max})", condition: "Condition", sellerRating: "Seller Rating", postedWithin: "Posted Within", @@ -658,22 +658,22 @@ export const en = { activeFilters: "Active filters", clearAll: "Clear all", applyFilters: "Apply Filters", - + // Condition options conditions: { - new: "New", - likeNew: "Like New", - good: "Good", - fair: "Fair" + new: "New", + likeNew: "Like New", + good: "Good", + fair: "Fair", }, categories: { electronics: "Electronics", clothing: "Clothing", homeAndGarden: "Home & Garden", - sports: "Sports & Outdoors" - }, - } - + sports: "Sports & Outdoors", + }, + }, + // Add more sections as needed }; diff --git a/apps/frontend/locales/es.ts b/apps/frontend/locales/es.ts index 42ee5cb3..a0b498ab 100644 --- a/apps/frontend/locales/es.ts +++ b/apps/frontend/locales/es.ts @@ -647,7 +647,7 @@ export const es = { showFilters: "Mostrar Filtros", category: "Categoría", selectCategory: "Seleccionar categoría...", - priceRange: "Rango de Precio ($${min} - $${max})", + priceRange: "Rango de Precio (${min} - ${max})", condition: "Condición", sellerRating: "Calificación del Vendedor", postedWithin: "Publicado Dentro", @@ -663,21 +663,21 @@ export const es = { activeFilters: "Filtros activos", clearAll: "Borrar todo", applyFilters: "Aplicar Filtros", - + // Condition options conditions: { - new: "Nuevo", - likeNew: "Como Nuevo", - good: "Bueno", - fair: "Regular" + new: "Nuevo", + likeNew: "Como Nuevo", + good: "Bueno", + fair: "Regular", }, categories: { electronics: "Electrónica", clothing: "Ropa", homeAndGarden: "Hogar y Jardín", - sports: "Deportes y Aire Libre" - } - } + sports: "Deportes y Aire Libre", + }, + }, // Add more sections as needed };