feat: enhance DataTable with custom empty state support and update GrnClient to utilize it
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
import { useState, useEffect, useCallback, useMemo } from 'react'
|
import { useState, useEffect, useCallback, useMemo } from 'react'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { HugeiconsIcon } from '@hugeicons/react'
|
import { HugeiconsIcon } from '@hugeicons/react'
|
||||||
import { Add01Icon } from '@hugeicons/core-free-icons'
|
import { Add01Icon, PackageDeliveredIcon } from '@hugeicons/core-free-icons'
|
||||||
import { DataTable } from '@/components/shared/data-table'
|
import { DataTable } from '@/components/shared/data-table'
|
||||||
import type { TableConfig } from '@/components/shared/data-table'
|
import type { TableConfig } from '@/components/shared/data-table'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
@@ -11,6 +11,7 @@ import { toast } from '@/components/ui/toast'
|
|||||||
import { grn as grnApi, getApiError, getPaginatedItems } from '@/lib/api/index'
|
import { grn as grnApi, getApiError, getPaginatedItems } from '@/lib/api/index'
|
||||||
import type { GrnResponse } from '@/types/api'
|
import type { GrnResponse } from '@/types/api'
|
||||||
import { GrnViewSheet } from './grn-view-sheet'
|
import { GrnViewSheet } from './grn-view-sheet'
|
||||||
|
import { EmptyState } from '@/components/shared/empty-state'
|
||||||
|
|
||||||
const fmtDate = (v: string) =>
|
const fmtDate = (v: string) =>
|
||||||
new Date(v).toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' })
|
new Date(v).toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' })
|
||||||
@@ -53,7 +54,19 @@ export function GrnClient() {
|
|||||||
rowKey: 'id',
|
rowKey: 'id',
|
||||||
serverSide: true,
|
serverSide: true,
|
||||||
stickyHeader: true,
|
stickyHeader: true,
|
||||||
emptyMessage: 'No goods receipts found.',
|
emptyState: (
|
||||||
|
<EmptyState
|
||||||
|
icon={PackageDeliveredIcon}
|
||||||
|
title="No goods receipts yet"
|
||||||
|
description="GRNs appear here once goods are received against a purchase order or booked as a direct receipt."
|
||||||
|
action={
|
||||||
|
<Button size="sm" onClick={() => router.push('/procurement/grn/new')}>
|
||||||
|
<HugeiconsIcon icon={Add01Icon} size={14} />
|
||||||
|
New GRN
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
pagination: { enabled: true, pageSize, pageSizeOptions: [10, 20, 50] },
|
pagination: { enabled: true, pageSize, pageSizeOptions: [10, 20, 50] },
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -620,9 +620,11 @@ export function DataTable<T extends object>({
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{!loading && displayData.length === 0 && (
|
{!loading && displayData.length === 0 && (
|
||||||
<div className="h-32 flex items-center justify-center text-muted-foreground text-sm">
|
config.emptyState ?? (
|
||||||
{config.emptyMessage ?? 'No records found.'}
|
<div className="h-32 flex items-center justify-center text-muted-foreground text-sm">
|
||||||
</div>
|
{config.emptyMessage ?? 'No records found.'}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
{!loading && displayData.map(row => (
|
{!loading && displayData.map(row => (
|
||||||
<MobileCard
|
<MobileCard
|
||||||
@@ -710,9 +712,13 @@ export function DataTable<T extends object>({
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
colSpan={visibleColumns.length + (config.selectable ? 1 : 0) + (config.expandable ? 1 : 0)}
|
colSpan={visibleColumns.length + (config.selectable ? 1 : 0) + (config.expandable ? 1 : 0)}
|
||||||
className="h-32 text-center text-muted-foreground"
|
className="p-0"
|
||||||
>
|
>
|
||||||
{config.emptyMessage ?? 'No records found.'}
|
{config.emptyState ?? (
|
||||||
|
<div className="h-32 flex items-center justify-center text-muted-foreground text-sm">
|
||||||
|
{config.emptyMessage ?? 'No records found.'}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -119,6 +119,8 @@ export interface TableConfig<T = object> {
|
|||||||
exportable?: boolean | ExportConfig;
|
exportable?: boolean | ExportConfig;
|
||||||
density?: 'compact' | 'normal' | 'comfortable';
|
density?: 'compact' | 'normal' | 'comfortable';
|
||||||
emptyMessage?: string;
|
emptyMessage?: string;
|
||||||
|
/** Custom rendered empty state. Overrides emptyMessage when both are provided. */
|
||||||
|
emptyState?: React.ReactNode;
|
||||||
rowClass?: (row: T) => string;
|
rowClass?: (row: T) => string;
|
||||||
isRowSelectable?: (row: T) => boolean;
|
isRowSelectable?: (row: T) => boolean;
|
||||||
expandRender?: (row: T) => React.ReactNode;
|
expandRender?: (row: T) => React.ReactNode;
|
||||||
|
|||||||
Reference in New Issue
Block a user