@burdenoff/microfe-theglobalfuel 2026.705.2 → 2026.705.4
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/theglobalfuel/TheGlobalFuelRoot.js +54 -46
- package/dist/theglobalfuel/TheGlobalFuelRoot.js.map +1 -1
- package/dist/theglobalfuel/TheGlobalFuelRoutes.js +10 -6
- package/dist/theglobalfuel/TheGlobalFuelRoutes.js.map +1 -1
- package/dist/theglobalfuel/components/DataTable.js +126 -58
- package/dist/theglobalfuel/components/DataTable.js.map +1 -1
- package/dist/theglobalfuel/components/EmptyState.js +4 -4
- package/dist/theglobalfuel/components/EmptyState.js.map +1 -1
- package/dist/theglobalfuel/components/MetricsCard.js +2 -2
- package/dist/theglobalfuel/components/MetricsCard.js.map +1 -1
- package/dist/theglobalfuel/components/WorldMap.js +115 -0
- package/dist/theglobalfuel/components/WorldMap.js.map +1 -0
- package/dist/theglobalfuel/components/index.js +9 -0
- package/dist/theglobalfuel/components/viz/AllocationBar.js +68 -0
- package/dist/theglobalfuel/components/viz/AllocationBar.js.map +1 -0
- package/dist/theglobalfuel/components/viz/AreaChart.js +102 -0
- package/dist/theglobalfuel/components/viz/AreaChart.js.map +1 -0
- package/dist/theglobalfuel/components/viz/AvatarStack.js +2 -0
- package/dist/theglobalfuel/components/viz/BarChart.js +4 -0
- package/dist/theglobalfuel/components/viz/CertificateCard.js +4 -0
- package/dist/theglobalfuel/components/viz/DonutChart.js +109 -0
- package/dist/theglobalfuel/components/viz/DonutChart.js.map +1 -0
- package/dist/theglobalfuel/components/viz/HBarFunnel.js +3 -0
- package/dist/theglobalfuel/components/viz/Heatmap.js +3 -0
- package/dist/theglobalfuel/components/viz/KanbanBoard.js +2 -0
- package/dist/theglobalfuel/components/viz/LineChart.js +4 -0
- package/dist/theglobalfuel/components/viz/OrgTree.js +2 -0
- package/dist/theglobalfuel/components/viz/PathSteps.js +68 -0
- package/dist/theglobalfuel/components/viz/PathSteps.js.map +1 -0
- package/dist/theglobalfuel/components/viz/ProgressRing.js +6 -0
- package/dist/theglobalfuel/components/viz/ProgressRing.js.map +1 -0
- package/dist/theglobalfuel/components/viz/RatingStars.js +3 -0
- package/dist/theglobalfuel/components/viz/SegmentedTabs.js +3 -0
- package/dist/theglobalfuel/components/viz/SkillBar.js +3 -0
- package/dist/theglobalfuel/components/viz/Sparkline.js +74 -0
- package/dist/theglobalfuel/components/viz/Sparkline.js.map +1 -0
- package/dist/theglobalfuel/components/viz/StatCard.js +3 -0
- package/dist/theglobalfuel/components/viz/StepProgress.js +64 -0
- package/dist/theglobalfuel/components/viz/StepProgress.js.map +1 -0
- package/dist/theglobalfuel/components/viz/Timeline.js +66 -0
- package/dist/theglobalfuel/components/viz/Timeline.js.map +1 -0
- package/dist/theglobalfuel/components/viz/index.js +23 -0
- package/dist/theglobalfuel/components/viz/lib/Avatar.js +1 -0
- package/dist/theglobalfuel/components/viz/lib/CartesianFrame.js +119 -0
- package/dist/theglobalfuel/components/viz/lib/CartesianFrame.js.map +1 -0
- package/dist/theglobalfuel/components/viz/lib/ResponsiveSvg.js +35 -0
- package/dist/theglobalfuel/components/viz/lib/ResponsiveSvg.js.map +1 -0
- package/dist/theglobalfuel/components/viz/lib/format.js +17 -0
- package/dist/theglobalfuel/components/viz/lib/format.js.map +1 -0
- package/dist/theglobalfuel/components/viz/lib/geometry.js +61 -0
- package/dist/theglobalfuel/components/viz/lib/geometry.js.map +1 -0
- package/dist/theglobalfuel/components/viz/lib/hooks.js +39 -0
- package/dist/theglobalfuel/components/viz/lib/hooks.js.map +1 -0
- package/dist/theglobalfuel/components/viz/lib/palette.js +27 -0
- package/dist/theglobalfuel/components/viz/lib/palette.js.map +1 -0
- package/dist/theglobalfuel/hooks/useCursorPager.js +6 -15
- package/dist/theglobalfuel/hooks/useCursorPager.js.map +1 -1
- package/dist/theglobalfuel/pages/assets/AssetDetailPage.js +431 -316
- package/dist/theglobalfuel/pages/assets/AssetDetailPage.js.map +1 -1
- package/dist/theglobalfuel/pages/assets/AssetsPage.js +99 -99
- package/dist/theglobalfuel/pages/assets/AssetsPage.js.map +1 -1
- package/dist/theglobalfuel/pages/compliance/CompliancePage.js +250 -250
- package/dist/theglobalfuel/pages/compliance/CompliancePage.js.map +1 -1
- package/dist/theglobalfuel/pages/contracts/ContractsPage.js +2 -2
- package/dist/theglobalfuel/pages/contracts/ContractsPage.js.map +1 -1
- package/dist/theglobalfuel/pages/dashboard/DashboardPage.js +525 -227
- package/dist/theglobalfuel/pages/dashboard/DashboardPage.js.map +1 -1
- package/dist/theglobalfuel/pages/emissions/EmissionsPage.js +255 -206
- package/dist/theglobalfuel/pages/emissions/EmissionsPage.js.map +1 -1
- package/dist/theglobalfuel/pages/inventory/InventoryPage.js +60 -60
- package/dist/theglobalfuel/pages/inventory/InventoryPage.js.map +1 -1
- package/dist/theglobalfuel/pages/production/ProductionPage.js +2 -2
- package/dist/theglobalfuel/pages/production/ProductionPage.js.map +1 -1
- package/dist/theglobalfuel/pages/provenance/ProvenancePage.js +465 -0
- package/dist/theglobalfuel/pages/provenance/ProvenancePage.js.map +1 -0
- package/dist/theglobalfuel/pages/reserves/ReservesPage.js +152 -152
- package/dist/theglobalfuel/pages/reserves/ReservesPage.js.map +1 -1
- package/dist/theglobalfuel/pages/shipments/ShipmentsPage.js +356 -227
- package/dist/theglobalfuel/pages/shipments/ShipmentsPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReservesPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/reserves/ReservesPage.tsx"],"sourcesContent":["/**\n * Reserve Estimates — booked recoverable volumes per asset, by category.\n * @module theglobalfuel/pages/reserves\n *\n * Reads `theListReserveEstimates` (a cursor connection — `{ items, pageInfo }`);\n * writes `theCreateReserveEstimate`. Asset names are resolved from `theListAssets`\n * since the reserve payload carries only `assetId`. No mock data.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, Layers, Database, Percent } 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 { MetricsCard } from '../../components/MetricsCard';\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 {\n useTheAssets,\n useTheReserveEstimates,\n useTheCreateReserveEstimate,\n useCursorPager,\n useNotify,\n} from '../../hooks';\nimport {\n formatDate,\n formatVolume,\n formatPercent,\n formatUnit,\n formatEnumLabel,\n} from '../../utils/formatters';\nimport { toBackendDate } from '../../utils';\nimport type { TheReserveEstimate, TheReserveCategory, TheUnit } from '../../types';\n\nconst CATEGORY_FILTERS: FilterOption<TheReserveCategory | 'ALL'>[] = [\n { value: 'ALL', label: 'All' },\n { value: 'PROVED', label: 'Proved' },\n { value: 'PROBABLE', label: 'Probable' },\n { value: 'POSSIBLE', label: 'Possible' },\n { value: 'CONTINGENT', label: 'Contingent' },\n { value: 'PROSPECTIVE', label: 'Prospective' },\n];\n\nconst RESERVE_CATEGORIES: TheReserveCategory[] = [\n 'PROVED',\n 'PROBABLE',\n 'POSSIBLE',\n 'CONTINGENT',\n 'PROSPECTIVE',\n];\n\nconst UNITS: TheUnit[] = ['BARRELS', 'CUBIC_METERS', 'TONNES', 'KILOGRAMS', 'MWH', 'GJ', 'MCF'];\n\nconst PAGE_SIZE = 25;\n\nconst today = (): string => new Date().toISOString().slice(0, 10);\n\ninterface CreateFormState {\n assetId: string;\n category: TheReserveCategory;\n asOfDate: string;\n recoverable: string;\n recoveryFactor: string;\n unit: TheUnit;\n methodology: string;\n notes: string;\n}\n\nconst EMPTY_FORM: CreateFormState = {\n assetId: '',\n category: 'PROVED',\n asOfDate: '',\n recoverable: '',\n recoveryFactor: '',\n unit: 'BARRELS',\n methodology: '',\n notes: '',\n};\n\nexport function ReservesPage() {\n const notify = useNotify();\n const [category, setCategory] = useState<TheReserveCategory | 'ALL'>('ALL');\n const [assetId, setAssetId] = useState<string>('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 // Asset registry — feeds both the filter Select and the create dialog, and\n // resolves asset names for the reserve rows (payload carries only assetId).\n const assets = useTheAssets({ pagination: { limit: 100, offset: 0 } });\n const assetMap = useMemo<Record<string, string>>(() => {\n const map: Record<string, string> = {};\n for (const a of assets.data?.items ?? []) map[a.id] = a.name;\n return map;\n }, [assets.data]);\n\n const assetScope = assetId === 'ALL' ? undefined : assetId;\n const categoryScope = category === 'ALL' ? undefined : category;\n\n const { data, isLoading, isError, refetch } = useTheReserveEstimates(assetScope, categoryScope, {\n limit: PAGE_SIZE,\n cursor: pager.cursor,\n });\n // Same-filter broad query for the header KPIs. The table is paginated to\n // PAGE_SIZE, so the metrics must read from a representative set (not one page)\n // or the counts/totals would silently reflect only the first 25 rows.\n const metricsQuery = useTheReserveEstimates(assetScope, categoryScope, { limit: 200 });\n const createEstimate = useTheCreateReserveEstimate();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n const metricsRows = useMemo(() => metricsQuery.data?.items ?? [], [metricsQuery.data]);\n\n // Header metrics — computed from the (filtered) portfolio, not just the current\n // page. We surface the total recoverable in the *dominant* unit so we never sum\n // apples & oranges.\n const metrics = useMemo(() => {\n const tally: Partial<Record<TheUnit, number>> = {};\n for (const r of metricsRows) tally[r.unit] = (tally[r.unit] ?? 0) + 1;\n const dominantUnit = (Object.entries(tally) as [TheUnit, number][]).sort(\n (a, b) => b[1] - a[1]\n )[0]?.[0];\n const totalRecoverable = dominantUnit\n ? metricsRows\n .filter((r) => r.unit === dominantUnit)\n .reduce((sum, r) => sum + r.recoverable, 0)\n : 0;\n const withFactor = metricsRows.filter((r) => r.recoveryFactor != null);\n const avgFactor = withFactor.length\n ? (withFactor.reduce((sum, r) => sum + (r.recoveryFactor ?? 0), 0) / withFactor.length) * 100\n : null;\n return { dominantUnit, totalRecoverable, avgFactor };\n }, [metricsRows]);\n\n const columns: Column<TheReserveEstimate>[] = [\n {\n key: 'asset',\n header: 'Asset',\n render: (r) => (\n <span className=\"font-semibold text-text-primary\">\n {assetMap[r.assetId] ?? <span className=\"text-text-tertiary\">Unknown asset</span>}\n </span>\n ),\n },\n {\n key: 'category',\n header: 'Category',\n render: (r) => <StatusBadge status={r.category} />,\n },\n {\n key: 'asOfDate',\n header: 'As of',\n hideOnMobile: true,\n sortValue: (r) => new Date(r.asOfDate).getTime(),\n render: (r) => <span className=\"text-text-secondary\">{formatDate(r.asOfDate)}</span>,\n },\n {\n key: 'recoverable',\n header: 'Recoverable',\n align: 'right',\n sortValue: (r) => r.recoverable,\n render: (r) => (\n <span className=\"tabular-nums font-medium text-text-primary\">\n {formatVolume(r.recoverable, r.unit)}\n </span>\n ),\n },\n {\n key: 'recoveryFactor',\n header: 'Recovery factor',\n align: 'right',\n hideOnMobile: true,\n sortValue: (r) => r.recoveryFactor ?? -1,\n render: (r) =>\n r.recoveryFactor != null ? (\n <span className=\"tabular-nums text-text-secondary\">\n {formatPercent(r.recoveryFactor * 100)}\n </span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'methodology',\n header: 'Methodology',\n hideOnMobile: true,\n render: (r) =>\n r.methodology ? (\n <span className=\"text-text-secondary\">{r.methodology}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n ];\n\n const openDialog = () => {\n setForm({ ...EMPTY_FORM, asOfDate: today() });\n setFormError(null);\n setDialogOpen(true);\n };\n\n const closeDialog = () => {\n setDialogOpen(false);\n setForm(EMPTY_FORM);\n setFormError(null);\n };\n\n const handleCreate = async () => {\n if (!form.assetId) {\n setFormError('Select the asset this estimate belongs to.');\n return;\n }\n // Anchor the date-only input at noon UTC so the calendar day survives every TZ.\n const asOfDate = toBackendDate(form.asOfDate);\n if (!asOfDate) {\n setFormError('An \"as of\" date is required.');\n return;\n }\n const recoverable = Number(form.recoverable);\n if (!form.recoverable || Number.isNaN(recoverable) || recoverable <= 0) {\n const message = 'Recoverable volume must be greater than zero.';\n setFormError(message);\n notify.error(message);\n return;\n }\n const recoveryFactor = form.recoveryFactor ? Number(form.recoveryFactor) : null;\n if (recoveryFactor != null && (recoveryFactor < 0 || recoveryFactor > 1)) {\n setFormError('Recovery factor must be between 0 and 1.');\n return;\n }\n setFormError(null);\n try {\n await createEstimate.mutateAsync({\n assetId: form.assetId,\n category: form.category,\n asOfDate,\n recoverable,\n recoveryFactor,\n unit: form.unit,\n methodology: form.methodology.trim() || null,\n notes: form.notes.trim() || null,\n });\n notify.success('Reserve estimate created');\n closeDialog();\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create reserve estimate.');\n notify.fromError(err);\n }\n };\n\n const noAssets = !assets.isLoading && (assets.data?.items.length ?? 0) === 0;\n\n return (\n <PageLayout\n title=\"Reserve Estimates\"\n description=\"Booked recoverable volumes per asset — proved, probable, possible, contingent & prospective.\"\n actions={\n <Button onClick={openDialog} disabled={noAssets}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Add estimate\n </Button>\n }\n >\n {/* KPI strip */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n icon={<Database className=\"h-5 w-5\" />}\n value={metricsRows.length}\n label=\"Reserve estimates\"\n featured\n />\n <MetricsCard\n icon={<Layers className=\"h-5 w-5\" />}\n value={\n metrics.dominantUnit\n ? formatVolume(metrics.totalRecoverable, metrics.dominantUnit)\n : '—'\n }\n label={\n metrics.dominantUnit\n ? `Total recoverable (${formatUnit(metrics.dominantUnit)})`\n : 'Total recoverable'\n }\n />\n <MetricsCard\n icon={<Percent className=\"h-5 w-5\" />}\n value={metrics.avgFactor != null ? formatPercent(metrics.avgFactor) : '—'}\n label=\"Avg recovery factor\"\n />\n </div>\n\n {/* Filters */}\n <div className=\"mt-6 mb-5 flex flex-wrap items-center gap-3\">\n <FilterTabs\n options={CATEGORY_FILTERS}\n value={category}\n onChange={(v) => {\n setCategory(v);\n pager.reset();\n }}\n />\n <Select\n value={assetId}\n onValueChange={(v) => {\n setAssetId(v);\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-56\" aria-label=\"Filter by asset\">\n <SelectValue placeholder=\"All assets\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All assets</SelectItem>\n {Object.entries(assetMap).map(([id, name]) => (\n <SelectItem key={id} value={id}>\n {name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading reserve estimates…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load reserve estimates.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Layers className=\"h-10 w-10\" />}\n title=\"No reserve estimates\"\n description={\n noAssets\n ? 'Register a resource asset first, then book its recoverable reserves here.'\n : category === 'ALL' && assetId === 'ALL'\n ? 'Book your first recoverable-reserves estimate against an asset.'\n : 'No estimates match these filters.'\n }\n action={\n !noAssets ? (\n <Button onClick={openDialog}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Add estimate\n </Button>\n ) : undefined\n }\n />\n ) : (\n <>\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(r) => r.id}\n defaultSort={{ key: 'asOfDate', dir: 'desc' }}\n />\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={rows.length}\n hasMore={data?.pageInfo?.hasMore ?? false}\n onPageChange={(p) => pager.onPageChange(p, data?.pageInfo?.cursor)}\n />\n </>\n )}\n\n {/* Add reserve estimate dialog */}\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => (open ? setDialogOpen(true) : closeDialog())}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Add reserve estimate</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Book a recoverable-reserves figure for an asset as of a valuation date.\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-1.5\">\n <Label htmlFor=\"reAsset\">Asset *</Label>\n <Select value={form.assetId} onValueChange={(v) => setForm({ ...form, assetId: v })}>\n <SelectTrigger id=\"reAsset\">\n <SelectValue placeholder=\"Select an asset\" />\n </SelectTrigger>\n <SelectContent>\n {Object.entries(assetMap).map(([id, name]) => (\n <SelectItem key={id} value={id}>\n {name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"reCategory\">Category</Label>\n <Select\n value={form.category}\n onValueChange={(v) => setForm({ ...form, category: v as TheReserveCategory })}\n >\n <SelectTrigger id=\"reCategory\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {RESERVE_CATEGORIES.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=\"reAsOf\">As of date *</Label>\n <Input\n id=\"reAsOf\"\n type=\"date\"\n value={form.asOfDate}\n onChange={(e) => setForm({ ...form, asOfDate: e.target.value })}\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=\"reRecoverable\">Recoverable *</Label>\n <Input\n id=\"reRecoverable\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.recoverable}\n onChange={(e) => setForm({ ...form, recoverable: e.target.value })}\n placeholder=\"1200000\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"reUnit\">Unit</Label>\n <Select\n value={form.unit}\n onValueChange={(v) => setForm({ ...form, unit: v as TheUnit })}\n >\n <SelectTrigger id=\"reUnit\">\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 className=\"grid gap-1.5\">\n <Label htmlFor=\"reFactor\">Recovery factor</Label>\n <Input\n id=\"reFactor\"\n type=\"number\"\n min=\"0\"\n max=\"1\"\n step=\"any\"\n value={form.recoveryFactor}\n onChange={(e) => setForm({ ...form, recoveryFactor: e.target.value })}\n placeholder=\"0.35\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"reMethodology\">Methodology</Label>\n <Input\n id=\"reMethodology\"\n value={form.methodology}\n onChange={(e) => setForm({ ...form, methodology: e.target.value })}\n placeholder=\"Volumetric / decline curve / PRMS deterministic\"\n />\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"reNotes\">Notes</Label>\n <Textarea\n id=\"reNotes\"\n rows={2}\n value={form.notes}\n onChange={(e) => setForm({ ...form, notes: e.target.value })}\n placeholder=\"Optional context about this estimate.\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={closeDialog}>\n Cancel\n </Button>\n <Button type=\"submit\" disabled={createEstimate.isPending}>\n {createEstimate.isPending ? 'Saving…' : 'Add estimate'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqDA,IAAM,KAA+D;CACnE;EAAE,OAAO;EAAO,OAAO;EAAO;CAC9B;EAAE,OAAO;EAAU,OAAO;EAAU;CACpC;EAAE,OAAO;EAAY,OAAO;EAAY;CACxC;EAAE,OAAO;EAAY,OAAO;EAAY;CACxC;EAAE,OAAO;EAAc,OAAO;EAAc;CAC5C;EAAE,OAAO;EAAe,OAAO;EAAe;CAC/C,EAEK,KAA2C;CAC/C;CACA;CACA;CACA;CACA;CACD,EAEK,KAAmB;CAAC;CAAW;CAAgB;CAAU;CAAa;CAAO;CAAM;CAAM,EAEzF,IAAY,IAEZ,2BAAsB,IAAI,MAAM,EAAC,aAAa,CAAC,MAAM,GAAG,GAAG,EAa3D,IAA8B;CAClC,SAAS;CACT,UAAU;CACV,UAAU;CACV,aAAa;CACb,gBAAgB;CAChB,MAAM;CACN,aAAa;CACb,OAAO;CACR;AAED,SAAgB,IAAe;CAC7B,IAAM,IAAS,GAAW,EACpB,CAAC,GAAU,KAAe,EAAqC,MAAM,EACrE,CAAC,GAAS,KAAc,EAAiB,MAAM,EAC/C,IAAQ,IAAgB,EACxB,CAAC,IAAY,KAAiB,EAAS,GAAM,EAC7C,CAAC,GAAM,KAAW,EAA0B,EAAW,EACvD,CAAC,GAAW,KAAgB,EAAwB,KAAK,EAIzD,IAAS,GAAa,EAAE,YAAY;EAAE,OAAO;EAAK,QAAQ;EAAG,EAAE,CAAC,EAChE,IAAW,QAAsC;EACrD,IAAM,IAA8B,EAAE;AACtC,OAAK,IAAM,KAAK,EAAO,MAAM,SAAS,EAAE,CAAE,GAAI,EAAE,MAAM,EAAE;AACxD,SAAO;IACN,CAAC,EAAO,KAAK,CAAC,EAEX,IAAa,MAAY,QAAQ,KAAA,IAAY,GAC7C,IAAgB,MAAa,QAAQ,KAAA,IAAY,GAEjD,EAAE,SAAM,eAAW,aAAS,gBAAY,EAAuB,GAAY,GAAe;EAC9F,OAAO;EACP,QAAQ,EAAM;EACf,CAAC,EAII,IAAe,EAAuB,GAAY,GAAe,EAAE,OAAO,KAAK,CAAC,EAChF,IAAiB,IAA6B,EAE9C,IAAO,QAAc,GAAM,SAAS,EAAE,EAAE,CAAC,EAAK,CAAC,EAC/C,IAAc,QAAc,EAAa,MAAM,SAAS,EAAE,EAAE,CAAC,EAAa,KAAK,CAAC,EAKhF,IAAU,QAAc;EAC5B,IAAM,IAA0C,EAAE;AAClD,OAAK,IAAM,KAAK,EAAa,GAAM,EAAE,SAAS,EAAM,EAAE,SAAS,KAAK;EACpE,IAAM,IAAgB,OAAO,QAAQ,EAAM,CAAyB,MACjE,GAAG,MAAM,EAAE,KAAK,EAAE,GACpB,CAAC,KAAK,IACD,IAAmB,IACrB,EACG,QAAQ,MAAM,EAAE,SAAS,EAAa,CACtC,QAAQ,GAAK,MAAM,IAAM,EAAE,aAAa,EAAE,GAC7C,GACE,IAAa,EAAY,QAAQ,MAAM,EAAE,kBAAkB,KAAK;AAItE,SAAO;GAAE;GAAc;GAAkB,WAHvB,EAAW,SACxB,EAAW,QAAQ,GAAK,MAAM,KAAO,EAAE,kBAAkB,IAAI,EAAE,GAAG,EAAW,SAAU,MACxF;GACgD;IACnD,CAAC,EAAY,CAAC,EAEX,KAAwC;EAC5C;GACE,KAAK;GACL,QAAQ;GACR,SAAS,MACP,kBAAC,QAAD;IAAM,WAAU;cACb,EAAS,EAAE,YAAY,kBAAC,QAAD;KAAM,WAAU;eAAqB;KAAoB,CAAA;IAC5E,CAAA;GAEV;EACD;GACE,KAAK;GACL,QAAQ;GACR,SAAS,MAAM,kBAAC,IAAD,EAAa,QAAQ,EAAE,UAAY,CAAA;GACnD;EACD;GACE,KAAK;GACL,QAAQ;GACR,cAAc;GACd,YAAY,MAAM,IAAI,KAAK,EAAE,SAAS,CAAC,SAAS;GAChD,SAAS,MAAM,kBAAC,QAAD;IAAM,WAAU;cAAuB,EAAW,EAAE,SAAS;IAAQ,CAAA;GACrF;EACD;GACE,KAAK;GACL,QAAQ;GACR,OAAO;GACP,YAAY,MAAM,EAAE;GACpB,SAAS,MACP,kBAAC,QAAD;IAAM,WAAU;cACb,EAAa,EAAE,aAAa,EAAE,KAAK;IAC/B,CAAA;GAEV;EACD;GACE,KAAK;GACL,QAAQ;GACR,OAAO;GACP,cAAc;GACd,YAAY,MAAM,EAAE,kBAAkB;GACtC,SAAS,MACP,EAAE,kBAAkB,OAKlB,kBAAC,QAAD;IAAM,WAAU;cAAqB;IAAQ,CAAA,GAJ7C,kBAAC,QAAD;IAAM,WAAU;cACb,EAAc,EAAE,iBAAiB,IAAI;IACjC,CAAA;GAIZ;EACD;GACE,KAAK;GACL,QAAQ;GACR,cAAc;GACd,SAAS,MACP,EAAE,cACA,kBAAC,QAAD;IAAM,WAAU;cAAuB,EAAE;IAAmB,CAAA,GAE5D,kBAAC,QAAD;IAAM,WAAU;cAAqB;IAAQ,CAAA;GAElD;EACF,EAEK,UAAmB;AAGvB,EAFA,EAAQ;GAAE,GAAG;GAAY,UAAU,GAAO;GAAE,CAAC,EAC7C,EAAa,KAAK,EAClB,EAAc,GAAK;IAGf,UAAoB;AAGxB,EAFA,EAAc,GAAM,EACpB,EAAQ,EAAW,EACnB,EAAa,KAAK;IAGd,KAAe,YAAY;AAC/B,MAAI,CAAC,EAAK,SAAS;AACjB,KAAa,6CAA6C;AAC1D;;EAGF,IAAM,IAAW,GAAc,EAAK,SAAS;AAC7C,MAAI,CAAC,GAAU;AACb,KAAa,iCAA+B;AAC5C;;EAEF,IAAM,IAAc,OAAO,EAAK,YAAY;AAC5C,MAAI,CAAC,EAAK,eAAe,OAAO,MAAM,EAAY,IAAI,KAAe,GAAG;GACtE,IAAM,IAAU;AAEhB,GADA,EAAa,EAAQ,EACrB,EAAO,MAAM,EAAQ;AACrB;;EAEF,IAAM,IAAiB,EAAK,iBAAiB,OAAO,EAAK,eAAe,GAAG;AAC3E,MAAI,KAAkB,SAAS,IAAiB,KAAK,IAAiB,IAAI;AACxE,KAAa,2CAA2C;AACxD;;AAEF,IAAa,KAAK;AAClB,MAAI;AAYF,GAXA,MAAM,EAAe,YAAY;IAC/B,SAAS,EAAK;IACd,UAAU,EAAK;IACf;IACA;IACA;IACA,MAAM,EAAK;IACX,aAAa,EAAK,YAAY,MAAM,IAAI;IACxC,OAAO,EAAK,MAAM,MAAM,IAAI;IAC7B,CAAC,EACF,EAAO,QAAQ,2BAA2B,EAC1C,GAAa;WACN,GAAK;AAEZ,GADA,EAAa,aAAe,QAAQ,EAAI,UAAU,qCAAqC,EACvF,EAAO,UAAU,EAAI;;IAInB,IAAW,CAAC,EAAO,cAAc,EAAO,MAAM,MAAM,UAAU,OAAO;AAE3E,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,GAAD;GAAQ,SAAS;GAAY,UAAU;aAAvC,CACE,kBAAC,GAAD,EAAM,WAAU,kBAAmB,CAAA,EAAA,gBAC5B;;YANb;GAUE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,MAAM,kBAAC,IAAD,EAAU,WAAU,WAAY,CAAA;MACtC,OAAO,EAAY;MACnB,OAAM;MACN,UAAA;MACA,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;MACpC,OACE,EAAQ,eACJ,EAAa,EAAQ,kBAAkB,EAAQ,aAAa,GAC5D;MAEN,OACE,EAAQ,eACJ,sBAAsB,EAAW,EAAQ,aAAa,CAAC,KACvD;MAEN,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,kBAAC,IAAD,EAAS,WAAU,WAAY,CAAA;MACrC,OAAO,EAAQ,aAAa,OAA0C,MAAnC,EAAc,EAAQ,UAAU;MACnE,OAAM;MACN,CAAA;KACE;;GAGN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KACE,SAAS;KACT,OAAO;KACP,WAAW,MAAM;AAEf,MADA,EAAY,EAAE,EACd,EAAM,OAAO;;KAEf,CAAA,EACF,kBAAC,GAAD;KACE,OAAO;KACP,gBAAgB,MAAM;AAEpB,MADA,EAAW,EAAE,EACb,EAAM,OAAO;;eAJjB,CAOE,kBAAC,GAAD;MAAe,WAAU;MAAO,cAAW;gBACzC,kBAAC,GAAD,EAAa,aAAY,cAAe,CAAA;MAC1B,CAAA,EAChB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;MAAY,OAAM;gBAAM;MAAuB,CAAA,EAC9C,OAAO,QAAQ,EAAS,CAAC,KAAK,CAAC,GAAI,OAClC,kBAAC,GAAD;MAAqB,OAAO;gBACzB;MACU,EAFI,EAEJ,CACb,CACY,EAAA,CAAA,CACT;OACL;;GAEL,KACC,kBAAC,GAAD,EAAa,OAAM,8BAA+B,CAAA,GAChD,KACF,kBAAC,IAAD;IAAW,SAAQ;IAAmC,eAAe,IAAS;IAAI,CAAA,GAChF,EAAK,WAAW,IAClB,kBAAC,IAAD;IACE,cAAa;IACb,MAAM,kBAAC,GAAD,EAAQ,WAAU,aAAc,CAAA;IACtC,OAAM;IACN,aACE,IACI,8EACA,MAAa,SAAS,MAAY,QAChC,oEACA;IAER,QACG,IAIG,KAAA,IAHF,kBAAC,GAAD;KAAQ,SAAS;eAAjB,CACE,kBAAC,GAAD,EAAM,WAAU,kBAAmB,CAAA,EAAA,gBAC5B;;IAGb,CAAA,GAEF,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,IAAD;IACW;IACH;IACN,SAAS,MAAM,EAAE;IACjB,aAAa;KAAE,KAAK;KAAY,KAAK;KAAQ;IAC7C,CAAA,EACF,kBAAC,GAAD;IACE,MAAM,EAAM;IACZ,UAAU;IACV,WAAW,EAAK;IAChB,SAAS,GAAM,UAAU,WAAW;IACpC,eAAe,MAAM,EAAM,aAAa,GAAG,GAAM,UAAU,OAAO;IAClE,CAAA,CACD,EAAA,CAAA;GAIL,kBAAC,IAAD;IACE,MAAM;IACN,eAAe,MAAU,IAAO,EAAc,GAAK,GAAG,GAAa;cAEnE,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,IAAD,EAAA,UAAuB,wBAA4C,CAAA,EACnE,kBAAC,IAAD,EAAA,UAA6B,2EAEC,CAAA,CACP,EAAA,CAAA,EAEzB,kBAAC,QAAD;KACE,WAAW,MAAM;AAEV,MADL,EAAE,gBAAgB,EACb,IAAc;;eAHvB,CAME,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACA,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAO,SAAQ;mBAAU;SAAe,CAAA,EACxC,kBAAC,GAAD;SAAQ,OAAO,EAAK;SAAS,gBAAgB,MAAM,EAAQ;UAAE,GAAG;UAAM,SAAS;UAAG,CAAC;mBAAnF,CACE,kBAAC,GAAD;UAAe,IAAG;oBAChB,kBAAC,GAAD,EAAa,aAAY,mBAAoB,CAAA;UAC/B,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,OAAO,QAAQ,EAAS,CAAC,KAAK,CAAC,GAAI,OAClC,kBAAC,GAAD;UAAqB,OAAO;oBACzB;UACU,EAFI,EAEJ,CACb,EACY,CAAA,CACT;WACL;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAO,SAAQ;oBAAa;UAAgB,CAAA,EAC5C,kBAAC,GAAD;UACE,OAAO,EAAK;UACZ,gBAAgB,MAAM,EAAQ;WAAE,GAAG;WAAM,UAAU;WAAyB,CAAC;oBAF/E,CAIE,kBAAC,GAAD;WAAe,IAAG;qBAChB,kBAAC,GAAD,EAAe,CAAA;WACD,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,GAAmB,KAAK,MACvB,kBAAC,GAAD;WAAoB,OAAO;qBACxB,EAAgB,EAAE;WACR,EAFI,EAEJ,CACb,EACY,CAAA,CACT;YACL;YACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAO,SAAQ;oBAAS;UAAoB,CAAA,EAC5C,kBAAC,GAAD;UACE,IAAG;UACH,MAAK;UACL,OAAO,EAAK;UACZ,WAAW,MAAM,EAAQ;WAAE,GAAG;WAAM,UAAU,EAAE,OAAO;WAAO,CAAC;UAC/D,CAAA,CACE;WACF;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD;WAAO,SAAQ;qBAAgB;WAAqB,CAAA,EACpD,kBAAC,GAAD;WACE,IAAG;WACH,MAAK;WACL,KAAI;WACJ,MAAK;WACL,OAAO,EAAK;WACZ,WAAW,MAAM,EAAQ;YAAE,GAAG;YAAM,aAAa,EAAE,OAAO;YAAO,CAAC;WAClE,aAAY;WACZ,CAAA,CACE;;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD;WAAO,SAAQ;qBAAS;WAAY,CAAA,EACpC,kBAAC,GAAD;WACE,OAAO,EAAK;WACZ,gBAAgB,MAAM,EAAQ;YAAE,GAAG;YAAM,MAAM;YAAc,CAAC;qBAFhE,CAIE,kBAAC,GAAD;YAAe,IAAG;sBAChB,kBAAC,GAAD,EAAe,CAAA;YACD,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,GAAM,KAAK,MACV,kBAAC,GAAD;YAAoB,OAAO;sBACxB,EAAW,EAAE;YACH,EAFI,EAEJ,CACb,EACY,CAAA,CACT;aACL;;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD;WAAO,SAAQ;qBAAW;WAAuB,CAAA,EACjD,kBAAC,GAAD;WACE,IAAG;WACH,MAAK;WACL,KAAI;WACJ,KAAI;WACJ,MAAK;WACL,OAAO,EAAK;WACZ,WAAW,MAAM,EAAQ;YAAE,GAAG;YAAM,gBAAgB,EAAE,OAAO;YAAO,CAAC;WACrE,aAAY;WACZ,CAAA,CACE;;SACF;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAO,SAAQ;mBAAgB;SAAmB,CAAA,EAClD,kBAAC,GAAD;SACE,IAAG;SACH,OAAO,EAAK;SACZ,WAAW,MAAM,EAAQ;UAAE,GAAG;UAAM,aAAa,EAAE,OAAO;UAAO,CAAC;SAClE,aAAY;SACZ,CAAA,CACE;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAO,SAAQ;mBAAU;SAAa,CAAA,EACtC,kBAAC,IAAD;SACE,IAAG;SACH,MAAM;SACN,OAAO,EAAK;SACZ,WAAW,MAAM,EAAQ;UAAE,GAAG;UAAM,OAAO,EAAE,OAAO;UAAO,CAAC;SAC5D,aAAY;SACZ,CAAA,CACE;;OAEL,KAAa,kBAAC,KAAD;QAAG,WAAU;kBAAkC;QAAc,CAAA;OACrE;SAEN,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,GAAD;MAAQ,MAAK;MAAS,SAAQ;MAAU,SAAS;gBAAa;MAErD,CAAA,EACT,kBAAC,GAAD;MAAQ,MAAK;MAAS,UAAU,EAAe;gBAC5C,EAAe,YAAY,YAAY;MACjC,CAAA,CACc,EAAA,CAAA,CACpB;OACiB,EAAA,CAAA;IACT,CAAA;GACR"}
|
|
1
|
+
{"version":3,"file":"ReservesPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/reserves/ReservesPage.tsx"],"sourcesContent":["/**\n * Reserve Estimates — booked recoverable volumes per asset, by category.\n * @module theglobalfuel/pages/reserves\n *\n * Reads `theListReserveEstimates` (a cursor connection — `{ items, pageInfo }`);\n * writes `theCreateReserveEstimate`. Asset names are resolved from `theListAssets`\n * since the reserve payload carries only `assetId`. No mock data.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, Layers, Database, Percent } 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 { MetricsCard } from '../../components/MetricsCard';\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 {\n useTheAssets,\n useTheReserveEstimates,\n useTheCreateReserveEstimate,\n useCursorPager,\n useNotify,\n} from '../../hooks';\nimport {\n formatDate,\n formatVolume,\n formatPercent,\n formatUnit,\n formatEnumLabel,\n} from '../../utils/formatters';\nimport { toBackendDate } from '../../utils';\nimport type { TheReserveEstimate, TheReserveCategory, TheUnit } from '../../types';\n\nconst CATEGORY_FILTERS: FilterOption<TheReserveCategory | 'ALL'>[] = [\n { value: 'ALL', label: 'All' },\n { value: 'PROVED', label: 'Proved' },\n { value: 'PROBABLE', label: 'Probable' },\n { value: 'POSSIBLE', label: 'Possible' },\n { value: 'CONTINGENT', label: 'Contingent' },\n { value: 'PROSPECTIVE', label: 'Prospective' },\n];\n\nconst RESERVE_CATEGORIES: TheReserveCategory[] = [\n 'PROVED',\n 'PROBABLE',\n 'POSSIBLE',\n 'CONTINGENT',\n 'PROSPECTIVE',\n];\n\nconst UNITS: TheUnit[] = ['BARRELS', 'CUBIC_METERS', 'TONNES', 'KILOGRAMS', 'MWH', 'GJ', 'MCF'];\n\nconst PAGE_SIZE = 25;\n\nconst today = (): string => new Date().toISOString().slice(0, 10);\n\ninterface CreateFormState {\n assetId: string;\n category: TheReserveCategory;\n asOfDate: string;\n recoverable: string;\n recoveryFactor: string;\n unit: TheUnit;\n methodology: string;\n notes: string;\n}\n\nconst EMPTY_FORM: CreateFormState = {\n assetId: '',\n category: 'PROVED',\n asOfDate: '',\n recoverable: '',\n recoveryFactor: '',\n unit: 'BARRELS',\n methodology: '',\n notes: '',\n};\n\nexport function ReservesPage() {\n const notify = useNotify();\n const [category, setCategory] = useState<TheReserveCategory | 'ALL'>('ALL');\n const [assetId, setAssetId] = useState<string>('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 // Asset registry — feeds both the filter Select and the create dialog, and\n // resolves asset names for the reserve rows (payload carries only assetId).\n const assets = useTheAssets({ pagination: { limit: 100, offset: 0 } });\n const assetMap = useMemo<Record<string, string>>(() => {\n const map: Record<string, string> = {};\n for (const a of assets.data?.items ?? []) map[a.id] = a.name;\n return map;\n }, [assets.data]);\n\n const assetScope = assetId === 'ALL' ? undefined : assetId;\n const categoryScope = category === 'ALL' ? undefined : category;\n\n const { data, isLoading, isError, refetch } = useTheReserveEstimates(assetScope, categoryScope, {\n limit: PAGE_SIZE,\n offset: pager.page * PAGE_SIZE,\n });\n // Same-filter broad query for the header KPIs. The table is paginated to\n // PAGE_SIZE, so the metrics must read from a representative set (not one page)\n // or the counts/totals would silently reflect only the first 25 rows.\n const metricsQuery = useTheReserveEstimates(assetScope, categoryScope, { limit: 200 });\n const createEstimate = useTheCreateReserveEstimate();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n const metricsRows = useMemo(() => metricsQuery.data?.items ?? [], [metricsQuery.data]);\n\n // Header metrics — computed from the (filtered) portfolio, not just the current\n // page. We surface the total recoverable in the *dominant* unit so we never sum\n // apples & oranges.\n const metrics = useMemo(() => {\n const tally: Partial<Record<TheUnit, number>> = {};\n for (const r of metricsRows) tally[r.unit] = (tally[r.unit] ?? 0) + 1;\n const dominantUnit = (Object.entries(tally) as [TheUnit, number][]).sort(\n (a, b) => b[1] - a[1]\n )[0]?.[0];\n const totalRecoverable = dominantUnit\n ? metricsRows\n .filter((r) => r.unit === dominantUnit)\n .reduce((sum, r) => sum + r.recoverable, 0)\n : 0;\n const withFactor = metricsRows.filter((r) => r.recoveryFactor != null);\n const avgFactor = withFactor.length\n ? (withFactor.reduce((sum, r) => sum + (r.recoveryFactor ?? 0), 0) / withFactor.length) * 100\n : null;\n return { dominantUnit, totalRecoverable, avgFactor };\n }, [metricsRows]);\n\n const columns: Column<TheReserveEstimate>[] = [\n {\n key: 'asset',\n header: 'Asset',\n render: (r) => (\n <span className=\"font-semibold text-text-primary\">\n {assetMap[r.assetId] ?? <span className=\"text-text-tertiary\">Unknown asset</span>}\n </span>\n ),\n },\n {\n key: 'category',\n header: 'Category',\n render: (r) => <StatusBadge status={r.category} />,\n },\n {\n key: 'asOfDate',\n header: 'As of',\n hideOnMobile: true,\n sortValue: (r) => new Date(r.asOfDate).getTime(),\n render: (r) => <span className=\"text-text-secondary\">{formatDate(r.asOfDate)}</span>,\n },\n {\n key: 'recoverable',\n header: 'Recoverable',\n align: 'right',\n sortValue: (r) => r.recoverable,\n render: (r) => (\n <span className=\"tabular-nums font-medium text-text-primary\">\n {formatVolume(r.recoverable, r.unit)}\n </span>\n ),\n },\n {\n key: 'recoveryFactor',\n header: 'Recovery factor',\n align: 'right',\n hideOnMobile: true,\n sortValue: (r) => r.recoveryFactor ?? -1,\n render: (r) =>\n r.recoveryFactor != null ? (\n <span className=\"tabular-nums text-text-secondary\">\n {formatPercent(r.recoveryFactor * 100)}\n </span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'methodology',\n header: 'Methodology',\n hideOnMobile: true,\n render: (r) =>\n r.methodology ? (\n <span className=\"text-text-secondary\">{r.methodology}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n ];\n\n const openDialog = () => {\n setForm({ ...EMPTY_FORM, asOfDate: today() });\n setFormError(null);\n setDialogOpen(true);\n };\n\n const closeDialog = () => {\n setDialogOpen(false);\n setForm(EMPTY_FORM);\n setFormError(null);\n };\n\n const handleCreate = async () => {\n if (!form.assetId) {\n setFormError('Select the asset this estimate belongs to.');\n return;\n }\n // Anchor the date-only input at noon UTC so the calendar day survives every TZ.\n const asOfDate = toBackendDate(form.asOfDate);\n if (!asOfDate) {\n setFormError('An \"as of\" date is required.');\n return;\n }\n const recoverable = Number(form.recoverable);\n if (!form.recoverable || Number.isNaN(recoverable) || recoverable <= 0) {\n const message = 'Recoverable volume must be greater than zero.';\n setFormError(message);\n notify.error(message);\n return;\n }\n const recoveryFactor = form.recoveryFactor ? Number(form.recoveryFactor) : null;\n if (recoveryFactor != null && (recoveryFactor < 0 || recoveryFactor > 1)) {\n setFormError('Recovery factor must be between 0 and 1.');\n return;\n }\n setFormError(null);\n try {\n await createEstimate.mutateAsync({\n assetId: form.assetId,\n category: form.category,\n asOfDate,\n recoverable,\n recoveryFactor,\n unit: form.unit,\n methodology: form.methodology.trim() || null,\n notes: form.notes.trim() || null,\n });\n notify.success('Reserve estimate created');\n closeDialog();\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create reserve estimate.');\n notify.fromError(err);\n }\n };\n\n const noAssets = !assets.isLoading && (assets.data?.items.length ?? 0) === 0;\n\n return (\n <PageLayout\n title=\"Reserve Estimates\"\n description=\"Booked recoverable volumes per asset — proved, probable, possible, contingent & prospective.\"\n actions={\n <Button onClick={openDialog} disabled={noAssets}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Add estimate\n </Button>\n }\n >\n {/* KPI strip */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n icon={<Database className=\"h-5 w-5\" />}\n value={metricsRows.length}\n label=\"Reserve estimates\"\n featured\n />\n <MetricsCard\n icon={<Layers className=\"h-5 w-5\" />}\n value={\n metrics.dominantUnit\n ? formatVolume(metrics.totalRecoverable, metrics.dominantUnit)\n : '—'\n }\n label={\n metrics.dominantUnit\n ? `Total recoverable (${formatUnit(metrics.dominantUnit)})`\n : 'Total recoverable'\n }\n />\n <MetricsCard\n icon={<Percent className=\"h-5 w-5\" />}\n value={metrics.avgFactor != null ? formatPercent(metrics.avgFactor) : '—'}\n label=\"Avg recovery factor\"\n />\n </div>\n\n {/* Filters */}\n <div className=\"mt-6 mb-5 flex flex-wrap items-center gap-3\">\n <FilterTabs\n options={CATEGORY_FILTERS}\n value={category}\n onChange={(v) => {\n setCategory(v);\n pager.reset();\n }}\n />\n <Select\n value={assetId}\n onValueChange={(v) => {\n setAssetId(v);\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-56\" aria-label=\"Filter by asset\">\n <SelectValue placeholder=\"All assets\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All assets</SelectItem>\n {Object.entries(assetMap).map(([id, name]) => (\n <SelectItem key={id} value={id}>\n {name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading reserve estimates…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load reserve estimates.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Layers className=\"h-10 w-10\" />}\n title=\"No reserve estimates\"\n description={\n noAssets\n ? 'Register a resource asset first, then book its recoverable reserves here.'\n : category === 'ALL' && assetId === 'ALL'\n ? 'Book your first recoverable-reserves estimate against an asset.'\n : 'No estimates match these filters.'\n }\n action={\n !noAssets ? (\n <Button onClick={openDialog}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Add estimate\n </Button>\n ) : undefined\n }\n />\n ) : (\n <>\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(r) => r.id}\n defaultSort={{ key: 'asOfDate', dir: 'desc' }}\n />\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={rows.length}\n hasMore={data?.pageInfo?.hasMore ?? false}\n onPageChange={pager.onPageChange}\n />\n </>\n )}\n\n {/* Add reserve estimate dialog */}\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => (open ? setDialogOpen(true) : closeDialog())}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Add reserve estimate</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Book a recoverable-reserves figure for an asset as of a valuation date.\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-1.5\">\n <Label htmlFor=\"reAsset\">Asset *</Label>\n <Select value={form.assetId} onValueChange={(v) => setForm({ ...form, assetId: v })}>\n <SelectTrigger id=\"reAsset\">\n <SelectValue placeholder=\"Select an asset\" />\n </SelectTrigger>\n <SelectContent>\n {Object.entries(assetMap).map(([id, name]) => (\n <SelectItem key={id} value={id}>\n {name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"reCategory\">Category</Label>\n <Select\n value={form.category}\n onValueChange={(v) => setForm({ ...form, category: v as TheReserveCategory })}\n >\n <SelectTrigger id=\"reCategory\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {RESERVE_CATEGORIES.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=\"reAsOf\">As of date *</Label>\n <Input\n id=\"reAsOf\"\n type=\"date\"\n value={form.asOfDate}\n onChange={(e) => setForm({ ...form, asOfDate: e.target.value })}\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=\"reRecoverable\">Recoverable *</Label>\n <Input\n id=\"reRecoverable\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.recoverable}\n onChange={(e) => setForm({ ...form, recoverable: e.target.value })}\n placeholder=\"1200000\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"reUnit\">Unit</Label>\n <Select\n value={form.unit}\n onValueChange={(v) => setForm({ ...form, unit: v as TheUnit })}\n >\n <SelectTrigger id=\"reUnit\">\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 className=\"grid gap-1.5\">\n <Label htmlFor=\"reFactor\">Recovery factor</Label>\n <Input\n id=\"reFactor\"\n type=\"number\"\n min=\"0\"\n max=\"1\"\n step=\"any\"\n value={form.recoveryFactor}\n onChange={(e) => setForm({ ...form, recoveryFactor: e.target.value })}\n placeholder=\"0.35\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"reMethodology\">Methodology</Label>\n <Input\n id=\"reMethodology\"\n value={form.methodology}\n onChange={(e) => setForm({ ...form, methodology: e.target.value })}\n placeholder=\"Volumetric / decline curve / PRMS deterministic\"\n />\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"reNotes\">Notes</Label>\n <Textarea\n id=\"reNotes\"\n rows={2}\n value={form.notes}\n onChange={(e) => setForm({ ...form, notes: e.target.value })}\n placeholder=\"Optional context about this estimate.\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={closeDialog}>\n Cancel\n </Button>\n <Button type=\"submit\" disabled={createEstimate.isPending}>\n {createEstimate.isPending ? 'Saving…' : 'Add estimate'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|