Skip to content

Instantly share code, notes, and snippets.

@joydeep-bhowmik
Last active May 13, 2024 09:39
Show Gist options
  • Save joydeep-bhowmik/11c35efcfe671d0fab8d28d9579ab1b2 to your computer and use it in GitHub Desktop.
Save joydeep-bhowmik/11c35efcfe671d0fab8d28d9579ab1b2 to your computer and use it in GitHub Desktop.
Laravel react datatabe component
import Section from "@/Components/Section";
import axios from "axios";
import { ReactNode, useState } from "react";
import DataTable from "react-data-table-component";
import { useQuery } from "react-query";
import { debounce } from "lodash";
import TextInput from "@/Components/TextInput";
import { useQueryClient } from "react-query";
import { $on } from "@/lib/utils";
type DataTable = {
searchable?: boolean;
columns: any;
remoteLink: string;
params?: [];
elements?: ReactNode;
};
// products.table
export default function Datatable({
searchable = false,
remoteLink = "",
columns,
params = [],
elements = null,
...props
}: DataTable) {
const [page, setPage] = useState(1);
const [key, setKey] = useState("");
const [perPage, setPerPage] = useState(1);
const queryClient = useQueryClient();
const fetchData = async () => {
try {
let response = await axios.post(remoteLink, {
page,
key,
perPage,
...params,
});
return response.data;
} catch (e) {
throw new Error(`An error occurred: ${(e as Error).message}`);
}
};
const { data, isLoading, isError, refetch, isFetching } = useQuery({
queryKey: [remoteLink, key, page, perPage, ...params],
queryFn: fetchData,
staleTime: Infinity,
});
const refresh = () => {
queryClient.invalidateQueries(remoteLink);
refetch();
};
$on("datatable-refresh", (event: CustomEvent) => {
const { id } = event.detail;
if (id == remoteLink) {
refresh();
}
});
const customSort = (rows: any, selector: any, direction: string) => {
return rows.sort((a: any, b: any) => {
// use the selector to resolve your field names by passing the sort comparators
const aField = selector(a).toLowerCase();
const bField = selector(b).toLowerCase();
let comparison = 0;
if (aField > bField) {
comparison = 1;
} else if (aField < bField) {
comparison = -1;
}
return direction === "desc" ? comparison * -1 : comparison;
});
};
return (
<div>
<div className="md:flex items-center flex-wrap gap-1">
{searchable && (
<TextInput
type="text"
onChange={debounce(
(e: any) => setKey(e.target.value),
500
)}
placeholder="Search"
className="!text-xs"
/>
)}
<div className="flex items-center gap-3 flex-wrap divide-x p-1 ">
<button
type="button"
onClick={refresh}
className={`bg p-1 rounded `}
disabled={isLoading || isFetching}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 24 24"
className={`w-5 h-5 ${
isFetching && "animate-spin"
}`}
>
<path d="M5.463 4.433A9.961 9.961 0 0112 2c5.523 0 10 4.477 10 10 0 2.136-.67 4.116-1.81 5.74L17 12h3A8 8 0 006.46 6.228l-.997-1.795zm13.074 15.134A9.961 9.961 0 0112 22C6.477 22 2 17.523 2 12c0-2.136.67-4.116 1.81-5.74L7 12H4a8 8 0 0013.54 5.772l.997 1.795z"></path>
</svg>
</button>
{elements}
</div>
</div>
<Section
className={`mt-1 ${
isLoading || isFetching || isError ? "!p-5" : "!p-0 "
}`}
childrenContainerClass="!p-0 !py-1"
>
{isError ? (
<div className="text-red-500 gap-2 flex items-center justify-center">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-5 h-5"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z"
/>
</svg>
Some error occurred!
</div>
) : (
<DataTable
{...props}
columns={columns}
data={data && data.data}
onChangePage={(page) => {
setPage(page);
}}
pagination
paginationServer
paginationPerPage={1}
paginationRowsPerPageOptions={[1, 25, 50, 100]}
paginationTotalRows={data && data.total}
progressPending={isLoading || isFetching}
onChangeRowsPerPage={(number) => setPerPage(number)}
progressComponent={<CustomLoader />}
sortFunction={customSort}
/>
)}
</Section>
</div>
);
}
function CustomLoader() {
return (
<div role="status ">
<svg
aria-hidden="true"
className="w-8 h-8 text-slate-200 animate-spin dark:text-slate-600 fill-[--primary]"
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor"
/>
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill"
/>
</svg>
<span className="sr-only">Loading...</span>
</div>
);
}
export function truncate(str: string, num: number): string {
if (str.length > num) {
return str.slice(0, num) + "...";
} else {
return str;
}
}
export function $on(EventName: string, callback: CallableFunction) {
document.addEventListener(EventName, (e) => callback(e));
}
export function $dispatch(EventName: string, data: any) {
const event = new CustomEvent(EventName, {
detail: data,
});
return document.dispatchEvent(event);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment