diff --git a/apps/cs/src/shared/lib/match-query-status.ts b/apps/cs/src/shared/lib/match-query-status.ts new file mode 100644 index 000000000..0e5f45829 --- /dev/null +++ b/apps/cs/src/shared/lib/match-query-status.ts @@ -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( + query: UseQueryResult>, + options: { + Loading?: JSX.Element; + Errored?: JSX.Element | ((error: unknown) => JSX.Element); + Empty?: JSX.Element; + Success: ( + data: UseQueryResult> & { + data: NonNullable["data"]>; + }, + ) => JSX.Element; + }, +): JSX.Element; +export function matchQueryStatus( + query: UseQueryResult>, + options: { + Loading?: JSX.Element; + Errored?: JSX.Element | ((error: unknown) => JSX.Element); + Success: (data: UseQueryResult>) => JSX.Element; + }, +): JSX.Element; +export function matchQueryStatus( + query: UseQueryResult>, + { + Loading, + Errored, + Empty, + Success, + }: { + Loading?: JSX.Element; + Errored?: JSX.Element | ((error: unknown) => JSX.Element); + Empty?: JSX.Element; + Success: (data: UseQueryResult>) => 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); +} diff --git a/apps/cs/src/shared/lib/use-data-table.tsx b/apps/cs/src/shared/lib/use-data-table.tsx new file mode 100644 index 000000000..b80040423 --- /dev/null +++ b/apps/cs/src/shared/lib/use-data-table.tsx @@ -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 = { + variant?: "default" | "secondary" | "line"; + className?: HTMLAttributes["className"]; + viewPagination?: boolean; + onRowClick?: (row: T) => void; +}; + +export const useDataTable = ( + query: UseQueryResult>, + tableOptions: Omit, "data" | "rowCount">, + dataTableOptions?: DataTableOptions, +) => { + const table = useReactTable({ + ...tableOptions, + data: query.data?.content ?? [], + rowCount: query.data?.totalElements ?? 0, + }); + + return matchQueryStatus(query, { + Empty: , + Success: () => { + return ; + }, + }); +}; diff --git a/apps/cs/src/shared/ui/no-data.tsx b/apps/cs/src/shared/ui/no-data.tsx new file mode 100644 index 000000000..b13152dcf --- /dev/null +++ b/apps/cs/src/shared/ui/no-data.tsx @@ -0,0 +1,17 @@ +import { cn } from "@common/components"; + +function NoData({ className }: { className?: string }) { + return ( +
+ + 조회된 데이터가 없습니다. +
+ ); +} + +export { NoData };