feat: useDataTable 훅 생성
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { type UseQueryResult } from "@tanstack/react-query";
|
||||
import type { PageableList } from "../model";
|
||||
|
||||
/**
|
||||
* Match the state of a query to a set of components.
|
||||
*
|
||||
* Useful for rendering different UI based on the state of a query.
|
||||
*/
|
||||
export function matchQueryStatus<T>(
|
||||
query: UseQueryResult<PageableList<T>>,
|
||||
options: {
|
||||
Loading?: JSX.Element;
|
||||
Errored?: JSX.Element | ((error: unknown) => JSX.Element);
|
||||
Empty?: JSX.Element;
|
||||
Success: (
|
||||
data: UseQueryResult<PageableList<T>> & {
|
||||
data: NonNullable<UseQueryResult<T>["data"]>;
|
||||
},
|
||||
) => JSX.Element;
|
||||
},
|
||||
): JSX.Element;
|
||||
export function matchQueryStatus<T>(
|
||||
query: UseQueryResult<PageableList<T>>,
|
||||
options: {
|
||||
Loading?: JSX.Element;
|
||||
Errored?: JSX.Element | ((error: unknown) => JSX.Element);
|
||||
Success: (data: UseQueryResult<PageableList<T>>) => JSX.Element;
|
||||
},
|
||||
): JSX.Element;
|
||||
export function matchQueryStatus<T>(
|
||||
query: UseQueryResult<PageableList<T>>,
|
||||
{
|
||||
Loading,
|
||||
Errored,
|
||||
Empty,
|
||||
Success,
|
||||
}: {
|
||||
Loading?: JSX.Element;
|
||||
Errored?: JSX.Element | ((error: unknown) => JSX.Element);
|
||||
Empty?: JSX.Element;
|
||||
Success: (data: UseQueryResult<PageableList<T>>) => JSX.Element;
|
||||
},
|
||||
): JSX.Element {
|
||||
if (query.isLoading && Loading) {
|
||||
return Loading;
|
||||
}
|
||||
|
||||
if (query.isError && Errored) {
|
||||
if (typeof Errored === "function") {
|
||||
return Errored(query.error);
|
||||
}
|
||||
return Errored;
|
||||
}
|
||||
|
||||
const isEmpty =
|
||||
query.data?.content === undefined ||
|
||||
query.data?.content === null ||
|
||||
(Array.isArray(query.data?.content) && query.data?.content.length === 0);
|
||||
|
||||
if (isEmpty && Empty) {
|
||||
return Empty;
|
||||
}
|
||||
|
||||
return Success(query);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { HTMLAttributes } from "react";
|
||||
import type { UseQueryResult } from "@tanstack/react-query";
|
||||
import { useReactTable, type TableOptions } from "@tanstack/react-table";
|
||||
import { DataTable } from "@common/components";
|
||||
import { NoData } from "../ui/no-data";
|
||||
import type { PageableList } from "../model";
|
||||
import { matchQueryStatus } from "./match-query-status";
|
||||
|
||||
type DataTableOptions<T> = {
|
||||
variant?: "default" | "secondary" | "line";
|
||||
className?: HTMLAttributes<HTMLTableElement>["className"];
|
||||
viewPagination?: boolean;
|
||||
onRowClick?: (row: T) => void;
|
||||
};
|
||||
|
||||
export const useDataTable = <T,>(
|
||||
query: UseQueryResult<PageableList<T>>,
|
||||
tableOptions: Omit<TableOptions<T>, "data" | "rowCount">,
|
||||
dataTableOptions?: DataTableOptions<T>,
|
||||
) => {
|
||||
const table = useReactTable({
|
||||
...tableOptions,
|
||||
data: query.data?.content ?? [],
|
||||
rowCount: query.data?.totalElements ?? 0,
|
||||
});
|
||||
|
||||
return matchQueryStatus(query, {
|
||||
Empty: <NoData />,
|
||||
Success: () => {
|
||||
return <DataTable table={table} {...dataTableOptions} />;
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
import { cn } from "@common/components";
|
||||
|
||||
function NoData({ className }: { className?: string }) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-96 flex-col items-center justify-center gap-4",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<i className="diveicon di-info-circle text-3xl" />
|
||||
조회된 데이터가 없습니다.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { NoData };
|
||||
Reference in New Issue
Block a user