Skip to content

Instantly share code, notes, and snippets.

@bkanhu
Created June 10, 2025 19:00
Show Gist options
  • Save bkanhu/fba1a4be5457c763333639a4a20ee710 to your computer and use it in GitHub Desktop.
Save bkanhu/fba1a4be5457c763333639a4a20ee710 to your computer and use it in GitHub Desktop.
NextJS Filter component with SearchParams and Custom Hooks.
"use client";
import { useRouter, useSearchParams } from "next/navigation";
import React from "react";
const FilterPanel = () => {
const router = useRouter();
const searchParams = useSearchParams();
const handleFilterChange = (e) => {
const params = new URLSearchParams(searchParams.toString());
const { name, value } = e.target;
if (value) {
params.set(name, value);
} else {
params.delete(name);
}
// Reset pagination when filter changes
params.delete("page");
router.replace(`?${params.toString()}`);
};
return (
<div>
<div>
<select
name="orderStatus"
id="orderStatus"
value={searchParams.get("orderStatus") || ""}
onChange={handleFilterChange}
>
<option value="">Choose a status</option>
<option value="initiated">Initiated</option>
<option value="in progress">In Progress</option>
<option value="shipped">Shipped</option>
<option value="delivered">Delivered</option>
<option value="completed">Completed</option>
</select>
</div>
<div>
<label htmlFor="startDate">Start Date</label>
<input
type="date"
name="startDate"
id="startDate"
value={searchParams.get("startDate") || ""}
onChange={handleFilterChange}
/>
</div>
<div>
<label htmlFor="endDate">End Date</label>
<input
type="date"
name="endDate"
id="endDate"
value={searchParams.get("endDate") || ""}
onChange={handleFilterChange}
/>
</div>
</div>
);
};
export default FilterPanel;
import React from "react";
import FilterPanel from "./FilterPanel";
import ProductSection from "./ProductSection";
const FilterPage = () => {
return (
<div>
<h1>FilterPage</h1>
<FilterPanel />
<ProductSection />
</div>
);
};
export default FilterPage;
"use client";
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination";
import { useRouter, useSearchParams } from "next/navigation";
const ProductSection = () => {
return (
<div>
ProductSection
<OrderPagination totalPages={10} />
</div>
);
};
const OrderPagination = ({ totalPages }) => {
const router = useRouter();
const searchParams = useSearchParams();
const currentPage = parseInt(searchParams.get("page") || "1", 10);
const goToPage = (page) => {
const params = new URLSearchParams(searchParams.toString());
params.set("page", String(page));
router.replace(`?${params.toString()}`);
};
return (
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious
onClick={() => {
if (currentPage > 1) goToPage(currentPage - 1);
}}
className={
currentPage === 1 ? "pointer-events-none opacity-50" : ""
}
/>
</PaginationItem>
<PaginationItem>
<span className="rounded border border-input bg-muted px-3 py-1 text-sm">
Page {currentPage} of {totalPages}
</span>
</PaginationItem>
<PaginationItem>
<PaginationNext
onClick={() => {
if (currentPage < totalPages) goToPage(currentPage + 1);
}}
className={
currentPage === totalPages ? "pointer-events-none opacity-50" : ""
}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
);
};
export default ProductSection;
"use client";
import { useSearchParams } from "next/navigation";
// Custom hook to get orderStatus, startDate, endDate, and page from URL.
const useOrderQueryParams = () => {
const searchParams = useSearchParams();
const orderStatus = searchParams.get("orderStatus") || "";
const startDate = searchParams.get("startDate") || "";
const endDate = searchParams.get("endDate") || "";
const page = parseInt(searchParams.get("page") || "1", 10);
return { orderStatus, startDate, endDate, page };
};
export default useOrderQueryParams;
"use client";
import { useEffect, useState } from "react";
import { useOrderQueryParams } from "./useOrderQueryParams";
export const useOrders = () => {
const { orderStatus, startDate, endDate, page } = useOrderQueryParams();
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
const fetchOrders = async () => {
setIsLoading(true);
setError(null);
try {
const params = new URLSearchParams();
if (orderStatus) params.set("orderStatus", orderStatus);
if (startDate) params.set("startDate", startDate);
if (endDate) params.set("endDate", endDate);
params.set("page", page.toString());
const res = await fetch(`/api/orders?${params.toString()}`, {
signal: controller.signal,
});
if (!res.ok) throw new Error("Failed to fetch orders");
const json = await res.json();
setData(json);
} catch (err) {
if (err.name !== "AbortError") {
setError(err.message || "Unknown error");
}
} finally {
setIsLoading(false);
}
};
fetchOrders();
return () => controller.abort();
}, [orderStatus, startDate, endDate, page]);
return { data, isLoading, error };
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment