@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.
Files changed (133) hide show
  1. package/dist/node_modules/{.bun/clsx@2.1.1/node_modules/clsx → clsx}/dist/clsx.js +1 -1
  2. package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
  3. package/dist/node_modules/{.bun/tailwind-merge@3.5.0/node_modules/tailwind-merge → tailwind-merge}/dist/bundle-mjs.js +212 -170
  4. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  5. package/dist/theglobalfuel/components/DataTable.js +37 -27
  6. package/dist/theglobalfuel/components/DataTable.js.map +1 -1
  7. package/dist/theglobalfuel/hooks/index.js +1 -0
  8. package/dist/theglobalfuel/hooks/useNotify.js +19 -0
  9. package/dist/theglobalfuel/hooks/useNotify.js.map +1 -0
  10. package/dist/theglobalfuel/hooks/useTheFiles.js +4 -1
  11. package/dist/theglobalfuel/hooks/useTheFiles.js.map +1 -1
  12. package/dist/theglobalfuel/hooks/useTheGlobalFuelApi.js +59 -31
  13. package/dist/theglobalfuel/hooks/useTheGlobalFuelApi.js.map +1 -1
  14. package/dist/theglobalfuel/pages/assets/AssetDetailPage.js +367 -321
  15. package/dist/theglobalfuel/pages/assets/AssetDetailPage.js.map +1 -1
  16. package/dist/theglobalfuel/pages/assets/AssetsPage.js +66 -54
  17. package/dist/theglobalfuel/pages/assets/AssetsPage.js.map +1 -1
  18. package/dist/theglobalfuel/pages/compliance/CompliancePage.js +346 -182
  19. package/dist/theglobalfuel/pages/compliance/CompliancePage.js.map +1 -1
  20. package/dist/theglobalfuel/pages/contracts/ContractDetailPage.js +418 -390
  21. package/dist/theglobalfuel/pages/contracts/ContractDetailPage.js.map +1 -1
  22. package/dist/theglobalfuel/pages/contracts/ContractsPage.js +238 -230
  23. package/dist/theglobalfuel/pages/contracts/ContractsPage.js.map +1 -1
  24. package/dist/theglobalfuel/pages/dashboard/DashboardPage.js +5 -3
  25. package/dist/theglobalfuel/pages/dashboard/DashboardPage.js.map +1 -1
  26. package/dist/theglobalfuel/pages/emissions/EmissionsPage.js +201 -177
  27. package/dist/theglobalfuel/pages/emissions/EmissionsPage.js.map +1 -1
  28. package/dist/theglobalfuel/pages/inventory/InventoryPage.js +271 -238
  29. package/dist/theglobalfuel/pages/inventory/InventoryPage.js.map +1 -1
  30. package/dist/theglobalfuel/pages/production/ProductionPage.js +185 -177
  31. package/dist/theglobalfuel/pages/production/ProductionPage.js.map +1 -1
  32. package/dist/theglobalfuel/pages/reserves/ReservesPage.js +160 -138
  33. package/dist/theglobalfuel/pages/reserves/ReservesPage.js.map +1 -1
  34. package/dist/theglobalfuel/pages/shipments/ShipmentsPage.js +250 -198
  35. package/dist/theglobalfuel/pages/shipments/ShipmentsPage.js.map +1 -1
  36. package/dist/theglobalfuel/utils/cn.js +2 -2
  37. package/dist/theglobalfuel/utils/formatters.js +6 -1
  38. package/dist/theglobalfuel/utils/formatters.js.map +1 -1
  39. package/dist/theglobalfuel/utils/transitions.js +70 -0
  40. package/dist/theglobalfuel/utils/transitions.js.map +1 -0
  41. package/package.json +1 -1
  42. package/dist/dev/main.d.ts +0 -2
  43. package/dist/dev/main.d.ts.map +0 -1
  44. package/dist/index.d.ts +0 -2
  45. package/dist/index.d.ts.map +0 -1
  46. package/dist/node_modules/.bun/clsx@2.1.1/node_modules/clsx/dist/clsx.js.map +0 -1
  47. package/dist/node_modules/.bun/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.js.map +0 -1
  48. package/dist/theglobalfuel/TheGlobalFuelRoot.d.ts +0 -5
  49. package/dist/theglobalfuel/TheGlobalFuelRoot.d.ts.map +0 -1
  50. package/dist/theglobalfuel/TheGlobalFuelRoutes.d.ts +0 -4
  51. package/dist/theglobalfuel/TheGlobalFuelRoutes.d.ts.map +0 -1
  52. package/dist/theglobalfuel/components/DataTable.d.ts +0 -28
  53. package/dist/theglobalfuel/components/DataTable.d.ts.map +0 -1
  54. package/dist/theglobalfuel/components/EmptyState.d.ts +0 -18
  55. package/dist/theglobalfuel/components/EmptyState.d.ts.map +0 -1
  56. package/dist/theglobalfuel/components/EvidenceUpload.d.ts +0 -14
  57. package/dist/theglobalfuel/components/EvidenceUpload.d.ts.map +0 -1
  58. package/dist/theglobalfuel/components/FileLink.d.ts +0 -15
  59. package/dist/theglobalfuel/components/FileLink.d.ts.map +0 -1
  60. package/dist/theglobalfuel/components/FilterTabs.d.ts +0 -18
  61. package/dist/theglobalfuel/components/FilterTabs.d.ts.map +0 -1
  62. package/dist/theglobalfuel/components/MetricsCard.d.ts +0 -23
  63. package/dist/theglobalfuel/components/MetricsCard.d.ts.map +0 -1
  64. package/dist/theglobalfuel/components/MiniBar.d.ts +0 -16
  65. package/dist/theglobalfuel/components/MiniBar.d.ts.map +0 -1
  66. package/dist/theglobalfuel/components/PageLayout.d.ts +0 -16
  67. package/dist/theglobalfuel/components/PageLayout.d.ts.map +0 -1
  68. package/dist/theglobalfuel/components/Pagination.d.ts +0 -22
  69. package/dist/theglobalfuel/components/Pagination.d.ts.map +0 -1
  70. package/dist/theglobalfuel/components/StateViews.d.ts +0 -24
  71. package/dist/theglobalfuel/components/StateViews.d.ts.map +0 -1
  72. package/dist/theglobalfuel/components/StatusBadge.d.ts +0 -9
  73. package/dist/theglobalfuel/components/StatusBadge.d.ts.map +0 -1
  74. package/dist/theglobalfuel/components/Tabs.d.ts +0 -17
  75. package/dist/theglobalfuel/components/Tabs.d.ts.map +0 -1
  76. package/dist/theglobalfuel/components/TheDiscussion.d.ts +0 -18
  77. package/dist/theglobalfuel/components/TheDiscussion.d.ts.map +0 -1
  78. package/dist/theglobalfuel/components/TheTags.d.ts +0 -17
  79. package/dist/theglobalfuel/components/TheTags.d.ts.map +0 -1
  80. package/dist/theglobalfuel/components/index.d.ts +0 -19
  81. package/dist/theglobalfuel/components/index.d.ts.map +0 -1
  82. package/dist/theglobalfuel/context/TheGlobalFuelContext.d.ts +0 -16
  83. package/dist/theglobalfuel/context/TheGlobalFuelContext.d.ts.map +0 -1
  84. package/dist/theglobalfuel/context/index.d.ts +0 -6
  85. package/dist/theglobalfuel/context/index.d.ts.map +0 -1
  86. package/dist/theglobalfuel/hooks/index.d.ts +0 -10
  87. package/dist/theglobalfuel/hooks/index.d.ts.map +0 -1
  88. package/dist/theglobalfuel/hooks/useCursorPager.d.ts +0 -33
  89. package/dist/theglobalfuel/hooks/useCursorPager.d.ts.map +0 -1
  90. package/dist/theglobalfuel/hooks/useTheComments.d.ts +0 -36
  91. package/dist/theglobalfuel/hooks/useTheComments.d.ts.map +0 -1
  92. package/dist/theglobalfuel/hooks/useTheFiles.d.ts +0 -47
  93. package/dist/theglobalfuel/hooks/useTheFiles.d.ts.map +0 -1
  94. package/dist/theglobalfuel/hooks/useTheGlobalFuelApi.d.ts +0 -75
  95. package/dist/theglobalfuel/hooks/useTheGlobalFuelApi.d.ts.map +0 -1
  96. package/dist/theglobalfuel/hooks/useTheTags.d.ts +0 -44
  97. package/dist/theglobalfuel/hooks/useTheTags.d.ts.map +0 -1
  98. package/dist/theglobalfuel/index.d.ts +0 -9
  99. package/dist/theglobalfuel/index.d.ts.map +0 -1
  100. package/dist/theglobalfuel/pages/assets/AssetDetailPage.d.ts +0 -13
  101. package/dist/theglobalfuel/pages/assets/AssetDetailPage.d.ts.map +0 -1
  102. package/dist/theglobalfuel/pages/assets/AssetsPage.d.ts +0 -10
  103. package/dist/theglobalfuel/pages/assets/AssetsPage.d.ts.map +0 -1
  104. package/dist/theglobalfuel/pages/compliance/CompliancePage.d.ts +0 -11
  105. package/dist/theglobalfuel/pages/compliance/CompliancePage.d.ts.map +0 -1
  106. package/dist/theglobalfuel/pages/contracts/ContractDetailPage.d.ts +0 -9
  107. package/dist/theglobalfuel/pages/contracts/ContractDetailPage.d.ts.map +0 -1
  108. package/dist/theglobalfuel/pages/contracts/ContractsPage.d.ts +0 -8
  109. package/dist/theglobalfuel/pages/contracts/ContractsPage.d.ts.map +0 -1
  110. package/dist/theglobalfuel/pages/dashboard/DashboardPage.d.ts +0 -13
  111. package/dist/theglobalfuel/pages/dashboard/DashboardPage.d.ts.map +0 -1
  112. package/dist/theglobalfuel/pages/emissions/EmissionsPage.d.ts +0 -12
  113. package/dist/theglobalfuel/pages/emissions/EmissionsPage.d.ts.map +0 -1
  114. package/dist/theglobalfuel/pages/inventory/InventoryPage.d.ts +0 -11
  115. package/dist/theglobalfuel/pages/inventory/InventoryPage.d.ts.map +0 -1
  116. package/dist/theglobalfuel/pages/production/ProductionPage.d.ts +0 -11
  117. package/dist/theglobalfuel/pages/production/ProductionPage.d.ts.map +0 -1
  118. package/dist/theglobalfuel/pages/reserves/ReservesPage.d.ts +0 -10
  119. package/dist/theglobalfuel/pages/reserves/ReservesPage.d.ts.map +0 -1
  120. package/dist/theglobalfuel/pages/shipments/ShipmentsPage.d.ts +0 -10
  121. package/dist/theglobalfuel/pages/shipments/ShipmentsPage.d.ts.map +0 -1
  122. package/dist/theglobalfuel/types/index.d.ts +0 -376
  123. package/dist/theglobalfuel/types/index.d.ts.map +0 -1
  124. package/dist/theglobalfuel/utils/cn.d.ts +0 -4
  125. package/dist/theglobalfuel/utils/cn.d.ts.map +0 -1
  126. package/dist/theglobalfuel/utils/formatters.d.ts +0 -36
  127. package/dist/theglobalfuel/utils/formatters.d.ts.map +0 -1
  128. package/dist/theglobalfuel/utils/i18n.d.ts +0 -6
  129. package/dist/theglobalfuel/utils/i18n.d.ts.map +0 -1
  130. package/dist/theglobalfuel/utils/index.d.ts +0 -9
  131. package/dist/theglobalfuel/utils/index.d.ts.map +0 -1
  132. package/dist/theglobalfuel/utils/navigation.d.ts +0 -14
  133. package/dist/theglobalfuel/utils/navigation.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"InventoryPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/inventory/InventoryPage.tsx"],"sourcesContent":["/**\n * Commodity inventory — list, filter, create lots & drive lot status.\n * @module theglobalfuel/pages/inventory\n *\n * Reads `theListInventoryLots`; writes `theCreateInventoryLot` and\n * `theSetInventoryLotStatus`. A KPI strip (lots on hand, available quantity &\n * inventory value) is aggregated client-side from a broad lot query. No mock\n * data — every number is derived from live `the*` responses.\n */\n\nimport { useMemo, useState, type ReactNode } from 'react';\nimport { Plus, Boxes, Warehouse, Layers, Coins } 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 useTheInventoryLots,\n useTheCreateInventoryLot,\n useTheSetInventoryLotStatus,\n useTheAssets,\n useCursorPager,\n} from '../../hooks';\nimport {\n formatDate,\n formatEnumLabel,\n formatMoney,\n formatNumber,\n formatUnit,\n formatVolume,\n} from '../../utils/formatters';\nimport type { TheInventoryLot, TheInventoryStatus, TheCommodityType, TheUnit } from '../../types';\n\nconst STATUS_FILTERS: FilterOption<TheInventoryStatus | 'ALL'>[] = [\n { value: 'ALL', label: 'All' },\n { value: 'AVAILABLE', label: 'Available' },\n { value: 'RESERVED', label: 'Reserved' },\n { value: 'IN_TRANSIT', label: 'In transit' },\n { value: 'CONSUMED', label: 'Consumed' },\n { value: 'WRITTEN_OFF', label: 'Written off' },\n];\n\nconst INVENTORY_STATUSES: TheInventoryStatus[] = [\n 'AVAILABLE',\n 'RESERVED',\n 'IN_TRANSIT',\n 'CONSUMED',\n 'WRITTEN_OFF',\n];\n\nconst COMMODITIES: TheCommodityType[] = [\n 'CRUDE_OIL',\n 'NATURAL_GAS',\n 'LNG',\n 'COAL',\n 'ELECTRICITY',\n 'HYDROGEN',\n 'BIOFUEL',\n 'IRON_ORE',\n 'COPPER',\n 'BAUXITE',\n 'GOLD',\n 'LITHIUM',\n 'RARE_EARTH',\n];\n\nconst UNITS: TheUnit[] = ['BARRELS', 'CUBIC_METERS', 'TONNES', 'KILOGRAMS', 'MWH', 'GJ', 'MCF'];\n\nconst PAGE_SIZE = 25;\n\n/** Book value of a lot in its own currency. */\nconst lotValue = (l: TheInventoryLot): number => l.quantity * l.unitValue;\n\ninterface CreateFormState {\n lotCode: string;\n commodity: TheCommodityType;\n assetId: string;\n quantity: string;\n unit: TheUnit;\n grade: string;\n location: string;\n unitValue: string;\n currency: string;\n producedAt: string;\n notes: string;\n}\n\nconst EMPTY_FORM: CreateFormState = {\n lotCode: '',\n commodity: 'CRUDE_OIL',\n assetId: '',\n quantity: '',\n unit: 'BARRELS',\n grade: '',\n location: '',\n unitValue: '',\n currency: 'USD',\n producedAt: '',\n notes: '',\n};\n\nexport function InventoryPage() {\n const [status, setStatus] = useState<TheInventoryStatus | 'ALL'>('ALL');\n const [commodity, setCommodity] = useState<TheCommodityType | 'ALL'>('ALL');\n const pager = useCursorPager();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<CreateFormState>(EMPTY_FORM);\n const [formError, setFormError] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useTheInventoryLots({\n status: status === 'ALL' ? undefined : status,\n commodity: commodity === 'ALL' ? undefined : commodity,\n pagination: { limit: PAGE_SIZE, cursor: pager.cursor },\n });\n\n // Broad, unfiltered query feeding the headline KPI strip (aggregated client-\n // side) and the \"produced by\" asset picker in the create dialog.\n const metricsQuery = useTheInventoryLots({ pagination: { limit: 200 } });\n const assets = useTheAssets({ pagination: { limit: 200 } });\n\n const createLot = useTheCreateInventoryLot();\n const setLotStatus = useTheSetInventoryLotStatus();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n\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.code ? `${a.name} · ${a.code}` : a.name;\n return map;\n }, [assets.data]);\n\n // ── Headline metrics (available inventory only, grouped by currency) ────────\n const metrics = useMemo(() => {\n const lots = metricsQuery.data?.items ?? [];\n const available = lots.filter((l) => l.status === 'AVAILABLE');\n const onHandQty = available.reduce((sum, l) => sum + (l.quantity ?? 0), 0);\n\n const valueByCurrency = new Map<string, number>();\n for (const l of available) {\n const cur = l.currency || 'USD';\n valueByCurrency.set(cur, (valueByCurrency.get(cur) ?? 0) + lotValue(l));\n }\n let topCurrency = 'USD';\n let topValue = 0;\n for (const [cur, val] of valueByCurrency) {\n if (val > topValue) {\n topValue = val;\n topCurrency = cur;\n }\n }\n return {\n totalLots: lots.length,\n availableCount: available.length,\n onHandQty,\n topCurrency,\n topValue,\n otherCurrencies: Math.max(0, valueByCurrency.size - 1),\n };\n }, [metricsQuery.data]);\n\n const columns: Column<TheInventoryLot>[] = [\n {\n key: 'lotCode',\n header: 'Lot',\n render: (l) => (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n <Boxes className=\"h-4 w-4\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate font-semibold text-text-primary\">{l.lotCode}</p>\n {l.assetId && assetMap[l.assetId] && (\n <p className=\"truncate text-xs text-text-tertiary\">{assetMap[l.assetId]}</p>\n )}\n </div>\n </div>\n ),\n },\n {\n key: 'commodity',\n header: 'Commodity',\n hideOnMobile: true,\n render: (l) => <span className=\"text-text-secondary\">{formatEnumLabel(l.commodity)}</span>,\n },\n {\n key: 'quantity',\n header: 'Quantity',\n align: 'right',\n sortValue: (l) => l.quantity,\n render: (l) => (\n <span className=\"tabular-nums text-text-primary\">{formatVolume(l.quantity, l.unit)}</span>\n ),\n },\n {\n key: 'grade',\n header: 'Grade',\n align: 'right',\n hideOnMobile: true,\n sortValue: (l) => l.grade ?? -1,\n render: (l) =>\n l.grade != null ? (\n <span className=\"tabular-nums text-text-secondary\">{formatNumber(l.grade)}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n render: (l) => <StatusBadge status={l.status} />,\n },\n {\n key: 'location',\n header: 'Location',\n hideOnMobile: true,\n render: (l) =>\n l.location ? (\n <span className=\"text-text-secondary\">{l.location}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'value',\n header: 'Value',\n align: 'right',\n hideOnMobile: true,\n sortValue: (l) => lotValue(l),\n render: (l) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatMoney(lotValue(l), l.currency)}\n </span>\n ),\n },\n {\n key: 'producedAt',\n header: 'Produced',\n align: 'right',\n hideOnMobile: true,\n sortValue: (l) => (l.producedAt ? new Date(l.producedAt).getTime() : 0),\n render: (l) => <span className=\"text-text-tertiary\">{formatDate(l.producedAt)}</span>,\n },\n {\n key: 'setStatus',\n header: '',\n align: 'right',\n render: (l) => (\n <Select\n value={l.status}\n onValueChange={(v) => setLotStatus.mutate({ id: l.id, status: v as TheInventoryStatus })}\n >\n <SelectTrigger className=\"h-8 w-36\" aria-label={`Change status for lot ${l.lotCode}`}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {INVENTORY_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ),\n },\n ];\n\n const resetForm = () => {\n setForm(EMPTY_FORM);\n setFormError(null);\n };\n\n const handleCreate = async () => {\n if (!form.lotCode.trim()) {\n setFormError('Lot code is required.');\n return;\n }\n if (!form.quantity) {\n setFormError('Quantity is required.');\n return;\n }\n setFormError(null);\n try {\n await createLot.mutateAsync({\n lotCode: form.lotCode.trim(),\n commodity: form.commodity,\n assetId: form.assetId || null,\n quantity: Number(form.quantity),\n unit: form.unit,\n grade: form.grade ? Number(form.grade) : null,\n location: form.location.trim() || null,\n unitValue: form.unitValue ? Number(form.unitValue) : null,\n currency: form.currency.trim() || 'USD',\n producedAt: form.producedAt ? new Date(form.producedAt).toISOString() : null,\n notes: form.notes.trim() || null,\n });\n setDialogOpen(false);\n resetForm();\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create inventory lot.');\n }\n };\n\n const onHandFooter: ReactNode =\n metricsQuery.data && metrics.availableCount > 0 ? (\n <p className=\"text-xs text-text-tertiary\">\n across {metrics.availableCount} available {metrics.availableCount === 1 ? 'lot' : 'lots'}\n </p>\n ) : undefined;\n\n const valueFooter: ReactNode =\n metricsQuery.data && metrics.otherCurrencies > 0 ? (\n <p className=\"text-xs text-text-tertiary\">\n in {metrics.topCurrency} · +{metrics.otherCurrencies} more{' '}\n {metrics.otherCurrencies === 1 ? 'currency' : 'currencies'}\n </p>\n ) : undefined;\n\n return (\n <PageLayout\n title=\"Inventory\"\n description=\"Commodity inventory lots — on-hand quantity, grade, location & book value across the portfolio.\"\n actions={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New lot\n </Button>\n }\n >\n {/* KPI strip */}\n <div className=\"mb-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n <MetricsCard\n icon={<Warehouse className=\"h-5 w-5\" />}\n value={metricsQuery.data ? formatNumber(metrics.totalLots) : '—'}\n label=\"Inventory lots\"\n featured\n footer={\n metricsQuery.data ? (\n <p className=\"text-xs text-text-tertiary\">\n {formatNumber(metrics.availableCount)} available\n </p>\n ) : undefined\n }\n />\n <MetricsCard\n icon={<Layers className=\"h-5 w-5\" />}\n value={metricsQuery.data ? formatNumber(metrics.onHandQty) : '—'}\n label=\"On-hand quantity\"\n accent=\"success\"\n footer={onHandFooter}\n />\n <MetricsCard\n icon={<Coins className=\"h-5 w-5\" />}\n value={metricsQuery.data ? formatMoney(metrics.topValue, metrics.topCurrency) : '—'}\n label=\"Inventory value\"\n footer={valueFooter}\n />\n </div>\n\n {/* Filters */}\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <FilterTabs\n options={STATUS_FILTERS}\n value={status}\n onChange={(v) => {\n setStatus(v);\n pager.reset();\n }}\n />\n <Select\n value={commodity}\n onValueChange={(v) => {\n setCommodity(v as TheCommodityType | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-48\">\n <SelectValue placeholder=\"All commodities\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All commodities</SelectItem>\n {COMMODITIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading inventory…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load inventory lots.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Boxes className=\"h-10 w-10\" />}\n title=\"No inventory lots yet\"\n description={\n status === 'ALL' && commodity === 'ALL'\n ? 'Create your first inventory lot to track on-hand commodity quantity, grade and value.'\n : 'No lots match these filters.'\n }\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New lot\n </Button>\n }\n />\n ) : (\n <>\n <DataTable columns={columns} rows={rows} rowKey={(l) => l.id} />\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 {/* New lot dialog */}\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n setDialogOpen(open);\n if (!open) resetForm();\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New inventory lot</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Register an on-hand quantity of a commodity — optionally attributed to a producing\n asset.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"lotCode\">Lot code *</Label>\n <Input\n id=\"lotCode\"\n value={form.lotCode}\n onChange={(e) => setForm({ ...form, lotCode: e.target.value })}\n placeholder=\"LOT-2026-0042\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"commodity\">Commodity *</Label>\n <Select\n value={form.commodity}\n onValueChange={(v) => setForm({ ...form, commodity: v as TheCommodityType })}\n >\n <SelectTrigger id=\"commodity\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {COMMODITIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"assetId\">Produced by asset</Label>\n <Select value={form.assetId} onValueChange={(v) => setForm({ ...form, assetId: v })}>\n <SelectTrigger id=\"assetId\">\n <SelectValue placeholder=\"Optional — link to a producing asset\" />\n </SelectTrigger>\n <SelectContent>\n {Object.entries(assetMap).map(([id, label]) => (\n <SelectItem key={id} value={id}>\n {label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-3\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"quantity\">Quantity *</Label>\n <Input\n id=\"quantity\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.quantity}\n onChange={(e) => setForm({ ...form, quantity: e.target.value })}\n placeholder=\"120000\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"unit\">Unit</Label>\n <Select\n value={form.unit}\n onValueChange={(v) => setForm({ ...form, unit: v as TheUnit })}\n >\n <SelectTrigger id=\"unit\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {UNITS.map((u) => (\n <SelectItem key={u} value={u}>\n {formatUnit(u)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"grade\">Grade</Label>\n <Input\n id=\"grade\"\n type=\"number\"\n step=\"any\"\n value={form.grade}\n onChange={(e) => setForm({ ...form, grade: e.target.value })}\n placeholder=\"0.32\"\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=\"unitValue\">Unit value</Label>\n <Input\n id=\"unitValue\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.unitValue}\n onChange={(e) => setForm({ ...form, unitValue: e.target.value })}\n placeholder=\"82.50\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"currency\">Currency</Label>\n <Input\n id=\"currency\"\n value={form.currency}\n onChange={(e) => setForm({ ...form, currency: e.target.value })}\n placeholder=\"USD\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"producedAt\">Produced at</Label>\n <Input\n id=\"producedAt\"\n type=\"date\"\n value={form.producedAt}\n onChange={(e) => setForm({ ...form, producedAt: e.target.value })}\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"location\">Location</Label>\n <Input\n id=\"location\"\n value={form.location}\n onChange={(e) => setForm({ ...form, location: e.target.value })}\n placeholder=\"Rotterdam Tank Farm 3\"\n />\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"notes\">Notes</Label>\n <Textarea\n id=\"notes\"\n rows={2}\n value={form.notes}\n onChange={(e) => setForm({ ...form, notes: e.target.value })}\n placeholder=\"Optional context about this lot.\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setDialogOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleCreate} disabled={createLot.isPending}>\n {createLot.isPending ? 'Creating…' : 'Create lot'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"InventoryPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/inventory/InventoryPage.tsx"],"sourcesContent":["/**\n * Commodity inventory — list, filter, create lots & drive lot status.\n * @module theglobalfuel/pages/inventory\n *\n * Reads `theListInventoryLots`; writes `theCreateInventoryLot` and\n * `theSetInventoryLotStatus`. A KPI strip (lots on hand, available quantity &\n * inventory value) is aggregated client-side from a broad lot query. No mock\n * data — every number is derived from live `the*` responses.\n */\n\nimport { useMemo, useState, type ReactNode } from 'react';\nimport { Plus, Boxes, Warehouse, Layers, Coins } 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 useNotify,\n useTheInventoryLots,\n useTheCreateInventoryLot,\n useTheSetInventoryLotStatus,\n useTheAssets,\n useCursorPager,\n} from '../../hooks';\nimport {\n formatDate,\n formatEnumLabel,\n formatMoney,\n formatNumber,\n formatUnit,\n formatVolume,\n} from '../../utils/formatters';\nimport { INVENTORY_TRANSITIONS, nextStatuses, toBackendDate } from '../../utils';\nimport type { TheInventoryLot, TheInventoryStatus, TheCommodityType, TheUnit } from '../../types';\n\nconst STATUS_FILTERS: FilterOption<TheInventoryStatus | 'ALL'>[] = [\n { value: 'ALL', label: 'All' },\n { value: 'AVAILABLE', label: 'Available' },\n { value: 'RESERVED', label: 'Reserved' },\n { value: 'IN_TRANSIT', label: 'In transit' },\n { value: 'CONSUMED', label: 'Consumed' },\n { value: 'WRITTEN_OFF', label: 'Written off' },\n];\n\n/** Sentinel Select value for \"no producing asset\" — Radix forbids an empty value. */\nconst NONE_ASSET_VALUE = '__none__';\n\nconst COMMODITIES: TheCommodityType[] = [\n 'CRUDE_OIL',\n 'NATURAL_GAS',\n 'LNG',\n 'COAL',\n 'ELECTRICITY',\n 'HYDROGEN',\n 'BIOFUEL',\n 'IRON_ORE',\n 'COPPER',\n 'BAUXITE',\n 'GOLD',\n 'LITHIUM',\n 'RARE_EARTH',\n];\n\nconst UNITS: TheUnit[] = ['BARRELS', 'CUBIC_METERS', 'TONNES', 'KILOGRAMS', 'MWH', 'GJ', 'MCF'];\n\nconst PAGE_SIZE = 25;\n\n/** Book value of a lot in its own currency. */\nconst lotValue = (l: TheInventoryLot): number => l.quantity * l.unitValue;\n\ninterface CreateFormState {\n lotCode: string;\n commodity: TheCommodityType;\n assetId: string;\n quantity: string;\n unit: TheUnit;\n grade: string;\n location: string;\n unitValue: string;\n currency: string;\n producedAt: string;\n notes: string;\n}\n\nconst EMPTY_FORM: CreateFormState = {\n lotCode: '',\n commodity: 'CRUDE_OIL',\n assetId: '',\n quantity: '',\n unit: 'BARRELS',\n grade: '',\n location: '',\n unitValue: '',\n currency: 'USD',\n producedAt: '',\n notes: '',\n};\n\nexport function InventoryPage() {\n const [status, setStatus] = useState<TheInventoryStatus | 'ALL'>('ALL');\n const [commodity, setCommodity] = useState<TheCommodityType | 'ALL'>('ALL');\n const pager = useCursorPager();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<CreateFormState>(EMPTY_FORM);\n const [formError, setFormError] = useState<string | null>(null);\n // Track the lot whose status mutation is in flight so we disable ONLY its own\n // Select (a shared isPending flag would freeze every row's control at once).\n const [pendingLotId, setPendingLotId] = useState<string | null>(null);\n\n const notify = useNotify();\n\n const { data, isLoading, isError, refetch } = useTheInventoryLots({\n status: status === 'ALL' ? undefined : status,\n commodity: commodity === 'ALL' ? undefined : commodity,\n pagination: { limit: PAGE_SIZE, cursor: pager.cursor },\n });\n\n // Broad, unfiltered query feeding the headline KPI strip (aggregated client-\n // side) and the \"produced by\" asset picker in the create dialog.\n const metricsQuery = useTheInventoryLots({ pagination: { limit: 200 } });\n const assets = useTheAssets({ pagination: { limit: 200 } });\n\n const createLot = useTheCreateInventoryLot();\n const setLotStatus = useTheSetInventoryLotStatus();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n\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.code ? `${a.name} · ${a.code}` : a.name;\n return map;\n }, [assets.data]);\n\n // ── Headline metrics (available inventory only) ─────────────────────────────\n // On-hand quantity is grouped BY UNIT — barrels, tonnes and MWh are physically\n // incommensurable, so a single cross-unit sum would be meaningless. Value is\n // likewise grouped BY CURRENCY. We surface the dominant bucket in the KPI value\n // and the honest full per-bucket breakdown in the footer.\n const metrics = useMemo(() => {\n const lots = metricsQuery.data?.items ?? [];\n const available = lots.filter((l) => l.status === 'AVAILABLE');\n\n const qtyByUnit = new Map<TheUnit, number>();\n for (const l of available) {\n qtyByUnit.set(l.unit, (qtyByUnit.get(l.unit) ?? 0) + (l.quantity ?? 0));\n }\n let topUnit: TheUnit | null = null;\n let topUnitQty = 0;\n for (const [unit, qty] of qtyByUnit) {\n if (qty > topUnitQty) {\n topUnitQty = qty;\n topUnit = unit;\n }\n }\n\n const valueByCurrency = new Map<string, number>();\n for (const l of available) {\n const cur = l.currency || 'USD';\n valueByCurrency.set(cur, (valueByCurrency.get(cur) ?? 0) + lotValue(l));\n }\n let topCurrency = 'USD';\n let topValue = 0;\n for (const [cur, val] of valueByCurrency) {\n if (val > topValue) {\n topValue = val;\n topCurrency = cur;\n }\n }\n\n return {\n totalLots: lots.length,\n availableCount: available.length,\n qtyByUnit,\n topUnit,\n topUnitQty,\n topCurrency,\n topValue,\n otherCurrencies: Math.max(0, valueByCurrency.size - 1),\n };\n }, [metricsQuery.data]);\n\n const columns: Column<TheInventoryLot>[] = [\n {\n key: 'lotCode',\n header: 'Lot',\n render: (l) => (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n <Boxes className=\"h-4 w-4\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate font-semibold text-text-primary\">{l.lotCode}</p>\n {l.assetId && assetMap[l.assetId] && (\n <p className=\"truncate text-xs text-text-tertiary\">{assetMap[l.assetId]}</p>\n )}\n </div>\n </div>\n ),\n },\n {\n key: 'commodity',\n header: 'Commodity',\n hideOnMobile: true,\n render: (l) => <span className=\"text-text-secondary\">{formatEnumLabel(l.commodity)}</span>,\n },\n {\n key: 'quantity',\n header: 'Quantity',\n align: 'right',\n sortValue: (l) => l.quantity,\n render: (l) => (\n <span className=\"tabular-nums text-text-primary\">{formatVolume(l.quantity, l.unit)}</span>\n ),\n },\n {\n key: 'grade',\n header: 'Grade',\n align: 'right',\n hideOnMobile: true,\n sortValue: (l) => l.grade ?? -1,\n render: (l) =>\n l.grade != null ? (\n <span className=\"tabular-nums text-text-secondary\">{formatNumber(l.grade)}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n render: (l) => <StatusBadge status={l.status} />,\n },\n {\n key: 'location',\n header: 'Location',\n hideOnMobile: true,\n render: (l) =>\n l.location ? (\n <span className=\"text-text-secondary\">{l.location}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'value',\n header: 'Value',\n align: 'right',\n hideOnMobile: true,\n sortValue: (l) => lotValue(l),\n render: (l) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatMoney(lotValue(l), l.currency)}\n </span>\n ),\n },\n {\n key: 'producedAt',\n header: 'Produced',\n align: 'right',\n hideOnMobile: true,\n sortValue: (l) => (l.producedAt ? new Date(l.producedAt).getTime() : 0),\n render: (l) => <span className=\"text-text-tertiary\">{formatDate(l.producedAt)}</span>,\n },\n {\n key: 'setStatus',\n header: '',\n align: 'right',\n render: (l) => {\n const next = nextStatuses(INVENTORY_TRANSITIONS, l.status);\n const isTerminal = next.length === 0;\n const isRowPending = pendingLotId === l.id;\n return (\n <Select\n value={l.status}\n disabled={isTerminal || isRowPending}\n onValueChange={(v) => {\n setPendingLotId(l.id);\n setLotStatus.mutate(\n { id: l.id, status: v as TheInventoryStatus },\n {\n onSuccess: () => notify.success('Lot status updated'),\n onError: (e) => notify.fromError(e),\n onSettled: () => setPendingLotId(null),\n }\n );\n }}\n >\n <SelectTrigger className=\"h-8 w-36\" aria-label={`Change status for lot ${l.lotCode}`}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {/* Current status is a disabled anchor so the trigger renders it;\n only LEGAL next states are selectable. Terminal lots\n (CONSUMED / WRITTEN_OFF) have no next state → Select disabled. */}\n <SelectItem value={l.status} disabled>\n {formatEnumLabel(l.status)}\n </SelectItem>\n {next.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n },\n },\n ];\n\n const resetForm = () => {\n setForm(EMPTY_FORM);\n setFormError(null);\n };\n\n const handleCreate = async () => {\n if (!form.lotCode.trim()) {\n setFormError('Lot code is required.');\n return;\n }\n const quantity = Number(form.quantity);\n if (!form.quantity || Number.isNaN(quantity) || quantity <= 0) {\n setFormError('Enter a quantity greater than zero.');\n notify.error('Enter a quantity greater than zero.');\n return;\n }\n setFormError(null);\n try {\n await createLot.mutateAsync({\n lotCode: form.lotCode.trim(),\n commodity: form.commodity,\n assetId: form.assetId || null,\n quantity,\n unit: form.unit,\n grade: form.grade ? Number(form.grade) : null,\n location: form.location.trim() || null,\n unitValue: form.unitValue ? Number(form.unitValue) : null,\n currency: form.currency.trim() || 'USD',\n producedAt: toBackendDate(form.producedAt) ?? null,\n notes: form.notes.trim() || null,\n });\n notify.success('Inventory lot created');\n setDialogOpen(false);\n resetForm();\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create inventory lot.');\n notify.fromError(err);\n }\n };\n\n // When multiple units are on hand, show the honest per-unit breakdown (never a\n // single cross-unit number); with a single unit, fall back to the lot count.\n const onHandFooter: ReactNode = (() => {\n if (!metricsQuery.data) return undefined;\n if (metrics.qtyByUnit.size > 1) {\n return (\n <p className=\"text-xs text-text-tertiary\">\n {[...metrics.qtyByUnit.entries()]\n .sort((a, b) => b[1] - a[1])\n .map(([unit, qty]) => formatVolume(qty, unit))\n .join(' · ')}\n </p>\n );\n }\n if (metrics.availableCount > 0) {\n return (\n <p className=\"text-xs text-text-tertiary\">\n across {metrics.availableCount} available {metrics.availableCount === 1 ? 'lot' : 'lots'}\n </p>\n );\n }\n return undefined;\n })();\n\n const valueFooter: ReactNode =\n metricsQuery.data && metrics.otherCurrencies > 0 ? (\n <p className=\"text-xs text-text-tertiary\">\n in {metrics.topCurrency} · +{metrics.otherCurrencies} more{' '}\n {metrics.otherCurrencies === 1 ? 'currency' : 'currencies'}\n </p>\n ) : undefined;\n\n return (\n <PageLayout\n title=\"Inventory\"\n description=\"Commodity inventory lots — on-hand quantity, grade, location & book value across the portfolio.\"\n actions={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New lot\n </Button>\n }\n >\n {/* KPI strip */}\n <div className=\"mb-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n <MetricsCard\n icon={<Warehouse className=\"h-5 w-5\" />}\n value={metricsQuery.data ? formatNumber(metrics.totalLots) : '—'}\n label=\"Inventory lots\"\n featured\n footer={\n metricsQuery.data ? (\n <p className=\"text-xs text-text-tertiary\">\n {formatNumber(metrics.availableCount)} available\n </p>\n ) : undefined\n }\n />\n <MetricsCard\n icon={<Layers className=\"h-5 w-5\" />}\n value={metricsQuery.data ? formatVolume(metrics.topUnitQty, metrics.topUnit) : '—'}\n label=\"On-hand quantity\"\n accent=\"success\"\n footer={onHandFooter}\n />\n <MetricsCard\n icon={<Coins className=\"h-5 w-5\" />}\n value={metricsQuery.data ? formatMoney(metrics.topValue, metrics.topCurrency) : '—'}\n label=\"Inventory value\"\n footer={valueFooter}\n />\n </div>\n\n {/* Filters */}\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <FilterTabs\n options={STATUS_FILTERS}\n value={status}\n onChange={(v) => {\n setStatus(v);\n pager.reset();\n }}\n />\n <Select\n value={commodity}\n onValueChange={(v) => {\n setCommodity(v as TheCommodityType | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-48\" aria-label=\"Filter by commodity\">\n <SelectValue placeholder=\"All commodities\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All commodities</SelectItem>\n {COMMODITIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading inventory…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load inventory lots.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Boxes className=\"h-10 w-10\" />}\n title=\"No inventory lots yet\"\n description={\n status === 'ALL' && commodity === 'ALL'\n ? 'Create your first inventory lot to track on-hand commodity quantity, grade and value.'\n : 'No lots match these filters.'\n }\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New lot\n </Button>\n }\n />\n ) : (\n <>\n <DataTable columns={columns} rows={rows} rowKey={(l) => l.id} />\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 {/* New lot dialog */}\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n setDialogOpen(open);\n if (!open) resetForm();\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New inventory lot</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Register an on-hand quantity of a commodity — optionally attributed to a producing\n asset.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <form\n onSubmit={(e) => {\n e.preventDefault();\n void handleCreate();\n }}\n >\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"lotCode\">Lot code *</Label>\n <Input\n id=\"lotCode\"\n value={form.lotCode}\n onChange={(e) => setForm({ ...form, lotCode: e.target.value })}\n placeholder=\"LOT-2026-0042\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"commodity\">Commodity *</Label>\n <Select\n value={form.commodity}\n onValueChange={(v) => setForm({ ...form, commodity: v as TheCommodityType })}\n >\n <SelectTrigger id=\"commodity\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {COMMODITIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"assetId\">Produced by asset</Label>\n <Select\n value={form.assetId || NONE_ASSET_VALUE}\n onValueChange={(v) =>\n setForm({ ...form, assetId: v === NONE_ASSET_VALUE ? '' : v })\n }\n >\n <SelectTrigger id=\"assetId\">\n <SelectValue placeholder=\"Optional — link to a producing asset\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={NONE_ASSET_VALUE}>None</SelectItem>\n {Object.entries(assetMap).map(([id, label]) => (\n <SelectItem key={id} value={id}>\n {label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-3\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"quantity\">Quantity *</Label>\n <Input\n id=\"quantity\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.quantity}\n onChange={(e) => setForm({ ...form, quantity: e.target.value })}\n placeholder=\"120000\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"unit\">Unit</Label>\n <Select\n value={form.unit}\n onValueChange={(v) => setForm({ ...form, unit: v as TheUnit })}\n >\n <SelectTrigger id=\"unit\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {UNITS.map((u) => (\n <SelectItem key={u} value={u}>\n {formatUnit(u)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"grade\">Grade</Label>\n <Input\n id=\"grade\"\n type=\"number\"\n step=\"any\"\n value={form.grade}\n onChange={(e) => setForm({ ...form, grade: e.target.value })}\n placeholder=\"0.32\"\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=\"unitValue\">Unit value</Label>\n <Input\n id=\"unitValue\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.unitValue}\n onChange={(e) => setForm({ ...form, unitValue: e.target.value })}\n placeholder=\"82.50\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"currency\">Currency</Label>\n <Input\n id=\"currency\"\n value={form.currency}\n onChange={(e) => setForm({ ...form, currency: e.target.value })}\n placeholder=\"USD\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"producedAt\">Produced at</Label>\n <Input\n id=\"producedAt\"\n type=\"date\"\n value={form.producedAt}\n onChange={(e) => setForm({ ...form, producedAt: e.target.value })}\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"location\">Location</Label>\n <Input\n id=\"location\"\n value={form.location}\n onChange={(e) => setForm({ ...form, location: e.target.value })}\n placeholder=\"Rotterdam Tank Farm 3\"\n />\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"notes\">Notes</Label>\n <Textarea\n id=\"notes\"\n rows={2}\n value={form.notes}\n onChange={(e) => setForm({ ...form, notes: e.target.value })}\n placeholder=\"Optional context about this lot.\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setDialogOpen(false);\n resetForm();\n }}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={createLot.isPending}>\n {createLot.isPending ? 'Creating…' : 'Create lot'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}