{{ theme.skipToContentLabel || 'Skip to content' }}

Flow Meter PDF Export

Date: 2026-02-16 Scope: Add PDF export functionality to the Flow Meter feature using the existing shared export page infrastructure.

Problem

Flow Meter is the only major data feature without a proper export page. The current export is a simple PNG screenshot of charts via modern-screenshot. Other features (Dust Levels, Dust Ranger) have full-featured export pages with chart selection, AI-generated descriptions, branded PDF output, and progress tracking.

Solution

Follow the established export page pattern: create a dedicated /flow-meter/export route that reuses the shared useExportPage hook and UI components, with a new FlowMeterPdfExportService for PDF generation and a new Edge Function for AI chart descriptions.

Architecture

New Files:
  src/features/flow-meter/config/chartConfig.ts          # Chart options definition
  src/features/flow-meter/services/flowMeterPdfExportService.ts  # PDF generation (jsPDF + modern-screenshot)
  src/app/(admin)/(pages)/flow-meter/export.tsx           # Export page component
  supabase/functions/generate-flow-meter-descriptions/    # AI description Edge Function

Modified Files:
  src/routes/Routes.tsx                                   # Add /flow-meter/export route
  src/app/(admin)/(pages)/flow-meter/index.tsx            # Replace PNG export with navigate to export page

Chart Configuration

Five selectable charts:

KeyLabelDefault Selected
dailySummaryDaily Water Usage Summary
waterUsageTimelineWater Usage Timeline
calendarHeatmapUsage Gap Calendar Heatmap
gapChartGap Analysis Chart
noDataDaysNo Data Days Table

Data Flow

  1. Flow Meter main page navigates to /flow-meter/export with location.state:

    typescript
    {
      siteSummary: selectedSiteSummary,  // records, refills, dailySummaries, totalLitres, totalRefilled
      selectedSite: string,
      dateRange: { start: Date, end: Date },
      chartType: "line" | "scatter",
    }
  2. Export page receives state, defines chartOptions, buildAIRequestBody, handleExportPdf

  3. Calls useExportPage() with Flow Meter-specific options:

    • storageKey: flow-meter-{siteName}
    • edgeFunctionName: "generate-flow-meter-descriptions"
    • Feature-specific buildAIRequestBody and onExport
  4. Renders shared components: ReportNameEditor, AIControlsPanel, ChartWithDescription wrappers, ExportSummarySection, ExportProgressModal

AI Description Edge Function

New Edge Function: generate-flow-meter-descriptions

System prompt positions the AI as a "Dustloc operational data analyst" that understands:

  • Dustloc device water dispensing and refill patterns
  • Daily usage trends and anomalies
  • Operational efficiency (dispensing frequency, refill cycles)
  • Data gaps and their operational implications

Request body:

typescript
{
  model: string,
  style: string,
  flowMeterStats: {
    totalLitres: number,
    dailyAverage: number,
    refillCount: number,
    tankLevel: number,
    totalRecords: number,
  },
  singleChart: string,  // chart key
  chartData: {
    dailySummaries: DailySummary[],
    records: FlowMeterRecord[],
    refills: DustLocRefill[],
  }
}

Chart-specific prompts per singleChart key:

  • dailySummary — Analyze daily dispensing volume trends, identify peak/low usage days
  • waterUsageTimeline — Analyze individual dispensing events over time, identify patterns in timing and volume
  • calendarHeatmap — Analyze the calendar view of usage gaps, identify periods of inactivity
  • gapChart — Analyze gaps between dispensing events, identify operational disruptions
  • noDataDays — Summarize days with no recorded data and potential causes

PDF Generation Service

FlowMeterPdfExportService follows DustLevelExportService pattern:

Cover Page:

  • Dust Ranger logo + title "Dustloc Flow Meter Report"
  • Site name, date range, timezone
  • Summary stat cards (2×2 portrait, 1×4 landscape):
    • Total Litres Dispensed
    • Daily Average
    • Refill Count
    • Tank Level
    • Total Records
    • Active Days

Chart Pages:

  • DOM discovery via document.querySelectorAll("[data-export-chart]")
  • Chart capture with domToJpeg (modern-screenshot)
  • Chart title + image + "KEY INSIGHTS" description box (orange left border)
  • Supports portrait/landscape orientation

Summary Page:

  • Optional summary/conclusion text (blue left border)
  • Page numbers + copyright footer on all pages

Main Page Changes

Replace the current PNG export flow:

  • Remove hidden #all-charts-export-container div
  • Remove handleExportAllCharts function and useChartExport hook usage
  • Change Export button to navigate("/flow-meter/export", { state: {...} })

Route Definition

typescript
{
  path: "/flow-meter/export",
  name: "FlowMeterExport",
  element: <FlowMeterExport />,
  requiredModule: "flow_meter",
  showDatePicker: true,
  showSiteSelector: true,
}

What Doesn't Change

  • Existing FlowMeterExportService (CSV/email) — untouched
  • Shared export infrastructure (useExportPage, ChartWithDescription, etc.) — consumed as-is
  • Flow Meter chart components — reused on the export page
  • Other features' export pages — unaffected