feat: implement debounced input search functionality and clean up TableList component
This commit is contained in:
parent
af41495643
commit
06387116f7
|
|
@ -10,11 +10,10 @@ import {
|
||||||
SortingState,
|
SortingState,
|
||||||
useReactTable,
|
useReactTable,
|
||||||
} from "@tanstack/react-table";
|
} from "@tanstack/react-table";
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Button, Label, Table } from "flowbite-react";
|
import { Button, Label, Table } from "flowbite-react";
|
||||||
import { HiChevronLeft, HiChevronRight, HiPlus } from "react-icons/hi";
|
import { HiChevronLeft, HiChevronRight, HiPlus } from "react-icons/hi";
|
||||||
import { useLocal } from "@/lib/utils/use-local";
|
import { useLocal } from "@/lib/utils/use-local";
|
||||||
import { debouncedHandler } from "@/lib/utils/debounceHandler";
|
|
||||||
import { FaSort, FaSortDown, FaSortUp } from "react-icons/fa6";
|
import { FaSort, FaSortDown, FaSortUp } from "react-icons/fa6";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { init_column } from "./lib/column";
|
import { init_column } from "./lib/column";
|
||||||
|
|
@ -196,7 +195,6 @@ export const TableList = <T extends object>({
|
||||||
{"Loading..."}
|
{"Loading..."}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
console.log(local.fieldResultFilter);
|
|
||||||
if (typeof onCount === "function") {
|
if (typeof onCount === "function") {
|
||||||
const params = await events("onload-param", {
|
const params = await events("onload-param", {
|
||||||
take: 1,
|
take: 1,
|
||||||
|
|
@ -273,6 +271,8 @@ export const TableList = <T extends object>({
|
||||||
sort: local.sort,
|
sort: local.sort,
|
||||||
take,
|
take,
|
||||||
paging: local.paging,
|
paging: local.paging,
|
||||||
|
...local.filter,
|
||||||
|
...local.fieldResultFilter,
|
||||||
});
|
});
|
||||||
if (!autoPagination) {
|
if (!autoPagination) {
|
||||||
res = paginateArray(res, take, local.paging);
|
res = paginateArray(res, take, local.paging);
|
||||||
|
|
@ -360,6 +360,7 @@ export const TableList = <T extends object>({
|
||||||
paging: 1,
|
paging: 1,
|
||||||
search: local.search,
|
search: local.search,
|
||||||
...local.filter,
|
...local.filter,
|
||||||
|
...local.fieldResultFilter,
|
||||||
});
|
});
|
||||||
const res = await onCount(params);
|
const res = await onCount(params);
|
||||||
local.count = res;
|
local.count = res;
|
||||||
|
|
@ -383,6 +384,8 @@ export const TableList = <T extends object>({
|
||||||
sort: local.sort,
|
sort: local.sort,
|
||||||
take,
|
take,
|
||||||
paging: 1,
|
paging: 1,
|
||||||
|
...local.filter,
|
||||||
|
...local.fieldResultFilter,
|
||||||
});
|
});
|
||||||
if (!autoPagination) {
|
if (!autoPagination) {
|
||||||
res = paginateArray(res, take, 1);
|
res = paginateArray(res, take, 1);
|
||||||
|
|
@ -552,12 +555,6 @@ export const TableList = <T extends object>({
|
||||||
onStateChange: setState,
|
onStateChange: setState,
|
||||||
debugTable: state.pagination.pageIndex > 2,
|
debugTable: state.pagination.pageIndex > 2,
|
||||||
}));
|
}));
|
||||||
const handleSearch = useCallback(
|
|
||||||
debouncedHandler(() => {
|
|
||||||
local.refresh();
|
|
||||||
}, 1000),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="tbl-wrapper flex flex-grow flex-col">
|
<div className="tbl-wrapper flex flex-grow flex-col">
|
||||||
|
|
@ -586,7 +583,7 @@ export const TableList = <T extends object>({
|
||||||
|
|
||||||
<div className="ml-auto flex items-center flex-row gap-x-1">
|
<div className="ml-auto flex items-center flex-row gap-x-1">
|
||||||
<div className="tbl-search hidden items-center sm:mb-0 sm:flex sm:divide-x sm:divide-gray-100">
|
<div className="tbl-search hidden items-center sm:mb-0 sm:flex sm:divide-x sm:divide-gray-100">
|
||||||
<form
|
<div
|
||||||
onSubmit={async (e) => {
|
onSubmit={async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await local.reload();
|
await local.reload();
|
||||||
|
|
@ -597,19 +594,19 @@ export const TableList = <T extends object>({
|
||||||
</Label>
|
</Label>
|
||||||
<div className="relative lg:w-56">
|
<div className="relative lg:w-56">
|
||||||
<InputSearch
|
<InputSearch
|
||||||
// className="bg-white search text-xs "
|
|
||||||
id="users-search"
|
id="users-search"
|
||||||
|
delay={1000}
|
||||||
name="users-search"
|
name="users-search"
|
||||||
placeholder={`Search`}
|
placeholder={`Search`}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const value = e.target.value;
|
const value = e.target.value;
|
||||||
local.search = value;
|
local.search = value;
|
||||||
local.render();
|
local.render();
|
||||||
handleSearch();
|
local.refresh();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{mode === "table" && filter && local?.fieldFilter?.length ? (
|
{mode === "table" && filter && local?.fieldFilter?.length ? (
|
||||||
<div className="flex flex-row items-center">
|
<div className="flex flex-row items-center">
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,48 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { HiSearch } from "react-icons/hi";
|
import { HiSearch } from "react-icons/hi";
|
||||||
|
import debounce from "lodash.debounce";
|
||||||
|
|
||||||
|
interface InputSearchProps extends React.ComponentProps<"input"> {
|
||||||
|
delay?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InputSearch = React.forwardRef<HTMLInputElement, InputSearchProps>(
|
||||||
|
({ className, type, onChange, delay = 100, ...props }, ref) => {
|
||||||
|
const debouncedLoadOptions = React.useMemo(
|
||||||
|
() =>
|
||||||
|
debounce((event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
if (onChange) onChange(event);
|
||||||
|
}, delay),
|
||||||
|
[delay, onChange]
|
||||||
|
);
|
||||||
|
|
||||||
const InputSearch = React.forwardRef<
|
|
||||||
HTMLInputElement,
|
|
||||||
React.ComponentProps<"input">
|
|
||||||
>(({ className, type, ...props }, ref) => {
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-row relative">
|
<div className="flex flex-row relative">
|
||||||
<HiSearch
|
<HiSearch className="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-500" />
|
||||||
className={cx(
|
|
||||||
"absolute",
|
|
||||||
css`
|
|
||||||
top: 50%;
|
|
||||||
left: 17px;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
className={cn(
|
className={cn(
|
||||||
"px-3 py-2 flex h-9 w-full rounded-md border border-gray-300 border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
"px-3 py-2 flex h-9 w-full rounded-md border border-gray-300 bg-transparent text-base shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||||
className,
|
className,
|
||||||
css`
|
"pl-10"
|
||||||
padding-left: 30px;
|
|
||||||
`
|
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
onChange={debouncedLoadOptions}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
if (event.key === "Enter" && onChange) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault(); // Mencegah submit form default jika ada
|
||||||
|
onChange(event as any); // Panggil `onChange` langsung saat Enter ditekan
|
||||||
|
}
|
||||||
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
InputSearch.displayName = "Input";
|
);
|
||||||
|
|
||||||
|
InputSearch.displayName = "InputSearch";
|
||||||
|
|
||||||
export { InputSearch };
|
export { InputSearch };
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue