feat(reports): financial report-level empty state
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,9 @@ import { rangeToBounds, type DateRange } from '@/lib/analytics/range';
|
||||
import { apiFetch } from '@/lib/api/client';
|
||||
import { formatMoney, formatMoneyCompact, formatNumber } from '@/lib/reports/format-currency';
|
||||
import type { ReportPayload } from '@/lib/reports/types';
|
||||
import { ReportEmptyState } from '@/components/reports/shared/report-empty-state';
|
||||
import type { Route } from 'next';
|
||||
import { Wallet } from 'lucide-react';
|
||||
|
||||
// ─── Payload types (mirror the /api/v1/reports/financial response) ───────────
|
||||
|
||||
@@ -119,6 +122,7 @@ interface FinancialPayload {
|
||||
refundLog: RefundRow[];
|
||||
expenseLedger: ExpenseLedgerRow[];
|
||||
range: { from: string; to: string };
|
||||
hasData: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -138,7 +142,7 @@ const DONUT_COLORS = [
|
||||
'hsl(var(--chart-6))',
|
||||
];
|
||||
|
||||
export function FinancialReportClient({ portSlug: _portSlug }: { portSlug: string }) {
|
||||
export function FinancialReportClient({ portSlug }: { portSlug: string }) {
|
||||
const searchParams = useSearchParams();
|
||||
const initialTemplateId = searchParams?.get('templateId') ?? null;
|
||||
|
||||
@@ -271,6 +275,25 @@ export function FinancialReportClient({ portSlug: _portSlug }: { portSlug: strin
|
||||
|
||||
const isLoading = query.isLoading || !kpis;
|
||||
|
||||
if (!query.isLoading && d && !d.hasData) {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<PageHeader
|
||||
eyebrow="Reports"
|
||||
title="Financial"
|
||||
description="Revenue collected, deposits, outstanding balances, cash flow, and expense breakdown."
|
||||
/>
|
||||
<ReportEmptyState
|
||||
icon={Wallet}
|
||||
title="No financial activity yet"
|
||||
body="Record a payment on a deal or log an expense to see revenue, deposits, and cash flow."
|
||||
actionLabel="Go to expenses"
|
||||
actionHref={`/${portSlug}/expenses` as Route}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<PageHeader
|
||||
|
||||
@@ -33,6 +33,7 @@ import { apiFetch } from '@/lib/api/client';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useUIStore } from '@/stores/ui-store';
|
||||
import type { ReportPayload } from '@/lib/reports/types';
|
||||
import { ReportEmptyState } from '@/components/reports/shared/report-empty-state';
|
||||
|
||||
import { OperationalHeatmap } from './operational-heatmap';
|
||||
import { OperationalSigningBoxPlot } from './operational-signing-box-plot';
|
||||
@@ -162,6 +163,8 @@ interface OperationalReportPayload {
|
||||
stuckSigning: StuckSigningRow[];
|
||||
highestValueVacant: HighestValueVacantRow[];
|
||||
range: { from: string; to: string };
|
||||
hasData: boolean;
|
||||
areaOptions: string[];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -312,6 +315,25 @@ export function OperationalReportClient({ portSlug }: { portSlug: string }) {
|
||||
};
|
||||
}
|
||||
|
||||
if (!query.isLoading && data && !data.hasData) {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<PageHeader
|
||||
eyebrow="Reports"
|
||||
title="Operational"
|
||||
description="Berth utilisation, tenancy lifecycle, signing turnaround, operational bottlenecks."
|
||||
/>
|
||||
<ReportEmptyState
|
||||
icon={Anchor}
|
||||
title="No berths yet"
|
||||
body="Add berths to see utilisation, occupancy, and signing turnaround."
|
||||
actionLabel="Add berths"
|
||||
actionHref={`/${portSlug}/berths` as Route}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<PageHeader
|
||||
|
||||
Reference in New Issue
Block a user