feat: add EmptyState component for improved no-data display in supplier payments
CI/CD - ERP Distribution / Build & Deploy Backend (pull_request) Failing after 12m51s
CI/CD - ERP Distribution / Build & Deploy Frontend (pull_request) Failing after 16m39s

This commit is contained in:
Kalana B. Thilakarathna
2026-10-19 22:35:01 +05:30
parent 7b6c9ac92a
commit 992cd292fa
2 changed files with 74 additions and 22 deletions
@@ -31,6 +31,8 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
import { toast } from '@/components/ui/toast'
import { TopLoader } from '@/components/shared/top-loader'
import { EmptyState } from '@/components/shared/empty-state'
import { ReceiptDollarIcon } from '@hugeicons/core-free-icons'
function formatDate(value: string) {
return new Date(value).toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' })
@@ -84,24 +86,26 @@ export function SupplierPaymentsClient({ supplierId }: { supplierId: string }) {
</div>
<div className="rounded-md border mt-4">
<Table>
<TableHeader>
<TableRow>
<TableHead>Paid At</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
<TableHead>Cheque / Account</TableHead>
<TableHead className="text-right">GRNs</TableHead>
<TableHead>Notes</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{loading ? (
<TableRow><TableCell colSpan={6}>Loading…</TableCell></TableRow>
) : payments.length === 0 ? (
<TableRow><TableCell colSpan={6}>No payments yet.</TableCell></TableRow>
) : (
payments.map(p => (
{!loading && payments.length === 0 ? (
<EmptyState
icon={ReceiptDollarIcon}
title="No payments yet"
description="Record a payment to settle one or more GRNs for this supplier."
/>
) : (
<Table>
<TableHeader>
<TableRow>
<TableHead>Paid At</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
<TableHead>Cheque / Account</TableHead>
<TableHead className="text-right">GRNs</TableHead>
<TableHead>Notes</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{payments.map(p => (
<TableRow key={p.id}>
<TableCell>{formatDate(p.paidAt)}</TableCell>
<TableCell><Badge variant="secondary">{p.method}</Badge></TableCell>
@@ -112,10 +116,10 @@ export function SupplierPaymentsClient({ supplierId }: { supplierId: string }) {
<TableCell className="text-right">{p.allocations.length}</TableCell>
<TableCell className="text-sm text-muted-foreground">{p.notes ?? '—'}</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
))}
</TableBody>
</Table>
)}
</div>
<div className="flex items-center justify-between mt-3 text-sm">
@@ -0,0 +1,48 @@
'use client'
import { HugeiconsIcon } from '@hugeicons/react'
import { cn } from '@/lib/utils'
type HugeiconDef = React.ComponentProps<typeof HugeiconsIcon>['icon']
interface EmptyStateProps {
icon?: HugeiconDef
title: string
description?: string
action?: React.ReactNode
className?: string
}
/**
* Centered empty-state for lists and tables. Soft icon in a ringed circle,
* tight title and a muted one-liner underneath. Caller can slot an action button.
*/
export function EmptyState({ icon, title, description, action, className }: EmptyStateProps) {
return (
<div className={cn('flex flex-col items-center justify-center gap-3 px-6 py-16 text-center', className)}>
{icon && (
<div
className="relative flex h-14 w-14 items-center justify-center rounded-full
bg-gradient-to-b from-muted/60 to-muted/20
ring-1 ring-border/60
shadow-[inset_0_0_0_1px_rgba(255,255,255,0.03)]"
>
<div
className="absolute inset-0 rounded-full opacity-70 blur-xl"
style={{ background: 'radial-gradient(closest-side, rgba(255,255,255,0.06), transparent 70%)' }}
/>
<HugeiconsIcon icon={icon} size={22} className="relative text-muted-foreground/80" />
</div>
)}
<div className="space-y-1">
<p className="text-sm font-medium text-foreground">{title}</p>
{description && (
<p className="text-xs text-muted-foreground max-w-sm mx-auto leading-relaxed">
{description}
</p>
)}
</div>
{action && <div className="mt-2">{action}</div>}
</div>
)
}