Careeroza
Real World Example
A Filterable Listing Like Myntra
Myntra's listing page keeps brand, price, size and sort in the URL (/shoes?brand=nike,puma&sort=price_asc). The server renders results from the URL; checkboxes in the sidebar just change the URL. ShopEase builds the same thing:
// app/products/page.tsx (server)
import Filters from './Filters'; // 'use client' sidebar that updates the URL
import { searchProducts } from '@/lib/products';
import { parseFilters } from '@/lib/filters';
export default async function ProductsPage({
searchParams,
}: {
searchParams: Promise<Record<string, string | string[] | undefined>>;
}) {
const filters = parseFilters(await searchParams);
const { items, total } = await searchProducts(filters);
return (
<div className="grid md:grid-cols-[260px_1fr] gap-6">
<Filters />
<section>
<p>{total} results</p>
{items.map((p) => (
<div key={p.id}>{p.name}</div>
))}
</section>
</div>
);
}Toggling a Brand
Example
The sidebar helper that adds or removes one brand from the query string:
function toggleParam(query: string, key: string, value: string): string {
const params = new URLSearchParams(query);
const values = params.getAll(key);
params.delete(key);
const next = values.includes(value) ? values.filter((v) => v !== value) : [...values, value];
next.sort().forEach((v) => params.append(key, v));
params.delete('page');
const s = params.toString();
return s ? '?' + s : '';
}
let url = '?sort=price_asc&page=3';
for (const brand of ['puma', 'nike', 'puma']) {
url = toggleParam(url.slice(1), 'brand', brand);
console.log('toggle ' + brand.padEnd(5) + ' -> /products' + url);
}Output
toggle puma -> /products?sort=price_asc&brand=puma toggle nike -> /products?sort=price_asc&brand=nike&brand=puma toggle puma -> /products?sort=price_asc&brand=nike