# Page Reference ## File Location `apps/dashboard/app/(authenticated)/
//page.tsx` Where `
` is the navigation section (e.g. `sales`, `inventory`, `hr`) and `` is the resource in kebab-case plural. ## Complete Template (ResourcePage Pattern) ```tsx "use client" import { ResourcePage } from '@/shared/data-view/resource-page' import { ColumnHeader } from '@/shared/data-view/table-view' import { Form } from '@/modules//-form' import { _ROUTES } from '@repo/api' import type { Client } from '@repo/api' export default function Page() { return ( Client> pageTitle="" title="" routeKey={_ROUTES.INDEX} getClient={(api) => api.} columns={({ actionsColumn }) => [ { accessorKey: "", header: ({ column }) => , }, { accessorKey: "", header: ({ column }) => , }, // Add more columns as needed... actionsColumn(), ]} renderForm={({ resourceId, initialData, onSuccess }) => ( <Form resourceId={resourceId} initialData={initialData} onSuccess={onSuccess} /> )} /> ) } ``` ## ResourcePage Props | Prop | Required | Description | |---|---|---| | `pageTitle` | No | Page heading text (e.g. "Customers") | | `title` | Yes | Singular noun for button/dialog (e.g. "Customer" → "Add Customer") | | `routeKey` | Yes | React Query cache key, use `ROUTES.INDEX` | | `getClient` | Yes | Selects the domain client from the authenticated API | | `columns` | Yes | Column definitions — use callback form to get `actionsColumn` helper | | `renderForm` | Yes | Renders the form component inside the dialog | | `queryOptions` | No | React Query overrides (`staleTime`, etc.) | ## Column Patterns ### Simple text column (sortable) ```tsx { accessorKey: "name", header: ({ column }) => , }, ``` ### Custom cell renderer ```tsx { accessorKey: "status", header: ({ column }) => , cell: ({ row }) => ( {row.original.status} ), }, ``` ### Column with icon ```tsx { accessorKey: "name", header: ({ column }) => , cell: ({ row }) => (
{row.original.name}
), }, ``` ### Non-sortable column ```tsx { accessorKey: "notes", header: () => Notes, enableSorting: false, }, ``` ### Actions column (always last) ```tsx actionsColumn(), ``` ## Real Example: Customers Page ```tsx "use client" import { ResourcePage } from '@/shared/data-view/resource-page' import { ColumnHeader } from '@/shared/data-view/table-view' import { CustomerForm } from '@/modules/customers/customer-form' import { CUSTOMER_ROUTES } from '@repo/api' import type { CustomersClient } from '@repo/api' import { Building2Icon, UserIcon } from 'lucide-react' export default function CustomersPage() { return ( pageTitle='Customers' title="Customer" routeKey={CUSTOMER_ROUTES.INDEX} getClient={(api) => api.customers} columns={({ actionsColumn }) => [ { accessorKey: "first_name", header: ({ column }) => , cell: ({ row }) => { const customerName = row.original.first_name const isCompany = row.original.customer_type?.name?.toLocaleLowerCase() === "company"; const companyName = row.original.company_name const name = isCompany && companyName ? `${customerName} (${row.original.last_name})` : customerName return (
{isCompany ? : } {name}
) }, }, { accessorKey: "email", header: ({ column }) => , }, { accessorKey: "phone", header: ({ column }) => , }, actionsColumn(), ]} renderForm={({ resourceId, initialData, onSuccess }) => ( )} /> ) } ``` ## Alternative: Manual DataTable Pattern (Read-Only or Custom Layout) Use only when you don't need create/edit/delete in a dialog: ```tsx "use client" import { DashboardHeader } from '@/base/components/layout/dashboard' import DashboardPage from '@/base/components/layout/dashboard/dashboard-page' import { ColumnHeader, DataTable, useDataTableQuery } from '@/shared/data-view/table-view' import { useAuthApi } from '@/shared/useApi' import { _ROUTES } from '@repo/api' import type { ColumnDef } from '@tanstack/react-table' const columns: ColumnDef[] = [ { accessorKey: "name", header: ({ column }) => , }, // ... more columns ] export default function Page() { const api = useAuthApi() const { data, isLoading, pagination, sorting, handleChange } = useDataTableQuery({ queryKey: [_ROUTES.INDEX], client: api., }) const response = data as any return ( }> ) } ```