@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":"ProductionPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/production/ProductionPage.tsx"],"sourcesContent":["/**\n * Production — every production record across all assets.\n * @module theglobalfuel/pages/production\n *\n * Reads `theListProductionRecords` (optionally filtered by asset); writes\n * `theRecordProduction`. Asset names are resolved from `theListAssets`. The KPI\n * strip summarises the volume + downtime captured on the current page. No mock\n * data — every number comes from the real `wspace-theglobalfuel-svc` contract.\n */\n\nimport { useMemo, useState, type ReactNode } from 'react';\nimport { Plus, BarChart3, Droplets, Clock, Gauge } 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 { DataTable, type Column } from '../../components/DataTable';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Pagination } from '../../components/Pagination';\nimport { useTheGlobalFuel } from '../../context';\nimport {\n useTheAssets,\n useTheProductionRecords,\n useTheRecordProduction,\n useCursorPager,\n} from '../../hooks';\nimport {\n formatDate,\n formatNumber,\n formatRelativeTime,\n formatVolume,\n formatEnumLabel,\n} from '../../utils/formatters';\nimport type { TheProductionRecord, TheUnit } from '../../types';\n\nconst UNITS: TheUnit[] = [\n 'BARRELS',\n 'CUBIC_METERS',\n 'TONNES',\n 'KILOGRAMS',\n 'MWH',\n 'GJ',\n 'MCF',\n];\n\nconst PAGE_SIZE = 25;\n\nconst today = (): string => new Date().toISOString().slice(0, 10);\n\ninterface RecordFormState {\n assetId: string;\n periodStart: string;\n periodEnd: string;\n volume: string;\n unit: TheUnit;\n grade: string;\n downtimeHours: string;\n notes: string;\n}\n\nconst emptyForm = (): RecordFormState => ({\n assetId: '',\n periodStart: today(),\n periodEnd: today(),\n volume: '',\n unit: 'BARRELS',\n grade: '',\n downtimeHours: '',\n notes: '',\n});\n\nexport function ProductionPage() {\n const { navigateTo } = useTheGlobalFuel();\n const [assetId, setAssetId] = useState<string>('ALL');\n const pager = useCursorPager();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<RecordFormState>(emptyForm);\n const [formError, setFormError] = useState<string | null>(null);\n\n // Assets feed the filter Select, the create picker, and the id→name map.\n const assetsQuery = useTheAssets({ pagination: { limit: 100 } });\n const assetMap = useMemo<Record<string, string>>(() => {\n const map: Record<string, string> = {};\n for (const a of assetsQuery.data?.items ?? []) map[a.id] = a.name;\n return map;\n }, [assetsQuery.data]);\n\n const { data, isLoading, isError, refetch } = useTheProductionRecords({\n assetId: assetId === 'ALL' ? undefined : assetId,\n pagination: { limit: PAGE_SIZE, cursor: pager.cursor },\n });\n const recordProduction = useTheRecordProduction();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n\n // KPI summary — page-scoped totals (volume grouped by unit, downtime summed).\n const { volumeValue, volumeFooter, downtimeTotal } = useMemo(() => {\n const byUnit = new Map<TheUnit, number>();\n let downtime = 0;\n for (const r of rows) {\n byUnit.set(r.unit, (byUnit.get(r.unit) ?? 0) + r.volume);\n downtime += r.downtimeHours;\n }\n const units = [...byUnit.entries()];\n let value: string;\n let footer: ReactNode | undefined;\n if (units.length === 0) {\n value = '—';\n } else if (units.length === 1) {\n value = formatVolume(units[0][1], units[0][0]);\n } else {\n value = 'Mixed units';\n footer = (\n <p className=\"text-xs tabular-nums text-text-tertiary\">\n {units.map(([u, v]) => formatVolume(v, u)).join(' · ')}\n </p>\n );\n }\n return { volumeValue: value, volumeFooter: footer, downtimeTotal: downtime };\n }, [rows]);\n\n const columns: Column<TheProductionRecord>[] = [\n {\n key: 'asset',\n header: 'Asset',\n render: (r) => (\n <div className=\"min-w-0\">\n <p className=\"truncate font-semibold text-text-primary\">\n {assetMap[r.assetId] ?? `${r.assetId.slice(0, 8)}…`}\n </p>\n </div>\n ),\n },\n {\n key: 'period',\n header: 'Period',\n hideOnMobile: true,\n sortValue: (r) => new Date(r.periodStart).getTime(),\n render: (r) => (\n <span className=\"text-text-secondary\">\n {formatDate(r.periodStart)} – {formatDate(r.periodEnd)}\n </span>\n ),\n },\n {\n key: 'volume',\n header: 'Volume',\n align: 'right',\n sortValue: (r) => r.volume,\n render: (r) => (\n <span className=\"tabular-nums font-medium text-text-primary\">\n {formatVolume(r.volume, r.unit)}\n </span>\n ),\n },\n {\n key: 'grade',\n header: 'Grade',\n align: 'right',\n hideOnMobile: true,\n sortValue: (r) => r.grade ?? 0,\n render: (r) =>\n r.grade != null ? (\n <span className=\"tabular-nums text-text-secondary\">{formatNumber(r.grade)}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'downtime',\n header: 'Downtime',\n align: 'right',\n hideOnMobile: true,\n sortValue: (r) => r.downtimeHours,\n render: (r) => (\n <span className=\"tabular-nums text-text-secondary\">{formatNumber(r.downtimeHours)}h</span>\n ),\n },\n {\n key: 'created',\n header: 'Logged',\n align: 'right',\n hideOnMobile: true,\n render: (r) => <span className=\"text-text-tertiary\">{formatRelativeTime(r.createdAt)}</span>,\n },\n ];\n\n const openDialog = () => {\n setForm(emptyForm());\n setFormError(null);\n setDialogOpen(true);\n };\n\n const handleRecord = async () => {\n if (!form.assetId) {\n setFormError('Select an asset.');\n return;\n }\n if (!form.periodStart || !form.periodEnd) {\n setFormError('Period start and end are required.');\n return;\n }\n if (new Date(form.periodEnd).getTime() < new Date(form.periodStart).getTime()) {\n setFormError('Period end must be on or after the period start.');\n return;\n }\n if (!form.volume) {\n setFormError('Volume is required.');\n return;\n }\n setFormError(null);\n try {\n await recordProduction.mutateAsync({\n assetId: form.assetId,\n periodStart: new Date(form.periodStart).toISOString(),\n periodEnd: new Date(form.periodEnd).toISOString(),\n volume: Number(form.volume),\n unit: form.unit,\n grade: form.grade ? Number(form.grade) : null,\n downtimeHours: form.downtimeHours ? Number(form.downtimeHours) : null,\n notes: form.notes.trim() || null,\n });\n setDialogOpen(false);\n setForm(emptyForm());\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to record production.');\n }\n };\n\n const assetOptions = assetsQuery.data?.items ?? [];\n\n return (\n <PageLayout\n title=\"Production\"\n description=\"Captured production volumes across every field, well, mine & plant — with downtime and grade.\"\n actions={\n <Button onClick={openDialog}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Record production\n </Button>\n }\n >\n {/* KPI strip — page-scoped totals */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n icon={<Droplets className=\"h-5 w-5\" />}\n value={volumeValue}\n label=\"Volume on this page\"\n featured\n footer={volumeFooter}\n />\n <MetricsCard\n icon={<Clock className=\"h-5 w-5\" />}\n value={`${formatNumber(downtimeTotal)}h`}\n label=\"Downtime on this page\"\n accent={downtimeTotal > 0 ? 'warning' : undefined}\n />\n <MetricsCard\n icon={<BarChart3 className=\"h-5 w-5\" />}\n value={rows.length}\n label=\"Records on this page\"\n />\n </div>\n\n {/* Filter */}\n <div className=\"mt-6 mb-5 flex flex-wrap items-center gap-3\">\n <Select\n value={assetId}\n onValueChange={(v) => {\n setAssetId(v);\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-56\">\n <SelectValue placeholder=\"All assets\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All assets</SelectItem>\n {assetOptions.map((a) => (\n <SelectItem key={a.id} value={a.id}>\n {a.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading production records…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load production records.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Gauge className=\"h-10 w-10\" />}\n title=\"No production recorded\"\n description={\n assetId === 'ALL'\n ? 'Record a production period to start tracking output, grade and downtime.'\n : 'No production has been recorded for this asset yet.'\n }\n action={\n <Button onClick={openDialog}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Record production\n </Button>\n }\n />\n ) : (\n <>\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(r) => r.id}\n onRowClick={(r) => navigateTo(`assets/${r.assetId}`)}\n defaultSort={{ key: 'period', 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={(target) => pager.onPageChange(target, data?.pageInfo?.cursor)}\n />\n </>\n )}\n\n {/* Record production dialog */}\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n setDialogOpen(open);\n if (!open) {\n setForm(emptyForm());\n setFormError(null);\n }\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Record production</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Log the volume produced by an asset over a reporting period.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"prAsset\">Asset *</Label>\n <Select\n value={form.assetId}\n onValueChange={(v) => setForm({ ...form, assetId: v })}\n >\n <SelectTrigger id=\"prAsset\">\n <SelectValue placeholder=\"Select an asset\" />\n </SelectTrigger>\n <SelectContent>\n {assetOptions.map((a) => (\n <SelectItem key={a.id} value={a.id}>\n {a.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=\"prStart\">Period start *</Label>\n <Input\n id=\"prStart\"\n type=\"date\"\n value={form.periodStart}\n onChange={(e) => setForm({ ...form, periodStart: e.target.value })}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"prEnd\">Period end *</Label>\n <Input\n id=\"prEnd\"\n type=\"date\"\n value={form.periodEnd}\n onChange={(e) => setForm({ ...form, periodEnd: e.target.value })}\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=\"prVolume\">Volume *</Label>\n <Input\n id=\"prVolume\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.volume}\n onChange={(e) => setForm({ ...form, volume: e.target.value })}\n placeholder=\"12500\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"prUnit\">Unit</Label>\n <Select\n value={form.unit}\n onValueChange={(v) => setForm({ ...form, unit: v as TheUnit })}\n >\n <SelectTrigger id=\"prUnit\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {UNITS.map((u) => (\n <SelectItem key={u} value={u}>\n {formatEnumLabel(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=\"prGrade\">Grade</Label>\n <Input\n id=\"prGrade\"\n type=\"number\"\n step=\"any\"\n value={form.grade}\n onChange={(e) => setForm({ ...form, grade: e.target.value })}\n placeholder=\"Quality / concentration\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"prDowntime\">Downtime (hours)</Label>\n <Input\n id=\"prDowntime\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.downtimeHours}\n onChange={(e) => setForm({ ...form, downtimeHours: e.target.value })}\n placeholder=\"0\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"prNotes\">Notes</Label>\n <Textarea\n id=\"prNotes\"\n rows={2}\n value={form.notes}\n onChange={(e) => setForm({ ...form, notes: e.target.value })}\n placeholder=\"Optional context about this period.\"\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={handleRecord} disabled={recordProduction.isPending}>\n {recordProduction.isPending ? 'Recording…' : 'Record production'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProductionPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/production/ProductionPage.tsx"],"sourcesContent":["/**\n * Production — every production record across all assets.\n * @module theglobalfuel/pages/production\n *\n * Reads `theListProductionRecords` (optionally filtered by asset); writes\n * `theRecordProduction`. Asset names are resolved from `theListAssets`. The KPI\n * strip summarises the volume + downtime captured on the current page. No mock\n * data — every number comes from the real `wspace-theglobalfuel-svc` contract.\n */\n\nimport { useMemo, useState, type ReactNode } from 'react';\nimport { Plus, BarChart3, Droplets, Clock, Gauge } 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 { DataTable, type Column } from '../../components/DataTable';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Pagination } from '../../components/Pagination';\nimport { useTheGlobalFuel } from '../../context';\nimport {\n useTheAssets,\n useTheProductionRecords,\n useTheRecordProduction,\n useCursorPager,\n useNotify,\n} from '../../hooks';\nimport {\n formatDate,\n formatNumber,\n formatRelativeTime,\n formatVolume,\n formatEnumLabel,\n} from '../../utils/formatters';\nimport { toBackendDate } from '../../utils';\nimport type { TheProductionRecord, TheUnit } from '../../types';\n\nconst UNITS: TheUnit[] = [\n 'BARRELS',\n 'CUBIC_METERS',\n 'TONNES',\n 'KILOGRAMS',\n 'MWH',\n 'GJ',\n 'MCF',\n];\n\nconst PAGE_SIZE = 25;\n\nconst today = (): string => new Date().toISOString().slice(0, 10);\n\ninterface RecordFormState {\n assetId: string;\n periodStart: string;\n periodEnd: string;\n volume: string;\n unit: TheUnit;\n grade: string;\n downtimeHours: string;\n notes: string;\n}\n\nconst emptyForm = (): RecordFormState => ({\n assetId: '',\n periodStart: today(),\n periodEnd: today(),\n volume: '',\n unit: 'BARRELS',\n grade: '',\n downtimeHours: '',\n notes: '',\n});\n\nexport function ProductionPage() {\n const { navigateTo } = useTheGlobalFuel();\n const notify = useNotify();\n const [assetId, setAssetId] = useState<string>('ALL');\n const pager = useCursorPager();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<RecordFormState>(emptyForm);\n const [formError, setFormError] = useState<string | null>(null);\n\n // Assets feed the filter Select, the create picker, and the id→name map.\n const assetsQuery = useTheAssets({ pagination: { limit: 100 } });\n const assetMap = useMemo<Record<string, string>>(() => {\n const map: Record<string, string> = {};\n for (const a of assetsQuery.data?.items ?? []) map[a.id] = a.name;\n return map;\n }, [assetsQuery.data]);\n\n const { data, isLoading, isError, refetch } = useTheProductionRecords({\n assetId: assetId === 'ALL' ? undefined : assetId,\n pagination: { limit: PAGE_SIZE, cursor: pager.cursor },\n });\n const recordProduction = useTheRecordProduction();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n\n // KPI summary — page-scoped totals (volume grouped by unit, downtime summed).\n const { volumeValue, volumeFooter, downtimeTotal } = useMemo(() => {\n const byUnit = new Map<TheUnit, number>();\n let downtime = 0;\n for (const r of rows) {\n byUnit.set(r.unit, (byUnit.get(r.unit) ?? 0) + r.volume);\n downtime += r.downtimeHours;\n }\n const units = [...byUnit.entries()];\n let value: string;\n let footer: ReactNode | undefined;\n if (units.length === 0) {\n value = '—';\n } else if (units.length === 1) {\n value = formatVolume(units[0][1], units[0][0]);\n } else {\n value = 'Mixed units';\n footer = (\n <p className=\"text-xs tabular-nums text-text-tertiary\">\n {units.map(([u, v]) => formatVolume(v, u)).join(' · ')}\n </p>\n );\n }\n return { volumeValue: value, volumeFooter: footer, downtimeTotal: downtime };\n }, [rows]);\n\n const columns: Column<TheProductionRecord>[] = [\n {\n key: 'asset',\n header: 'Asset',\n render: (r) => (\n <div className=\"min-w-0\">\n <p className=\"truncate font-semibold text-text-primary\">\n {assetMap[r.assetId] ?? `${r.assetId.slice(0, 8)}…`}\n </p>\n </div>\n ),\n },\n {\n key: 'period',\n header: 'Period',\n hideOnMobile: true,\n sortValue: (r) => new Date(r.periodStart).getTime(),\n render: (r) => (\n <span className=\"text-text-secondary\">\n {formatDate(r.periodStart)} – {formatDate(r.periodEnd)}\n </span>\n ),\n },\n {\n key: 'volume',\n header: 'Volume',\n align: 'right',\n sortValue: (r) => r.volume,\n render: (r) => (\n <span className=\"tabular-nums font-medium text-text-primary\">\n {formatVolume(r.volume, r.unit)}\n </span>\n ),\n },\n {\n key: 'grade',\n header: 'Grade',\n align: 'right',\n hideOnMobile: true,\n sortValue: (r) => r.grade ?? 0,\n render: (r) =>\n r.grade != null ? (\n <span className=\"tabular-nums text-text-secondary\">{formatNumber(r.grade)}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'downtime',\n header: 'Downtime',\n align: 'right',\n hideOnMobile: true,\n sortValue: (r) => r.downtimeHours,\n render: (r) => (\n <span className=\"tabular-nums text-text-secondary\">{formatNumber(r.downtimeHours)}h</span>\n ),\n },\n {\n key: 'created',\n header: 'Logged',\n align: 'right',\n hideOnMobile: true,\n render: (r) => <span className=\"text-text-tertiary\">{formatRelativeTime(r.createdAt)}</span>,\n },\n ];\n\n const openDialog = () => {\n setForm(emptyForm());\n setFormError(null);\n setDialogOpen(true);\n };\n\n const closeDialog = () => {\n setDialogOpen(false);\n setForm(emptyForm());\n setFormError(null);\n };\n\n const handleRecord = async () => {\n if (!form.assetId) {\n setFormError('Select an asset.');\n return;\n }\n // Anchor date-only inputs at noon UTC so the calendar day survives every TZ.\n const periodStart = toBackendDate(form.periodStart);\n const periodEnd = toBackendDate(form.periodEnd);\n if (!periodStart || !periodEnd) {\n setFormError('Period start and end are required.');\n return;\n }\n if (new Date(periodEnd).getTime() < new Date(periodStart).getTime()) {\n setFormError('Period end must be on or after the period start.');\n return;\n }\n const volume = Number(form.volume);\n if (!form.volume || Number.isNaN(volume) || volume <= 0) {\n const message = 'Volume must be greater than zero.';\n setFormError(message);\n notify.error(message);\n return;\n }\n setFormError(null);\n try {\n await recordProduction.mutateAsync({\n assetId: form.assetId,\n periodStart,\n periodEnd,\n volume,\n unit: form.unit,\n grade: form.grade ? Number(form.grade) : null,\n downtimeHours: form.downtimeHours ? Number(form.downtimeHours) : null,\n notes: form.notes.trim() || null,\n });\n notify.success('Production recorded');\n closeDialog();\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to record production.');\n notify.fromError(err);\n }\n };\n\n const assetOptions = assetsQuery.data?.items ?? [];\n\n return (\n <PageLayout\n title=\"Production\"\n description=\"Captured production volumes across every field, well, mine & plant — with downtime and grade.\"\n actions={\n <Button onClick={openDialog}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Record production\n </Button>\n }\n >\n {/* KPI strip — page-scoped totals */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n icon={<Droplets className=\"h-5 w-5\" />}\n value={volumeValue}\n label=\"Volume on this page\"\n featured\n footer={volumeFooter}\n />\n <MetricsCard\n icon={<Clock className=\"h-5 w-5\" />}\n value={`${formatNumber(downtimeTotal)}h`}\n label=\"Downtime on this page\"\n accent={downtimeTotal > 0 ? 'warning' : undefined}\n />\n <MetricsCard\n icon={<BarChart3 className=\"h-5 w-5\" />}\n value={rows.length}\n label=\"Records on this page\"\n />\n </div>\n\n {/* Filter */}\n <div className=\"mt-6 mb-5 flex flex-wrap items-center gap-3\">\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 {assetOptions.map((a) => (\n <SelectItem key={a.id} value={a.id}>\n {a.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading production records…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load production records.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Gauge className=\"h-10 w-10\" />}\n title=\"No production recorded\"\n description={\n assetId === 'ALL'\n ? 'Record a production period to start tracking output, grade and downtime.'\n : 'No production has been recorded for this asset yet.'\n }\n action={\n <Button onClick={openDialog}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Record production\n </Button>\n }\n />\n ) : (\n <>\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(r) => r.id}\n onRowClick={(r) => navigateTo(`assets/${r.assetId}`)}\n rowLabel={(r) => `Open ${assetMap[r.assetId] ?? 'asset'}`}\n defaultSort={{ key: 'period', 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={(target) => pager.onPageChange(target, data?.pageInfo?.cursor)}\n />\n </>\n )}\n\n {/* Record production dialog */}\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => (open ? setDialogOpen(true) : closeDialog())}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Record production</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Log the volume produced by an asset over a reporting period.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <form\n onSubmit={(e) => {\n e.preventDefault();\n void handleRecord();\n }}\n >\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"prAsset\">Asset *</Label>\n <Select\n value={form.assetId}\n onValueChange={(v) => setForm({ ...form, assetId: v })}\n >\n <SelectTrigger id=\"prAsset\">\n <SelectValue placeholder=\"Select an asset\" />\n </SelectTrigger>\n <SelectContent>\n {assetOptions.map((a) => (\n <SelectItem key={a.id} value={a.id}>\n {a.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=\"prStart\">Period start *</Label>\n <Input\n id=\"prStart\"\n type=\"date\"\n value={form.periodStart}\n onChange={(e) => setForm({ ...form, periodStart: e.target.value })}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"prEnd\">Period end *</Label>\n <Input\n id=\"prEnd\"\n type=\"date\"\n value={form.periodEnd}\n onChange={(e) => setForm({ ...form, periodEnd: e.target.value })}\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=\"prVolume\">Volume *</Label>\n <Input\n id=\"prVolume\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.volume}\n onChange={(e) => setForm({ ...form, volume: e.target.value })}\n placeholder=\"12500\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"prUnit\">Unit</Label>\n <Select\n value={form.unit}\n onValueChange={(v) => setForm({ ...form, unit: v as TheUnit })}\n >\n <SelectTrigger id=\"prUnit\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {UNITS.map((u) => (\n <SelectItem key={u} value={u}>\n {formatEnumLabel(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=\"prGrade\">Grade</Label>\n <Input\n id=\"prGrade\"\n type=\"number\"\n step=\"any\"\n value={form.grade}\n onChange={(e) => setForm({ ...form, grade: e.target.value })}\n placeholder=\"Quality / concentration\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"prDowntime\">Downtime (hours)</Label>\n <Input\n id=\"prDowntime\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.downtimeHours}\n onChange={(e) => setForm({ ...form, downtimeHours: e.target.value })}\n placeholder=\"0\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"prNotes\">Notes</Label>\n <Textarea\n id=\"prNotes\"\n rows={2}\n value={form.notes}\n onChange={(e) => setForm({ ...form, notes: e.target.value })}\n placeholder=\"Optional context about this period.\"\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={recordProduction.isPending}>\n {recordProduction.isPending ? 'Recording…' : 'Record production'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import { PageLayout as e } from "../../components/PageLayout.js";
|
|
2
2
|
import { MetricsCard as t } from "../../components/MetricsCard.js";
|
|
3
|
-
import { formatDate as n, formatEnumLabel as r, formatPercent as i, formatUnit as a, formatVolume as o } from "../../utils/formatters.js";
|
|
4
|
-
import { StatusBadge as
|
|
5
|
-
import { DataTable as
|
|
6
|
-
import { ErrorView as
|
|
7
|
-
import { EmptyState as
|
|
8
|
-
import { useTheAssets as
|
|
3
|
+
import { formatDate as n, formatEnumLabel as r, formatPercent as i, formatUnit as a, formatVolume as o, toBackendDate as ee } from "../../utils/formatters.js";
|
|
4
|
+
import { StatusBadge as te } from "../../components/StatusBadge.js";
|
|
5
|
+
import { DataTable as ne } from "../../components/DataTable.js";
|
|
6
|
+
import { ErrorView as re, LoadingView as s } from "../../components/StateViews.js";
|
|
7
|
+
import { EmptyState as ie } from "../../components/EmptyState.js";
|
|
8
|
+
import { useTheAssets as ae, useTheCreateReserveEstimate as oe, useTheReserveEstimates as c } from "../../hooks/useTheGlobalFuelApi.js";
|
|
9
|
+
import { useCursorPager as se } from "../../hooks/useCursorPager.js";
|
|
10
|
+
import { useNotify as l } from "../../hooks/useNotify.js";
|
|
9
11
|
import "../../hooks/index.js";
|
|
10
|
-
import { FilterTabs as
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
12
|
+
import { FilterTabs as u } from "../../components/FilterTabs.js";
|
|
13
|
+
import { Pagination as d } from "../../components/Pagination.js";
|
|
14
|
+
import { useMemo as f, useState as p } from "react";
|
|
15
|
+
import { Database as ce, Layers as m, Percent as le, Plus as h } from "lucide-react";
|
|
16
|
+
import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
17
|
+
import { Button as y, Input as b, Label as x, ResponsiveDialog as ue, ResponsiveDialogContent as de, ResponsiveDialogDescription as fe, ResponsiveDialogFooter as pe, ResponsiveDialogHeader as me, ResponsiveDialogTitle as he, Select as S, SelectContent as C, SelectItem as w, SelectTrigger as T, SelectValue as E, Textarea as ge } from "@burdenoff/fe-libs/ui";
|
|
15
18
|
//#region src/theglobalfuel/pages/reserves/ReservesPage.tsx
|
|
16
|
-
var
|
|
19
|
+
var _e = [
|
|
17
20
|
{
|
|
18
21
|
value: "ALL",
|
|
19
22
|
label: "All"
|
|
@@ -38,13 +41,13 @@ var j = [
|
|
|
38
41
|
value: "PROSPECTIVE",
|
|
39
42
|
label: "Prospective"
|
|
40
43
|
}
|
|
41
|
-
],
|
|
44
|
+
], ve = [
|
|
42
45
|
"PROVED",
|
|
43
46
|
"PROBABLE",
|
|
44
47
|
"POSSIBLE",
|
|
45
48
|
"CONTINGENT",
|
|
46
49
|
"PROSPECTIVE"
|
|
47
|
-
],
|
|
50
|
+
], ye = [
|
|
48
51
|
"BARRELS",
|
|
49
52
|
"CUBIC_METERS",
|
|
50
53
|
"TONNES",
|
|
@@ -52,7 +55,7 @@ var j = [
|
|
|
52
55
|
"MWH",
|
|
53
56
|
"GJ",
|
|
54
57
|
"MCF"
|
|
55
|
-
],
|
|
58
|
+
], D = 25, O = () => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), k = {
|
|
56
59
|
assetId: "",
|
|
57
60
|
category: "PROVED",
|
|
58
61
|
asOfDate: "",
|
|
@@ -62,30 +65,33 @@ var j = [
|
|
|
62
65
|
methodology: "",
|
|
63
66
|
notes: ""
|
|
64
67
|
};
|
|
65
|
-
function
|
|
66
|
-
let [
|
|
68
|
+
function A() {
|
|
69
|
+
let A = l(), [j, M] = p("ALL"), [N, P] = p("ALL"), F = se(), [be, I] = p(!1), [L, R] = p(k), [z, B] = p(null), V = ae({ pagination: {
|
|
67
70
|
limit: 100,
|
|
68
71
|
offset: 0
|
|
69
|
-
} }),
|
|
72
|
+
} }), H = f(() => {
|
|
70
73
|
let e = {};
|
|
71
|
-
for (let t of
|
|
74
|
+
for (let t of V.data?.items ?? []) e[t.id] = t.name;
|
|
72
75
|
return e;
|
|
73
|
-
}, [
|
|
76
|
+
}, [V.data]), U = N === "ALL" ? void 0 : N, W = j === "ALL" ? void 0 : j, { data: G, isLoading: xe, isError: Se, refetch: Ce } = c(U, W, {
|
|
77
|
+
limit: D,
|
|
78
|
+
cursor: F.cursor
|
|
79
|
+
}), K = c(U, W, { limit: 200 }), q = oe(), J = f(() => G?.items ?? [], [G]), Y = f(() => K.data?.items ?? [], [K.data]), X = f(() => {
|
|
74
80
|
let e = {};
|
|
75
|
-
for (let t of
|
|
76
|
-
let t = Object.entries(e).sort((e, t) => t[1] - e[1])[0]?.[0], n = t ?
|
|
81
|
+
for (let t of Y) e[t.unit] = (e[t.unit] ?? 0) + 1;
|
|
82
|
+
let t = Object.entries(e).sort((e, t) => t[1] - e[1])[0]?.[0], n = t ? Y.filter((e) => e.unit === t).reduce((e, t) => e + t.recoverable, 0) : 0, r = Y.filter((e) => e.recoveryFactor != null);
|
|
77
83
|
return {
|
|
78
84
|
dominantUnit: t,
|
|
79
85
|
totalRecoverable: n,
|
|
80
86
|
avgFactor: r.length ? r.reduce((e, t) => e + (t.recoveryFactor ?? 0), 0) / r.length * 100 : null
|
|
81
87
|
};
|
|
82
|
-
}, [
|
|
88
|
+
}, [Y]), we = [
|
|
83
89
|
{
|
|
84
90
|
key: "asset",
|
|
85
91
|
header: "Asset",
|
|
86
92
|
render: (e) => /* @__PURE__ */ _("span", {
|
|
87
93
|
className: "font-semibold text-text-primary",
|
|
88
|
-
children:
|
|
94
|
+
children: H[e.assetId] ?? /* @__PURE__ */ _("span", {
|
|
89
95
|
className: "text-text-tertiary",
|
|
90
96
|
children: "Unknown asset"
|
|
91
97
|
})
|
|
@@ -94,7 +100,7 @@ function I() {
|
|
|
94
100
|
{
|
|
95
101
|
key: "category",
|
|
96
102
|
header: "Category",
|
|
97
|
-
render: (e) => /* @__PURE__ */ _(
|
|
103
|
+
render: (e) => /* @__PURE__ */ _(te, { status: e.category })
|
|
98
104
|
},
|
|
99
105
|
{
|
|
100
106
|
key: "asOfDate",
|
|
@@ -142,125 +148,141 @@ function I() {
|
|
|
142
148
|
children: "—"
|
|
143
149
|
})
|
|
144
150
|
}
|
|
145
|
-
],
|
|
146
|
-
|
|
147
|
-
...
|
|
148
|
-
asOfDate:
|
|
149
|
-
}),
|
|
150
|
-
},
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
], Z = () => {
|
|
152
|
+
R({
|
|
153
|
+
...k,
|
|
154
|
+
asOfDate: O()
|
|
155
|
+
}), B(null), I(!0);
|
|
156
|
+
}, Q = () => {
|
|
157
|
+
I(!1), R(k), B(null);
|
|
158
|
+
}, Te = async () => {
|
|
159
|
+
if (!L.assetId) {
|
|
160
|
+
B("Select the asset this estimate belongs to.");
|
|
153
161
|
return;
|
|
154
162
|
}
|
|
155
|
-
|
|
156
|
-
|
|
163
|
+
let e = ee(L.asOfDate);
|
|
164
|
+
if (!e) {
|
|
165
|
+
B("An \"as of\" date is required.");
|
|
157
166
|
return;
|
|
158
167
|
}
|
|
159
|
-
|
|
160
|
-
|
|
168
|
+
let t = Number(L.recoverable);
|
|
169
|
+
if (!L.recoverable || Number.isNaN(t) || t <= 0) {
|
|
170
|
+
let e = "Recoverable volume must be greater than zero.";
|
|
171
|
+
B(e), A.error(e);
|
|
161
172
|
return;
|
|
162
173
|
}
|
|
163
|
-
let
|
|
164
|
-
if (
|
|
165
|
-
|
|
174
|
+
let n = L.recoveryFactor ? Number(L.recoveryFactor) : null;
|
|
175
|
+
if (n != null && (n < 0 || n > 1)) {
|
|
176
|
+
B("Recovery factor must be between 0 and 1.");
|
|
166
177
|
return;
|
|
167
178
|
}
|
|
168
|
-
|
|
179
|
+
B(null);
|
|
169
180
|
try {
|
|
170
|
-
await
|
|
171
|
-
assetId:
|
|
172
|
-
category:
|
|
173
|
-
asOfDate:
|
|
174
|
-
recoverable:
|
|
175
|
-
recoveryFactor:
|
|
176
|
-
unit:
|
|
177
|
-
methodology:
|
|
178
|
-
notes:
|
|
179
|
-
}),
|
|
181
|
+
await q.mutateAsync({
|
|
182
|
+
assetId: L.assetId,
|
|
183
|
+
category: L.category,
|
|
184
|
+
asOfDate: e,
|
|
185
|
+
recoverable: t,
|
|
186
|
+
recoveryFactor: n,
|
|
187
|
+
unit: L.unit,
|
|
188
|
+
methodology: L.methodology.trim() || null,
|
|
189
|
+
notes: L.notes.trim() || null
|
|
190
|
+
}), A.success("Reserve estimate created"), Q();
|
|
180
191
|
} catch (e) {
|
|
181
|
-
|
|
192
|
+
B(e instanceof Error ? e.message : "Failed to create reserve estimate."), A.fromError(e);
|
|
182
193
|
}
|
|
183
|
-
}, $ = !
|
|
194
|
+
}, $ = !V.isLoading && (V.data?.items.length ?? 0) === 0;
|
|
184
195
|
return /* @__PURE__ */ v(e, {
|
|
185
196
|
title: "Reserve Estimates",
|
|
186
197
|
description: "Booked recoverable volumes per asset — proved, probable, possible, contingent & prospective.",
|
|
187
198
|
actions: /* @__PURE__ */ v(y, {
|
|
188
|
-
onClick:
|
|
199
|
+
onClick: Z,
|
|
189
200
|
disabled: $,
|
|
190
|
-
children: [/* @__PURE__ */ _(
|
|
201
|
+
children: [/* @__PURE__ */ _(h, { className: "mr-1.5 h-4 w-4" }), " Add estimate"]
|
|
191
202
|
}),
|
|
192
203
|
children: [
|
|
193
204
|
/* @__PURE__ */ v("div", {
|
|
194
205
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-3",
|
|
195
206
|
children: [
|
|
196
207
|
/* @__PURE__ */ _(t, {
|
|
197
|
-
icon: /* @__PURE__ */ _(
|
|
198
|
-
value:
|
|
208
|
+
icon: /* @__PURE__ */ _(ce, { className: "h-5 w-5" }),
|
|
209
|
+
value: Y.length,
|
|
199
210
|
label: "Reserve estimates",
|
|
200
211
|
featured: !0
|
|
201
212
|
}),
|
|
202
213
|
/* @__PURE__ */ _(t, {
|
|
203
214
|
icon: /* @__PURE__ */ _(m, { className: "h-5 w-5" }),
|
|
204
|
-
value:
|
|
205
|
-
label:
|
|
215
|
+
value: X.dominantUnit ? o(X.totalRecoverable, X.dominantUnit) : "—",
|
|
216
|
+
label: X.dominantUnit ? `Total recoverable (${a(X.dominantUnit)})` : "Total recoverable"
|
|
206
217
|
}),
|
|
207
218
|
/* @__PURE__ */ _(t, {
|
|
208
|
-
icon: /* @__PURE__ */ _(
|
|
209
|
-
value:
|
|
219
|
+
icon: /* @__PURE__ */ _(le, { className: "h-5 w-5" }),
|
|
220
|
+
value: X.avgFactor == null ? "—" : i(X.avgFactor),
|
|
210
221
|
label: "Avg recovery factor"
|
|
211
222
|
})
|
|
212
223
|
]
|
|
213
224
|
}),
|
|
214
225
|
/* @__PURE__ */ v("div", {
|
|
215
226
|
className: "mt-6 mb-5 flex flex-wrap items-center gap-3",
|
|
216
|
-
children: [/* @__PURE__ */ _(
|
|
217
|
-
options:
|
|
218
|
-
value:
|
|
219
|
-
onChange:
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
227
|
+
children: [/* @__PURE__ */ _(u, {
|
|
228
|
+
options: _e,
|
|
229
|
+
value: j,
|
|
230
|
+
onChange: (e) => {
|
|
231
|
+
M(e), F.reset();
|
|
232
|
+
}
|
|
233
|
+
}), /* @__PURE__ */ v(S, {
|
|
234
|
+
value: N,
|
|
235
|
+
onValueChange: (e) => {
|
|
236
|
+
P(e), F.reset();
|
|
237
|
+
},
|
|
238
|
+
children: [/* @__PURE__ */ _(T, {
|
|
224
239
|
className: "w-56",
|
|
225
|
-
|
|
226
|
-
|
|
240
|
+
"aria-label": "Filter by asset",
|
|
241
|
+
children: /* @__PURE__ */ _(E, { placeholder: "All assets" })
|
|
242
|
+
}), /* @__PURE__ */ v(C, { children: [/* @__PURE__ */ _(w, {
|
|
227
243
|
value: "ALL",
|
|
228
244
|
children: "All assets"
|
|
229
|
-
}), Object.entries(
|
|
245
|
+
}), Object.entries(H).map(([e, t]) => /* @__PURE__ */ _(w, {
|
|
230
246
|
value: e,
|
|
231
247
|
children: t
|
|
232
248
|
}, e))] })]
|
|
233
249
|
})]
|
|
234
250
|
}),
|
|
235
|
-
|
|
251
|
+
xe ? /* @__PURE__ */ _(s, { label: "Loading reserve estimates…" }) : Se ? /* @__PURE__ */ _(re, {
|
|
236
252
|
message: "Couldn't load reserve estimates.",
|
|
237
|
-
onRetry: () =>
|
|
238
|
-
}) :
|
|
253
|
+
onRetry: () => Ce()
|
|
254
|
+
}) : J.length === 0 ? /* @__PURE__ */ _(ie, {
|
|
239
255
|
illustration: "empty-data",
|
|
240
256
|
icon: /* @__PURE__ */ _(m, { className: "h-10 w-10" }),
|
|
241
257
|
title: "No reserve estimates",
|
|
242
|
-
description: $ ? "Register a resource asset first, then book its recoverable reserves here." :
|
|
258
|
+
description: $ ? "Register a resource asset first, then book its recoverable reserves here." : j === "ALL" && N === "ALL" ? "Book your first recoverable-reserves estimate against an asset." : "No estimates match these filters.",
|
|
243
259
|
action: $ ? void 0 : /* @__PURE__ */ v(y, {
|
|
244
|
-
onClick:
|
|
245
|
-
children: [/* @__PURE__ */ _(
|
|
260
|
+
onClick: Z,
|
|
261
|
+
children: [/* @__PURE__ */ _(h, { className: "mr-1.5 h-4 w-4" }), " Add estimate"]
|
|
246
262
|
})
|
|
247
|
-
}) : /* @__PURE__ */ _(
|
|
248
|
-
columns:
|
|
249
|
-
rows:
|
|
263
|
+
}) : /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(ne, {
|
|
264
|
+
columns: we,
|
|
265
|
+
rows: J,
|
|
250
266
|
rowKey: (e) => e.id,
|
|
251
267
|
defaultSort: {
|
|
252
268
|
key: "asOfDate",
|
|
253
269
|
dir: "desc"
|
|
254
270
|
}
|
|
255
|
-
}),
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
271
|
+
}), /* @__PURE__ */ _(d, {
|
|
272
|
+
page: F.page,
|
|
273
|
+
pageSize: D,
|
|
274
|
+
itemCount: J.length,
|
|
275
|
+
hasMore: G?.pageInfo?.hasMore ?? !1,
|
|
276
|
+
onPageChange: (e) => F.onPageChange(e, G?.pageInfo?.cursor)
|
|
277
|
+
})] }),
|
|
278
|
+
/* @__PURE__ */ _(ue, {
|
|
279
|
+
open: be,
|
|
280
|
+
onOpenChange: (e) => e ? I(!0) : Q(),
|
|
281
|
+
children: /* @__PURE__ */ v(de, { children: [/* @__PURE__ */ v(me, { children: [/* @__PURE__ */ _(he, { children: "Add reserve estimate" }), /* @__PURE__ */ _(fe, { children: "Book a recoverable-reserves figure for an asset as of a valuation date." })] }), /* @__PURE__ */ v("form", {
|
|
282
|
+
onSubmit: (e) => {
|
|
283
|
+
e.preventDefault(), Te();
|
|
284
|
+
},
|
|
285
|
+
children: [/* @__PURE__ */ v("div", {
|
|
264
286
|
className: "grid gap-4 py-2",
|
|
265
287
|
children: [
|
|
266
288
|
/* @__PURE__ */ v("div", {
|
|
@@ -268,16 +290,16 @@ function I() {
|
|
|
268
290
|
children: [/* @__PURE__ */ _(x, {
|
|
269
291
|
htmlFor: "reAsset",
|
|
270
292
|
children: "Asset *"
|
|
271
|
-
}), /* @__PURE__ */ v(
|
|
272
|
-
value:
|
|
273
|
-
onValueChange: (e) =>
|
|
274
|
-
...
|
|
293
|
+
}), /* @__PURE__ */ v(S, {
|
|
294
|
+
value: L.assetId,
|
|
295
|
+
onValueChange: (e) => R({
|
|
296
|
+
...L,
|
|
275
297
|
assetId: e
|
|
276
298
|
}),
|
|
277
|
-
children: [/* @__PURE__ */ _(
|
|
299
|
+
children: [/* @__PURE__ */ _(T, {
|
|
278
300
|
id: "reAsset",
|
|
279
|
-
children: /* @__PURE__ */ _(
|
|
280
|
-
}), /* @__PURE__ */ _(
|
|
301
|
+
children: /* @__PURE__ */ _(E, { placeholder: "Select an asset" })
|
|
302
|
+
}), /* @__PURE__ */ _(C, { children: Object.entries(H).map(([e, t]) => /* @__PURE__ */ _(w, {
|
|
281
303
|
value: e,
|
|
282
304
|
children: t
|
|
283
305
|
}, e)) })]
|
|
@@ -290,16 +312,16 @@ function I() {
|
|
|
290
312
|
children: [/* @__PURE__ */ _(x, {
|
|
291
313
|
htmlFor: "reCategory",
|
|
292
314
|
children: "Category"
|
|
293
|
-
}), /* @__PURE__ */ v(
|
|
294
|
-
value:
|
|
295
|
-
onValueChange: (e) =>
|
|
296
|
-
...
|
|
315
|
+
}), /* @__PURE__ */ v(S, {
|
|
316
|
+
value: L.category,
|
|
317
|
+
onValueChange: (e) => R({
|
|
318
|
+
...L,
|
|
297
319
|
category: e
|
|
298
320
|
}),
|
|
299
|
-
children: [/* @__PURE__ */ _(
|
|
321
|
+
children: [/* @__PURE__ */ _(T, {
|
|
300
322
|
id: "reCategory",
|
|
301
|
-
children: /* @__PURE__ */ _(
|
|
302
|
-
}), /* @__PURE__ */ _(
|
|
323
|
+
children: /* @__PURE__ */ _(E, {})
|
|
324
|
+
}), /* @__PURE__ */ _(C, { children: ve.map((e) => /* @__PURE__ */ _(w, {
|
|
303
325
|
value: e,
|
|
304
326
|
children: r(e)
|
|
305
327
|
}, e)) })]
|
|
@@ -312,9 +334,9 @@ function I() {
|
|
|
312
334
|
}), /* @__PURE__ */ _(b, {
|
|
313
335
|
id: "reAsOf",
|
|
314
336
|
type: "date",
|
|
315
|
-
value:
|
|
316
|
-
onChange: (e) =>
|
|
317
|
-
...
|
|
337
|
+
value: L.asOfDate,
|
|
338
|
+
onChange: (e) => R({
|
|
339
|
+
...L,
|
|
318
340
|
asOfDate: e.target.value
|
|
319
341
|
})
|
|
320
342
|
})]
|
|
@@ -333,9 +355,9 @@ function I() {
|
|
|
333
355
|
type: "number",
|
|
334
356
|
min: "0",
|
|
335
357
|
step: "any",
|
|
336
|
-
value:
|
|
337
|
-
onChange: (e) =>
|
|
338
|
-
...
|
|
358
|
+
value: L.recoverable,
|
|
359
|
+
onChange: (e) => R({
|
|
360
|
+
...L,
|
|
339
361
|
recoverable: e.target.value
|
|
340
362
|
}),
|
|
341
363
|
placeholder: "1200000"
|
|
@@ -346,16 +368,16 @@ function I() {
|
|
|
346
368
|
children: [/* @__PURE__ */ _(x, {
|
|
347
369
|
htmlFor: "reUnit",
|
|
348
370
|
children: "Unit"
|
|
349
|
-
}), /* @__PURE__ */ v(
|
|
350
|
-
value:
|
|
351
|
-
onValueChange: (e) =>
|
|
352
|
-
...
|
|
371
|
+
}), /* @__PURE__ */ v(S, {
|
|
372
|
+
value: L.unit,
|
|
373
|
+
onValueChange: (e) => R({
|
|
374
|
+
...L,
|
|
353
375
|
unit: e
|
|
354
376
|
}),
|
|
355
|
-
children: [/* @__PURE__ */ _(
|
|
377
|
+
children: [/* @__PURE__ */ _(T, {
|
|
356
378
|
id: "reUnit",
|
|
357
|
-
children: /* @__PURE__ */ _(
|
|
358
|
-
}), /* @__PURE__ */ _(
|
|
379
|
+
children: /* @__PURE__ */ _(E, {})
|
|
380
|
+
}), /* @__PURE__ */ _(C, { children: ye.map((e) => /* @__PURE__ */ _(w, {
|
|
359
381
|
value: e,
|
|
360
382
|
children: a(e)
|
|
361
383
|
}, e)) })]
|
|
@@ -372,9 +394,9 @@ function I() {
|
|
|
372
394
|
min: "0",
|
|
373
395
|
max: "1",
|
|
374
396
|
step: "any",
|
|
375
|
-
value:
|
|
376
|
-
onChange: (e) =>
|
|
377
|
-
...
|
|
397
|
+
value: L.recoveryFactor,
|
|
398
|
+
onChange: (e) => R({
|
|
399
|
+
...L,
|
|
378
400
|
recoveryFactor: e.target.value
|
|
379
401
|
}),
|
|
380
402
|
placeholder: "0.35"
|
|
@@ -389,9 +411,9 @@ function I() {
|
|
|
389
411
|
children: "Methodology"
|
|
390
412
|
}), /* @__PURE__ */ _(b, {
|
|
391
413
|
id: "reMethodology",
|
|
392
|
-
value:
|
|
393
|
-
onChange: (e) =>
|
|
394
|
-
...
|
|
414
|
+
value: L.methodology,
|
|
415
|
+
onChange: (e) => R({
|
|
416
|
+
...L,
|
|
395
417
|
methodology: e.target.value
|
|
396
418
|
}),
|
|
397
419
|
placeholder: "Volumetric / decline curve / PRMS deterministic"
|
|
@@ -402,38 +424,38 @@ function I() {
|
|
|
402
424
|
children: [/* @__PURE__ */ _(x, {
|
|
403
425
|
htmlFor: "reNotes",
|
|
404
426
|
children: "Notes"
|
|
405
|
-
}), /* @__PURE__ */ _(
|
|
427
|
+
}), /* @__PURE__ */ _(ge, {
|
|
406
428
|
id: "reNotes",
|
|
407
429
|
rows: 2,
|
|
408
|
-
value:
|
|
409
|
-
onChange: (e) =>
|
|
410
|
-
...
|
|
430
|
+
value: L.notes,
|
|
431
|
+
onChange: (e) => R({
|
|
432
|
+
...L,
|
|
411
433
|
notes: e.target.value
|
|
412
434
|
}),
|
|
413
435
|
placeholder: "Optional context about this estimate."
|
|
414
436
|
})]
|
|
415
437
|
}),
|
|
416
|
-
|
|
438
|
+
z && /* @__PURE__ */ _("p", {
|
|
417
439
|
className: "text-sm text-status-error-text",
|
|
418
|
-
children:
|
|
440
|
+
children: z
|
|
419
441
|
})
|
|
420
442
|
]
|
|
421
|
-
}),
|
|
422
|
-
|
|
443
|
+
}), /* @__PURE__ */ v(pe, { children: [/* @__PURE__ */ _(y, {
|
|
444
|
+
type: "button",
|
|
423
445
|
variant: "outline",
|
|
424
|
-
onClick:
|
|
446
|
+
onClick: Q,
|
|
425
447
|
children: "Cancel"
|
|
426
448
|
}), /* @__PURE__ */ _(y, {
|
|
427
|
-
|
|
428
|
-
disabled:
|
|
429
|
-
children:
|
|
430
|
-
})] })
|
|
431
|
-
] })
|
|
449
|
+
type: "submit",
|
|
450
|
+
disabled: q.isPending,
|
|
451
|
+
children: q.isPending ? "Saving…" : "Add estimate"
|
|
452
|
+
})] })]
|
|
453
|
+
})] })
|
|
432
454
|
})
|
|
433
455
|
]
|
|
434
456
|
});
|
|
435
457
|
}
|
|
436
458
|
//#endregion
|
|
437
|
-
export {
|
|
459
|
+
export { A as ReservesPage };
|
|
438
460
|
|
|
439
461
|
//# sourceMappingURL=ReservesPage.js.map
|