@burdenoff/microfe-theglobalfuel 2026.705.4 → 2026.709.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +3 -1
- package/dist/theglobalfuel/TheGlobalFuelRoutes.js +1 -1
- package/dist/theglobalfuel/TheGlobalFuelRoutes.js.map +1 -1
- package/dist/theglobalfuel/hooks/index.js +1 -0
- package/dist/theglobalfuel/hooks/useTheAnalytics.js +45 -0
- package/dist/theglobalfuel/hooks/useTheAnalytics.js.map +1 -0
- package/dist/theglobalfuel/index.js +2 -0
- package/dist/theglobalfuel/pages/assets/AssetDetailPage.js +284 -279
- package/dist/theglobalfuel/pages/assets/AssetDetailPage.js.map +1 -1
- package/dist/theglobalfuel/pages/assets/AssetsPage.js +141 -138
- package/dist/theglobalfuel/pages/assets/AssetsPage.js.map +1 -1
- package/dist/theglobalfuel/pages/contracts/ContractsPage.js +234 -231
- package/dist/theglobalfuel/pages/contracts/ContractsPage.js.map +1 -1
- package/dist/theglobalfuel/pages/dashboard/DashboardPage.js +243 -238
- package/dist/theglobalfuel/pages/dashboard/DashboardPage.js.map +1 -1
- package/dist/theglobalfuel/pages/provenance/ProvenancePage.js +13 -13
- package/dist/theglobalfuel/pages/provenance/ProvenancePage.js.map +1 -1
- package/dist/theglobalfuel/services/assistantApi.js +225 -0
- package/dist/theglobalfuel/services/assistantApi.js.map +1 -0
- package/dist/theglobalfuel/services/createSandboxAssistantTransport.js +120 -0
- package/dist/theglobalfuel/services/createSandboxAssistantTransport.js.map +1 -0
- package/dist/theglobalfuel/utils/pageContext.js +65 -0
- package/dist/theglobalfuel/utils/pageContext.js.map +1 -0
- package/package.json +5 -1
- package/dist/node_modules/clsx/dist/clsx.js +0 -18
- package/dist/node_modules/clsx/dist/clsx.js.map +0 -1
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +0 -1716
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/dashboard/DashboardPage.tsx"],"sourcesContent":["/**\n * Dashboard — TheGlobalFuel resources operating-system overview.\n * @module theglobalfuel/pages/dashboard\n *\n * The hero landing (eager-loaded). Every figure is aggregated client-side from\n * the real `the*` list endpoints — no mock data. The page opens with the domain\n * KPI grid (registry / commerce / sustainability), then a rich analytics band:\n * - a PRODUCTION TREND area chart (metered output bucketed by month),\n * - a COMMODITY MIX donut (share of assets by commodity), and\n * - an EMISSIONS-BY-SCOPE donut (tonnes CO₂e per GHG scope);\n * a COMMODITY PORTFOLIO grid (one glass card per commodity present, with real\n * asset counts, summed capacity and a production sparkline); an ASSETS-BY-\n * LIFECYCLE distribution; and recent-activity tables. All charts derive from\n * the fetched arrays and degrade to pre-launch empty states.\n */\n\nimport { useMemo, type ReactNode } from 'react';\nimport {\n Layers,\n ScrollText,\n Ship,\n Factory,\n Boxes,\n ShieldCheck,\n ArrowRight,\n ArrowUpRight,\n Fuel,\n GitBranch,\n Gauge,\n Activity,\n ClipboardList,\n} from 'lucide-react';\nimport { GlassCard, Spinner } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { MiniBar } from '../../components/MiniBar';\nimport { DataTable, type Column } from '../../components/DataTable';\nimport { LoadingView, ErrorView, Section } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport {\n AreaChart,\n DonutChart,\n Sparkline,\n chartPalette,\n type LabeledValue,\n type Segment,\n} from '../../components/viz';\nimport { cn } from '../../utils/cn';\nimport { useTheGlobalFuel } from '../../context';\nimport {\n useTheAssets,\n useTheContracts,\n useTheShipments,\n useTheEmissionRecords,\n useTheInventoryLots,\n useTheComplianceCerts,\n useTheProductionRecords,\n} from '../../hooks';\nimport {\n formatNumber,\n formatPercent,\n formatDate,\n formatRelativeTime,\n formatEnumLabel,\n formatVolume,\n formatTonnesCo2e,\n isExpired,\n} from '../../utils/formatters';\nimport type {\n TheAssetStatus,\n TheCommodityType,\n TheEmissionScope,\n TheOfftakeContract,\n TheProductionRecord,\n} from '../../types';\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst EXPIRY_WINDOW_DAYS = 30;\n\n/** True when a cert expires within the next 30 days (but hasn't yet). */\nconst isExpiringSoon = (date: string | null | undefined): boolean => {\n if (!date) return false;\n const t = new Date(date).getTime();\n if (Number.isNaN(t)) return false;\n const diff = t - Date.now();\n return diff >= 0 && diff <= EXPIRY_WINDOW_DAYS * DAY_MS;\n};\n\n/** Asset lifecycle → MiniBar fill token (semantic, maturity-ordered). */\nconst ASSET_STATUS_BAR: Record<TheAssetStatus, string> = {\n EXPLORATION: 'bg-[var(--color-accent-indigo)]',\n APPRAISAL: 'bg-[var(--color-accent-blue)]',\n DEVELOPMENT: 'bg-[var(--color-accent-teal)]',\n PRODUCING: 'bg-status-success-text',\n SUSPENDED: 'bg-status-warning-text',\n DECOMMISSIONING: 'bg-status-error-text',\n RETIRED: 'bg-[var(--color-text-tertiary)]',\n};\n\n/** GHG scope → donut segment color token (Scope 1 direct · 2 energy · 3 chain). */\nconst SCOPE_COLOR: Record<TheEmissionScope, string> = {\n SCOPE_1: 'var(--color-status-error-text)',\n SCOPE_2: 'var(--color-status-warning-text)',\n SCOPE_3: 'var(--color-accent-blue)',\n};\n\nconst ALL_SCOPES: TheEmissionScope[] = ['SCOPE_1', 'SCOPE_2', 'SCOPE_3'];\n\n// ── Month bucketing (UTC-stable, gap-free) ───────────────────────────────────\n\n/** UTC year-month key (e.g. \"2026-07\"). */\nconst monthKey = (d: Date): string =>\n `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;\n\nconst MONTH_FMT = new Intl.DateTimeFormat(undefined, {\n month: 'short',\n year: '2-digit',\n timeZone: 'UTC',\n});\n\nconst monthLabel = (year: number, month1: number): string =>\n MONTH_FMT.format(new Date(Date.UTC(year, month1 - 1, 1)));\n\n/** Sum `valueOf` into UTC-month buckets keyed by the `dateOf` field. */\nfunction bucketByMonth<T>(\n rows: readonly T[],\n dateOf: (row: T) => string | null | undefined,\n valueOf: (row: T) => number\n): Map<string, number> {\n const buckets = new Map<string, number>();\n for (const row of rows) {\n const raw = dateOf(row);\n if (!raw) continue;\n const d = new Date(raw);\n if (Number.isNaN(d.getTime())) continue;\n const key = monthKey(d);\n buckets.set(key, (buckets.get(key) ?? 0) + valueOf(row));\n }\n return buckets;\n}\n\n/**\n * Expand month buckets into a gap-free ordered series from the earliest to the\n * latest populated month (so a trend line stays continuous), then keep only the\n * most recent `maxMonths` so a stray old record can't blow out the axis.\n */\nfunction monthlySeries(buckets: Map<string, number>, maxMonths = 18): LabeledValue[] {\n const keys = [...buckets.keys()].sort();\n if (keys.length === 0) return [];\n const parse = (k: string): [number, number] => {\n const [y, m] = k.split('-');\n return [Number(y), Number(m)];\n };\n const [maxY, maxM] = parse(keys[keys.length - 1]);\n let [y, m] = parse(keys[0]);\n const series: LabeledValue[] = [];\n let guard = 0;\n while ((y < maxY || (y === maxY && m <= maxM)) && guard < 240) {\n series.push({\n label: monthLabel(y, m),\n value: buckets.get(`${y}-${String(m).padStart(2, '0')}`) ?? 0,\n });\n m += 1;\n if (m > 12) {\n m = 1;\n y += 1;\n }\n guard += 1;\n }\n return series.length > maxMonths ? series.slice(series.length - maxMonths) : series;\n}\n\n/** Group rows by a discriminator, sorted by descending count, with % of total. */\nfunction distribution<T>(\n rows: T[],\n keyOf: (row: T) => string\n): { key: string; count: number; pct: number }[] {\n const counts = new Map<string, number>();\n for (const row of rows) {\n const k = keyOf(row);\n counts.set(k, (counts.get(k) ?? 0) + 1);\n }\n const total = rows.length;\n return [...counts.entries()]\n .sort((a, b) => b[1] - a[1])\n .map(([key, count]) => ({ key, count, pct: total ? (count / total) * 100 : 0 }));\n}\n\n// ── Distribution card (MiniBar rows) ─────────────────────────────────────────\n\ninterface DistBar {\n key: string;\n label: ReactNode;\n /** Pre-formatted primary figure shown right of the bar. */\n value: string;\n /** 0–100 — drives the bar width + the muted percentage. */\n pct: number;\n barClassName: string;\n}\n\ninterface DistributionCardProps {\n title: string;\n description: string;\n icon: ReactNode;\n linkLabel: string;\n onLink: () => void;\n isLoading: boolean;\n isError: boolean;\n onRetry: () => void;\n emptyLabel: string;\n bars: DistBar[];\n footer?: ReactNode;\n className?: string;\n}\n\n/** A titled glass card that renders a compact set of MiniBar distribution rows. */\nfunction DistributionCard({\n title,\n description,\n icon,\n linkLabel,\n onLink,\n isLoading,\n isError,\n onRetry,\n emptyLabel,\n bars,\n footer,\n className,\n}: DistributionCardProps) {\n return (\n <GlassCard treatment=\"glass\" className={cn('flex flex-col p-5', className)}>\n <div className=\"mb-4 flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 items-start gap-2.5\">\n <span className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n {icon}\n </span>\n <div className=\"min-w-0\">\n <h2 className=\"text-base font-semibold text-text-primary\">{title}</h2>\n <p className=\"mt-0.5 text-xs text-text-tertiary\">{description}</p>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={onLink}\n className=\"inline-flex shrink-0 items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n {linkLabel} <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n\n {isLoading ? (\n <div className=\"flex items-center gap-2 py-8 text-sm text-text-secondary\">\n <Spinner size=\"sm\" /> Loading…\n </div>\n ) : isError ? (\n <div className=\"flex flex-col items-start gap-2 py-6\">\n <p className=\"text-sm text-status-error-text\">Couldn't load {title.toLowerCase()}.</p>\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"rounded-lg border border-border-seam px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Retry\n </button>\n </div>\n ) : bars.length === 0 ? (\n <div className=\"flex flex-1 flex-col items-center justify-center rounded-xl border border-dashed border-border-seam py-8 text-center\">\n <p className=\"text-sm text-text-secondary\">{emptyLabel}</p>\n </div>\n ) : (\n <div className=\"flex flex-1 flex-col justify-between gap-4\">\n <div className=\"space-y-3\">\n {bars.map((bar) => (\n <div key={bar.key} className=\"flex items-center gap-3\">\n <div className=\"w-24 shrink-0 truncate text-sm text-text-secondary sm:w-28\">\n {bar.label}\n </div>\n <MiniBar value={bar.pct} barClassName={bar.barClassName} className=\"flex-1\" height={8} />\n <span className=\"w-16 shrink-0 whitespace-nowrap text-right text-sm font-medium tabular-nums text-text-primary\">\n {bar.value}\n </span>\n <span className=\"hidden w-11 shrink-0 text-right text-xs tabular-nums text-text-tertiary sm:inline\">\n {formatPercent(bar.pct)}\n </span>\n </div>\n ))}\n </div>\n {footer && (\n <p className=\"border-t border-border-seam/70 pt-3 text-xs text-text-tertiary\">{footer}</p>\n )}\n </div>\n )}\n </GlassCard>\n );\n}\n\n// ── Chart card (titled glass panel for a chart body) ─────────────────────────\n\ninterface ChartCardProps {\n title: string;\n caption: string;\n icon: ReactNode;\n link?: { label: string; onClick: () => void };\n isLoading: boolean;\n isError: boolean;\n onRetry: () => void;\n isEmpty: boolean;\n emptyLabel: string;\n footer?: ReactNode;\n className?: string;\n children: ReactNode;\n}\n\n/** A titled glass card wrapping a viz-kit chart, with loading/error/empty states. */\nfunction ChartCard({\n title,\n caption,\n icon,\n link,\n isLoading,\n isError,\n onRetry,\n isEmpty,\n emptyLabel,\n footer,\n className,\n children,\n}: ChartCardProps) {\n return (\n <GlassCard treatment=\"glass\" className={cn('flex flex-col p-5', className)}>\n <div className=\"mb-4 flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 items-start gap-2.5\">\n <span className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n {icon}\n </span>\n <div className=\"min-w-0\">\n <h2 className=\"text-base font-semibold text-text-primary\">{title}</h2>\n <p className=\"mt-0.5 text-xs text-text-tertiary\">{caption}</p>\n </div>\n </div>\n {link ? (\n <button\n type=\"button\"\n onClick={link.onClick}\n className=\"inline-flex shrink-0 items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n {link.label} <ArrowRight className=\"h-4 w-4\" />\n </button>\n ) : null}\n </div>\n\n {isLoading ? (\n <div className=\"flex flex-1 items-center gap-2 py-8 text-sm text-text-secondary\">\n <Spinner size=\"sm\" /> Loading…\n </div>\n ) : isError ? (\n <div className=\"flex flex-1 flex-col items-start gap-2 py-6\">\n <p className=\"text-sm text-status-error-text\">Couldn't load {title.toLowerCase()}.</p>\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"rounded-lg border border-border-seam px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Retry\n </button>\n </div>\n ) : isEmpty ? (\n <div className=\"flex flex-1 flex-col items-center justify-center rounded-xl border border-dashed border-border-seam py-10 text-center\">\n <p className=\"text-sm text-text-secondary\">{emptyLabel}</p>\n </div>\n ) : (\n <div className=\"flex flex-1 flex-col justify-between gap-4\">\n <div className=\"flex-1\">{children}</div>\n {footer ? (\n <p className=\"border-t border-border-seam/70 pt-3 text-xs text-text-tertiary\">{footer}</p>\n ) : null}\n </div>\n )}\n </GlassCard>\n );\n}\n\n// ── Commodity portfolio card ─────────────────────────────────────────────────\n\ninterface CommodityPortfolioEntry {\n key: TheCommodityType;\n name: string;\n /** Tokenized commodity color, shared with the commodity-mix donut. */\n color: string;\n assetCount: number;\n producing: number;\n capacity: number;\n /** Dominant `TheUnit` token across the commodity's assets. */\n unit: string;\n /** Monthly production volumes (oldest first) — empty when none logged. */\n spark: number[];\n}\n\nfunction CommodityCard({ card, onOpen }: { card: CommodityPortfolioEntry; onOpen: () => void }) {\n return (\n <GlassCard treatment=\"metric\" className=\"p-0\">\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${card.name} assets`}\n className=\"flex w-full flex-col gap-4 rounded-[var(--radius-card)] p-5 text-left outline-none transition-transform duration-200 hover:-translate-y-0.5 focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex min-w-0 items-center gap-2.5\">\n <span\n aria-hidden=\"true\"\n className=\"size-2.5 shrink-0 rounded-full\"\n style={{ backgroundColor: card.color }}\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold text-text-primary\">{card.name}</p>\n <p className=\"text-xs text-text-tertiary\">\n {card.assetCount} {card.assetCount === 1 ? 'asset' : 'assets'}\n </p>\n </div>\n </div>\n <ArrowUpRight className=\"h-4 w-4 shrink-0 text-text-tertiary\" />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"min-w-0\">\n <p className=\"text-[11px] uppercase tracking-wide text-text-tertiary\">Capacity/day</p>\n <p className=\"mt-0.5 truncate text-sm font-semibold tabular-nums text-text-primary\">\n {card.capacity > 0 ? formatVolume(card.capacity, card.unit) : '—'}\n </p>\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-[11px] uppercase tracking-wide text-text-tertiary\">Producing</p>\n <p className=\"mt-0.5 text-sm font-semibold tabular-nums text-text-primary\">\n {card.producing}{' '}\n <span className=\"text-xs font-normal text-text-tertiary\">of {card.assetCount}</span>\n </p>\n </div>\n </div>\n\n {card.spark.length >= 2 ? (\n <div>\n <Sparkline\n data={card.spark}\n variant=\"area\"\n height={40}\n label={`${card.name} monthly production`}\n />\n <p className=\"mt-1 text-[11px] text-text-tertiary\">Monthly output</p>\n </div>\n ) : (\n <p className=\"text-xs text-text-tertiary\">No production logged yet.</p>\n )}\n </button>\n </GlassCard>\n );\n}\n\nexport function DashboardPage() {\n const { navigateTo, currentUser } = useTheGlobalFuel();\n\n // Real backend queries. Aggregate domains fetch a generous page (200) so the\n // charts + portfolio reflect the whole book; commerce lists stay at 50.\n const assets = useTheAssets({ pagination: { limit: 200 } });\n const contracts = useTheContracts({ pagination: { limit: 50 } });\n const shipments = useTheShipments(undefined, 'IN_TRANSIT');\n const emissions = useTheEmissionRecords({ pagination: { limit: 200 } });\n const inventory = useTheInventoryLots({ pagination: { limit: 50 } });\n const compliance = useTheComplianceCerts();\n const production = useTheProductionRecords({ pagination: { limit: 200 } });\n\n const assetRows = useMemo(() => assets.data?.items ?? [], [assets.data]);\n const contractRows = useMemo(() => contracts.data?.items ?? [], [contracts.data]);\n const inTransitRows = useMemo(() => shipments.data?.items ?? [], [shipments.data]);\n const emissionRows = useMemo(() => emissions.data?.items ?? [], [emissions.data]);\n const inventoryRows = useMemo(() => inventory.data?.items ?? [], [inventory.data]);\n const certRows = useMemo(() => compliance.data?.items ?? [], [compliance.data]);\n const productionRows = useMemo(() => production.data?.items ?? [], [production.data]);\n\n // ── KPI aggregates ─────────────────────────────────────────────────────────\n const producingCount = assetRows.filter((a) => a.status === 'PRODUCING').length;\n const activeContracts = contractRows.filter((c) => c.status === 'ACTIVE').length;\n const totalTonnes = emissionRows.reduce((sum, e) => sum + (e.co2eTonnes ?? 0), 0);\n const verifiedEmissions = emissionRows.filter((e) => e.verified).length;\n const availableLots = inventoryRows.filter((l) => l.status === 'AVAILABLE').length;\n const totalProductionVolume = productionRows.reduce((sum, p) => sum + (p.volume ?? 0), 0);\n\n const pendingCerts = certRows.filter((c) => c.status === 'PENDING').length;\n const expiringCerts = certRows.filter(\n (c) => c.expiresAt != null && (isExpired(c.expiresAt) || isExpiringSoon(c.expiresAt))\n ).length;\n const attentionCerts = certRows.filter(\n (c) =>\n c.status === 'PENDING' ||\n (c.expiresAt != null && (isExpired(c.expiresAt) || isExpiringSoon(c.expiresAt)))\n ).length;\n\n const withPlus = (rows: unknown[], hasMore: boolean | undefined): string =>\n hasMore ? `${rows.length}+` : formatNumber(rows.length);\n\n // ── Production trend (metered output by month) ───────────────────────────────\n const productionSeries = useMemo<LabeledValue[]>(\n () =>\n monthlySeries(\n bucketByMonth(\n productionRows,\n (p) => p.periodEnd,\n (p) => p.volume ?? 0\n )\n ),\n [productionRows]\n );\n\n // ── Commodity distribution + shared per-commodity colors ─────────────────────\n const commodityDist = useMemo(() => distribution(assetRows, (a) => a.commodity), [assetRows]);\n\n const commodityColor = useMemo(() => {\n const palette = chartPalette(commodityDist.length);\n const map = new Map<string, string>();\n commodityDist.forEach((d, i) => map.set(d.key, palette[i]));\n return map;\n }, [commodityDist]);\n\n const commodityMix = useMemo<Segment[]>(\n () =>\n commodityDist.map((d) => ({\n label: formatEnumLabel(d.key),\n value: d.count,\n color: commodityColor.get(d.key),\n })),\n [commodityDist, commodityColor]\n );\n\n // ── Emissions by scope (tonnes CO₂e) ─────────────────────────────────────────\n const scopeMix = useMemo<Segment[]>(() => {\n if (emissionRows.length === 0) return [];\n const totals: Record<TheEmissionScope, number> = { SCOPE_1: 0, SCOPE_2: 0, SCOPE_3: 0 };\n for (const e of emissionRows) totals[e.scope] += e.co2eTonnes ?? 0;\n return ALL_SCOPES.filter((s) => totals[s] > 0).map((s) => ({\n label: formatEnumLabel(s),\n value: totals[s],\n color: SCOPE_COLOR[s],\n }));\n }, [emissionRows]);\n\n // ── Assets by lifecycle (MiniBar rows) ───────────────────────────────────────\n const lifecycleBars = useMemo<DistBar[]>(\n () =>\n distribution(assetRows, (a) => a.status).map((d) => ({\n key: d.key,\n label: <StatusBadge status={d.key} />,\n value: formatNumber(d.count),\n pct: d.pct,\n barClassName: ASSET_STATUS_BAR[d.key as TheAssetStatus] ?? 'bg-action-primary-bg',\n })),\n [assetRows]\n );\n\n // ── Commodity portfolio (one entry per commodity with assets) ────────────────\n const assetCommodity = useMemo(() => {\n const m = new Map<string, TheCommodityType>();\n for (const a of assetRows) m.set(a.id, a.commodity);\n return m;\n }, [assetRows]);\n\n const commodityCards = useMemo<CommodityPortfolioEntry[]>(() => {\n if (commodityDist.length === 0) return [];\n\n // Per-commodity asset aggregates.\n interface Agg {\n count: number;\n producing: number;\n capacity: number;\n units: Map<string, number>;\n }\n const agg = new Map<string, Agg>();\n for (const a of assetRows) {\n const cur =\n agg.get(a.commodity) ??\n { count: 0, producing: 0, capacity: 0, units: new Map<string, number>() };\n cur.count += 1;\n if (a.status === 'PRODUCING') cur.producing += 1;\n cur.capacity += a.capacityPerDay ?? 0;\n if (a.capacityUnit) cur.units.set(a.capacityUnit, (cur.units.get(a.capacityUnit) ?? 0) + 1);\n agg.set(a.commodity, cur);\n }\n\n // Per-commodity monthly production buckets → sparkline series.\n const prodBuckets = new Map<string, Map<string, number>>();\n for (const p of productionRows) {\n const commodity = assetCommodity.get(p.assetId);\n if (!commodity) continue;\n const d = new Date(p.periodEnd);\n if (Number.isNaN(d.getTime())) continue;\n const mk = monthKey(d);\n let bucket = prodBuckets.get(commodity);\n if (!bucket) {\n bucket = new Map<string, number>();\n prodBuckets.set(commodity, bucket);\n }\n bucket.set(mk, (bucket.get(mk) ?? 0) + (p.volume ?? 0));\n }\n\n const dominantUnit = (units: Map<string, number>): string => {\n let best = '';\n let bestN = -1;\n for (const [unit, n] of units) {\n if (n > bestN) {\n best = unit;\n bestN = n;\n }\n }\n return best;\n };\n\n return commodityDist.map((d) => {\n const a =\n agg.get(d.key) ??\n { count: 0, producing: 0, capacity: 0, units: new Map<string, number>() };\n const bucket = prodBuckets.get(d.key);\n const spark = bucket ? monthlySeries(bucket, 12).map((s) => s.value) : [];\n return {\n key: d.key as TheCommodityType,\n name: formatEnumLabel(d.key),\n color: commodityColor.get(d.key) ?? 'var(--color-accent-primary)',\n assetCount: a.count,\n producing: a.producing,\n capacity: a.capacity,\n unit: dominantUnit(a.units),\n spark,\n };\n });\n }, [assetRows, productionRows, assetCommodity, commodityDist, commodityColor]);\n\n // ── Recent activity ────────────────────────────────────────────────────────\n const assetName = useMemo(() => {\n const m = new Map<string, string>();\n for (const a of assetRows) m.set(a.id, a.name);\n return m;\n }, [assetRows]);\n\n const recentContracts = useMemo(\n () =>\n [...contractRows]\n .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())\n .slice(0, 6),\n [contractRows]\n );\n\n const recentProduction = useMemo(\n () =>\n [...productionRows]\n .sort((a, b) => new Date(b.periodEnd).getTime() - new Date(a.periodEnd).getTime())\n .slice(0, 6),\n [productionRows]\n );\n\n const contractColumns: Column<TheOfftakeContract>[] = [\n {\n key: 'reference',\n header: 'Reference',\n render: (c) => <span className=\"font-medium text-text-primary\">{c.reference}</span>,\n },\n {\n key: 'counterparty',\n header: 'Counterparty',\n hideOnMobile: true,\n render: (c) => <span className=\"text-text-secondary\">{c.counterparty}</span>,\n },\n {\n key: 'commodity',\n header: 'Commodity',\n hideOnMobile: true,\n render: (c) => <span className=\"text-text-secondary\">{formatEnumLabel(c.commodity)}</span>,\n },\n { key: 'side', header: 'Side', render: (c) => <StatusBadge status={c.side} /> },\n {\n key: 'volume',\n header: 'Volume',\n align: 'right',\n hideOnMobile: true,\n render: (c) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatVolume(c.contractedVolume, c.unit)}\n </span>\n ),\n },\n { key: 'status', header: 'Status', render: (c) => <StatusBadge status={c.status} /> },\n {\n key: 'created',\n header: 'Created',\n align: 'right',\n hideOnMobile: true,\n render: (c) => <span className=\"text-text-tertiary\">{formatRelativeTime(c.createdAt)}</span>,\n },\n ];\n\n const productionColumns: Column<TheProductionRecord>[] = [\n {\n key: 'asset',\n header: 'Asset',\n render: (p) => (\n <span className=\"font-medium text-text-primary\">\n {assetName.get(p.assetId) ?? 'Unknown asset'}\n </span>\n ),\n },\n {\n key: 'period',\n header: 'Period',\n hideOnMobile: true,\n render: (p) => (\n <span className=\"text-text-secondary\">\n {formatDate(p.periodStart)} – {formatDate(p.periodEnd)}\n </span>\n ),\n },\n {\n key: 'volume',\n header: 'Volume',\n align: 'right',\n render: (p) => (\n <span className=\"tabular-nums font-medium text-text-primary\">\n {formatVolume(p.volume, p.unit)}\n </span>\n ),\n },\n {\n key: 'downtime',\n header: 'Downtime',\n align: 'right',\n hideOnMobile: true,\n render: (p) => (\n <span className=\"tabular-nums text-text-secondary\">{formatNumber(p.downtimeHours)} h</span>\n ),\n },\n {\n key: 'logged',\n header: 'Logged',\n align: 'right',\n hideOnMobile: true,\n render: (p) => <span className=\"text-text-tertiary\">{formatRelativeTime(p.createdAt)}</span>,\n },\n ];\n\n const greetingName = currentUser?.firstName || currentUser?.name || 'there';\n const description = `Welcome back, ${greetingName} — your energy, mineral & commodity resource control room.`;\n\n // Full-page loader only while every primary domain is still loading its first page.\n const initialLoading =\n assets.isLoading &&\n contracts.isLoading &&\n emissions.isLoading &&\n inventory.isLoading &&\n compliance.isLoading;\n\n if (initialLoading) {\n return (\n <PageLayout title=\"TheGlobalFuel\" titleGradient aurora description={description}>\n <LoadingView label=\"Loading your resource portfolio…\" />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title=\"TheGlobalFuel\" titleGradient aurora description={description}>\n {/* KPI grid */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6\">\n <MetricsCard\n icon={<Layers className=\"h-5 w-5\" />}\n value={withPlus(assetRows, assets.data?.pageInfo?.hasMore)}\n label=\"Resource assets\"\n featured\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={assetRows.length ? (producingCount / assetRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-status-success-text\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{producingCount}</span> producing\n </p>\n </div>\n }\n />\n\n <MetricsCard\n icon={<ScrollText className=\"h-5 w-5\" />}\n value={withPlus(contractRows, contracts.data?.pageInfo?.hasMore)}\n label=\"Offtake contracts\"\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={contractRows.length ? (activeContracts / contractRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-action-primary-bg\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{activeContracts}</span> active\n </p>\n </div>\n }\n />\n\n <MetricsCard\n icon={<Ship className=\"h-5 w-5\" />}\n value={shipments.isError ? '—' : formatNumber(inTransitRows.length)}\n label=\"Shipments in transit\"\n footer={\n <p className=\"text-xs text-text-tertiary\">\n {inTransitRows.length > 0 ? 'In motion across carriers' : 'No active movements'}\n </p>\n }\n />\n\n <MetricsCard\n icon={<Factory className=\"h-5 w-5\" />}\n value={emissions.isError ? '—' : formatTonnesCo2e(totalTonnes)}\n label=\"Emissions logged\"\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={emissionRows.length ? (verifiedEmissions / emissionRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-status-success-text\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{verifiedEmissions}</span>{' '}\n verified\n </p>\n </div>\n }\n />\n\n <MetricsCard\n icon={<Boxes className=\"h-5 w-5\" />}\n value={inventory.isError ? '—' : formatNumber(availableLots)}\n label=\"Inventory available\"\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={inventoryRows.length ? (availableLots / inventoryRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-action-primary-bg\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">\n {withPlus(inventoryRows, inventory.data?.pageInfo?.hasMore)}\n </span>{' '}\n lots total\n </p>\n </div>\n }\n />\n\n <MetricsCard\n icon={<ShieldCheck className=\"h-5 w-5\" />}\n value={compliance.isError ? '—' : formatNumber(attentionCerts)}\n label=\"Certs need attention\"\n accent={attentionCerts > 0 ? 'warning' : certRows.length > 0 ? 'success' : undefined}\n footer={\n <p\n className={\n attentionCerts > 0\n ? 'text-xs font-medium text-status-warning-text'\n : 'text-xs text-text-tertiary'\n }\n >\n {certRows.length === 0\n ? 'No certifications tracked yet'\n : attentionCerts > 0\n ? `${pendingCerts} pending · ${expiringCerts} expiring`\n : 'All certifications current'}\n </p>\n }\n />\n </div>\n\n {/* Analytics — production trend + commodity mix (real aggregates) */}\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <ChartCard\n className=\"lg:col-span-2\"\n title=\"Production trend\"\n caption=\"Metered output aggregated by month across your producing assets.\"\n icon={<Activity className=\"h-4 w-4\" />}\n link={{ label: 'Production', onClick: () => navigateTo('production') }}\n isLoading={production.isLoading}\n isError={production.isError}\n onRetry={() => production.refetch()}\n isEmpty={productionSeries.length === 0}\n emptyLabel=\"No production logged yet — record output to build the trend.\"\n footer={\n productionSeries.length > 0\n ? `${formatNumber(totalProductionVolume, { maximumFractionDigits: 0 })} total volume across ${withPlus(productionRows, production.data?.pageInfo?.hasMore)} records`\n : undefined\n }\n >\n <AreaChart series={productionSeries} height={220} title=\"Monthly production volume\" />\n </ChartCard>\n\n <ChartCard\n title=\"Commodity mix\"\n caption=\"Share of assets across your commodity streams.\"\n icon={<Fuel className=\"h-4 w-4\" />}\n link={{ label: 'Assets', onClick: () => navigateTo('assets') }}\n isLoading={assets.isLoading}\n isError={assets.isError}\n onRetry={() => assets.refetch()}\n isEmpty={commodityMix.length === 0}\n emptyLabel=\"No assets registered yet.\"\n footer={\n commodityMix.length > 0\n ? `${withPlus(assetRows, assets.data?.pageInfo?.hasMore)} assets · ${commodityMix.length} ${commodityMix.length === 1 ? 'commodity' : 'commodities'}`\n : undefined\n }\n >\n <div className=\"flex items-center justify-center py-2\">\n <DonutChart\n segments={commodityMix}\n size={168}\n centerLabel={formatNumber(assetRows.length)}\n centerCaption=\"assets\"\n valueFormatter={(v) => formatNumber(v)}\n title=\"Assets by commodity\"\n />\n </div>\n </ChartCard>\n </div>\n\n {/* Commodity portfolio — one model, every commodity */}\n <Section\n title=\"Commodity portfolio\"\n description=\"One model, every commodity — assets, capacity and output across your book.\"\n >\n {assets.isLoading ? (\n <LoadingView label=\"Loading commodities…\" />\n ) : assets.isError ? (\n <ErrorView\n message=\"Couldn't load your commodity portfolio.\"\n onRetry={() => assets.refetch()}\n />\n ) : commodityCards.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Layers className=\"h-10 w-10\" />}\n title=\"No commodities yet\"\n description=\"Register your first resource asset to build out your commodity portfolio.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n {commodityCards.map((card) => (\n <CommodityCard key={card.key} card={card} onOpen={() => navigateTo('assets')} />\n ))}\n </div>\n )}\n </Section>\n\n {/* Lifecycle distribution + emissions by scope */}\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <DistributionCard\n title=\"Assets by lifecycle\"\n description=\"Where the portfolio sits from exploration to retirement.\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n linkLabel=\"Assets\"\n onLink={() => navigateTo('assets')}\n isLoading={assets.isLoading}\n isError={assets.isError}\n onRetry={() => assets.refetch()}\n emptyLabel=\"No assets to profile yet.\"\n bars={lifecycleBars}\n footer={\n assetRows.length > 0\n ? `${producingCount} of ${withPlus(assetRows, assets.data?.pageInfo?.hasMore)} currently producing`\n : undefined\n }\n />\n\n <ChartCard\n title=\"Emissions by scope\"\n caption=\"GHG Protocol Scope 1 / 2 / 3 — tonnes CO₂e logged.\"\n icon={<Gauge className=\"h-4 w-4\" />}\n link={{ label: 'Emissions', onClick: () => navigateTo('emissions') }}\n isLoading={emissions.isLoading}\n isError={emissions.isError}\n onRetry={() => emissions.refetch()}\n isEmpty={scopeMix.length === 0}\n emptyLabel=\"No emission records logged yet.\"\n footer={\n emissionRows.length > 0\n ? `${formatTonnesCo2e(totalTonnes)} across ${withPlus(emissionRows, emissions.data?.pageInfo?.hasMore)} records`\n : undefined\n }\n >\n <div className=\"flex items-center justify-center py-2\">\n <DonutChart\n segments={scopeMix}\n size={168}\n centerLabel={formatNumber(totalTonnes, {\n notation: 'compact',\n maximumFractionDigits: 1,\n })}\n centerCaption=\"t CO₂e\"\n valueFormatter={(v) =>\n `${formatNumber(v, { maximumFractionDigits: v >= 100 ? 0 : 1 })} t`\n }\n title=\"Emissions by scope\"\n />\n </div>\n </ChartCard>\n </div>\n\n {/* Recent offtake contracts */}\n <Section\n title=\"Recent offtake contracts\"\n description=\"Latest buy/sell agreements across your commodity book.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('contracts')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n All contracts <ArrowRight className=\"h-4 w-4\" />\n </button>\n }\n >\n {contracts.isLoading ? (\n <LoadingView label=\"Loading contracts…\" />\n ) : contracts.isError ? (\n <ErrorView message=\"Couldn't load contracts.\" onRetry={() => contracts.refetch()} />\n ) : recentContracts.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<ScrollText className=\"h-10 w-10\" />}\n title=\"No contracts yet\"\n description=\"Draft your first offtake contract to start tracking commodity trade.\"\n />\n ) : (\n <DataTable\n columns={contractColumns}\n rows={recentContracts}\n rowKey={(c) => c.id}\n onRowClick={(c) => navigateTo(`contracts/${c.id}`)}\n rowLabel={(c) => `Open contract ${c.reference}`}\n />\n )}\n </Section>\n\n {/* Recent production */}\n <Section\n title=\"Recent production\"\n description=\"Latest metered output captured against your producing assets.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('production')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n All production <ArrowRight className=\"h-4 w-4\" />\n </button>\n }\n >\n {production.isLoading ? (\n <LoadingView label=\"Loading production…\" />\n ) : production.isError ? (\n <ErrorView message=\"Couldn't load production records.\" onRetry={() => production.refetch()} />\n ) : recentProduction.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<ClipboardList className=\"h-10 w-10\" />}\n title=\"No production logged yet\"\n description=\"Record production against an asset to build its output history.\"\n />\n ) : (\n <DataTable\n columns={productionColumns}\n rows={recentProduction}\n rowKey={(p) => p.id}\n onRowClick={(p) => navigateTo(`assets/${p.assetId}`)}\n rowLabel={(p) => `Open ${assetName.get(p.assetId) ?? 'asset'}`}\n />\n )}\n </Section>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/dashboard/DashboardPage.tsx"],"sourcesContent":["/**\n * Dashboard — TheGlobalFuel resources operating-system overview.\n * @module theglobalfuel/pages/dashboard\n *\n * The hero landing (eager-loaded). Every figure is aggregated client-side from\n * the real `the*` list endpoints — no mock data. The page opens with the domain\n * KPI grid (registry / commerce / sustainability), then a rich analytics band:\n * - a PRODUCTION TREND area chart (metered output bucketed by month),\n * - a COMMODITY MIX donut (share of assets by commodity), and\n * - an EMISSIONS-BY-SCOPE donut (tonnes CO₂e per GHG scope);\n * a COMMODITY PORTFOLIO grid (one glass card per commodity present, with real\n * asset counts, summed capacity and a production sparkline); an ASSETS-BY-\n * LIFECYCLE distribution; and recent-activity tables. All charts derive from\n * the fetched arrays and degrade to pre-launch empty states.\n */\n\nimport { useMemo, useEffect, type ReactNode } from 'react';\nimport {\n Layers,\n ScrollText,\n Ship,\n Factory,\n Boxes,\n ShieldCheck,\n ArrowRight,\n ArrowUpRight,\n Fuel,\n GitBranch,\n Gauge,\n Activity,\n ClipboardList,\n} from 'lucide-react';\nimport { GlassCard, Spinner } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { MiniBar } from '../../components/MiniBar';\nimport { DataTable, type Column } from '../../components/DataTable';\nimport { LoadingView, ErrorView, Section } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport {\n AreaChart,\n DonutChart,\n Sparkline,\n chartPalette,\n type LabeledValue,\n type Segment,\n} from '../../components/viz';\nimport { cn } from '../../utils/cn';\nimport { useTheGlobalFuel } from '../../context';\nimport {\n useTheAssets,\n useTheContracts,\n useTheShipments,\n useTheEmissionRecords,\n useTheInventoryLots,\n useTheComplianceCerts,\n useTheProductionRecords,\n useTheAnalytics,\n} from '../../hooks';\nimport {\n formatNumber,\n formatPercent,\n formatDate,\n formatRelativeTime,\n formatEnumLabel,\n formatVolume,\n formatTonnesCo2e,\n isExpired,\n} from '../../utils/formatters';\nimport type {\n TheAssetStatus,\n TheCommodityType,\n TheEmissionScope,\n TheOfftakeContract,\n TheProductionRecord,\n} from '../../types';\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst EXPIRY_WINDOW_DAYS = 30;\n\n/** True when a cert expires within the next 30 days (but hasn't yet). */\nconst isExpiringSoon = (date: string | null | undefined): boolean => {\n if (!date) return false;\n const t = new Date(date).getTime();\n if (Number.isNaN(t)) return false;\n const diff = t - Date.now();\n return diff >= 0 && diff <= EXPIRY_WINDOW_DAYS * DAY_MS;\n};\n\n/** Asset lifecycle → MiniBar fill token (semantic, maturity-ordered). */\nconst ASSET_STATUS_BAR: Record<TheAssetStatus, string> = {\n EXPLORATION: 'bg-[var(--color-accent-indigo)]',\n APPRAISAL: 'bg-[var(--color-accent-blue)]',\n DEVELOPMENT: 'bg-[var(--color-accent-teal)]',\n PRODUCING: 'bg-status-success-text',\n SUSPENDED: 'bg-status-warning-text',\n DECOMMISSIONING: 'bg-status-error-text',\n RETIRED: 'bg-[var(--color-text-tertiary)]',\n};\n\n/** GHG scope → donut segment color token (Scope 1 direct · 2 energy · 3 chain). */\nconst SCOPE_COLOR: Record<TheEmissionScope, string> = {\n SCOPE_1: 'var(--color-status-error-text)',\n SCOPE_2: 'var(--color-status-warning-text)',\n SCOPE_3: 'var(--color-accent-blue)',\n};\n\nconst ALL_SCOPES: TheEmissionScope[] = ['SCOPE_1', 'SCOPE_2', 'SCOPE_3'];\n\n// ── Month bucketing (UTC-stable, gap-free) ───────────────────────────────────\n\n/** UTC year-month key (e.g. \"2026-07\"). */\nconst monthKey = (d: Date): string =>\n `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;\n\nconst MONTH_FMT = new Intl.DateTimeFormat(undefined, {\n month: 'short',\n year: '2-digit',\n timeZone: 'UTC',\n});\n\nconst monthLabel = (year: number, month1: number): string =>\n MONTH_FMT.format(new Date(Date.UTC(year, month1 - 1, 1)));\n\n/** Sum `valueOf` into UTC-month buckets keyed by the `dateOf` field. */\nfunction bucketByMonth<T>(\n rows: readonly T[],\n dateOf: (row: T) => string | null | undefined,\n valueOf: (row: T) => number\n): Map<string, number> {\n const buckets = new Map<string, number>();\n for (const row of rows) {\n const raw = dateOf(row);\n if (!raw) continue;\n const d = new Date(raw);\n if (Number.isNaN(d.getTime())) continue;\n const key = monthKey(d);\n buckets.set(key, (buckets.get(key) ?? 0) + valueOf(row));\n }\n return buckets;\n}\n\n/**\n * Expand month buckets into a gap-free ordered series from the earliest to the\n * latest populated month (so a trend line stays continuous), then keep only the\n * most recent `maxMonths` so a stray old record can't blow out the axis.\n */\nfunction monthlySeries(buckets: Map<string, number>, maxMonths = 18): LabeledValue[] {\n const keys = [...buckets.keys()].sort();\n if (keys.length === 0) return [];\n const parse = (k: string): [number, number] => {\n const [y, m] = k.split('-');\n return [Number(y), Number(m)];\n };\n const [maxY, maxM] = parse(keys[keys.length - 1]);\n let [y, m] = parse(keys[0]);\n const series: LabeledValue[] = [];\n let guard = 0;\n while ((y < maxY || (y === maxY && m <= maxM)) && guard < 240) {\n series.push({\n label: monthLabel(y, m),\n value: buckets.get(`${y}-${String(m).padStart(2, '0')}`) ?? 0,\n });\n m += 1;\n if (m > 12) {\n m = 1;\n y += 1;\n }\n guard += 1;\n }\n return series.length > maxMonths ? series.slice(series.length - maxMonths) : series;\n}\n\n/** Group rows by a discriminator, sorted by descending count, with % of total. */\nfunction distribution<T>(\n rows: T[],\n keyOf: (row: T) => string\n): { key: string; count: number; pct: number }[] {\n const counts = new Map<string, number>();\n for (const row of rows) {\n const k = keyOf(row);\n counts.set(k, (counts.get(k) ?? 0) + 1);\n }\n const total = rows.length;\n return [...counts.entries()]\n .sort((a, b) => b[1] - a[1])\n .map(([key, count]) => ({ key, count, pct: total ? (count / total) * 100 : 0 }));\n}\n\n// ── Distribution card (MiniBar rows) ─────────────────────────────────────────\n\ninterface DistBar {\n key: string;\n label: ReactNode;\n /** Pre-formatted primary figure shown right of the bar. */\n value: string;\n /** 0–100 — drives the bar width + the muted percentage. */\n pct: number;\n barClassName: string;\n}\n\ninterface DistributionCardProps {\n title: string;\n description: string;\n icon: ReactNode;\n linkLabel: string;\n onLink: () => void;\n isLoading: boolean;\n isError: boolean;\n onRetry: () => void;\n emptyLabel: string;\n bars: DistBar[];\n footer?: ReactNode;\n className?: string;\n}\n\n/** A titled glass card that renders a compact set of MiniBar distribution rows. */\nfunction DistributionCard({\n title,\n description,\n icon,\n linkLabel,\n onLink,\n isLoading,\n isError,\n onRetry,\n emptyLabel,\n bars,\n footer,\n className,\n}: DistributionCardProps) {\n return (\n <GlassCard treatment=\"glass\" className={cn('flex flex-col p-5', className)}>\n <div className=\"mb-4 flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 items-start gap-2.5\">\n <span className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n {icon}\n </span>\n <div className=\"min-w-0\">\n <h2 className=\"text-base font-semibold text-text-primary\">{title}</h2>\n <p className=\"mt-0.5 text-xs text-text-tertiary\">{description}</p>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={onLink}\n className=\"inline-flex shrink-0 items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n {linkLabel} <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n\n {isLoading ? (\n <div className=\"flex items-center gap-2 py-8 text-sm text-text-secondary\">\n <Spinner size=\"sm\" /> Loading…\n </div>\n ) : isError ? (\n <div className=\"flex flex-col items-start gap-2 py-6\">\n <p className=\"text-sm text-status-error-text\">Couldn't load {title.toLowerCase()}.</p>\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"rounded-lg border border-border-seam px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Retry\n </button>\n </div>\n ) : bars.length === 0 ? (\n <div className=\"flex flex-1 flex-col items-center justify-center rounded-xl border border-dashed border-border-seam py-8 text-center\">\n <p className=\"text-sm text-text-secondary\">{emptyLabel}</p>\n </div>\n ) : (\n <div className=\"flex flex-1 flex-col justify-between gap-4\">\n <div className=\"space-y-3\">\n {bars.map((bar) => (\n <div key={bar.key} className=\"flex items-center gap-3\">\n <div className=\"w-24 shrink-0 truncate text-sm text-text-secondary sm:w-28\">\n {bar.label}\n </div>\n <MiniBar value={bar.pct} barClassName={bar.barClassName} className=\"flex-1\" height={8} />\n <span className=\"w-16 shrink-0 whitespace-nowrap text-right text-sm font-medium tabular-nums text-text-primary\">\n {bar.value}\n </span>\n <span className=\"hidden w-11 shrink-0 text-right text-xs tabular-nums text-text-tertiary sm:inline\">\n {formatPercent(bar.pct)}\n </span>\n </div>\n ))}\n </div>\n {footer && (\n <p className=\"border-t border-border-seam/70 pt-3 text-xs text-text-tertiary\">{footer}</p>\n )}\n </div>\n )}\n </GlassCard>\n );\n}\n\n// ── Chart card (titled glass panel for a chart body) ─────────────────────────\n\ninterface ChartCardProps {\n title: string;\n caption: string;\n icon: ReactNode;\n link?: { label: string; onClick: () => void };\n isLoading: boolean;\n isError: boolean;\n onRetry: () => void;\n isEmpty: boolean;\n emptyLabel: string;\n footer?: ReactNode;\n className?: string;\n children: ReactNode;\n}\n\n/** A titled glass card wrapping a viz-kit chart, with loading/error/empty states. */\nfunction ChartCard({\n title,\n caption,\n icon,\n link,\n isLoading,\n isError,\n onRetry,\n isEmpty,\n emptyLabel,\n footer,\n className,\n children,\n}: ChartCardProps) {\n return (\n <GlassCard treatment=\"glass\" className={cn('flex flex-col p-5', className)}>\n <div className=\"mb-4 flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 items-start gap-2.5\">\n <span className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n {icon}\n </span>\n <div className=\"min-w-0\">\n <h2 className=\"text-base font-semibold text-text-primary\">{title}</h2>\n <p className=\"mt-0.5 text-xs text-text-tertiary\">{caption}</p>\n </div>\n </div>\n {link ? (\n <button\n type=\"button\"\n onClick={link.onClick}\n className=\"inline-flex shrink-0 items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n {link.label} <ArrowRight className=\"h-4 w-4\" />\n </button>\n ) : null}\n </div>\n\n {isLoading ? (\n <div className=\"flex flex-1 items-center gap-2 py-8 text-sm text-text-secondary\">\n <Spinner size=\"sm\" /> Loading…\n </div>\n ) : isError ? (\n <div className=\"flex flex-1 flex-col items-start gap-2 py-6\">\n <p className=\"text-sm text-status-error-text\">Couldn't load {title.toLowerCase()}.</p>\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"rounded-lg border border-border-seam px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Retry\n </button>\n </div>\n ) : isEmpty ? (\n <div className=\"flex flex-1 flex-col items-center justify-center rounded-xl border border-dashed border-border-seam py-10 text-center\">\n <p className=\"text-sm text-text-secondary\">{emptyLabel}</p>\n </div>\n ) : (\n <div className=\"flex flex-1 flex-col justify-between gap-4\">\n <div className=\"flex-1\">{children}</div>\n {footer ? (\n <p className=\"border-t border-border-seam/70 pt-3 text-xs text-text-tertiary\">{footer}</p>\n ) : null}\n </div>\n )}\n </GlassCard>\n );\n}\n\n// ── Commodity portfolio card ─────────────────────────────────────────────────\n\ninterface CommodityPortfolioEntry {\n key: TheCommodityType;\n name: string;\n /** Tokenized commodity color, shared with the commodity-mix donut. */\n color: string;\n assetCount: number;\n producing: number;\n capacity: number;\n /** Dominant `TheUnit` token across the commodity's assets. */\n unit: string;\n /** Monthly production volumes (oldest first) — empty when none logged. */\n spark: number[];\n}\n\nfunction CommodityCard({ card, onOpen }: { card: CommodityPortfolioEntry; onOpen: () => void }) {\n return (\n <GlassCard treatment=\"metric\" className=\"p-0\">\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${card.name} assets`}\n className=\"flex w-full flex-col gap-4 rounded-[var(--radius-card)] p-5 text-left outline-none transition-transform duration-200 hover:-translate-y-0.5 focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex min-w-0 items-center gap-2.5\">\n <span\n aria-hidden=\"true\"\n className=\"size-2.5 shrink-0 rounded-full\"\n style={{ backgroundColor: card.color }}\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold text-text-primary\">{card.name}</p>\n <p className=\"text-xs text-text-tertiary\">\n {card.assetCount} {card.assetCount === 1 ? 'asset' : 'assets'}\n </p>\n </div>\n </div>\n <ArrowUpRight className=\"h-4 w-4 shrink-0 text-text-tertiary\" />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"min-w-0\">\n <p className=\"text-[11px] uppercase tracking-wide text-text-tertiary\">Capacity/day</p>\n <p className=\"mt-0.5 truncate text-sm font-semibold tabular-nums text-text-primary\">\n {card.capacity > 0 ? formatVolume(card.capacity, card.unit) : '—'}\n </p>\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-[11px] uppercase tracking-wide text-text-tertiary\">Producing</p>\n <p className=\"mt-0.5 text-sm font-semibold tabular-nums text-text-primary\">\n {card.producing}{' '}\n <span className=\"text-xs font-normal text-text-tertiary\">of {card.assetCount}</span>\n </p>\n </div>\n </div>\n\n {card.spark.length >= 2 ? (\n <div>\n <Sparkline\n data={card.spark}\n variant=\"area\"\n height={40}\n label={`${card.name} monthly production`}\n />\n <p className=\"mt-1 text-[11px] text-text-tertiary\">Monthly output</p>\n </div>\n ) : (\n <p className=\"text-xs text-text-tertiary\">No production logged yet.</p>\n )}\n </button>\n </GlassCard>\n );\n}\n\nexport function DashboardPage() {\n const { navigateTo, currentUser } = useTheGlobalFuel();\n const { trackDashboardViewed } = useTheAnalytics();\n\n useEffect(() => {\n trackDashboardViewed();\n }, [trackDashboardViewed]);\n\n // Real backend queries. Aggregate domains fetch a generous page (200) so the\n // charts + portfolio reflect the whole book; commerce lists stay at 50.\n const assets = useTheAssets({ pagination: { limit: 200 } });\n const contracts = useTheContracts({ pagination: { limit: 50 } });\n const shipments = useTheShipments(undefined, 'IN_TRANSIT');\n const emissions = useTheEmissionRecords({ pagination: { limit: 200 } });\n const inventory = useTheInventoryLots({ pagination: { limit: 50 } });\n const compliance = useTheComplianceCerts();\n const production = useTheProductionRecords({ pagination: { limit: 200 } });\n\n const assetRows = useMemo(() => assets.data?.items ?? [], [assets.data]);\n const contractRows = useMemo(() => contracts.data?.items ?? [], [contracts.data]);\n const inTransitRows = useMemo(() => shipments.data?.items ?? [], [shipments.data]);\n const emissionRows = useMemo(() => emissions.data?.items ?? [], [emissions.data]);\n const inventoryRows = useMemo(() => inventory.data?.items ?? [], [inventory.data]);\n const certRows = useMemo(() => compliance.data?.items ?? [], [compliance.data]);\n const productionRows = useMemo(() => production.data?.items ?? [], [production.data]);\n\n // ── KPI aggregates ─────────────────────────────────────────────────────────\n const producingCount = assetRows.filter((a) => a.status === 'PRODUCING').length;\n const activeContracts = contractRows.filter((c) => c.status === 'ACTIVE').length;\n const totalTonnes = emissionRows.reduce((sum, e) => sum + (e.co2eTonnes ?? 0), 0);\n const verifiedEmissions = emissionRows.filter((e) => e.verified).length;\n const availableLots = inventoryRows.filter((l) => l.status === 'AVAILABLE').length;\n const totalProductionVolume = productionRows.reduce((sum, p) => sum + (p.volume ?? 0), 0);\n\n const pendingCerts = certRows.filter((c) => c.status === 'PENDING').length;\n const expiringCerts = certRows.filter(\n (c) => c.expiresAt != null && (isExpired(c.expiresAt) || isExpiringSoon(c.expiresAt))\n ).length;\n const attentionCerts = certRows.filter(\n (c) =>\n c.status === 'PENDING' ||\n (c.expiresAt != null && (isExpired(c.expiresAt) || isExpiringSoon(c.expiresAt)))\n ).length;\n\n const withPlus = (rows: unknown[], hasMore: boolean | undefined): string =>\n hasMore ? `${rows.length}+` : formatNumber(rows.length);\n\n // ── Production trend (metered output by month) ───────────────────────────────\n const productionSeries = useMemo<LabeledValue[]>(\n () =>\n monthlySeries(\n bucketByMonth(\n productionRows,\n (p) => p.periodEnd,\n (p) => p.volume ?? 0\n )\n ),\n [productionRows]\n );\n\n // ── Commodity distribution + shared per-commodity colors ─────────────────────\n const commodityDist = useMemo(() => distribution(assetRows, (a) => a.commodity), [assetRows]);\n\n const commodityColor = useMemo(() => {\n const palette = chartPalette(commodityDist.length);\n const map = new Map<string, string>();\n commodityDist.forEach((d, i) => map.set(d.key, palette[i]));\n return map;\n }, [commodityDist]);\n\n const commodityMix = useMemo<Segment[]>(\n () =>\n commodityDist.map((d) => ({\n label: formatEnumLabel(d.key),\n value: d.count,\n color: commodityColor.get(d.key),\n })),\n [commodityDist, commodityColor]\n );\n\n // ── Emissions by scope (tonnes CO₂e) ─────────────────────────────────────────\n const scopeMix = useMemo<Segment[]>(() => {\n if (emissionRows.length === 0) return [];\n const totals: Record<TheEmissionScope, number> = { SCOPE_1: 0, SCOPE_2: 0, SCOPE_3: 0 };\n for (const e of emissionRows) totals[e.scope] += e.co2eTonnes ?? 0;\n return ALL_SCOPES.filter((s) => totals[s] > 0).map((s) => ({\n label: formatEnumLabel(s),\n value: totals[s],\n color: SCOPE_COLOR[s],\n }));\n }, [emissionRows]);\n\n // ── Assets by lifecycle (MiniBar rows) ───────────────────────────────────────\n const lifecycleBars = useMemo<DistBar[]>(\n () =>\n distribution(assetRows, (a) => a.status).map((d) => ({\n key: d.key,\n label: <StatusBadge status={d.key} />,\n value: formatNumber(d.count),\n pct: d.pct,\n barClassName: ASSET_STATUS_BAR[d.key as TheAssetStatus] ?? 'bg-action-primary-bg',\n })),\n [assetRows]\n );\n\n // ── Commodity portfolio (one entry per commodity with assets) ────────────────\n const assetCommodity = useMemo(() => {\n const m = new Map<string, TheCommodityType>();\n for (const a of assetRows) m.set(a.id, a.commodity);\n return m;\n }, [assetRows]);\n\n const commodityCards = useMemo<CommodityPortfolioEntry[]>(() => {\n if (commodityDist.length === 0) return [];\n\n // Per-commodity asset aggregates.\n interface Agg {\n count: number;\n producing: number;\n capacity: number;\n units: Map<string, number>;\n }\n const agg = new Map<string, Agg>();\n for (const a of assetRows) {\n const cur =\n agg.get(a.commodity) ??\n { count: 0, producing: 0, capacity: 0, units: new Map<string, number>() };\n cur.count += 1;\n if (a.status === 'PRODUCING') cur.producing += 1;\n cur.capacity += a.capacityPerDay ?? 0;\n if (a.capacityUnit) cur.units.set(a.capacityUnit, (cur.units.get(a.capacityUnit) ?? 0) + 1);\n agg.set(a.commodity, cur);\n }\n\n // Per-commodity monthly production buckets → sparkline series.\n const prodBuckets = new Map<string, Map<string, number>>();\n for (const p of productionRows) {\n const commodity = assetCommodity.get(p.assetId);\n if (!commodity) continue;\n const d = new Date(p.periodEnd);\n if (Number.isNaN(d.getTime())) continue;\n const mk = monthKey(d);\n let bucket = prodBuckets.get(commodity);\n if (!bucket) {\n bucket = new Map<string, number>();\n prodBuckets.set(commodity, bucket);\n }\n bucket.set(mk, (bucket.get(mk) ?? 0) + (p.volume ?? 0));\n }\n\n const dominantUnit = (units: Map<string, number>): string => {\n let best = '';\n let bestN = -1;\n for (const [unit, n] of units) {\n if (n > bestN) {\n best = unit;\n bestN = n;\n }\n }\n return best;\n };\n\n return commodityDist.map((d) => {\n const a =\n agg.get(d.key) ??\n { count: 0, producing: 0, capacity: 0, units: new Map<string, number>() };\n const bucket = prodBuckets.get(d.key);\n const spark = bucket ? monthlySeries(bucket, 12).map((s) => s.value) : [];\n return {\n key: d.key as TheCommodityType,\n name: formatEnumLabel(d.key),\n color: commodityColor.get(d.key) ?? 'var(--color-accent-primary)',\n assetCount: a.count,\n producing: a.producing,\n capacity: a.capacity,\n unit: dominantUnit(a.units),\n spark,\n };\n });\n }, [assetRows, productionRows, assetCommodity, commodityDist, commodityColor]);\n\n // ── Recent activity ────────────────────────────────────────────────────────\n const assetName = useMemo(() => {\n const m = new Map<string, string>();\n for (const a of assetRows) m.set(a.id, a.name);\n return m;\n }, [assetRows]);\n\n const recentContracts = useMemo(\n () =>\n [...contractRows]\n .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())\n .slice(0, 6),\n [contractRows]\n );\n\n const recentProduction = useMemo(\n () =>\n [...productionRows]\n .sort((a, b) => new Date(b.periodEnd).getTime() - new Date(a.periodEnd).getTime())\n .slice(0, 6),\n [productionRows]\n );\n\n const contractColumns: Column<TheOfftakeContract>[] = [\n {\n key: 'reference',\n header: 'Reference',\n render: (c) => <span className=\"font-medium text-text-primary\">{c.reference}</span>,\n },\n {\n key: 'counterparty',\n header: 'Counterparty',\n hideOnMobile: true,\n render: (c) => <span className=\"text-text-secondary\">{c.counterparty}</span>,\n },\n {\n key: 'commodity',\n header: 'Commodity',\n hideOnMobile: true,\n render: (c) => <span className=\"text-text-secondary\">{formatEnumLabel(c.commodity)}</span>,\n },\n { key: 'side', header: 'Side', render: (c) => <StatusBadge status={c.side} /> },\n {\n key: 'volume',\n header: 'Volume',\n align: 'right',\n hideOnMobile: true,\n render: (c) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatVolume(c.contractedVolume, c.unit)}\n </span>\n ),\n },\n { key: 'status', header: 'Status', render: (c) => <StatusBadge status={c.status} /> },\n {\n key: 'created',\n header: 'Created',\n align: 'right',\n hideOnMobile: true,\n render: (c) => <span className=\"text-text-tertiary\">{formatRelativeTime(c.createdAt)}</span>,\n },\n ];\n\n const productionColumns: Column<TheProductionRecord>[] = [\n {\n key: 'asset',\n header: 'Asset',\n render: (p) => (\n <span className=\"font-medium text-text-primary\">\n {assetName.get(p.assetId) ?? 'Unknown asset'}\n </span>\n ),\n },\n {\n key: 'period',\n header: 'Period',\n hideOnMobile: true,\n render: (p) => (\n <span className=\"text-text-secondary\">\n {formatDate(p.periodStart)} – {formatDate(p.periodEnd)}\n </span>\n ),\n },\n {\n key: 'volume',\n header: 'Volume',\n align: 'right',\n render: (p) => (\n <span className=\"tabular-nums font-medium text-text-primary\">\n {formatVolume(p.volume, p.unit)}\n </span>\n ),\n },\n {\n key: 'downtime',\n header: 'Downtime',\n align: 'right',\n hideOnMobile: true,\n render: (p) => (\n <span className=\"tabular-nums text-text-secondary\">{formatNumber(p.downtimeHours)} h</span>\n ),\n },\n {\n key: 'logged',\n header: 'Logged',\n align: 'right',\n hideOnMobile: true,\n render: (p) => <span className=\"text-text-tertiary\">{formatRelativeTime(p.createdAt)}</span>,\n },\n ];\n\n const greetingName = currentUser?.firstName || currentUser?.name || 'there';\n const description = `Welcome back, ${greetingName} — your energy, mineral & commodity resource control room.`;\n\n // Full-page loader only while every primary domain is still loading its first page.\n const initialLoading =\n assets.isLoading &&\n contracts.isLoading &&\n emissions.isLoading &&\n inventory.isLoading &&\n compliance.isLoading;\n\n if (initialLoading) {\n return (\n <PageLayout title=\"TheGlobalFuel\" titleGradient aurora description={description}>\n <LoadingView label=\"Loading your resource portfolio…\" />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title=\"TheGlobalFuel\" titleGradient aurora description={description}>\n {/* KPI grid */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6\">\n <MetricsCard\n icon={<Layers className=\"h-5 w-5\" />}\n value={withPlus(assetRows, assets.data?.pageInfo?.hasMore)}\n label=\"Resource assets\"\n featured\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={assetRows.length ? (producingCount / assetRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-status-success-text\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{producingCount}</span> producing\n </p>\n </div>\n }\n />\n\n <MetricsCard\n icon={<ScrollText className=\"h-5 w-5\" />}\n value={withPlus(contractRows, contracts.data?.pageInfo?.hasMore)}\n label=\"Offtake contracts\"\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={contractRows.length ? (activeContracts / contractRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-action-primary-bg\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{activeContracts}</span> active\n </p>\n </div>\n }\n />\n\n <MetricsCard\n icon={<Ship className=\"h-5 w-5\" />}\n value={shipments.isError ? '—' : formatNumber(inTransitRows.length)}\n label=\"Shipments in transit\"\n footer={\n <p className=\"text-xs text-text-tertiary\">\n {inTransitRows.length > 0 ? 'In motion across carriers' : 'No active movements'}\n </p>\n }\n />\n\n <MetricsCard\n icon={<Factory className=\"h-5 w-5\" />}\n value={emissions.isError ? '—' : formatTonnesCo2e(totalTonnes)}\n label=\"Emissions logged\"\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={emissionRows.length ? (verifiedEmissions / emissionRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-status-success-text\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{verifiedEmissions}</span>{' '}\n verified\n </p>\n </div>\n }\n />\n\n <MetricsCard\n icon={<Boxes className=\"h-5 w-5\" />}\n value={inventory.isError ? '—' : formatNumber(availableLots)}\n label=\"Inventory available\"\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={inventoryRows.length ? (availableLots / inventoryRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-action-primary-bg\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">\n {withPlus(inventoryRows, inventory.data?.pageInfo?.hasMore)}\n </span>{' '}\n lots total\n </p>\n </div>\n }\n />\n\n <MetricsCard\n icon={<ShieldCheck className=\"h-5 w-5\" />}\n value={compliance.isError ? '—' : formatNumber(attentionCerts)}\n label=\"Certs need attention\"\n accent={attentionCerts > 0 ? 'warning' : certRows.length > 0 ? 'success' : undefined}\n footer={\n <p\n className={\n attentionCerts > 0\n ? 'text-xs font-medium text-status-warning-text'\n : 'text-xs text-text-tertiary'\n }\n >\n {certRows.length === 0\n ? 'No certifications tracked yet'\n : attentionCerts > 0\n ? `${pendingCerts} pending · ${expiringCerts} expiring`\n : 'All certifications current'}\n </p>\n }\n />\n </div>\n\n {/* Analytics — production trend + commodity mix (real aggregates) */}\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <ChartCard\n className=\"lg:col-span-2\"\n title=\"Production trend\"\n caption=\"Metered output aggregated by month across your producing assets.\"\n icon={<Activity className=\"h-4 w-4\" />}\n link={{ label: 'Production', onClick: () => navigateTo('production') }}\n isLoading={production.isLoading}\n isError={production.isError}\n onRetry={() => production.refetch()}\n isEmpty={productionSeries.length === 0}\n emptyLabel=\"No production logged yet — record output to build the trend.\"\n footer={\n productionSeries.length > 0\n ? `${formatNumber(totalProductionVolume, { maximumFractionDigits: 0 })} total volume across ${withPlus(productionRows, production.data?.pageInfo?.hasMore)} records`\n : undefined\n }\n >\n <AreaChart series={productionSeries} height={220} title=\"Monthly production volume\" />\n </ChartCard>\n\n <ChartCard\n title=\"Commodity mix\"\n caption=\"Share of assets across your commodity streams.\"\n icon={<Fuel className=\"h-4 w-4\" />}\n link={{ label: 'Assets', onClick: () => navigateTo('assets') }}\n isLoading={assets.isLoading}\n isError={assets.isError}\n onRetry={() => assets.refetch()}\n isEmpty={commodityMix.length === 0}\n emptyLabel=\"No assets registered yet.\"\n footer={\n commodityMix.length > 0\n ? `${withPlus(assetRows, assets.data?.pageInfo?.hasMore)} assets · ${commodityMix.length} ${commodityMix.length === 1 ? 'commodity' : 'commodities'}`\n : undefined\n }\n >\n <div className=\"flex items-center justify-center py-2\">\n <DonutChart\n segments={commodityMix}\n size={168}\n centerLabel={formatNumber(assetRows.length)}\n centerCaption=\"assets\"\n valueFormatter={(v) => formatNumber(v)}\n title=\"Assets by commodity\"\n />\n </div>\n </ChartCard>\n </div>\n\n {/* Commodity portfolio — one model, every commodity */}\n <Section\n title=\"Commodity portfolio\"\n description=\"One model, every commodity — assets, capacity and output across your book.\"\n >\n {assets.isLoading ? (\n <LoadingView label=\"Loading commodities…\" />\n ) : assets.isError ? (\n <ErrorView\n message=\"Couldn't load your commodity portfolio.\"\n onRetry={() => assets.refetch()}\n />\n ) : commodityCards.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Layers className=\"h-10 w-10\" />}\n title=\"No commodities yet\"\n description=\"Register your first resource asset to build out your commodity portfolio.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n {commodityCards.map((card) => (\n <CommodityCard key={card.key} card={card} onOpen={() => navigateTo('assets')} />\n ))}\n </div>\n )}\n </Section>\n\n {/* Lifecycle distribution + emissions by scope */}\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <DistributionCard\n title=\"Assets by lifecycle\"\n description=\"Where the portfolio sits from exploration to retirement.\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n linkLabel=\"Assets\"\n onLink={() => navigateTo('assets')}\n isLoading={assets.isLoading}\n isError={assets.isError}\n onRetry={() => assets.refetch()}\n emptyLabel=\"No assets to profile yet.\"\n bars={lifecycleBars}\n footer={\n assetRows.length > 0\n ? `${producingCount} of ${withPlus(assetRows, assets.data?.pageInfo?.hasMore)} currently producing`\n : undefined\n }\n />\n\n <ChartCard\n title=\"Emissions by scope\"\n caption=\"GHG Protocol Scope 1 / 2 / 3 — tonnes CO₂e logged.\"\n icon={<Gauge className=\"h-4 w-4\" />}\n link={{ label: 'Emissions', onClick: () => navigateTo('emissions') }}\n isLoading={emissions.isLoading}\n isError={emissions.isError}\n onRetry={() => emissions.refetch()}\n isEmpty={scopeMix.length === 0}\n emptyLabel=\"No emission records logged yet.\"\n footer={\n emissionRows.length > 0\n ? `${formatTonnesCo2e(totalTonnes)} across ${withPlus(emissionRows, emissions.data?.pageInfo?.hasMore)} records`\n : undefined\n }\n >\n <div className=\"flex items-center justify-center py-2\">\n <DonutChart\n segments={scopeMix}\n size={168}\n centerLabel={formatNumber(totalTonnes, {\n notation: 'compact',\n maximumFractionDigits: 1,\n })}\n centerCaption=\"t CO₂e\"\n valueFormatter={(v) =>\n `${formatNumber(v, { maximumFractionDigits: v >= 100 ? 0 : 1 })} t`\n }\n title=\"Emissions by scope\"\n />\n </div>\n </ChartCard>\n </div>\n\n {/* Recent offtake contracts */}\n <Section\n title=\"Recent offtake contracts\"\n description=\"Latest buy/sell agreements across your commodity book.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('contracts')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n All contracts <ArrowRight className=\"h-4 w-4\" />\n </button>\n }\n >\n {contracts.isLoading ? (\n <LoadingView label=\"Loading contracts…\" />\n ) : contracts.isError ? (\n <ErrorView message=\"Couldn't load contracts.\" onRetry={() => contracts.refetch()} />\n ) : recentContracts.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<ScrollText className=\"h-10 w-10\" />}\n title=\"No contracts yet\"\n description=\"Draft your first offtake contract to start tracking commodity trade.\"\n />\n ) : (\n <DataTable\n columns={contractColumns}\n rows={recentContracts}\n rowKey={(c) => c.id}\n onRowClick={(c) => navigateTo(`contracts/${c.id}`)}\n rowLabel={(c) => `Open contract ${c.reference}`}\n />\n )}\n </Section>\n\n {/* Recent production */}\n <Section\n title=\"Recent production\"\n description=\"Latest metered output captured against your producing assets.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('production')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n All production <ArrowRight className=\"h-4 w-4\" />\n </button>\n }\n >\n {production.isLoading ? (\n <LoadingView label=\"Loading production…\" />\n ) : production.isError ? (\n <ErrorView message=\"Couldn't load production records.\" onRetry={() => production.refetch()} />\n ) : recentProduction.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<ClipboardList className=\"h-10 w-10\" />}\n title=\"No production logged yet\"\n description=\"Record production against an asset to build its output history.\"\n />\n ) : (\n <DataTable\n columns={productionColumns}\n rows={recentProduction}\n rowKey={(p) => p.id}\n onRowClick={(p) => navigateTo(`assets/${p.assetId}`)}\n rowLabel={(p) => `Open ${assetName.get(p.assetId) ?? 'asset'}`}\n />\n )}\n </Section>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -111,7 +111,7 @@ function E({ icon: e, label: t, value: n, caption: r }) {
|
|
|
111
111
|
});
|
|
112
112
|
}
|
|
113
113
|
function D() {
|
|
114
|
-
let { navigateTo: d } = e(), C = ae({ pagination: x }), w = f(() => C.data?.items ?? [], [C.data]), [T, D] = fe(""),
|
|
114
|
+
let { navigateTo: d } = e(), C = ae({ pagination: x }), w = f(() => C.data?.items ?? [], [C.data]), [T, D] = fe(""), De = f(() => w.find((e) => e.status === "PRODUCING")?.id ?? w[0]?.id ?? "", [w]), O = T || De, k = ie(O || void 0), A = ue({ pagination: x }), j = le({
|
|
115
115
|
assetId: O || void 0,
|
|
116
116
|
pagination: x
|
|
117
117
|
}), M = oe(O || void 0, void 0, void 0, x), N = ce({
|
|
@@ -120,14 +120,14 @@ function D() {
|
|
|
120
120
|
}), P = f(() => {
|
|
121
121
|
let e = [...N.data?.items ?? []].sort(S((e) => e.createdAt));
|
|
122
122
|
return (e.find((e) => e.deliveredVolume > 0 && e.side === "SELL") ?? e.find((e) => e.deliveredVolume > 0) ?? e.find((e) => e.side === "SELL") ?? e[0])?.id;
|
|
123
|
-
}, [N.data]), F = se(P), I = f(() => [...k.data?.productionRecords ?? []].sort(S((e) => e.periodEnd)), [k.data]), L = I[0], R = f(() => (A.data?.items ?? []).filter((e) => e.assetId === O).sort(S((e) => e.producedAt)), [A.data, O]), z = R[0], B = f(() => F.data?.shipments ?? [], [F.data]), V = f(() => [...B].filter((e) => e.status === "DELIVERED").sort(S((e) => e.deliveredAt))[0], [B]), H = f(() => V ?? [...B].sort(S((e) => e.departedAt ?? e.scheduledAt))[0], [V, B]),
|
|
123
|
+
}, [N.data]), F = se(P), I = f(() => [...k.data?.productionRecords ?? []].sort(S((e) => e.periodEnd)), [k.data]), L = I[0], R = f(() => (A.data?.items ?? []).filter((e) => e.assetId === O).sort(S((e) => e.producedAt)), [A.data, O]), z = R[0], B = f(() => F.data?.shipments ?? [], [F.data]), V = f(() => [...B].filter((e) => e.status === "DELIVERED").sort(S((e) => e.deliveredAt))[0], [B]), H = f(() => V ?? [...B].sort(S((e) => e.departedAt ?? e.scheduledAt))[0], [V, B]), Oe = f(() => N.data?.items.find((e) => e.id === P), [N.data, P]), U = f(() => M.data?.items ?? [], [M.data]), W = f(() => U.find((e) => e.category === "CHAIN_OF_CUSTODY") ?? U.find((e) => e.status === "APPROVED") ?? U[0], [U]), G = W?.status === "APPROVED", ke = f(() => j.data?.items ?? [], [j.data]), Ae = ke.reduce((e, t) => e + (t.co2eTonnes ?? 0), 0), je = ke.filter((e) => e.verified).length, K = k.data, q = [
|
|
124
124
|
!!K,
|
|
125
125
|
I.length > 0,
|
|
126
126
|
R.length > 0,
|
|
127
127
|
!!H,
|
|
128
128
|
!!V,
|
|
129
129
|
G
|
|
130
|
-
],
|
|
130
|
+
], Me = q.filter(Boolean).length, J = q.findIndex((e) => !e), Ne = J === -1 ? q.length : J, Y = G && !!V, X = (e) => q[e] ? "done" : e === Ne ? "active" : "todo", Pe = [
|
|
131
131
|
{
|
|
132
132
|
label: "Asset",
|
|
133
133
|
description: "Origin"
|
|
@@ -152,7 +152,7 @@ function D() {
|
|
|
152
152
|
label: "Certificate",
|
|
153
153
|
description: "Verified"
|
|
154
154
|
}
|
|
155
|
-
], Z = H && (H.origin || H.destination) ? [H.origin, H.destination].filter(Boolean).join(" → ") : void 0,
|
|
155
|
+
], Z = H && (H.origin || H.destination) ? [H.origin, H.destination].filter(Boolean).join(" → ") : void 0, Fe = K ? [
|
|
156
156
|
{
|
|
157
157
|
step: 1,
|
|
158
158
|
icon: /* @__PURE__ */ v(g, {}),
|
|
@@ -198,7 +198,7 @@ function D() {
|
|
|
198
198
|
icon: /* @__PURE__ */ v(m, {}),
|
|
199
199
|
label: "Delivered",
|
|
200
200
|
primary: V ? s(V.volume, V.unit) : "Awaiting delivery",
|
|
201
|
-
secondary: V && [V.deliveredAt ? i(V.deliveredAt) : null,
|
|
201
|
+
secondary: V && [V.deliveredAt ? i(V.deliveredAt) : null, Oe ? `Contract ${Oe.reference}` : null].filter(Boolean).join(" · ") || void 0,
|
|
202
202
|
state: X(4),
|
|
203
203
|
present: !!V
|
|
204
204
|
},
|
|
@@ -213,7 +213,7 @@ function D() {
|
|
|
213
213
|
state: X(5),
|
|
214
214
|
present: !!W
|
|
215
215
|
}
|
|
216
|
-
] : [],
|
|
216
|
+
] : [], Ie = f(() => {
|
|
217
217
|
if (!K) return [];
|
|
218
218
|
let e = [], t = (t, n) => {
|
|
219
219
|
if (!t) return;
|
|
@@ -329,7 +329,7 @@ function D() {
|
|
|
329
329
|
})]
|
|
330
330
|
}), /* @__PURE__ */ y("div", {
|
|
331
331
|
className: t("flex items-center gap-2 self-start rounded-full px-3.5 py-1.5 text-sm font-medium", Y ? "bg-status-success-bg-subtle text-status-success-text" : "bg-bg-sunken text-text-secondary"),
|
|
332
|
-
children: [v(Y ? _ : ve, { className: "h-4 w-4" }), Y ? "Chain of custody verified" : `Traceability in progress · ${
|
|
332
|
+
children: [v(Y ? _ : ve, { className: "h-4 w-4" }), Y ? "Chain of custody verified" : `Traceability in progress · ${Me}/6`]
|
|
333
333
|
})]
|
|
334
334
|
}), k.isLoading ? /* @__PURE__ */ v("div", {
|
|
335
335
|
className: "mt-6",
|
|
@@ -345,13 +345,13 @@ function D() {
|
|
|
345
345
|
treatment: "glass",
|
|
346
346
|
className: "mt-6 p-5",
|
|
347
347
|
children: /* @__PURE__ */ v(re, {
|
|
348
|
-
steps:
|
|
349
|
-
current:
|
|
348
|
+
steps: Pe,
|
|
349
|
+
current: Ne
|
|
350
350
|
})
|
|
351
351
|
}),
|
|
352
352
|
/* @__PURE__ */ v("div", {
|
|
353
353
|
className: "mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6",
|
|
354
|
-
children:
|
|
354
|
+
children: Fe.map((e) => /* @__PURE__ */ v(Ee, { node: e }, e.step))
|
|
355
355
|
}),
|
|
356
356
|
/* @__PURE__ */ y("div", {
|
|
357
357
|
className: "mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
@@ -370,7 +370,7 @@ function D() {
|
|
|
370
370
|
className: "text-xs text-text-tertiary",
|
|
371
371
|
children: "Recorded custody events, oldest to newest."
|
|
372
372
|
})] })]
|
|
373
|
-
}),
|
|
373
|
+
}), Ie.length > 0 ? /* @__PURE__ */ v(ne, { items: Ie }) : /* @__PURE__ */ v("div", {
|
|
374
374
|
className: "rounded-xl border border-dashed border-border-seam py-8 text-center text-sm text-text-secondary",
|
|
375
375
|
children: "No dated custody events yet."
|
|
376
376
|
})]
|
|
@@ -434,8 +434,8 @@ function D() {
|
|
|
434
434
|
/* @__PURE__ */ v(E, {
|
|
435
435
|
icon: /* @__PURE__ */ v(pe, {}),
|
|
436
436
|
label: "Emissions",
|
|
437
|
-
value: j.isError ? "—" : ee(
|
|
438
|
-
caption: `${
|
|
437
|
+
value: j.isError ? "—" : ee(Ae),
|
|
438
|
+
caption: `${je} verified`
|
|
439
439
|
}),
|
|
440
440
|
/* @__PURE__ */ v(E, {
|
|
441
441
|
icon: /* @__PURE__ */ v(_, {}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProvenancePage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/provenance/ProvenancePage.tsx"],"sourcesContent":["/**\n * Provenance — chain-of-custody traceability (pit → port → certificate).\n * @module theglobalfuel/pages/provenance\n *\n * The flagship end-to-end traceability view. The user picks a resource asset and\n * we assemble its custody chain entirely from REAL linked records:\n * Asset (registry) → Production → Inventory lot → Shipment (+ document) →\n * Delivered → Chain-of-custody certificate (+ evidence)\n *\n * Sources — all `the*` endpoints, no mock data:\n * - useTheAsset(id) → the asset + nested productionRecords/reserves\n * - useTheInventoryLots() → filtered client-side to lot.assetId === id\n * - useTheEmissionRecords() → attributed emissions for the summary\n * - useTheComplianceCerts(id) → CHAIN_OF_CUSTODY / evidence certs\n * - useTheContracts({commodity}) + useTheContract() → offtake + nested shipments\n *\n * The chain renders as a StepProgress flow + a row of rich node cards (each\n * carrying the real record and a FileLink for its document/evidence), a Timeline\n * of the real dated events, an origin map and a provenance summary. Every stage\n * degrades gracefully when its downstream record does not exist yet (pre-launch).\n */\n\nimport { useMemo, useState, type ReactNode } from 'react';\nimport {\n Link2,\n MapPin,\n Gauge,\n Boxes,\n Ship,\n CheckCircle2,\n ShieldCheck,\n Shield,\n Fuel,\n Factory,\n Route,\n Layers,\n} from 'lucide-react';\nimport {\n GlassCard,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n LoadingView,\n ErrorView,\n EmptyState,\n FileLink,\n WorldMap,\n StepProgress,\n Timeline,\n type TimelineItem,\n type StepProgressStep,\n type PathStepState,\n} from '../../components';\nimport { useTheGlobalFuel } from '../../context';\nimport {\n useTheAssets,\n useTheAsset,\n useTheInventoryLots,\n useTheEmissionRecords,\n useTheComplianceCerts,\n useTheContracts,\n useTheContract,\n} from '../../hooks';\nimport { cn } from '../../utils/cn';\nimport {\n formatDate,\n formatVolume,\n formatEnumLabel,\n formatCoords,\n formatNumber,\n formatTonnesCo2e,\n} from '../../utils';\nimport type { TheProductionRecord, TheInventoryLot, TheShipment } from '../../types';\n\nconst PAGE: { limit: number } = { limit: 200 };\n\n/** Latest-first by an optional date field, falling back to createdAt. */\nfunction byDateDesc<T extends { createdAt: string }>(pick: (row: T) => string | null | undefined) {\n return (a: T, b: T): number => {\n const av = new Date(pick(a) ?? a.createdAt).getTime();\n const bv = new Date(pick(b) ?? b.createdAt).getTime();\n return bv - av;\n };\n}\n\n// ── Chain node card ──────────────────────────────────────────────────────────\n\ninterface ChainNodeVM {\n step: number;\n icon: ReactNode;\n label: string;\n /** Real primary value; shown muted as \"Pending\" when the artifact is absent. */\n primary: ReactNode;\n secondary?: ReactNode;\n badge?: ReactNode;\n fileId?: string | null;\n state: PathStepState;\n present: boolean;\n}\n\nconst NUMBER_STYLE: Record<PathStepState, string> = {\n done: 'bg-status-success-bg-subtle text-status-success-text',\n active: 'bg-[var(--color-accent-soft)] text-accent',\n todo: 'bg-bg-sunken text-text-muted',\n locked: 'bg-bg-sunken text-text-muted',\n};\n\nconst ICON_STYLE: Record<PathStepState, string> = {\n done: 'bg-status-success-bg-subtle text-status-success-text',\n active: 'bg-[var(--color-accent-soft)] text-accent',\n todo: 'bg-bg-sunken text-text-tertiary',\n locked: 'bg-bg-sunken text-text-tertiary',\n};\n\nconst DOT_STYLE: Record<PathStepState, string> = {\n done: 'bg-status-success-text',\n active: 'bg-[var(--color-accent-primary)] motion-safe:animate-vc-glow-pulse',\n todo: 'bg-border-strong',\n locked: 'bg-border-strong',\n};\n\nfunction ChainNodeCard({ node }: { node: ChainNodeVM }) {\n return (\n <GlassCard\n treatment=\"glass\"\n className={cn(\n 'relative flex h-full flex-col gap-3 p-5 transition-shadow',\n node.state === 'done' && 'shadow-[inset_0_2px_0_0_var(--color-status-success-text)]',\n node.state === 'active' && 'shadow-[inset_0_2px_0_0_var(--color-accent-primary)]'\n )}\n >\n <div className=\"flex items-center justify-between\">\n <span\n className={cn(\n 'flex size-7 items-center justify-center rounded-full text-xs font-semibold tabular-nums',\n NUMBER_STYLE[node.state]\n )}\n >\n {node.step}\n </span>\n <span aria-hidden=\"true\" className={cn('size-2 rounded-full', DOT_STYLE[node.state])} />\n </div>\n\n <span\n className={cn(\n 'flex size-11 items-center justify-center rounded-xl [&_svg]:size-6',\n ICON_STYLE[node.state]\n )}\n >\n {node.icon}\n </span>\n\n <div className=\"min-w-0\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-tertiary\">\n {node.label}\n </p>\n <p\n className={cn(\n 'mt-1 truncate text-base font-semibold',\n node.present ? 'text-text-primary' : 'text-text-muted'\n )}\n title={typeof node.primary === 'string' ? node.primary : undefined}\n >\n {node.present ? node.primary : 'Pending'}\n </p>\n {node.present && node.secondary && (\n <p className=\"mt-0.5 line-clamp-2 text-xs text-text-secondary\">{node.secondary}</p>\n )}\n </div>\n\n {(node.badge || (node.present && node.fileId)) && (\n <div className=\"mt-auto flex flex-wrap items-center gap-2 pt-1\">\n {node.badge}\n {node.present && node.fileId && <FileLink fileId={node.fileId} />}\n </div>\n )}\n </GlassCard>\n );\n}\n\n// ── Summary cell ─────────────────────────────────────────────────────────────\n\nfunction SummaryCell({\n icon,\n label,\n value,\n caption,\n}: {\n icon: ReactNode;\n label: string;\n value: ReactNode;\n caption?: ReactNode;\n}) {\n return (\n <div className=\"flex items-start gap-3\">\n <span className=\"mt-0.5 flex size-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent [&_svg]:size-4\">\n {icon}\n </span>\n <div className=\"min-w-0\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-tertiary\">{label}</p>\n <p className=\"mt-0.5 truncate text-sm font-semibold text-text-primary\">{value}</p>\n {caption && <p className=\"truncate text-xs text-text-tertiary\">{caption}</p>}\n </div>\n </div>\n );\n}\n\n// ── Page ─────────────────────────────────────────────────────────────────────\n\nexport function ProvenancePage() {\n const { navigateTo } = useTheGlobalFuel();\n\n const assets = useTheAssets({ pagination: PAGE });\n const assetRows = useMemo(() => assets.data?.items ?? [], [assets.data]);\n\n const [selectedAssetId, setSelectedAssetId] = useState<string>('');\n // Auto-focus the first asset (no effect needed) so the chain renders at once;\n // an explicit user selection always wins.\n const effectiveAssetId = selectedAssetId || assetRows[0]?.id || '';\n\n const asset = useTheAsset(effectiveAssetId || undefined);\n const inventory = useTheInventoryLots({ pagination: PAGE });\n const emissions = useTheEmissionRecords({\n assetId: effectiveAssetId || undefined,\n pagination: PAGE,\n });\n const compliance = useTheComplianceCerts(\n effectiveAssetId || undefined,\n undefined,\n undefined,\n PAGE\n );\n const contracts = useTheContracts({ commodity: asset.data?.commodity, pagination: PAGE });\n\n // Pick the contract most likely to carry a delivered shipment for this\n // commodity: prefer one that has already delivered volume (SELL first), else\n // the most recent. Its nested shipments give us the movement + delivery nodes.\n const pickedContractId = useMemo(() => {\n const rows = [...(contracts.data?.items ?? [])].sort(byDateDesc((c) => c.createdAt));\n const pick =\n rows.find((c) => c.deliveredVolume > 0 && c.side === 'SELL') ??\n rows.find((c) => c.deliveredVolume > 0) ??\n rows.find((c) => c.side === 'SELL') ??\n rows[0];\n return pick?.id;\n }, [contracts.data]);\n\n const contractDetail = useTheContract(pickedContractId);\n\n // ── Derive the chain from real linked records ──────────────────────────────\n const productionRecords = useMemo(\n () => [...(asset.data?.productionRecords ?? [])].sort(byDateDesc((r) => r.periodEnd)),\n [asset.data]\n );\n const latestProduction: TheProductionRecord | undefined = productionRecords[0];\n\n const assetLots = useMemo<TheInventoryLot[]>(\n () =>\n (inventory.data?.items ?? [])\n .filter((l) => l.assetId === effectiveAssetId)\n .sort(byDateDesc((l) => l.producedAt)),\n [inventory.data, effectiveAssetId]\n );\n const latestLot: TheInventoryLot | undefined = assetLots[0];\n\n const shipments = useMemo<TheShipment[]>(\n () => contractDetail.data?.shipments ?? [],\n [contractDetail.data]\n );\n const deliveredShipment = useMemo<TheShipment | undefined>(\n () =>\n [...shipments]\n .filter((s) => s.status === 'DELIVERED')\n .sort(byDateDesc((s) => s.deliveredAt))[0],\n [shipments]\n );\n const primaryShipment = useMemo<TheShipment | undefined>(\n () =>\n deliveredShipment ?? [...shipments].sort(byDateDesc((s) => s.departedAt ?? s.scheduledAt))[0],\n [deliveredShipment, shipments]\n );\n const pickedContract = useMemo(\n () => contracts.data?.items.find((c) => c.id === pickedContractId),\n [contracts.data, pickedContractId]\n );\n\n const certRows = useMemo(() => compliance.data?.items ?? [], [compliance.data]);\n const custodyCert = useMemo(\n () =>\n certRows.find((c) => c.category === 'CHAIN_OF_CUSTODY') ??\n certRows.find((c) => c.status === 'APPROVED') ??\n certRows[0],\n [certRows]\n );\n const certApproved = custodyCert?.status === 'APPROVED';\n\n const emissionRows = useMemo(() => emissions.data?.items ?? [], [emissions.data]);\n const totalTonnes = emissionRows.reduce((sum, e) => sum + (e.co2eTonnes ?? 0), 0);\n const verifiedEmissions = emissionRows.filter((e) => e.verified).length;\n\n const a = asset.data;\n\n // Stage completeness, in chain order.\n const completeFlags = [\n Boolean(a),\n productionRecords.length > 0,\n assetLots.length > 0,\n Boolean(primaryShipment),\n Boolean(deliveredShipment),\n certApproved,\n ];\n const completeCount = completeFlags.filter(Boolean).length;\n const firstIncomplete = completeFlags.findIndex((f) => !f);\n const current = firstIncomplete === -1 ? completeFlags.length : firstIncomplete;\n const verified = certApproved && Boolean(deliveredShipment);\n\n const stateFor = (i: number): PathStepState =>\n completeFlags[i] ? 'done' : i === current ? 'active' : 'todo';\n\n const progressSteps: StepProgressStep[] = [\n { label: 'Asset', description: 'Origin' },\n { label: 'Production', description: 'Extracted' },\n { label: 'Inventory', description: 'Lotted' },\n { label: 'Shipment', description: 'In transit' },\n { label: 'Delivered', description: 'Received' },\n { label: 'Certificate', description: 'Verified' },\n ];\n\n const shipmentRoute =\n primaryShipment && (primaryShipment.origin || primaryShipment.destination)\n ? [primaryShipment.origin, primaryShipment.destination].filter(Boolean).join(' → ')\n : undefined;\n\n const nodes: ChainNodeVM[] = a\n ? [\n {\n step: 1,\n icon: <MapPin />,\n label: 'Asset',\n primary: a.name,\n secondary: a.location ?? formatCoords(a.latitude, a.longitude),\n badge: <StatusBadge status={a.status} />,\n state: stateFor(0),\n present: true,\n },\n {\n step: 2,\n icon: <Gauge />,\n label: 'Production',\n primary: latestProduction\n ? formatVolume(latestProduction.volume, latestProduction.unit)\n : 'Not yet recorded',\n secondary: latestProduction\n ? `${formatDate(latestProduction.periodStart)} – ${formatDate(latestProduction.periodEnd)}`\n : undefined,\n state: stateFor(1),\n present: Boolean(latestProduction),\n },\n {\n step: 3,\n icon: <Boxes />,\n label: 'Inventory lot',\n primary: latestLot ? latestLot.lotCode : 'No lot yet',\n secondary: latestLot ? formatVolume(latestLot.quantity, latestLot.unit) : undefined,\n badge: latestLot ? <StatusBadge status={latestLot.status} /> : undefined,\n state: stateFor(2),\n present: Boolean(latestLot),\n },\n {\n step: 4,\n icon: <Ship />,\n label: 'Shipment',\n primary: primaryShipment ? primaryShipment.reference : 'Not shipped',\n secondary: primaryShipment\n ? [formatEnumLabel(primaryShipment.mode), shipmentRoute].filter(Boolean).join(' · ')\n : undefined,\n badge: primaryShipment ? <StatusBadge status={primaryShipment.status} /> : undefined,\n fileId: primaryShipment?.document?.id,\n state: stateFor(3),\n present: Boolean(primaryShipment),\n },\n {\n step: 5,\n icon: <CheckCircle2 />,\n label: 'Delivered',\n primary: deliveredShipment\n ? formatVolume(deliveredShipment.volume, deliveredShipment.unit)\n : 'Awaiting delivery',\n secondary: deliveredShipment\n ? [\n deliveredShipment.deliveredAt ? formatDate(deliveredShipment.deliveredAt) : null,\n pickedContract ? `Contract ${pickedContract.reference}` : null,\n ]\n .filter(Boolean)\n .join(' · ') || undefined\n : undefined,\n state: stateFor(4),\n present: Boolean(deliveredShipment),\n },\n {\n step: 6,\n icon: <ShieldCheck />,\n label: 'Certificate',\n primary: custodyCert ? (custodyCert.certNumber ?? custodyCert.title) : 'No certificate',\n secondary: custodyCert ? formatEnumLabel(custodyCert.category) : undefined,\n badge: custodyCert ? <StatusBadge status={custodyCert.status} /> : undefined,\n fileId: custodyCert?.evidence?.id,\n state: stateFor(5),\n present: Boolean(custodyCert),\n },\n ]\n : [];\n\n // ── Timeline (real dated events, ascending) ────────────────────────────────\n const timelineItems = useMemo<TimelineItem[]>(() => {\n if (!a) return [];\n const raw: { date: string; item: Omit<TimelineItem, 'time'> }[] = [];\n const push = (date: string | null | undefined, item: Omit<TimelineItem, 'time'>) => {\n if (!date) return;\n const t = new Date(date).getTime();\n if (Number.isNaN(t)) return;\n raw.push({ date, item });\n };\n\n push(a.commissionedAt ?? a.createdAt, {\n title: 'Asset registered',\n meta: a.name,\n tone: 'accent',\n icon: <MapPin className=\"h-3 w-3\" />,\n });\n if (latestProduction) {\n push(latestProduction.periodEnd ?? latestProduction.createdAt, {\n title: 'Production recorded',\n meta: formatVolume(latestProduction.volume, latestProduction.unit),\n tone: 'info',\n icon: <Gauge className=\"h-3 w-3\" />,\n });\n }\n if (latestLot) {\n push(latestLot.producedAt ?? latestLot.createdAt, {\n title: 'Inventory lot created',\n meta: `${latestLot.lotCode} · ${formatVolume(latestLot.quantity, latestLot.unit)}`,\n tone: 'info',\n icon: <Boxes className=\"h-3 w-3\" />,\n });\n }\n if (primaryShipment) {\n push(primaryShipment.departedAt ?? primaryShipment.scheduledAt ?? primaryShipment.createdAt, {\n title: primaryShipment.departedAt ? 'Shipment departed' : 'Shipment scheduled',\n meta: [primaryShipment.reference, shipmentRoute].filter(Boolean).join(' · '),\n tone: 'accent',\n icon: <Ship className=\"h-3 w-3\" />,\n });\n }\n if (deliveredShipment?.deliveredAt) {\n push(deliveredShipment.deliveredAt, {\n title: 'Delivered',\n meta: formatVolume(deliveredShipment.volume, deliveredShipment.unit),\n tone: 'success',\n icon: <CheckCircle2 className=\"h-3 w-3\" />,\n });\n }\n if (custodyCert) {\n push(custodyCert.issuedAt ?? custodyCert.createdAt, {\n title: certApproved ? 'Certificate approved' : 'Certificate registered',\n meta: custodyCert.certNumber ?? custodyCert.title,\n tone: certApproved ? 'success' : 'warning',\n icon: <ShieldCheck className=\"h-3 w-3\" />,\n });\n }\n\n return raw\n .sort((x, y) => new Date(x.date).getTime() - new Date(y.date).getTime())\n .map(({ date, item }) => ({ ...item, time: formatDate(date) }));\n }, [\n a,\n latestProduction,\n latestLot,\n primaryShipment,\n deliveredShipment,\n custodyCert,\n certApproved,\n shipmentRoute,\n ]);\n\n const originPoint =\n a && typeof a.latitude === 'number' && typeof a.longitude === 'number'\n ? { lat: a.latitude, lng: a.longitude, label: a.name, primary: true }\n : null;\n\n const description =\n 'Pit to port to certificate — end-to-end traceability from origin to verified certificate.';\n\n // ── Render ─────────────────────────────────────────────────────────────────\n if (assets.isLoading && assetRows.length === 0) {\n return (\n <PageLayout title=\"Provenance\" description={description}>\n <LoadingView label=\"Loading assets…\" />\n </PageLayout>\n );\n }\n if (assets.isError) {\n return (\n <PageLayout title=\"Provenance\" description={description}>\n <ErrorView message=\"Couldn't load assets to trace.\" onRetry={() => assets.refetch()} />\n </PageLayout>\n );\n }\n if (assetRows.length === 0) {\n return (\n <PageLayout title=\"Provenance\" description={description}>\n <EmptyState\n illustration=\"empty-data\"\n icon={<Link2 className=\"h-10 w-10\" />}\n title=\"No assets to trace\"\n description=\"Register a resource asset to build its end-to-end chain of custody.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('assets')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n Go to assets\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title=\"Provenance\" description={description}>\n {/* Control bar: asset picker + trust state */}\n <GlassCard\n treatment=\"glass\"\n className=\"flex flex-col gap-4 p-5 sm:flex-row sm:items-center sm:justify-between\"\n >\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <label\n htmlFor=\"provenance-asset\"\n className=\"text-xs font-medium uppercase tracking-wide text-text-tertiary\"\n >\n Trace asset\n </label>\n <Select value={effectiveAssetId} onValueChange={setSelectedAssetId}>\n <SelectTrigger\n id=\"provenance-asset\"\n className=\"h-10 w-full sm:w-96\"\n aria-label=\"Select an asset to trace\"\n >\n <SelectValue placeholder=\"Select an asset to trace\" />\n </SelectTrigger>\n <SelectContent>\n {assetRows.map((row) => (\n <SelectItem key={row.id} value={row.id}>\n {row.name} · {formatEnumLabel(row.commodity)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div\n className={cn(\n 'flex items-center gap-2 self-start rounded-full px-3.5 py-1.5 text-sm font-medium',\n verified\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-bg-sunken text-text-secondary'\n )}\n >\n {verified ? <ShieldCheck className=\"h-4 w-4\" /> : <Shield className=\"h-4 w-4\" />}\n {verified ? 'Chain of custody verified' : `Traceability in progress · ${completeCount}/6`}\n </div>\n </GlassCard>\n\n {asset.isLoading ? (\n <div className=\"mt-6\">\n <LoadingView label=\"Assembling chain of custody…\" />\n </div>\n ) : asset.isError || !a ? (\n <div className=\"mt-6\">\n <ErrorView\n message=\"Couldn't load this asset's provenance.\"\n onRetry={() => asset.refetch()}\n />\n </div>\n ) : (\n <>\n {/* Flow ribbon */}\n <GlassCard treatment=\"glass\" className=\"mt-6 p-5\">\n <StepProgress steps={progressSteps} current={current} />\n </GlassCard>\n\n {/* Chain nodes */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6\">\n {nodes.map((node) => (\n <ChainNodeCard key={node.step} node={node} />\n ))}\n </div>\n\n {/* Timeline + origin */}\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <GlassCard treatment=\"glass\" className=\"p-5 lg:col-span-2\">\n <div className=\"mb-4 flex items-center gap-2.5\">\n <span className=\"flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n <Route className=\"h-4 w-4\" />\n </span>\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">\n Traceability timeline\n </h2>\n <p className=\"text-xs text-text-tertiary\">\n Recorded custody events, oldest to newest.\n </p>\n </div>\n </div>\n {timelineItems.length > 0 ? (\n <Timeline items={timelineItems} />\n ) : (\n <div className=\"rounded-xl border border-dashed border-border-seam py-8 text-center text-sm text-text-secondary\">\n No dated custody events yet.\n </div>\n )}\n </GlassCard>\n\n <GlassCard treatment=\"glass\" className=\"flex flex-col gap-4 p-5\">\n <div className=\"flex items-center gap-2.5\">\n <span className=\"flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n <MapPin className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0\">\n <h2 className=\"text-base font-semibold text-text-primary\">Origin</h2>\n <p className=\"truncate text-xs text-text-tertiary\">\n {a.location ?? formatEnumLabel(a.kind)}\n </p>\n </div>\n </div>\n {originPoint ? (\n <WorldMap points={[originPoint]} />\n ) : (\n <div className=\"rounded-xl border border-dashed border-border-seam py-8 text-center text-sm text-text-secondary\">\n No coordinates recorded for this asset.\n </div>\n )}\n </GlassCard>\n </div>\n\n {/* Provenance summary */}\n <GlassCard treatment=\"glass\" className=\"mt-6 p-5\">\n <h2 className=\"mb-4 text-base font-semibold text-text-primary\">Provenance summary</h2>\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6\">\n <SummaryCell\n icon={<Fuel />}\n label=\"Commodity\"\n value={formatEnumLabel(a.commodity)}\n caption={formatEnumLabel(a.kind)}\n />\n <SummaryCell\n icon={<MapPin />}\n label=\"Origin\"\n value={a.location ?? a.name}\n caption={formatCoords(a.latitude, a.longitude)}\n />\n <SummaryCell\n icon={<Gauge />}\n label=\"Production\"\n value={`${formatNumber(productionRecords.length)} records`}\n caption={\n latestProduction\n ? `Latest ${formatVolume(latestProduction.volume, latestProduction.unit)}`\n : 'None yet'\n }\n />\n <SummaryCell\n icon={<Boxes />}\n label=\"Inventory\"\n value={`${formatNumber(assetLots.length)} lots`}\n caption={latestLot ? latestLot.lotCode : 'None yet'}\n />\n <SummaryCell\n icon={<Factory />}\n label=\"Emissions\"\n value={emissions.isError ? '—' : formatTonnesCo2e(totalTonnes)}\n caption={`${verifiedEmissions} verified`}\n />\n <SummaryCell\n icon={<ShieldCheck />}\n label=\"Certificates\"\n value={`${formatNumber(certRows.length)} tracked`}\n caption={\n certApproved ? 'Custody approved' : custodyCert ? 'Under review' : 'None yet'\n }\n />\n </div>\n </GlassCard>\n\n {/* Reserves footnote — surface proved reserves when present */}\n {(a.reserveEstimates?.length ?? 0) > 0 && (\n <p className=\"mt-4 flex items-center gap-1.5 text-xs text-text-tertiary\">\n <Layers className=\"h-3.5 w-3.5\" />\n {formatNumber(a.reserveEstimates?.length ?? 0)} reserve estimate\n {(a.reserveEstimates?.length ?? 0) === 1 ? '' : 's'} on record for this asset.\n </p>\n )}\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProvenancePage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/provenance/ProvenancePage.tsx"],"sourcesContent":["/**\n * Provenance — chain-of-custody traceability (pit → port → certificate).\n * @module theglobalfuel/pages/provenance\n *\n * The flagship end-to-end traceability view. The user picks a resource asset and\n * we assemble its custody chain entirely from REAL linked records:\n * Asset (registry) → Production → Inventory lot → Shipment (+ document) →\n * Delivered → Chain-of-custody certificate (+ evidence)\n *\n * Sources — all `the*` endpoints, no mock data:\n * - useTheAsset(id) → the asset + nested productionRecords/reserves\n * - useTheInventoryLots() → filtered client-side to lot.assetId === id\n * - useTheEmissionRecords() → attributed emissions for the summary\n * - useTheComplianceCerts(id) → CHAIN_OF_CUSTODY / evidence certs\n * - useTheContracts({commodity}) + useTheContract() → offtake + nested shipments\n *\n * The chain renders as a StepProgress flow + a row of rich node cards (each\n * carrying the real record and a FileLink for its document/evidence), a Timeline\n * of the real dated events, an origin map and a provenance summary. Every stage\n * degrades gracefully when its downstream record does not exist yet (pre-launch).\n */\n\nimport { useMemo, useState, type ReactNode } from 'react';\nimport {\n Link2,\n MapPin,\n Gauge,\n Boxes,\n Ship,\n CheckCircle2,\n ShieldCheck,\n Shield,\n Fuel,\n Factory,\n Route,\n Layers,\n} from 'lucide-react';\nimport {\n GlassCard,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n LoadingView,\n ErrorView,\n EmptyState,\n FileLink,\n WorldMap,\n StepProgress,\n Timeline,\n type TimelineItem,\n type StepProgressStep,\n type PathStepState,\n} from '../../components';\nimport { useTheGlobalFuel } from '../../context';\nimport {\n useTheAssets,\n useTheAsset,\n useTheInventoryLots,\n useTheEmissionRecords,\n useTheComplianceCerts,\n useTheContracts,\n useTheContract,\n} from '../../hooks';\nimport { cn } from '../../utils/cn';\nimport {\n formatDate,\n formatVolume,\n formatEnumLabel,\n formatCoords,\n formatNumber,\n formatTonnesCo2e,\n} from '../../utils';\nimport type { TheProductionRecord, TheInventoryLot, TheShipment } from '../../types';\n\nconst PAGE: { limit: number } = { limit: 200 };\n\n/** Latest-first by an optional date field, falling back to createdAt. */\nfunction byDateDesc<T extends { createdAt: string }>(pick: (row: T) => string | null | undefined) {\n return (a: T, b: T): number => {\n const av = new Date(pick(a) ?? a.createdAt).getTime();\n const bv = new Date(pick(b) ?? b.createdAt).getTime();\n return bv - av;\n };\n}\n\n// ── Chain node card ──────────────────────────────────────────────────────────\n\ninterface ChainNodeVM {\n step: number;\n icon: ReactNode;\n label: string;\n /** Real primary value; shown muted as \"Pending\" when the artifact is absent. */\n primary: ReactNode;\n secondary?: ReactNode;\n badge?: ReactNode;\n fileId?: string | null;\n state: PathStepState;\n present: boolean;\n}\n\nconst NUMBER_STYLE: Record<PathStepState, string> = {\n done: 'bg-status-success-bg-subtle text-status-success-text',\n active: 'bg-[var(--color-accent-soft)] text-accent',\n todo: 'bg-bg-sunken text-text-muted',\n locked: 'bg-bg-sunken text-text-muted',\n};\n\nconst ICON_STYLE: Record<PathStepState, string> = {\n done: 'bg-status-success-bg-subtle text-status-success-text',\n active: 'bg-[var(--color-accent-soft)] text-accent',\n todo: 'bg-bg-sunken text-text-tertiary',\n locked: 'bg-bg-sunken text-text-tertiary',\n};\n\nconst DOT_STYLE: Record<PathStepState, string> = {\n done: 'bg-status-success-text',\n active: 'bg-[var(--color-accent-primary)] motion-safe:animate-vc-glow-pulse',\n todo: 'bg-border-strong',\n locked: 'bg-border-strong',\n};\n\nfunction ChainNodeCard({ node }: { node: ChainNodeVM }) {\n return (\n <GlassCard\n treatment=\"glass\"\n className={cn(\n 'relative flex h-full flex-col gap-3 p-5 transition-shadow',\n node.state === 'done' && 'shadow-[inset_0_2px_0_0_var(--color-status-success-text)]',\n node.state === 'active' && 'shadow-[inset_0_2px_0_0_var(--color-accent-primary)]'\n )}\n >\n <div className=\"flex items-center justify-between\">\n <span\n className={cn(\n 'flex size-7 items-center justify-center rounded-full text-xs font-semibold tabular-nums',\n NUMBER_STYLE[node.state]\n )}\n >\n {node.step}\n </span>\n <span aria-hidden=\"true\" className={cn('size-2 rounded-full', DOT_STYLE[node.state])} />\n </div>\n\n <span\n className={cn(\n 'flex size-11 items-center justify-center rounded-xl [&_svg]:size-6',\n ICON_STYLE[node.state]\n )}\n >\n {node.icon}\n </span>\n\n <div className=\"min-w-0\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-tertiary\">\n {node.label}\n </p>\n <p\n className={cn(\n 'mt-1 truncate text-base font-semibold',\n node.present ? 'text-text-primary' : 'text-text-muted'\n )}\n title={typeof node.primary === 'string' ? node.primary : undefined}\n >\n {node.present ? node.primary : 'Pending'}\n </p>\n {node.present && node.secondary && (\n <p className=\"mt-0.5 line-clamp-2 text-xs text-text-secondary\">{node.secondary}</p>\n )}\n </div>\n\n {(node.badge || (node.present && node.fileId)) && (\n <div className=\"mt-auto flex flex-wrap items-center gap-2 pt-1\">\n {node.badge}\n {node.present && node.fileId && <FileLink fileId={node.fileId} />}\n </div>\n )}\n </GlassCard>\n );\n}\n\n// ── Summary cell ─────────────────────────────────────────────────────────────\n\nfunction SummaryCell({\n icon,\n label,\n value,\n caption,\n}: {\n icon: ReactNode;\n label: string;\n value: ReactNode;\n caption?: ReactNode;\n}) {\n return (\n <div className=\"flex items-start gap-3\">\n <span className=\"mt-0.5 flex size-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent [&_svg]:size-4\">\n {icon}\n </span>\n <div className=\"min-w-0\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-tertiary\">{label}</p>\n <p className=\"mt-0.5 truncate text-sm font-semibold text-text-primary\">{value}</p>\n {caption && <p className=\"truncate text-xs text-text-tertiary\">{caption}</p>}\n </div>\n </div>\n );\n}\n\n// ── Page ─────────────────────────────────────────────────────────────────────\n\nexport function ProvenancePage() {\n const { navigateTo } = useTheGlobalFuel();\n\n const assets = useTheAssets({ pagination: PAGE });\n const assetRows = useMemo(() => assets.data?.items ?? [], [assets.data]);\n\n const [selectedAssetId, setSelectedAssetId] = useState<string>('');\n // Auto-focus a *producing* asset first (no effect needed) — those carry the\n // downstream production / shipment / certificate activity, so the chain reads\n // as a real, populated trace on first paint instead of a string of \"Pending\"\n // nodes. Falls back to the first asset. An explicit user selection always wins.\n const defaultAssetId = useMemo(() => {\n const producing = assetRows.find((a) => a.status === 'PRODUCING');\n return producing?.id ?? assetRows[0]?.id ?? '';\n }, [assetRows]);\n const effectiveAssetId = selectedAssetId || defaultAssetId;\n\n const asset = useTheAsset(effectiveAssetId || undefined);\n const inventory = useTheInventoryLots({ pagination: PAGE });\n const emissions = useTheEmissionRecords({\n assetId: effectiveAssetId || undefined,\n pagination: PAGE,\n });\n const compliance = useTheComplianceCerts(\n effectiveAssetId || undefined,\n undefined,\n undefined,\n PAGE\n );\n const contracts = useTheContracts({ commodity: asset.data?.commodity, pagination: PAGE });\n\n // Pick the contract most likely to carry a delivered shipment for this\n // commodity: prefer one that has already delivered volume (SELL first), else\n // the most recent. Its nested shipments give us the movement + delivery nodes.\n const pickedContractId = useMemo(() => {\n const rows = [...(contracts.data?.items ?? [])].sort(byDateDesc((c) => c.createdAt));\n const pick =\n rows.find((c) => c.deliveredVolume > 0 && c.side === 'SELL') ??\n rows.find((c) => c.deliveredVolume > 0) ??\n rows.find((c) => c.side === 'SELL') ??\n rows[0];\n return pick?.id;\n }, [contracts.data]);\n\n const contractDetail = useTheContract(pickedContractId);\n\n // ── Derive the chain from real linked records ──────────────────────────────\n const productionRecords = useMemo(\n () => [...(asset.data?.productionRecords ?? [])].sort(byDateDesc((r) => r.periodEnd)),\n [asset.data]\n );\n const latestProduction: TheProductionRecord | undefined = productionRecords[0];\n\n const assetLots = useMemo<TheInventoryLot[]>(\n () =>\n (inventory.data?.items ?? [])\n .filter((l) => l.assetId === effectiveAssetId)\n .sort(byDateDesc((l) => l.producedAt)),\n [inventory.data, effectiveAssetId]\n );\n const latestLot: TheInventoryLot | undefined = assetLots[0];\n\n const shipments = useMemo<TheShipment[]>(\n () => contractDetail.data?.shipments ?? [],\n [contractDetail.data]\n );\n const deliveredShipment = useMemo<TheShipment | undefined>(\n () =>\n [...shipments]\n .filter((s) => s.status === 'DELIVERED')\n .sort(byDateDesc((s) => s.deliveredAt))[0],\n [shipments]\n );\n const primaryShipment = useMemo<TheShipment | undefined>(\n () =>\n deliveredShipment ?? [...shipments].sort(byDateDesc((s) => s.departedAt ?? s.scheduledAt))[0],\n [deliveredShipment, shipments]\n );\n const pickedContract = useMemo(\n () => contracts.data?.items.find((c) => c.id === pickedContractId),\n [contracts.data, pickedContractId]\n );\n\n const certRows = useMemo(() => compliance.data?.items ?? [], [compliance.data]);\n const custodyCert = useMemo(\n () =>\n certRows.find((c) => c.category === 'CHAIN_OF_CUSTODY') ??\n certRows.find((c) => c.status === 'APPROVED') ??\n certRows[0],\n [certRows]\n );\n const certApproved = custodyCert?.status === 'APPROVED';\n\n const emissionRows = useMemo(() => emissions.data?.items ?? [], [emissions.data]);\n const totalTonnes = emissionRows.reduce((sum, e) => sum + (e.co2eTonnes ?? 0), 0);\n const verifiedEmissions = emissionRows.filter((e) => e.verified).length;\n\n const a = asset.data;\n\n // Stage completeness, in chain order.\n const completeFlags = [\n Boolean(a),\n productionRecords.length > 0,\n assetLots.length > 0,\n Boolean(primaryShipment),\n Boolean(deliveredShipment),\n certApproved,\n ];\n const completeCount = completeFlags.filter(Boolean).length;\n const firstIncomplete = completeFlags.findIndex((f) => !f);\n const current = firstIncomplete === -1 ? completeFlags.length : firstIncomplete;\n const verified = certApproved && Boolean(deliveredShipment);\n\n const stateFor = (i: number): PathStepState =>\n completeFlags[i] ? 'done' : i === current ? 'active' : 'todo';\n\n const progressSteps: StepProgressStep[] = [\n { label: 'Asset', description: 'Origin' },\n { label: 'Production', description: 'Extracted' },\n { label: 'Inventory', description: 'Lotted' },\n { label: 'Shipment', description: 'In transit' },\n { label: 'Delivered', description: 'Received' },\n { label: 'Certificate', description: 'Verified' },\n ];\n\n const shipmentRoute =\n primaryShipment && (primaryShipment.origin || primaryShipment.destination)\n ? [primaryShipment.origin, primaryShipment.destination].filter(Boolean).join(' → ')\n : undefined;\n\n const nodes: ChainNodeVM[] = a\n ? [\n {\n step: 1,\n icon: <MapPin />,\n label: 'Asset',\n primary: a.name,\n secondary: a.location ?? formatCoords(a.latitude, a.longitude),\n badge: <StatusBadge status={a.status} />,\n state: stateFor(0),\n present: true,\n },\n {\n step: 2,\n icon: <Gauge />,\n label: 'Production',\n primary: latestProduction\n ? formatVolume(latestProduction.volume, latestProduction.unit)\n : 'Not yet recorded',\n secondary: latestProduction\n ? `${formatDate(latestProduction.periodStart)} – ${formatDate(latestProduction.periodEnd)}`\n : undefined,\n state: stateFor(1),\n present: Boolean(latestProduction),\n },\n {\n step: 3,\n icon: <Boxes />,\n label: 'Inventory lot',\n primary: latestLot ? latestLot.lotCode : 'No lot yet',\n secondary: latestLot ? formatVolume(latestLot.quantity, latestLot.unit) : undefined,\n badge: latestLot ? <StatusBadge status={latestLot.status} /> : undefined,\n state: stateFor(2),\n present: Boolean(latestLot),\n },\n {\n step: 4,\n icon: <Ship />,\n label: 'Shipment',\n primary: primaryShipment ? primaryShipment.reference : 'Not shipped',\n secondary: primaryShipment\n ? [formatEnumLabel(primaryShipment.mode), shipmentRoute].filter(Boolean).join(' · ')\n : undefined,\n badge: primaryShipment ? <StatusBadge status={primaryShipment.status} /> : undefined,\n fileId: primaryShipment?.document?.id,\n state: stateFor(3),\n present: Boolean(primaryShipment),\n },\n {\n step: 5,\n icon: <CheckCircle2 />,\n label: 'Delivered',\n primary: deliveredShipment\n ? formatVolume(deliveredShipment.volume, deliveredShipment.unit)\n : 'Awaiting delivery',\n secondary: deliveredShipment\n ? [\n deliveredShipment.deliveredAt ? formatDate(deliveredShipment.deliveredAt) : null,\n pickedContract ? `Contract ${pickedContract.reference}` : null,\n ]\n .filter(Boolean)\n .join(' · ') || undefined\n : undefined,\n state: stateFor(4),\n present: Boolean(deliveredShipment),\n },\n {\n step: 6,\n icon: <ShieldCheck />,\n label: 'Certificate',\n primary: custodyCert ? (custodyCert.certNumber ?? custodyCert.title) : 'No certificate',\n secondary: custodyCert ? formatEnumLabel(custodyCert.category) : undefined,\n badge: custodyCert ? <StatusBadge status={custodyCert.status} /> : undefined,\n fileId: custodyCert?.evidence?.id,\n state: stateFor(5),\n present: Boolean(custodyCert),\n },\n ]\n : [];\n\n // ── Timeline (real dated events, ascending) ────────────────────────────────\n const timelineItems = useMemo<TimelineItem[]>(() => {\n if (!a) return [];\n const raw: { date: string; item: Omit<TimelineItem, 'time'> }[] = [];\n const push = (date: string | null | undefined, item: Omit<TimelineItem, 'time'>) => {\n if (!date) return;\n const t = new Date(date).getTime();\n if (Number.isNaN(t)) return;\n raw.push({ date, item });\n };\n\n push(a.commissionedAt ?? a.createdAt, {\n title: 'Asset registered',\n meta: a.name,\n tone: 'accent',\n icon: <MapPin className=\"h-3 w-3\" />,\n });\n if (latestProduction) {\n push(latestProduction.periodEnd ?? latestProduction.createdAt, {\n title: 'Production recorded',\n meta: formatVolume(latestProduction.volume, latestProduction.unit),\n tone: 'info',\n icon: <Gauge className=\"h-3 w-3\" />,\n });\n }\n if (latestLot) {\n push(latestLot.producedAt ?? latestLot.createdAt, {\n title: 'Inventory lot created',\n meta: `${latestLot.lotCode} · ${formatVolume(latestLot.quantity, latestLot.unit)}`,\n tone: 'info',\n icon: <Boxes className=\"h-3 w-3\" />,\n });\n }\n if (primaryShipment) {\n push(primaryShipment.departedAt ?? primaryShipment.scheduledAt ?? primaryShipment.createdAt, {\n title: primaryShipment.departedAt ? 'Shipment departed' : 'Shipment scheduled',\n meta: [primaryShipment.reference, shipmentRoute].filter(Boolean).join(' · '),\n tone: 'accent',\n icon: <Ship className=\"h-3 w-3\" />,\n });\n }\n if (deliveredShipment?.deliveredAt) {\n push(deliveredShipment.deliveredAt, {\n title: 'Delivered',\n meta: formatVolume(deliveredShipment.volume, deliveredShipment.unit),\n tone: 'success',\n icon: <CheckCircle2 className=\"h-3 w-3\" />,\n });\n }\n if (custodyCert) {\n push(custodyCert.issuedAt ?? custodyCert.createdAt, {\n title: certApproved ? 'Certificate approved' : 'Certificate registered',\n meta: custodyCert.certNumber ?? custodyCert.title,\n tone: certApproved ? 'success' : 'warning',\n icon: <ShieldCheck className=\"h-3 w-3\" />,\n });\n }\n\n return raw\n .sort((x, y) => new Date(x.date).getTime() - new Date(y.date).getTime())\n .map(({ date, item }) => ({ ...item, time: formatDate(date) }));\n }, [\n a,\n latestProduction,\n latestLot,\n primaryShipment,\n deliveredShipment,\n custodyCert,\n certApproved,\n shipmentRoute,\n ]);\n\n const originPoint =\n a && typeof a.latitude === 'number' && typeof a.longitude === 'number'\n ? { lat: a.latitude, lng: a.longitude, label: a.name, primary: true }\n : null;\n\n const description =\n 'Pit to port to certificate — end-to-end traceability from origin to verified certificate.';\n\n // ── Render ─────────────────────────────────────────────────────────────────\n if (assets.isLoading && assetRows.length === 0) {\n return (\n <PageLayout title=\"Provenance\" description={description}>\n <LoadingView label=\"Loading assets…\" />\n </PageLayout>\n );\n }\n if (assets.isError) {\n return (\n <PageLayout title=\"Provenance\" description={description}>\n <ErrorView message=\"Couldn't load assets to trace.\" onRetry={() => assets.refetch()} />\n </PageLayout>\n );\n }\n if (assetRows.length === 0) {\n return (\n <PageLayout title=\"Provenance\" description={description}>\n <EmptyState\n illustration=\"empty-data\"\n icon={<Link2 className=\"h-10 w-10\" />}\n title=\"No assets to trace\"\n description=\"Register a resource asset to build its end-to-end chain of custody.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('assets')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n Go to assets\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title=\"Provenance\" description={description}>\n {/* Control bar: asset picker + trust state */}\n <GlassCard\n treatment=\"glass\"\n className=\"flex flex-col gap-4 p-5 sm:flex-row sm:items-center sm:justify-between\"\n >\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <label\n htmlFor=\"provenance-asset\"\n className=\"text-xs font-medium uppercase tracking-wide text-text-tertiary\"\n >\n Trace asset\n </label>\n <Select value={effectiveAssetId} onValueChange={setSelectedAssetId}>\n <SelectTrigger\n id=\"provenance-asset\"\n className=\"h-10 w-full sm:w-96\"\n aria-label=\"Select an asset to trace\"\n >\n <SelectValue placeholder=\"Select an asset to trace\" />\n </SelectTrigger>\n <SelectContent>\n {assetRows.map((row) => (\n <SelectItem key={row.id} value={row.id}>\n {row.name} · {formatEnumLabel(row.commodity)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div\n className={cn(\n 'flex items-center gap-2 self-start rounded-full px-3.5 py-1.5 text-sm font-medium',\n verified\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-bg-sunken text-text-secondary'\n )}\n >\n {verified ? <ShieldCheck className=\"h-4 w-4\" /> : <Shield className=\"h-4 w-4\" />}\n {verified ? 'Chain of custody verified' : `Traceability in progress · ${completeCount}/6`}\n </div>\n </GlassCard>\n\n {asset.isLoading ? (\n <div className=\"mt-6\">\n <LoadingView label=\"Assembling chain of custody…\" />\n </div>\n ) : asset.isError || !a ? (\n <div className=\"mt-6\">\n <ErrorView\n message=\"Couldn't load this asset's provenance.\"\n onRetry={() => asset.refetch()}\n />\n </div>\n ) : (\n <>\n {/* Flow ribbon */}\n <GlassCard treatment=\"glass\" className=\"mt-6 p-5\">\n <StepProgress steps={progressSteps} current={current} />\n </GlassCard>\n\n {/* Chain nodes */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6\">\n {nodes.map((node) => (\n <ChainNodeCard key={node.step} node={node} />\n ))}\n </div>\n\n {/* Timeline + origin */}\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <GlassCard treatment=\"glass\" className=\"p-5 lg:col-span-2\">\n <div className=\"mb-4 flex items-center gap-2.5\">\n <span className=\"flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n <Route className=\"h-4 w-4\" />\n </span>\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">\n Traceability timeline\n </h2>\n <p className=\"text-xs text-text-tertiary\">\n Recorded custody events, oldest to newest.\n </p>\n </div>\n </div>\n {timelineItems.length > 0 ? (\n <Timeline items={timelineItems} />\n ) : (\n <div className=\"rounded-xl border border-dashed border-border-seam py-8 text-center text-sm text-text-secondary\">\n No dated custody events yet.\n </div>\n )}\n </GlassCard>\n\n <GlassCard treatment=\"glass\" className=\"flex flex-col gap-4 p-5\">\n <div className=\"flex items-center gap-2.5\">\n <span className=\"flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n <MapPin className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0\">\n <h2 className=\"text-base font-semibold text-text-primary\">Origin</h2>\n <p className=\"truncate text-xs text-text-tertiary\">\n {a.location ?? formatEnumLabel(a.kind)}\n </p>\n </div>\n </div>\n {originPoint ? (\n <WorldMap points={[originPoint]} />\n ) : (\n <div className=\"rounded-xl border border-dashed border-border-seam py-8 text-center text-sm text-text-secondary\">\n No coordinates recorded for this asset.\n </div>\n )}\n </GlassCard>\n </div>\n\n {/* Provenance summary */}\n <GlassCard treatment=\"glass\" className=\"mt-6 p-5\">\n <h2 className=\"mb-4 text-base font-semibold text-text-primary\">Provenance summary</h2>\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6\">\n <SummaryCell\n icon={<Fuel />}\n label=\"Commodity\"\n value={formatEnumLabel(a.commodity)}\n caption={formatEnumLabel(a.kind)}\n />\n <SummaryCell\n icon={<MapPin />}\n label=\"Origin\"\n value={a.location ?? a.name}\n caption={formatCoords(a.latitude, a.longitude)}\n />\n <SummaryCell\n icon={<Gauge />}\n label=\"Production\"\n value={`${formatNumber(productionRecords.length)} records`}\n caption={\n latestProduction\n ? `Latest ${formatVolume(latestProduction.volume, latestProduction.unit)}`\n : 'None yet'\n }\n />\n <SummaryCell\n icon={<Boxes />}\n label=\"Inventory\"\n value={`${formatNumber(assetLots.length)} lots`}\n caption={latestLot ? latestLot.lotCode : 'None yet'}\n />\n <SummaryCell\n icon={<Factory />}\n label=\"Emissions\"\n value={emissions.isError ? '—' : formatTonnesCo2e(totalTonnes)}\n caption={`${verifiedEmissions} verified`}\n />\n <SummaryCell\n icon={<ShieldCheck />}\n label=\"Certificates\"\n value={`${formatNumber(certRows.length)} tracked`}\n caption={\n certApproved ? 'Custody approved' : custodyCert ? 'Under review' : 'None yet'\n }\n />\n </div>\n </GlassCard>\n\n {/* Reserves footnote — surface proved reserves when present */}\n {(a.reserveEstimates?.length ?? 0) > 0 && (\n <p className=\"mt-4 flex items-center gap-1.5 text-xs text-text-tertiary\">\n <Layers className=\"h-3.5 w-3.5\" />\n {formatNumber(a.reserveEstimates?.length ?? 0)} reserve estimate\n {(a.reserveEstimates?.length ?? 0) === 1 ? '' : 's'} on record for this asset.\n </p>\n )}\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|