feat: filters, search and sorting is working as expected

This commit is contained in:
Pablo Lara
2024-09-05 13:12:20 +02:00
parent ac93672752
commit bb32af93b2
5 changed files with 60 additions and 21 deletions
+5 -3
View File
@@ -26,11 +26,13 @@ export const getProvider = async ({
// Handle multiple filters
Object.entries(filters).forEach(([key, value]) => {
url.searchParams.append(key, String(value));
if (key !== "filter[search]") {
url.searchParams.append(key, String(value));
}
});
console.log({ query });
try {
const providers = await fetch(`${url.toString()}`, {
const providers = await fetch(url.toString(), {
headers: {
"X-Tenant-ID": `${tenantId}`,
},
+7 -9
View File
@@ -1,5 +1,4 @@
import { Spacer } from "@nextui-org/react";
import { redirect } from "next/navigation";
import { Suspense } from "react";
import { getProvider } from "@/actions";
@@ -41,25 +40,24 @@ const SSRDataTable = async ({
}: {
searchParams: SearchParamsProps;
}) => {
const query = searchParams?.query || "";
const page = searchParams?.page || "1";
const sort = searchParams?.sort || "";
const page = parseInt(searchParams.page?.toString() || "1", 10);
const sort = searchParams.sort?.toString() || "";
// Extract all filter parameters
const filters = Object.fromEntries(
Object.entries(searchParams).filter(([key]) => key.startsWith("filter[")),
);
const providersData = await getProvider({ query, page, sort, filters });
const [providers] = await Promise.all([providersData]);
// Extract query from filters
const query = (filters["filter[search]"] as string) || "";
if (providers?.errors) redirect("/providers");
const providersData = await getProvider({ query, page, sort, filters });
return (
<DataTableProvider
columns={ColumnsProvider}
data={providers?.data ?? []}
metadata={providers?.meta}
data={providersData.data}
metadata={providersData.meta}
/>
);
};
@@ -27,7 +27,8 @@ export const DataTableColumnHeader = <TData, TValue>({
const searchParams = useSearchParams();
const getToggleSortingHandler = () => {
const currentSortParam = searchParams.get("sort");
const currentParams = new URLSearchParams(searchParams.toString());
const currentSortParam = currentParams.get("sort");
let newSortParam = "";
if (currentSortParam === `${param}`) {
@@ -41,13 +42,21 @@ export const DataTableColumnHeader = <TData, TValue>({
newSortParam = `${param}`;
}
// Construct the new URL with the sorting parameter
const newUrl = newSortParam ? `${pathname}?sort=${newSortParam}` : pathname;
// Update or remove the sort parameter
if (newSortParam) {
currentParams.set("sort", newSortParam);
} else {
currentParams.delete("sort");
}
// Construct the new URL with all parameters
const newUrl = `${pathname}?${currentParams.toString()}`;
router.push(newUrl, {
scroll: false,
});
};
const renderSortIcon = () => {
const currentSortParam = searchParams.get("sort");
if (
@@ -1,4 +1,5 @@
import { Button, Input } from "@nextui-org/react";
import { XCircle } from "lucide-react"; // Import the clear icon
import { useRouter, useSearchParams } from "next/navigation";
import { useCallback, useEffect, useMemo, useState } from "react";
@@ -11,7 +12,10 @@ interface FilterColumnTableProps {
export function FilterColumnTable({ filters }: FilterColumnTableProps) {
const router = useRouter();
const searchParams = useSearchParams();
const [searchQuery, setSearchQuery] = useState("");
const [searchQuery, setSearchQuery] = useState(() => {
// Initialize searchQuery with the current search filter value from URL
return searchParams.get("filter[search]") || "";
});
const debouncedSearchQuery = useDebounce(searchQuery, 300);
const activeFilters = useMemo(() => {
@@ -54,19 +58,29 @@ export function FilterColumnTable({ filters }: FilterColumnTableProps) {
} else {
params.delete("filter[search]");
}
console.log(params.toString(), "en el apply search");
router.push(`?${params.toString()}`, { scroll: false });
router.replace(`?${params.toString()}`, { scroll: false });
},
[router, searchParams],
);
const clearAllFilters = useCallback(() => {
const params = new URLSearchParams();
router.push(`?${params.toString()}`, { scroll: false });
setSearchQuery(""); // Clear the search input
}, [router]);
const clearIconSearch = () => {
setSearchQuery("");
applySearch("");
};
useEffect(() => {
applySearch(debouncedSearchQuery);
}, [debouncedSearchQuery, applySearch]);
return (
<div className="flex flex-col md:flex-row justify-between space-y-4 w-full items-center">
<div className="w-full md:w-1/3">
<div className="w-full md:w-1/3 flex space-x-2">
<Input
placeholder="Search..."
value={searchQuery}
@@ -76,9 +90,16 @@ export function FilterColumnTable({ filters }: FilterColumnTableProps) {
applySearch(searchQuery);
}
}}
endContent={
searchQuery && (
<button onClick={clearIconSearch} className="focus:outline-none">
<XCircle className="h-4 w-4 text-default-400" />
</button>
)
}
/>
</div>
<div className="flex items-center space-x-2">
<div className="flex items-center space-x-2 flex-wrap">
{filters.flatMap(({ key, values }) =>
values.map((value) => (
<Button
@@ -86,11 +107,20 @@ export function FilterColumnTable({ filters }: FilterColumnTableProps) {
onClick={() => applyFilter(key, value)}
// eslint-disable-next-line security/detect-object-injection
variant={activeFilters[key] === value ? "faded" : "light"}
size="sm"
>
{value || "All"}
</Button>
)),
)}
<Button
onClick={clearAllFilters}
variant="flat"
color="default"
size="sm"
>
Clear Filters
</Button>
</div>
</div>
);
+1 -1
View File
@@ -4,7 +4,7 @@ export function useDebounce<T>(value: T, delay?: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value);
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay ?? 800);
const timer = setTimeout(() => setDebouncedValue(value), delay ?? 900);
return () => {
clearTimeout(timer);