updates
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
"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
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
export { useResourcePage } from "./use-resource-page"
|
||||
export { ResourcePage } from "./resource-page"
|
||||
export { CrudResource } from "./crud-resource"
|
||||
|
||||
export type {
|
||||
ResourcePageClient,
|
||||
@@ -14,3 +15,9 @@ export type {
|
||||
ResourcePageContext,
|
||||
ResourcePageProps,
|
||||
} from "./resource-page"
|
||||
|
||||
export type {
|
||||
CrudResourceColumnHelpers,
|
||||
CrudResourceContext,
|
||||
CrudResourceProps,
|
||||
} from "./crud-resource"
|
||||
|
||||
@@ -4,9 +4,12 @@ import React from "react"
|
||||
import DashboardPage from "@/base/components/layout/dashboard/dashboard-page"
|
||||
import type { DashboardHeaderProps } from "@/base/components/layout/dashboard"
|
||||
import { Card, CardContent } from "@/shared/components/ui/card"
|
||||
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"
|
||||
import type { ResourcePageClient, ResourceItem } from "./use-resource-page"
|
||||
import { CrudResource, type CrudResourceContext, type CrudResourceColumnHelpers, type CrudResourceProps } from "./crud-resource"
|
||||
|
||||
// Re-exported for backward compatibility
|
||||
export type ResourcePageColumnHelpers<TClient extends ResourcePageClient> = CrudResourceColumnHelpers<TClient>
|
||||
export type ResourcePageContext<TClient extends ResourcePageClient> = CrudResourceContext<TClient>
|
||||
|
||||
export type ResourceFormProps<TClient extends ResourcePageClient> = {
|
||||
resourceId: string | null
|
||||
@@ -19,114 +22,47 @@ export type ResourcePageHeaderHelpers<TClient extends ResourcePageClient> = {
|
||||
invalidateQuery: () => void
|
||||
}
|
||||
|
||||
export type ResourcePageColumnHelpers<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 ResourcePageContext<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: ResourcePageContext<TClient>) => React.ReactNode)
|
||||
|
||||
export type ResourcePageProps<TClient extends ResourcePageClient> = UseResourcePageOptions<TClient> & {
|
||||
columns: ColumnDef<ResourceItem<TClient>>[] | ((helpers: ResourcePageColumnHelpers<TClient>) => ColumnDef<ResourceItem<TClient>>[])
|
||||
export type ResourcePageProps<TClient extends ResourcePageClient> = Omit<CrudResourceProps<TClient>, "render"> & {
|
||||
headerProps?: DashboardHeaderProps | ((helpers: ResourcePageHeaderHelpers<TClient>) => DashboardHeaderProps)
|
||||
header?: ReactNodeOrRender<TClient> | null
|
||||
pageTitle?: string
|
||||
paramKey?: string
|
||||
onRowClick?: (row: ResourceItem<TClient>) => void
|
||||
toolbar?: ReactNodeOrRender<TClient>
|
||||
tableHeader?: ReactNodeOrRender<TClient>
|
||||
|
||||
}
|
||||
|
||||
export function ResourcePage<TClient extends ResourcePageClient>({
|
||||
columns: columnsProp,
|
||||
headerProps: headerPropsProp,
|
||||
header,
|
||||
pageTitle,
|
||||
routeKey,
|
||||
getClient,
|
||||
queryOptions,
|
||||
paramKey,
|
||||
onRowClick,
|
||||
toolbar,
|
||||
tableHeader,
|
||||
extraParams,
|
||||
...crudResourceProps
|
||||
}: ResourcePageProps<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: ResourcePageContext<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 resolvedHeaderProps = typeof headerPropsProp === "function"
|
||||
? headerPropsProp({
|
||||
selectedItem: page.selectedItem,
|
||||
invalidateQuery: () => page.invalidateQuery(),
|
||||
})
|
||||
: headerPropsProp
|
||||
|
||||
const resolvedHeader = typeof header === "function" ? header(context) : header
|
||||
const resolvedToolbar = typeof toolbar === "function" ? toolbar(context) : toolbar
|
||||
|
||||
return (
|
||||
<DashboardPage
|
||||
header={resolvedHeader}
|
||||
headerProps={resolvedHeaderProps}
|
||||
title={pageTitle}
|
||||
toolbar={resolvedToolbar}
|
||||
>
|
||||
<Card>
|
||||
<CardContent className="space-y-4">
|
||||
{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}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</DashboardPage>
|
||||
<CrudResource<TClient>
|
||||
{...crudResourceProps}
|
||||
render={(table, context) => {
|
||||
const resolvedHeaderProps = typeof headerPropsProp === "function"
|
||||
? headerPropsProp({
|
||||
selectedItem: context.selectedItem,
|
||||
invalidateQuery: context.invalidateQuery,
|
||||
})
|
||||
: headerPropsProp
|
||||
|
||||
const resolvedHeader = typeof header === "function" ? header(context) : header
|
||||
|
||||
return (
|
||||
<DashboardPage
|
||||
header={resolvedHeader}
|
||||
headerProps={resolvedHeaderProps}
|
||||
fullscreen
|
||||
>
|
||||
<Card className="rounded-none">
|
||||
<CardContent className="space-y-4">
|
||||
{table}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</DashboardPage>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user