fix(reports): split PDF widget catalogue out of the DB-touching service
export-dashboard-pdf-button.tsx imported PDF_DASHBOARD_WIDGETS +
PdfDashboardWidgetId from dashboard-report-data.service.ts. JS modules
evaluate their imports eagerly, so the button transitively pulled in
that file's top-level `import { getKpis } from './dashboard.service'`,
which pulled in `@/lib/db`, which pulls in `postgres`, which crashed
the client bundle with:
Module not found: Can't resolve 'fs'
./node_modules/.../postgres/src/index.js [Client Component Browser]
Split the pure data + types into the new file
src/lib/services/dashboard-report-widgets.ts and re-export from the
original service for backwards compatibility. The button now imports
from the pure file; the server-only route (reports/generate) keeps
using the resolver as before.
tsc clean, dashboard loads.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,7 @@ import {
|
||||
import {
|
||||
PDF_DASHBOARD_WIDGETS,
|
||||
type PdfDashboardWidgetId,
|
||||
} from '@/lib/services/dashboard-report-data.service';
|
||||
} from '@/lib/services/dashboard-report-widgets';
|
||||
import { triggerBlobDownload } from '@/lib/utils/download';
|
||||
import { usePermissions } from '@/hooks/use-permissions';
|
||||
import { resolvePortIdFromSlug } from '@/lib/api/client';
|
||||
|
||||
@@ -21,61 +21,16 @@ import {
|
||||
} from './dashboard.service';
|
||||
import type { DashboardReportData } from '@/lib/pdf/reports/dashboard-report';
|
||||
|
||||
/**
|
||||
* Maps widget ids the dashboard PDF understands. The id space is
|
||||
* intentionally a subset of the on-screen `DASHBOARD_WIDGETS`
|
||||
* registry — only widgets that have a sensible printable form
|
||||
* appear here. The dialog's widget picker filters its option list
|
||||
* by this set.
|
||||
*/
|
||||
export const PDF_DASHBOARD_WIDGET_IDS = [
|
||||
'kpi_overview',
|
||||
'pipeline_funnel',
|
||||
'berth_status',
|
||||
'source_conversion',
|
||||
'hot_deals',
|
||||
] as const;
|
||||
|
||||
export type PdfDashboardWidgetId = (typeof PDF_DASHBOARD_WIDGET_IDS)[number];
|
||||
|
||||
export interface PdfDashboardWidgetOption {
|
||||
id: PdfDashboardWidgetId;
|
||||
label: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public widget list (label + description) for the export dialog.
|
||||
* Mirrored from the on-screen widget-registry but with PDF-friendly
|
||||
* copy: a "Berth heat" chart is "Berth demand ranking" in print.
|
||||
*/
|
||||
export const PDF_DASHBOARD_WIDGETS: readonly PdfDashboardWidgetOption[] = [
|
||||
{
|
||||
id: 'kpi_overview',
|
||||
label: 'Key metrics',
|
||||
description: 'Total clients, active interests, pipeline value, occupancy %.',
|
||||
},
|
||||
{
|
||||
id: 'pipeline_funnel',
|
||||
label: 'Pipeline funnel',
|
||||
description: 'Active interests grouped by pipeline stage.',
|
||||
},
|
||||
{
|
||||
id: 'berth_status',
|
||||
label: 'Berth status distribution',
|
||||
description: 'Available / under offer / reserved / sold counts.',
|
||||
},
|
||||
{
|
||||
id: 'source_conversion',
|
||||
label: 'Source conversion',
|
||||
description: 'Inquiries → Clients → Interests → Won, by lead source.',
|
||||
},
|
||||
{
|
||||
id: 'hot_deals',
|
||||
label: 'Hot deals',
|
||||
description: 'Top 5 active interests by deal-health score.',
|
||||
},
|
||||
];
|
||||
// Pure data/types now live in `dashboard-report-widgets.ts` so the
|
||||
// client-side export button can import them without dragging this
|
||||
// file's DB-touching imports into the browser bundle. Re-exported
|
||||
// here so existing consumers keep working.
|
||||
export {
|
||||
PDF_DASHBOARD_WIDGET_IDS,
|
||||
PDF_DASHBOARD_WIDGETS,
|
||||
type PdfDashboardWidgetId,
|
||||
type PdfDashboardWidgetOption,
|
||||
} from './dashboard-report-widgets';
|
||||
|
||||
export async function resolveDashboardReportData(
|
||||
portId: string,
|
||||
|
||||
61
src/lib/services/dashboard-report-widgets.ts
Normal file
61
src/lib/services/dashboard-report-widgets.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Pure data + types for the dashboard-PDF report's widget catalogue.
|
||||
*
|
||||
* Lives in its own file so client-side surfaces (the "Export as PDF"
|
||||
* dialog) can import the catalogue without dragging the server-side
|
||||
* resolver — which imports the DB layer — into the client bundle.
|
||||
* Before this split, `export-dashboard-pdf-button.tsx` pulled
|
||||
* `PDF_DASHBOARD_WIDGETS` from `dashboard-report-data.service.ts`,
|
||||
* whose top-level `import { getKpis } from './dashboard.service'`
|
||||
* dragged in `postgres` and crashed the client build with
|
||||
* "Module not found: Can't resolve 'fs'".
|
||||
*/
|
||||
|
||||
export const PDF_DASHBOARD_WIDGET_IDS = [
|
||||
'kpi_overview',
|
||||
'pipeline_funnel',
|
||||
'berth_status',
|
||||
'source_conversion',
|
||||
'hot_deals',
|
||||
] as const;
|
||||
|
||||
export type PdfDashboardWidgetId = (typeof PDF_DASHBOARD_WIDGET_IDS)[number];
|
||||
|
||||
export interface PdfDashboardWidgetOption {
|
||||
id: PdfDashboardWidgetId;
|
||||
label: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public widget list (label + description) for the export dialog.
|
||||
* Mirrored from the on-screen widget-registry but with PDF-friendly
|
||||
* copy: a "Berth heat" chart is "Berth demand ranking" in print.
|
||||
*/
|
||||
export const PDF_DASHBOARD_WIDGETS: readonly PdfDashboardWidgetOption[] = [
|
||||
{
|
||||
id: 'kpi_overview',
|
||||
label: 'Key metrics',
|
||||
description: 'Total clients, active interests, pipeline value, occupancy %.',
|
||||
},
|
||||
{
|
||||
id: 'pipeline_funnel',
|
||||
label: 'Pipeline funnel',
|
||||
description: 'Active interests grouped by pipeline stage.',
|
||||
},
|
||||
{
|
||||
id: 'berth_status',
|
||||
label: 'Berth status distribution',
|
||||
description: 'Available / under offer / reserved / sold counts.',
|
||||
},
|
||||
{
|
||||
id: 'source_conversion',
|
||||
label: 'Source conversion',
|
||||
description: 'Inquiries → Clients → Interests → Won, by lead source.',
|
||||
},
|
||||
{
|
||||
id: 'hot_deals',
|
||||
label: 'Hot deals',
|
||||
description: 'Top 5 active interests by deal-health score.',
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user