@burdenoff/microfe-theglobalfuel 2026.704.1 → 2026.705.2
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/node_modules/{.bun/clsx@2.1.1/node_modules/clsx → clsx}/dist/clsx.js +1 -1
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
- package/dist/node_modules/{.bun/tailwind-merge@3.5.0/node_modules/tailwind-merge → tailwind-merge}/dist/bundle-mjs.js +212 -170
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
- package/dist/theglobalfuel/components/DataTable.js +37 -27
- package/dist/theglobalfuel/components/DataTable.js.map +1 -1
- package/dist/theglobalfuel/hooks/index.js +1 -0
- package/dist/theglobalfuel/hooks/useNotify.js +19 -0
- package/dist/theglobalfuel/hooks/useNotify.js.map +1 -0
- package/dist/theglobalfuel/hooks/useTheFiles.js +4 -1
- package/dist/theglobalfuel/hooks/useTheFiles.js.map +1 -1
- package/dist/theglobalfuel/hooks/useTheGlobalFuelApi.js +59 -31
- package/dist/theglobalfuel/hooks/useTheGlobalFuelApi.js.map +1 -1
- package/dist/theglobalfuel/pages/assets/AssetDetailPage.js +367 -321
- package/dist/theglobalfuel/pages/assets/AssetDetailPage.js.map +1 -1
- package/dist/theglobalfuel/pages/assets/AssetsPage.js +66 -54
- package/dist/theglobalfuel/pages/assets/AssetsPage.js.map +1 -1
- package/dist/theglobalfuel/pages/compliance/CompliancePage.js +346 -182
- package/dist/theglobalfuel/pages/compliance/CompliancePage.js.map +1 -1
- package/dist/theglobalfuel/pages/contracts/ContractDetailPage.js +418 -390
- package/dist/theglobalfuel/pages/contracts/ContractDetailPage.js.map +1 -1
- package/dist/theglobalfuel/pages/contracts/ContractsPage.js +238 -230
- package/dist/theglobalfuel/pages/contracts/ContractsPage.js.map +1 -1
- package/dist/theglobalfuel/pages/dashboard/DashboardPage.js +5 -3
- package/dist/theglobalfuel/pages/dashboard/DashboardPage.js.map +1 -1
- package/dist/theglobalfuel/pages/emissions/EmissionsPage.js +201 -177
- package/dist/theglobalfuel/pages/emissions/EmissionsPage.js.map +1 -1
- package/dist/theglobalfuel/pages/inventory/InventoryPage.js +271 -238
- package/dist/theglobalfuel/pages/inventory/InventoryPage.js.map +1 -1
- package/dist/theglobalfuel/pages/production/ProductionPage.js +185 -177
- package/dist/theglobalfuel/pages/production/ProductionPage.js.map +1 -1
- package/dist/theglobalfuel/pages/reserves/ReservesPage.js +160 -138
- package/dist/theglobalfuel/pages/reserves/ReservesPage.js.map +1 -1
- package/dist/theglobalfuel/pages/shipments/ShipmentsPage.js +250 -198
- package/dist/theglobalfuel/pages/shipments/ShipmentsPage.js.map +1 -1
- package/dist/theglobalfuel/utils/cn.js +2 -2
- package/dist/theglobalfuel/utils/formatters.js +6 -1
- package/dist/theglobalfuel/utils/formatters.js.map +1 -1
- package/dist/theglobalfuel/utils/transitions.js +70 -0
- package/dist/theglobalfuel/utils/transitions.js.map +1 -0
- package/package.json +1 -1
- package/dist/dev/main.d.ts +0 -2
- package/dist/dev/main.d.ts.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/node_modules/.bun/clsx@2.1.1/node_modules/clsx/dist/clsx.js.map +0 -1
- package/dist/node_modules/.bun/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.js.map +0 -1
- package/dist/theglobalfuel/TheGlobalFuelRoot.d.ts +0 -5
- package/dist/theglobalfuel/TheGlobalFuelRoot.d.ts.map +0 -1
- package/dist/theglobalfuel/TheGlobalFuelRoutes.d.ts +0 -4
- package/dist/theglobalfuel/TheGlobalFuelRoutes.d.ts.map +0 -1
- package/dist/theglobalfuel/components/DataTable.d.ts +0 -28
- package/dist/theglobalfuel/components/DataTable.d.ts.map +0 -1
- package/dist/theglobalfuel/components/EmptyState.d.ts +0 -18
- package/dist/theglobalfuel/components/EmptyState.d.ts.map +0 -1
- package/dist/theglobalfuel/components/EvidenceUpload.d.ts +0 -14
- package/dist/theglobalfuel/components/EvidenceUpload.d.ts.map +0 -1
- package/dist/theglobalfuel/components/FileLink.d.ts +0 -15
- package/dist/theglobalfuel/components/FileLink.d.ts.map +0 -1
- package/dist/theglobalfuel/components/FilterTabs.d.ts +0 -18
- package/dist/theglobalfuel/components/FilterTabs.d.ts.map +0 -1
- package/dist/theglobalfuel/components/MetricsCard.d.ts +0 -23
- package/dist/theglobalfuel/components/MetricsCard.d.ts.map +0 -1
- package/dist/theglobalfuel/components/MiniBar.d.ts +0 -16
- package/dist/theglobalfuel/components/MiniBar.d.ts.map +0 -1
- package/dist/theglobalfuel/components/PageLayout.d.ts +0 -16
- package/dist/theglobalfuel/components/PageLayout.d.ts.map +0 -1
- package/dist/theglobalfuel/components/Pagination.d.ts +0 -22
- package/dist/theglobalfuel/components/Pagination.d.ts.map +0 -1
- package/dist/theglobalfuel/components/StateViews.d.ts +0 -24
- package/dist/theglobalfuel/components/StateViews.d.ts.map +0 -1
- package/dist/theglobalfuel/components/StatusBadge.d.ts +0 -9
- package/dist/theglobalfuel/components/StatusBadge.d.ts.map +0 -1
- package/dist/theglobalfuel/components/Tabs.d.ts +0 -17
- package/dist/theglobalfuel/components/Tabs.d.ts.map +0 -1
- package/dist/theglobalfuel/components/TheDiscussion.d.ts +0 -18
- package/dist/theglobalfuel/components/TheDiscussion.d.ts.map +0 -1
- package/dist/theglobalfuel/components/TheTags.d.ts +0 -17
- package/dist/theglobalfuel/components/TheTags.d.ts.map +0 -1
- package/dist/theglobalfuel/components/index.d.ts +0 -19
- package/dist/theglobalfuel/components/index.d.ts.map +0 -1
- package/dist/theglobalfuel/context/TheGlobalFuelContext.d.ts +0 -16
- package/dist/theglobalfuel/context/TheGlobalFuelContext.d.ts.map +0 -1
- package/dist/theglobalfuel/context/index.d.ts +0 -6
- package/dist/theglobalfuel/context/index.d.ts.map +0 -1
- package/dist/theglobalfuel/hooks/index.d.ts +0 -10
- package/dist/theglobalfuel/hooks/index.d.ts.map +0 -1
- package/dist/theglobalfuel/hooks/useCursorPager.d.ts +0 -33
- package/dist/theglobalfuel/hooks/useCursorPager.d.ts.map +0 -1
- package/dist/theglobalfuel/hooks/useTheComments.d.ts +0 -36
- package/dist/theglobalfuel/hooks/useTheComments.d.ts.map +0 -1
- package/dist/theglobalfuel/hooks/useTheFiles.d.ts +0 -47
- package/dist/theglobalfuel/hooks/useTheFiles.d.ts.map +0 -1
- package/dist/theglobalfuel/hooks/useTheGlobalFuelApi.d.ts +0 -75
- package/dist/theglobalfuel/hooks/useTheGlobalFuelApi.d.ts.map +0 -1
- package/dist/theglobalfuel/hooks/useTheTags.d.ts +0 -44
- package/dist/theglobalfuel/hooks/useTheTags.d.ts.map +0 -1
- package/dist/theglobalfuel/index.d.ts +0 -9
- package/dist/theglobalfuel/index.d.ts.map +0 -1
- package/dist/theglobalfuel/pages/assets/AssetDetailPage.d.ts +0 -13
- package/dist/theglobalfuel/pages/assets/AssetDetailPage.d.ts.map +0 -1
- package/dist/theglobalfuel/pages/assets/AssetsPage.d.ts +0 -10
- package/dist/theglobalfuel/pages/assets/AssetsPage.d.ts.map +0 -1
- package/dist/theglobalfuel/pages/compliance/CompliancePage.d.ts +0 -11
- package/dist/theglobalfuel/pages/compliance/CompliancePage.d.ts.map +0 -1
- package/dist/theglobalfuel/pages/contracts/ContractDetailPage.d.ts +0 -9
- package/dist/theglobalfuel/pages/contracts/ContractDetailPage.d.ts.map +0 -1
- package/dist/theglobalfuel/pages/contracts/ContractsPage.d.ts +0 -8
- package/dist/theglobalfuel/pages/contracts/ContractsPage.d.ts.map +0 -1
- package/dist/theglobalfuel/pages/dashboard/DashboardPage.d.ts +0 -13
- package/dist/theglobalfuel/pages/dashboard/DashboardPage.d.ts.map +0 -1
- package/dist/theglobalfuel/pages/emissions/EmissionsPage.d.ts +0 -12
- package/dist/theglobalfuel/pages/emissions/EmissionsPage.d.ts.map +0 -1
- package/dist/theglobalfuel/pages/inventory/InventoryPage.d.ts +0 -11
- package/dist/theglobalfuel/pages/inventory/InventoryPage.d.ts.map +0 -1
- package/dist/theglobalfuel/pages/production/ProductionPage.d.ts +0 -11
- package/dist/theglobalfuel/pages/production/ProductionPage.d.ts.map +0 -1
- package/dist/theglobalfuel/pages/reserves/ReservesPage.d.ts +0 -10
- package/dist/theglobalfuel/pages/reserves/ReservesPage.d.ts.map +0 -1
- package/dist/theglobalfuel/pages/shipments/ShipmentsPage.d.ts +0 -10
- package/dist/theglobalfuel/pages/shipments/ShipmentsPage.d.ts.map +0 -1
- package/dist/theglobalfuel/types/index.d.ts +0 -376
- package/dist/theglobalfuel/types/index.d.ts.map +0 -1
- package/dist/theglobalfuel/utils/cn.d.ts +0 -4
- package/dist/theglobalfuel/utils/cn.d.ts.map +0 -1
- package/dist/theglobalfuel/utils/formatters.d.ts +0 -36
- package/dist/theglobalfuel/utils/formatters.d.ts.map +0 -1
- package/dist/theglobalfuel/utils/i18n.d.ts +0 -6
- package/dist/theglobalfuel/utils/i18n.d.ts.map +0 -1
- package/dist/theglobalfuel/utils/index.d.ts +0 -9
- package/dist/theglobalfuel/utils/index.d.ts.map +0 -1
- package/dist/theglobalfuel/utils/navigation.d.ts +0 -14
- package/dist/theglobalfuel/utils/navigation.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContractsPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/contracts/ContractsPage.tsx"],"sourcesContent":["/**\n * Offtake contracts — list, filter, and create commodity purchase/sale contracts.\n * @module theglobalfuel/pages/contracts\n *\n * Reads `theListContracts`; writes `theCreateContract`.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, FileSignature } from 'lucide-react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataTable, type Column } from '../../components/DataTable';\nimport { FilterTabs, type FilterOption } from '../../components/FilterTabs';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Pagination } from '../../components/Pagination';\nimport { MiniBar } from '../../components/MiniBar';\nimport { useTheGlobalFuel } from '../../context';\nimport { useTheContracts, useTheCreateContract, useCursorPager } from '../../hooks';\nimport { formatEnumLabel, formatMoney, formatUnit, formatVolume } from '../../utils/formatters';\nimport type {\n TheOfftakeContract,\n TheContractStatus,\n TheContractSide,\n TheCommodityType,\n ThePricingBasis,\n TheUnit,\n} from '../../types';\n\nconst STATUS_FILTERS: FilterOption<TheContractStatus | 'ALL'>[] = [\n { value: 'ALL', label: 'All' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'NEGOTIATION', label: 'Negotiation' },\n { value: 'SIGNED', label: 'Signed' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'COMPLETED', label: 'Completed' },\n { value: 'SUSPENDED', label: 'Suspended' },\n { value: 'TERMINATED', label: 'Terminated' },\n];\n\nconst SIDES: TheContractSide[] = ['BUY', 'SELL'];\nconst PRICING_BASES: ThePricingBasis[] = ['FIXED', 'INDEX_LINKED', 'FORMULA', 'SPOT'];\nconst COMMODITIES: TheCommodityType[] = [\n 'CRUDE_OIL',\n 'NATURAL_GAS',\n 'LNG',\n 'COAL',\n 'ELECTRICITY',\n 'HYDROGEN',\n 'BIOFUEL',\n 'IRON_ORE',\n 'COPPER',\n 'BAUXITE',\n 'GOLD',\n 'LITHIUM',\n 'RARE_EARTH',\n];\nconst UNITS: TheUnit[] = ['BARRELS', 'CUBIC_METERS', 'TONNES', 'KILOGRAMS', 'MWH', 'GJ', 'MCF'];\n\nconst PAGE_SIZE = 25;\n\nconst clampPercent = (value: number): number => Math.max(0, Math.min(100, value));\n\n/** Fraction of a contract's volume that has been delivered (0–100). */\nconst deliveryPct = (c: TheOfftakeContract): number =>\n c.contractedVolume > 0 ? clampPercent((c.deliveredVolume / c.contractedVolume) * 100) : 0;\n\ninterface CreateFormState {\n reference: string;\n counterparty: string;\n commodity: TheCommodityType;\n side: TheContractSide;\n pricingBasis: ThePricingBasis;\n pricePerUnit: string;\n priceIndex: string;\n currency: string;\n contractedVolume: string;\n unit: TheUnit;\n deliveryLocation: string;\n startDate: string;\n endDate: string;\n notes: string;\n}\n\nconst EMPTY_FORM: CreateFormState = {\n reference: '',\n counterparty: '',\n commodity: 'CRUDE_OIL',\n side: 'SELL',\n pricingBasis: 'FIXED',\n pricePerUnit: '',\n priceIndex: '',\n currency: 'USD',\n contractedVolume: '',\n unit: 'BARRELS',\n deliveryLocation: '',\n startDate: '',\n endDate: '',\n notes: '',\n};\n\nexport function ContractsPage() {\n const { navigateTo } = useTheGlobalFuel();\n const [status, setStatus] = useState<TheContractStatus | 'ALL'>('ALL');\n const [side, setSide] = useState<TheContractSide | 'ALL'>('ALL');\n const [commodity, setCommodity] = useState<TheCommodityType | 'ALL'>('ALL');\n const pager = useCursorPager();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<CreateFormState>(EMPTY_FORM);\n const [formError, setFormError] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useTheContracts({\n status: status === 'ALL' ? undefined : status,\n side: side === 'ALL' ? undefined : side,\n commodity: commodity === 'ALL' ? undefined : commodity,\n pagination: { limit: PAGE_SIZE, cursor: pager.cursor },\n });\n const createContract = useTheCreateContract();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n\n const columns: Column<TheOfftakeContract>[] = [\n {\n key: 'reference',\n header: 'Contract',\n render: (c) => (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n <FileSignature className=\"h-4 w-4\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate font-semibold text-text-primary\">{c.reference}</p>\n <p className=\"truncate text-xs text-text-tertiary\">{c.counterparty}</p>\n </div>\n </div>\n ),\n },\n {\n key: 'side',\n header: 'Side',\n render: (c) => <StatusBadge status={c.side} />,\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 {\n key: 'status',\n header: 'Status',\n render: (c) => <StatusBadge status={c.status} />,\n },\n {\n key: 'price',\n header: 'Price',\n align: 'right',\n hideOnMobile: true,\n sortValue: (c) => c.pricePerUnit,\n render: (c) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatMoney(c.pricePerUnit, c.currency)}\n <span className=\"text-text-tertiary\">/{formatUnit(c.unit)}</span>\n </span>\n ),\n },\n {\n key: 'delivery',\n header: 'Delivered',\n sortValue: (c) => deliveryPct(c),\n render: (c) => {\n const pct = deliveryPct(c);\n return (\n <div className=\"min-w-[9rem]\">\n <MiniBar\n value={pct}\n barClassName=\"bg-[var(--color-status-success-text)]\"\n className=\"mb-1\"\n />\n <p className=\"text-xs tabular-nums text-text-tertiary\">\n {formatVolume(c.deliveredVolume, c.unit)} / {formatVolume(c.contractedVolume, c.unit)}\n </p>\n </div>\n );\n },\n },\n {\n key: 'updated',\n header: 'Updated',\n align: 'right',\n hideOnMobile: true,\n render: (c) => (\n <span className=\"text-text-tertiary\">\n {new Date(c.updatedAt).toLocaleDateString(undefined, {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n })}\n </span>\n ),\n },\n ];\n\n const resetForm = () => {\n setForm(EMPTY_FORM);\n setFormError(null);\n };\n\n const handleCreate = async () => {\n if (!form.reference.trim()) {\n setFormError('Contract reference is required.');\n return;\n }\n if (!form.counterparty.trim()) {\n setFormError('Counterparty is required.');\n return;\n }\n setFormError(null);\n try {\n const created = await createContract.mutateAsync({\n reference: form.reference.trim(),\n counterparty: form.counterparty.trim(),\n commodity: form.commodity,\n side: form.side,\n pricingBasis: form.pricingBasis,\n pricePerUnit: form.pricePerUnit ? Number(form.pricePerUnit) : null,\n priceIndex: form.priceIndex.trim() || null,\n currency: form.currency.trim() || 'USD',\n contractedVolume: form.contractedVolume ? Number(form.contractedVolume) : null,\n unit: form.unit,\n deliveryLocation: form.deliveryLocation.trim() || null,\n startDate: form.startDate ? new Date(form.startDate).toISOString() : null,\n endDate: form.endDate ? new Date(form.endDate).toISOString() : null,\n notes: form.notes.trim() || null,\n });\n setDialogOpen(false);\n resetForm();\n navigateTo(`contracts/${created.id}`);\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create contract.');\n }\n };\n\n return (\n <PageLayout\n title=\"Offtake Contracts\"\n description=\"Commodity purchase & sale agreements — pricing, contracted volume and delivery progress.\"\n actions={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New contract\n </Button>\n }\n >\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <FilterTabs\n options={STATUS_FILTERS}\n value={status}\n onChange={(v) => {\n setStatus(v);\n pager.reset();\n }}\n />\n <Select\n value={side}\n onValueChange={(v) => {\n setSide(v as TheContractSide | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-40\">\n <SelectValue placeholder=\"All sides\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All sides</SelectItem>\n {SIDES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select\n value={commodity}\n onValueChange={(v) => {\n setCommodity(v as TheCommodityType | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-48\">\n <SelectValue placeholder=\"All commodities\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All commodities</SelectItem>\n {COMMODITIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading contracts…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load contracts.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<FileSignature className=\"h-10 w-10\" />}\n title=\"No contracts yet\"\n description={\n status === 'ALL' && side === 'ALL' && commodity === 'ALL'\n ? 'Create your first offtake contract to track pricing, volume and delivery.'\n : 'No contracts match these filters.'\n }\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New contract\n </Button>\n }\n />\n ) : (\n <>\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(c) => c.id}\n onRowClick={(c) => navigateTo(`contracts/${c.id}`)}\n />\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={rows.length}\n hasMore={data?.pageInfo?.hasMore ?? false}\n onPageChange={(target) => pager.onPageChange(target, data?.pageInfo?.cursor)}\n />\n </>\n )}\n\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n setDialogOpen(open);\n if (!open) resetForm();\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New offtake contract</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Register a commodity purchase or sale agreement with a counterparty.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"reference\">Reference *</Label>\n <Input\n id=\"reference\"\n value={form.reference}\n onChange={(e) => setForm({ ...form, reference: e.target.value })}\n placeholder=\"OFT-2026-0142\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"counterparty\">Counterparty *</Label>\n <Input\n id=\"counterparty\"\n value={form.counterparty}\n onChange={(e) => setForm({ ...form, counterparty: e.target.value })}\n placeholder=\"Vitol S.A.\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"commodity\">Commodity *</Label>\n <Select\n value={form.commodity}\n onValueChange={(v) => setForm({ ...form, commodity: v as TheCommodityType })}\n >\n <SelectTrigger id=\"commodity\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {COMMODITIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"side\">Side</Label>\n <Select\n value={form.side}\n onValueChange={(v) => setForm({ ...form, side: v as TheContractSide })}\n >\n <SelectTrigger id=\"side\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SIDES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"pricingBasis\">Pricing basis</Label>\n <Select\n value={form.pricingBasis}\n onValueChange={(v) => setForm({ ...form, pricingBasis: v as ThePricingBasis })}\n >\n <SelectTrigger id=\"pricingBasis\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PRICING_BASES.map((p) => (\n <SelectItem key={p} value={p}>\n {formatEnumLabel(p)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"priceIndex\">Price index</Label>\n <Input\n id=\"priceIndex\"\n value={form.priceIndex}\n onChange={(e) => setForm({ ...form, priceIndex: e.target.value })}\n placeholder=\"Brent, TTF, Henry Hub\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-3\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"pricePerUnit\">Price / unit</Label>\n <Input\n id=\"pricePerUnit\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.pricePerUnit}\n onChange={(e) => setForm({ ...form, pricePerUnit: e.target.value })}\n placeholder=\"82.50\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"currency\">Currency</Label>\n <Input\n id=\"currency\"\n value={form.currency}\n onChange={(e) => setForm({ ...form, currency: e.target.value })}\n placeholder=\"USD\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"unit\">Unit</Label>\n <Select\n value={form.unit}\n onValueChange={(v) => setForm({ ...form, unit: v as TheUnit })}\n >\n <SelectTrigger id=\"unit\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {UNITS.map((u) => (\n <SelectItem key={u} value={u}>\n {formatUnit(u)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"contractedVolume\">Contracted volume</Label>\n <Input\n id=\"contractedVolume\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.contractedVolume}\n onChange={(e) => setForm({ ...form, contractedVolume: e.target.value })}\n placeholder=\"500000\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"deliveryLocation\">Delivery location</Label>\n <Input\n id=\"deliveryLocation\"\n value={form.deliveryLocation}\n onChange={(e) => setForm({ ...form, deliveryLocation: e.target.value })}\n placeholder=\"Rotterdam\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"startDate\">Start date</Label>\n <Input\n id=\"startDate\"\n type=\"date\"\n value={form.startDate}\n onChange={(e) => setForm({ ...form, startDate: e.target.value })}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"endDate\">End date</Label>\n <Input\n id=\"endDate\"\n type=\"date\"\n value={form.endDate}\n onChange={(e) => setForm({ ...form, endDate: e.target.value })}\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"notes\">Notes</Label>\n <Textarea\n id=\"notes\"\n rows={2}\n value={form.notes}\n onChange={(e) => setForm({ ...form, notes: e.target.value })}\n placeholder=\"Optional context about this contract.\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setDialogOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleCreate} disabled={createContract.isPending}>\n {createContract.isPending ? 'Creating…' : 'Create contract'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ContractsPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/contracts/ContractsPage.tsx"],"sourcesContent":["/**\n * Offtake contracts — list, filter, and create commodity purchase/sale contracts.\n * @module theglobalfuel/pages/contracts\n *\n * Reads `theListContracts`; writes `theCreateContract`.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, FileSignature } from 'lucide-react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataTable, type Column } from '../../components/DataTable';\nimport { FilterTabs, type FilterOption } from '../../components/FilterTabs';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Pagination } from '../../components/Pagination';\nimport { MiniBar } from '../../components/MiniBar';\nimport { useTheGlobalFuel } from '../../context';\nimport { useTheContracts, useTheCreateContract, useCursorPager, useNotify } from '../../hooks';\nimport { formatEnumLabel, formatMoney, formatUnit, formatVolume } from '../../utils/formatters';\nimport { toBackendDate } from '../../utils';\nimport type {\n TheOfftakeContract,\n TheContractStatus,\n TheContractSide,\n TheCommodityType,\n ThePricingBasis,\n TheUnit,\n} from '../../types';\n\nconst STATUS_FILTERS: FilterOption<TheContractStatus | 'ALL'>[] = [\n { value: 'ALL', label: 'All' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'NEGOTIATION', label: 'Negotiation' },\n { value: 'SIGNED', label: 'Signed' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'COMPLETED', label: 'Completed' },\n { value: 'SUSPENDED', label: 'Suspended' },\n { value: 'TERMINATED', label: 'Terminated' },\n];\n\nconst SIDES: TheContractSide[] = ['BUY', 'SELL'];\nconst PRICING_BASES: ThePricingBasis[] = ['FIXED', 'INDEX_LINKED', 'FORMULA', 'SPOT'];\nconst COMMODITIES: TheCommodityType[] = [\n 'CRUDE_OIL',\n 'NATURAL_GAS',\n 'LNG',\n 'COAL',\n 'ELECTRICITY',\n 'HYDROGEN',\n 'BIOFUEL',\n 'IRON_ORE',\n 'COPPER',\n 'BAUXITE',\n 'GOLD',\n 'LITHIUM',\n 'RARE_EARTH',\n];\nconst UNITS: TheUnit[] = ['BARRELS', 'CUBIC_METERS', 'TONNES', 'KILOGRAMS', 'MWH', 'GJ', 'MCF'];\n\nconst PAGE_SIZE = 25;\n\nconst clampPercent = (value: number): number => Math.max(0, Math.min(100, value));\n\n/** Fraction of a contract's volume that has been delivered (0–100). */\nconst deliveryPct = (c: TheOfftakeContract): number =>\n c.contractedVolume > 0 ? clampPercent((c.deliveredVolume / c.contractedVolume) * 100) : 0;\n\ninterface CreateFormState {\n reference: string;\n counterparty: string;\n commodity: TheCommodityType;\n side: TheContractSide;\n pricingBasis: ThePricingBasis;\n pricePerUnit: string;\n priceIndex: string;\n currency: string;\n contractedVolume: string;\n unit: TheUnit;\n deliveryLocation: string;\n startDate: string;\n endDate: string;\n notes: string;\n}\n\nconst EMPTY_FORM: CreateFormState = {\n reference: '',\n counterparty: '',\n commodity: 'CRUDE_OIL',\n side: 'SELL',\n pricingBasis: 'FIXED',\n pricePerUnit: '',\n priceIndex: '',\n currency: 'USD',\n contractedVolume: '',\n unit: 'BARRELS',\n deliveryLocation: '',\n startDate: '',\n endDate: '',\n notes: '',\n};\n\nexport function ContractsPage() {\n const { navigateTo } = useTheGlobalFuel();\n const notify = useNotify();\n const [status, setStatus] = useState<TheContractStatus | 'ALL'>('ALL');\n const [side, setSide] = useState<TheContractSide | 'ALL'>('ALL');\n const [commodity, setCommodity] = useState<TheCommodityType | 'ALL'>('ALL');\n const pager = useCursorPager();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<CreateFormState>(EMPTY_FORM);\n const [formError, setFormError] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useTheContracts({\n status: status === 'ALL' ? undefined : status,\n side: side === 'ALL' ? undefined : side,\n commodity: commodity === 'ALL' ? undefined : commodity,\n pagination: { limit: PAGE_SIZE, cursor: pager.cursor },\n });\n const createContract = useTheCreateContract();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n\n const columns: Column<TheOfftakeContract>[] = [\n {\n key: 'reference',\n header: 'Contract',\n render: (c) => (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n <FileSignature className=\"h-4 w-4\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate font-semibold text-text-primary\">{c.reference}</p>\n <p className=\"truncate text-xs text-text-tertiary\">{c.counterparty}</p>\n </div>\n </div>\n ),\n },\n {\n key: 'side',\n header: 'Side',\n render: (c) => <StatusBadge status={c.side} />,\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 {\n key: 'status',\n header: 'Status',\n render: (c) => <StatusBadge status={c.status} />,\n },\n {\n key: 'price',\n header: 'Price',\n align: 'right',\n hideOnMobile: true,\n sortValue: (c) => c.pricePerUnit,\n render: (c) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatMoney(c.pricePerUnit, c.currency)}\n <span className=\"text-text-tertiary\">/{formatUnit(c.unit)}</span>\n </span>\n ),\n },\n {\n key: 'delivery',\n header: 'Delivered',\n sortValue: (c) => deliveryPct(c),\n render: (c) => {\n const pct = deliveryPct(c);\n return (\n <div className=\"min-w-[9rem]\">\n <MiniBar\n value={pct}\n barClassName=\"bg-[var(--color-status-success-text)]\"\n className=\"mb-1\"\n />\n <p className=\"text-xs tabular-nums text-text-tertiary\">\n {formatVolume(c.deliveredVolume, c.unit)} / {formatVolume(c.contractedVolume, c.unit)}\n </p>\n </div>\n );\n },\n },\n {\n key: 'updated',\n header: 'Updated',\n align: 'right',\n hideOnMobile: true,\n render: (c) => (\n <span className=\"text-text-tertiary\">\n {new Date(c.updatedAt).toLocaleDateString(undefined, {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n })}\n </span>\n ),\n },\n ];\n\n const resetForm = () => {\n setForm(EMPTY_FORM);\n setFormError(null);\n };\n\n const handleCreate = async () => {\n if (!form.reference.trim()) {\n setFormError('Contract reference is required.');\n return;\n }\n if (!form.counterparty.trim()) {\n setFormError('Counterparty is required.');\n return;\n }\n setFormError(null);\n try {\n const created = await createContract.mutateAsync({\n reference: form.reference.trim(),\n counterparty: form.counterparty.trim(),\n commodity: form.commodity,\n side: form.side,\n pricingBasis: form.pricingBasis,\n pricePerUnit: form.pricePerUnit ? Number(form.pricePerUnit) : null,\n priceIndex: form.priceIndex.trim() || null,\n currency: form.currency.trim().toUpperCase() || 'USD',\n contractedVolume: form.contractedVolume ? Number(form.contractedVolume) : null,\n unit: form.unit,\n deliveryLocation: form.deliveryLocation.trim() || null,\n startDate: toBackendDate(form.startDate) ?? null,\n endDate: toBackendDate(form.endDate) ?? null,\n notes: form.notes.trim() || null,\n });\n notify.success('Contract created');\n setDialogOpen(false);\n resetForm();\n navigateTo(`contracts/${created.id}`);\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create contract.');\n notify.fromError(err);\n }\n };\n\n return (\n <PageLayout\n title=\"Offtake Contracts\"\n description=\"Commodity purchase & sale agreements — pricing, contracted volume and delivery progress.\"\n actions={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New contract\n </Button>\n }\n >\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <FilterTabs\n options={STATUS_FILTERS}\n value={status}\n onChange={(v) => {\n setStatus(v);\n pager.reset();\n }}\n />\n <Select\n value={side}\n onValueChange={(v) => {\n setSide(v as TheContractSide | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-40\" aria-label=\"Filter by side\">\n <SelectValue placeholder=\"All sides\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All sides</SelectItem>\n {SIDES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select\n value={commodity}\n onValueChange={(v) => {\n setCommodity(v as TheCommodityType | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-48\" aria-label=\"Filter by commodity\">\n <SelectValue placeholder=\"All commodities\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All commodities</SelectItem>\n {COMMODITIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading contracts…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load contracts.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<FileSignature className=\"h-10 w-10\" />}\n title=\"No contracts yet\"\n description={\n status === 'ALL' && side === 'ALL' && commodity === 'ALL'\n ? 'Create your first offtake contract to track pricing, volume and delivery.'\n : 'No contracts match these filters.'\n }\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New contract\n </Button>\n }\n />\n ) : (\n <>\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(c) => c.id}\n onRowClick={(c) => navigateTo(`contracts/${c.id}`)}\n rowLabel={(c) => `Open ${c.reference}`}\n />\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={rows.length}\n hasMore={data?.pageInfo?.hasMore ?? false}\n onPageChange={(target) => pager.onPageChange(target, data?.pageInfo?.cursor)}\n />\n </>\n )}\n\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n setDialogOpen(open);\n if (!open) resetForm();\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New offtake contract</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Register a commodity purchase or sale agreement with a counterparty.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <form\n onSubmit={(e) => {\n e.preventDefault();\n void handleCreate();\n }}\n >\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"reference\">Reference *</Label>\n <Input\n id=\"reference\"\n value={form.reference}\n onChange={(e) => setForm({ ...form, reference: e.target.value })}\n placeholder=\"OFT-2026-0142\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"counterparty\">Counterparty *</Label>\n <Input\n id=\"counterparty\"\n value={form.counterparty}\n onChange={(e) => setForm({ ...form, counterparty: e.target.value })}\n placeholder=\"Vitol S.A.\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"commodity\">Commodity *</Label>\n <Select\n value={form.commodity}\n onValueChange={(v) => setForm({ ...form, commodity: v as TheCommodityType })}\n >\n <SelectTrigger id=\"commodity\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {COMMODITIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"side\">Side</Label>\n <Select\n value={form.side}\n onValueChange={(v) => setForm({ ...form, side: v as TheContractSide })}\n >\n <SelectTrigger id=\"side\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SIDES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"pricingBasis\">Pricing basis</Label>\n <Select\n value={form.pricingBasis}\n onValueChange={(v) => setForm({ ...form, pricingBasis: v as ThePricingBasis })}\n >\n <SelectTrigger id=\"pricingBasis\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PRICING_BASES.map((p) => (\n <SelectItem key={p} value={p}>\n {formatEnumLabel(p)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"priceIndex\">Price index</Label>\n <Input\n id=\"priceIndex\"\n value={form.priceIndex}\n onChange={(e) => setForm({ ...form, priceIndex: e.target.value })}\n placeholder=\"Brent, TTF, Henry Hub\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-3\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"pricePerUnit\">Price / unit</Label>\n <Input\n id=\"pricePerUnit\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.pricePerUnit}\n onChange={(e) => setForm({ ...form, pricePerUnit: e.target.value })}\n placeholder=\"82.50\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"currency\">Currency</Label>\n <Input\n id=\"currency\"\n value={form.currency}\n onChange={(e) => setForm({ ...form, currency: e.target.value })}\n placeholder=\"USD\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"unit\">Unit</Label>\n <Select\n value={form.unit}\n onValueChange={(v) => setForm({ ...form, unit: v as TheUnit })}\n >\n <SelectTrigger id=\"unit\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {UNITS.map((u) => (\n <SelectItem key={u} value={u}>\n {formatUnit(u)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"contractedVolume\">Contracted volume</Label>\n <Input\n id=\"contractedVolume\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.contractedVolume}\n onChange={(e) => setForm({ ...form, contractedVolume: e.target.value })}\n placeholder=\"500000\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"deliveryLocation\">Delivery location</Label>\n <Input\n id=\"deliveryLocation\"\n value={form.deliveryLocation}\n onChange={(e) => setForm({ ...form, deliveryLocation: e.target.value })}\n placeholder=\"Rotterdam\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"startDate\">Start date</Label>\n <Input\n id=\"startDate\"\n type=\"date\"\n value={form.startDate}\n onChange={(e) => setForm({ ...form, startDate: e.target.value })}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"endDate\">End date</Label>\n <Input\n id=\"endDate\"\n type=\"date\"\n value={form.endDate}\n onChange={(e) => setForm({ ...form, endDate: e.target.value })}\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"notes\">Notes</Label>\n <Textarea\n id=\"notes\"\n rows={2}\n value={form.notes}\n onChange={(e) => setForm({ ...form, notes: e.target.value })}\n placeholder=\"Optional context about this contract.\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setDialogOpen(false);\n resetForm();\n }}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={createContract.isPending}>\n {createContract.isPending ? 'Creating…' : 'Create contract'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -141,7 +141,7 @@ function A({ title: e, description: t, icon: n, linkLabel: r, onLink: i, isLoadi
|
|
|
141
141
|
});
|
|
142
142
|
}
|
|
143
143
|
function j() {
|
|
144
|
-
let { navigateTo: o, currentUser: w } = e(), T = ee({ pagination: { limit: 50 } }), E = ne({ pagination: { limit: 50 } }), D = oe(void 0, "IN_TRANSIT"), j = re({ pagination: { limit: 50 } }), M = ie({ pagination: { limit: 50 } }), N = te(), P = ae({ pagination: { limit: 12 } }), F = v(() => T.data?.items ?? [], [T.data]), I = v(() => E.data?.items ?? [], [E.data]), L = v(() => D.data ?? [], [D.data]), R = v(() => j.data?.items ?? [], [j.data]), z = v(() => M.data?.items ?? [], [M.data]), B = v(() => N.data ?? [], [N.data]), V = v(() => P.data?.items ?? [], [P.data]), H = F.filter((e) => e.status === "PRODUCING").length, U = I.filter((e) => e.status === "ACTIVE").length, W = R.reduce((e, t) => e + (t.co2eTonnes ?? 0), 0), G = R.filter((e) => e.verified).length, K = z.filter((e) => e.status === "AVAILABLE").length, ve = B.filter((e) => e.status === "PENDING").length, ye = B.filter((e) => e.expiresAt != null && (u(e.expiresAt) || O(e.expiresAt))).length, q = B.filter((e) => e.status === "PENDING" || e.expiresAt != null && (u(e.expiresAt) || O(e.expiresAt))).length, J = (e, t) => t ? `${e.length}+` : a(e.length), Y = v(() => k(F, (e) => e.commodity).map((e) => ({
|
|
144
|
+
let { navigateTo: o, currentUser: w } = e(), T = ee({ pagination: { limit: 50 } }), E = ne({ pagination: { limit: 50 } }), D = oe(void 0, "IN_TRANSIT"), j = re({ pagination: { limit: 50 } }), M = ie({ pagination: { limit: 50 } }), N = te(), P = ae({ pagination: { limit: 12 } }), F = v(() => T.data?.items ?? [], [T.data]), I = v(() => E.data?.items ?? [], [E.data]), L = v(() => D.data?.items ?? [], [D.data]), R = v(() => j.data?.items ?? [], [j.data]), z = v(() => M.data?.items ?? [], [M.data]), B = v(() => N.data?.items ?? [], [N.data]), V = v(() => P.data?.items ?? [], [P.data]), H = F.filter((e) => e.status === "PRODUCING").length, U = I.filter((e) => e.status === "ACTIVE").length, W = R.reduce((e, t) => e + (t.co2eTonnes ?? 0), 0), G = R.filter((e) => e.verified).length, K = z.filter((e) => e.status === "AVAILABLE").length, ve = B.filter((e) => e.status === "PENDING").length, ye = B.filter((e) => e.expiresAt != null && (u(e.expiresAt) || O(e.expiresAt))).length, q = B.filter((e) => e.status === "PENDING" || e.expiresAt != null && (u(e.expiresAt) || O(e.expiresAt))).length, J = (e, t) => t ? `${e.length}+` : a(e.length), Y = v(() => k(F, (e) => e.commodity).map((e) => ({
|
|
145
145
|
key: e.key,
|
|
146
146
|
label: /* @__PURE__ */ S("span", {
|
|
147
147
|
className: "truncate",
|
|
@@ -471,7 +471,8 @@ function j() {
|
|
|
471
471
|
columns: Se,
|
|
472
472
|
rows: Z,
|
|
473
473
|
rowKey: (e) => e.id,
|
|
474
|
-
onRowClick: (e) => o(`contracts/${e.id}`)
|
|
474
|
+
onRowClick: (e) => o(`contracts/${e.id}`),
|
|
475
|
+
rowLabel: (e) => `Open contract ${e.reference}`
|
|
475
476
|
})
|
|
476
477
|
}),
|
|
477
478
|
/* @__PURE__ */ S(g, {
|
|
@@ -495,7 +496,8 @@ function j() {
|
|
|
495
496
|
columns: Ce,
|
|
496
497
|
rows: Q,
|
|
497
498
|
rowKey: (e) => e.id,
|
|
498
|
-
onRowClick: (e) => o(`assets/${e.assetId}`)
|
|
499
|
+
onRowClick: (e) => o(`assets/${e.assetId}`),
|
|
500
|
+
rowLabel: (e) => `Open ${X.get(e.assetId) ?? "asset"}`
|
|
499
501
|
})
|
|
500
502
|
})
|
|
501
503
|
]
|
|
@@ -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. KPIs summarise the registry\n * (Assets / Production), commerce (Contracts / Shipments / Inventory) and\n * sustainability (Emissions / Compliance) domains; distribution cards derive\n * bars straight from the fetched arrays; recent-activity tables link into the\n * relevant detail routes. Pre-launch empty states are handled gracefully.\n */\n\nimport { useMemo, type ReactNode } from 'react';\nimport {\n Layers,\n ScrollText,\n Ship,\n Factory,\n Boxes,\n ShieldCheck,\n ArrowRight,\n Fuel,\n GitBranch,\n Gauge,\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 { 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 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 → MiniBar fill token (Scope 1 direct · 2 energy · 3 value-chain). */\nconst SCOPE_BAR: Record<TheEmissionScope, string> = {\n SCOPE_1: 'bg-status-error-text',\n SCOPE_2: 'bg-status-warning-text',\n SCOPE_3: 'bg-[var(--color-accent-blue)]',\n};\n\nconst ALL_SCOPES: TheEmissionScope[] = ['SCOPE_1', 'SCOPE_2', 'SCOPE_3'];\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\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}\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}: DistributionCardProps) {\n return (\n <GlassCard treatment=\"glass\" className=\"flex flex-col p-5\">\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\nexport function DashboardPage() {\n const { navigateTo, currentUser } = useTheGlobalFuel();\n\n // Real backend queries (limit 50 for connection lists — plenty for a summary).\n const assets = useTheAssets({ pagination: { limit: 50 } });\n const contracts = useTheContracts({ pagination: { limit: 50 } });\n const shipments = useTheShipments(undefined, 'IN_TRANSIT');\n const emissions = useTheEmissionRecords({ pagination: { limit: 50 } });\n const inventory = useTheInventoryLots({ pagination: { limit: 50 } });\n const compliance = useTheComplianceCerts();\n const production = useTheProductionRecords({ pagination: { limit: 12 } });\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 ?? [], [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 ?? [], [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\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 // ── Distribution derivations ───────────────────────────────────────────────\n const commodityBars = useMemo<DistBar[]>(\n () =>\n distribution(assetRows, (a) => a.commodity).map((d) => ({\n key: d.key,\n label: <span className=\"truncate\">{formatEnumLabel(d.key)}</span>,\n value: formatNumber(d.count),\n pct: d.pct,\n barClassName: 'bg-[var(--color-accent-blue)]',\n })),\n [assetRows]\n );\n\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 const scopeBars = useMemo<DistBar[]>(() => {\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] = (totals[e.scope] ?? 0) + (e.co2eTonnes ?? 0);\n const grand = totals.SCOPE_1 + totals.SCOPE_2 + totals.SCOPE_3;\n return ALL_SCOPES.map((scope) => ({\n key: scope,\n label: <StatusBadge status={scope} />,\n value: `${formatNumber(totals[scope], { maximumFractionDigits: totals[scope] >= 100 ? 0 : 1 })} t`,\n pct: grand > 0 ? (totals[scope] / grand) * 100 : 0,\n barClassName: SCOPE_BAR[scope],\n }));\n }, [emissionRows]);\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 {/* Distribution cards — every bar derived from the fetched arrays */}\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <DistributionCard\n title=\"Assets by commodity\"\n description=\"Portfolio mix across energy, mineral & metal streams.\"\n icon={<Fuel 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 registered yet.\"\n bars={commodityBars}\n footer={\n assetRows.length > 0\n ? `${withPlus(assetRows, assets.data?.pageInfo?.hasMore)} assets across ${commodityBars.length} ${commodityBars.length === 1 ? 'commodity' : 'commodities'}`\n : undefined\n }\n />\n\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 <DistributionCard\n title=\"Emissions by scope\"\n description=\"GHG Protocol Scope 1 / 2 / 3 (tonnes CO₂e logged).\"\n icon={<Gauge className=\"h-4 w-4\" />}\n linkLabel=\"Emissions\"\n onLink={() => navigateTo('emissions')}\n isLoading={emissions.isLoading}\n isError={emissions.isError}\n onRetry={() => emissions.refetch()}\n emptyLabel=\"No emission records logged yet.\"\n bars={scopeBars}\n footer={\n emissionRows.length > 0\n ? `${formatTonnesCo2e(totalTonnes)} across ${withPlus(emissionRows, emissions.data?.pageInfo?.hasMore)} records`\n : undefined\n }\n />\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 />\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 />\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. KPIs summarise the registry\n * (Assets / Production), commerce (Contracts / Shipments / Inventory) and\n * sustainability (Emissions / Compliance) domains; distribution cards derive\n * bars straight from the fetched arrays; recent-activity tables link into the\n * relevant detail routes. Pre-launch empty states are handled gracefully.\n */\n\nimport { useMemo, type ReactNode } from 'react';\nimport {\n Layers,\n ScrollText,\n Ship,\n Factory,\n Boxes,\n ShieldCheck,\n ArrowRight,\n Fuel,\n GitBranch,\n Gauge,\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 { 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 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 → MiniBar fill token (Scope 1 direct · 2 energy · 3 value-chain). */\nconst SCOPE_BAR: Record<TheEmissionScope, string> = {\n SCOPE_1: 'bg-status-error-text',\n SCOPE_2: 'bg-status-warning-text',\n SCOPE_3: 'bg-[var(--color-accent-blue)]',\n};\n\nconst ALL_SCOPES: TheEmissionScope[] = ['SCOPE_1', 'SCOPE_2', 'SCOPE_3'];\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\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}\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}: DistributionCardProps) {\n return (\n <GlassCard treatment=\"glass\" className=\"flex flex-col p-5\">\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\nexport function DashboardPage() {\n const { navigateTo, currentUser } = useTheGlobalFuel();\n\n // Real backend queries (limit 50 for connection lists — plenty for a summary).\n const assets = useTheAssets({ pagination: { limit: 50 } });\n const contracts = useTheContracts({ pagination: { limit: 50 } });\n const shipments = useTheShipments(undefined, 'IN_TRANSIT');\n const emissions = useTheEmissionRecords({ pagination: { limit: 50 } });\n const inventory = useTheInventoryLots({ pagination: { limit: 50 } });\n const compliance = useTheComplianceCerts();\n const production = useTheProductionRecords({ pagination: { limit: 12 } });\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\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 // ── Distribution derivations ───────────────────────────────────────────────\n const commodityBars = useMemo<DistBar[]>(\n () =>\n distribution(assetRows, (a) => a.commodity).map((d) => ({\n key: d.key,\n label: <span className=\"truncate\">{formatEnumLabel(d.key)}</span>,\n value: formatNumber(d.count),\n pct: d.pct,\n barClassName: 'bg-[var(--color-accent-blue)]',\n })),\n [assetRows]\n );\n\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 const scopeBars = useMemo<DistBar[]>(() => {\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] = (totals[e.scope] ?? 0) + (e.co2eTonnes ?? 0);\n const grand = totals.SCOPE_1 + totals.SCOPE_2 + totals.SCOPE_3;\n return ALL_SCOPES.map((scope) => ({\n key: scope,\n label: <StatusBadge status={scope} />,\n value: `${formatNumber(totals[scope], { maximumFractionDigits: totals[scope] >= 100 ? 0 : 1 })} t`,\n pct: grand > 0 ? (totals[scope] / grand) * 100 : 0,\n barClassName: SCOPE_BAR[scope],\n }));\n }, [emissionRows]);\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 {/* Distribution cards — every bar derived from the fetched arrays */}\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <DistributionCard\n title=\"Assets by commodity\"\n description=\"Portfolio mix across energy, mineral & metal streams.\"\n icon={<Fuel 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 registered yet.\"\n bars={commodityBars}\n footer={\n assetRows.length > 0\n ? `${withPlus(assetRows, assets.data?.pageInfo?.hasMore)} assets across ${commodityBars.length} ${commodityBars.length === 1 ? 'commodity' : 'commodities'}`\n : undefined\n }\n />\n\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 <DistributionCard\n title=\"Emissions by scope\"\n description=\"GHG Protocol Scope 1 / 2 / 3 (tonnes CO₂e logged).\"\n icon={<Gauge className=\"h-4 w-4\" />}\n linkLabel=\"Emissions\"\n onLink={() => navigateTo('emissions')}\n isLoading={emissions.isLoading}\n isError={emissions.isError}\n onRetry={() => emissions.refetch()}\n emptyLabel=\"No emission records logged yet.\"\n bars={scopeBars}\n footer={\n emissionRows.length > 0\n ? `${formatTonnesCo2e(totalTonnes)} across ${withPlus(emissionRows, emissions.data?.pageInfo?.hasMore)} records`\n : undefined\n }\n />\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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"}
|