96 lines
3.3 KiB
TypeScript
96 lines
3.3 KiB
TypeScript
"use client"
|
|
|
|
import React from "react"
|
|
import { DataTable, type ActionsColumnOptions } from "@/shared/data-view/table-view"
|
|
import { useResourcePage, type UseResourcePageOptions, type ResourceItem, type ResourcePageClient } from "./use-resource-page"
|
|
import type { ColumnDef } from "@tanstack/react-table"
|
|
|
|
export type CrudResourceColumnHelpers<TClient extends ResourcePageClient> = {
|
|
actionsColumn: (options?: Partial<ActionsColumnOptions<ResourceItem<TClient>>>) => ColumnDef<ResourceItem<TClient>, unknown>
|
|
openEdit: (row: ResourceItem<TClient>) => void
|
|
deleteItem: (id: string) => Promise<unknown>
|
|
}
|
|
|
|
export type CrudResourceContext<TClient extends ResourcePageClient> = {
|
|
selectedItem: ResourceItem<TClient> | null
|
|
isDialogOpen: boolean
|
|
dialogResourceId: string | null
|
|
isLoading: boolean
|
|
data: ResourceItem<TClient>[]
|
|
openCreate: () => void
|
|
openEdit: (row: ResourceItem<TClient>) => void
|
|
closeDialog: () => void
|
|
deleteItem: (id: string) => Promise<unknown>
|
|
invalidateQuery: () => void
|
|
}
|
|
|
|
type ReactNodeOrRender<TClient extends ResourcePageClient> =
|
|
| React.ReactNode
|
|
| ((context: CrudResourceContext<TClient>) => React.ReactNode)
|
|
|
|
export type CrudResourceProps<TClient extends ResourcePageClient> = UseResourcePageOptions<TClient> & {
|
|
columns: ColumnDef<ResourceItem<TClient>>[] | ((helpers: CrudResourceColumnHelpers<TClient>) => ColumnDef<ResourceItem<TClient>>[])
|
|
onRowClick?: (row: ResourceItem<TClient>) => void
|
|
tableHeader?: ReactNodeOrRender<TClient>
|
|
render?: (table: React.ReactElement, context: CrudResourceContext<TClient>) => React.ReactElement
|
|
}
|
|
|
|
export function CrudResource<TClient extends ResourcePageClient>({
|
|
columns: columnsProp,
|
|
routeKey,
|
|
getClient,
|
|
queryOptions,
|
|
paramKey,
|
|
extraParams,
|
|
onRowClick,
|
|
tableHeader,
|
|
render,
|
|
}: CrudResourceProps<TClient>) {
|
|
type TItem = ResourceItem<TClient>
|
|
|
|
const page = useResourcePage<TClient>({ routeKey, getClient, queryOptions, paramKey, extraParams })
|
|
|
|
const columns = typeof columnsProp === "function"
|
|
? columnsProp({
|
|
actionsColumn: page.actionsColumn,
|
|
openEdit: page.openEdit,
|
|
deleteItem: page.deleteItem,
|
|
})
|
|
: columnsProp
|
|
|
|
type ListResponse = { data?: TItem[] }
|
|
const responseData = page.data as ListResponse | undefined
|
|
const items = (responseData?.data ?? []) as TItem[]
|
|
|
|
const context: CrudResourceContext<TClient> = {
|
|
selectedItem: page.selectedItem,
|
|
isDialogOpen: page.isDialogOpen,
|
|
dialogResourceId: page.dialogResourceId,
|
|
isLoading: page.isLoading,
|
|
data: items,
|
|
openCreate: page.openCreate,
|
|
openEdit: page.openEdit,
|
|
closeDialog: page.closeDialog,
|
|
deleteItem: page.deleteItem,
|
|
invalidateQuery: () => page.invalidateQuery(),
|
|
}
|
|
|
|
const table = (
|
|
<>
|
|
{tableHeader && (typeof tableHeader === "function" ? tableHeader(context) : tableHeader)}
|
|
<DataTable
|
|
columns={columns}
|
|
data={items}
|
|
pagination={page.pagination}
|
|
sorting={page.sorting}
|
|
onChange={page.handleChange}
|
|
isLoading={page.isLoading}
|
|
onRowClick={onRowClick}
|
|
/>
|
|
</>
|
|
)
|
|
|
|
if (render) return render(table, context)
|
|
return table
|
|
}
|