@burdenoff/microfe-theglobalfuel 2026.709.1 → 2026.709.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/README.md +3 -0
- package/dist/dev/main.d.ts +2 -0
- package/dist/dev/main.d.ts.map +1 -0
- package/dist/generated/global-operations.d.ts +2 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-types.d.ts +18199 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +2 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-types.d.ts +43046 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/theglobalfuel/TheGlobalFuelRoot.d.ts +5 -0
- package/dist/theglobalfuel/TheGlobalFuelRoot.d.ts.map +1 -0
- package/dist/theglobalfuel/TheGlobalFuelRoot.js +106 -104
- package/dist/theglobalfuel/TheGlobalFuelRoot.js.map +1 -1
- package/dist/theglobalfuel/TheGlobalFuelRoutes.d.ts +4 -0
- package/dist/theglobalfuel/TheGlobalFuelRoutes.d.ts.map +1 -0
- package/dist/theglobalfuel/TheGlobalFuelRoutes.js +60 -38
- package/dist/theglobalfuel/TheGlobalFuelRoutes.js.map +1 -1
- package/dist/theglobalfuel/components/DataTable.d.ts +30 -0
- package/dist/theglobalfuel/components/DataTable.d.ts.map +1 -0
- package/dist/theglobalfuel/components/DataTable.js.map +1 -1
- package/dist/theglobalfuel/components/EmptyState.d.ts +18 -0
- package/dist/theglobalfuel/components/EmptyState.d.ts.map +1 -0
- package/dist/theglobalfuel/components/EvidenceUpload.d.ts +14 -0
- package/dist/theglobalfuel/components/EvidenceUpload.d.ts.map +1 -0
- package/dist/theglobalfuel/components/FileLink.d.ts +15 -0
- package/dist/theglobalfuel/components/FileLink.d.ts.map +1 -0
- package/dist/theglobalfuel/components/FilterTabs.d.ts +18 -0
- package/dist/theglobalfuel/components/FilterTabs.d.ts.map +1 -0
- package/dist/theglobalfuel/components/MetricsCard.d.ts +23 -0
- package/dist/theglobalfuel/components/MetricsCard.d.ts.map +1 -0
- package/dist/theglobalfuel/components/MiniBar.d.ts +16 -0
- package/dist/theglobalfuel/components/MiniBar.d.ts.map +1 -0
- package/dist/theglobalfuel/components/PageLayout.d.ts +18 -0
- package/dist/theglobalfuel/components/PageLayout.d.ts.map +1 -0
- package/dist/theglobalfuel/components/PageLayout.js +2 -1
- package/dist/theglobalfuel/components/PageLayout.js.map +1 -1
- package/dist/theglobalfuel/components/Pagination.d.ts +22 -0
- package/dist/theglobalfuel/components/Pagination.d.ts.map +1 -0
- package/dist/theglobalfuel/components/StateViews.d.ts +24 -0
- package/dist/theglobalfuel/components/StateViews.d.ts.map +1 -0
- package/dist/theglobalfuel/components/StatusBadge.d.ts +9 -0
- package/dist/theglobalfuel/components/StatusBadge.d.ts.map +1 -0
- package/dist/theglobalfuel/components/Tabs.d.ts +17 -0
- package/dist/theglobalfuel/components/Tabs.d.ts.map +1 -0
- package/dist/theglobalfuel/components/TheDiscussion.d.ts +18 -0
- package/dist/theglobalfuel/components/TheDiscussion.d.ts.map +1 -0
- package/dist/theglobalfuel/components/TheTags.d.ts +17 -0
- package/dist/theglobalfuel/components/TheTags.d.ts.map +1 -0
- package/dist/theglobalfuel/components/WorldMap.d.ts +18 -0
- package/dist/theglobalfuel/components/WorldMap.d.ts.map +1 -0
- package/dist/theglobalfuel/components/WorldMap.js.map +1 -1
- package/dist/theglobalfuel/components/index.d.ts +21 -0
- package/dist/theglobalfuel/components/index.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/AllocationBar.d.ts +21 -0
- package/dist/theglobalfuel/components/viz/AllocationBar.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/AreaChart.d.ts +18 -0
- package/dist/theglobalfuel/components/viz/AreaChart.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/AvatarStack.d.ts +13 -0
- package/dist/theglobalfuel/components/viz/AvatarStack.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/BarChart.d.ts +17 -0
- package/dist/theglobalfuel/components/viz/BarChart.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/CertificateCard.d.ts +14 -0
- package/dist/theglobalfuel/components/viz/CertificateCard.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/DonutChart.d.ts +20 -0
- package/dist/theglobalfuel/components/viz/DonutChart.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/HBarFunnel.d.ts +17 -0
- package/dist/theglobalfuel/components/viz/HBarFunnel.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/Heatmap.d.ts +26 -0
- package/dist/theglobalfuel/components/viz/Heatmap.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/KanbanBoard.d.ts +17 -0
- package/dist/theglobalfuel/components/viz/KanbanBoard.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/LineChart.d.ts +20 -0
- package/dist/theglobalfuel/components/viz/LineChart.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/OrgTree.d.ts +14 -0
- package/dist/theglobalfuel/components/viz/OrgTree.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/PathSteps.d.ts +17 -0
- package/dist/theglobalfuel/components/viz/PathSteps.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/ProgressRing.d.ts +20 -0
- package/dist/theglobalfuel/components/viz/ProgressRing.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/RatingStars.d.ts +14 -0
- package/dist/theglobalfuel/components/viz/RatingStars.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/SegmentedTabs.d.ts +26 -0
- package/dist/theglobalfuel/components/viz/SegmentedTabs.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/SkillBar.d.ts +17 -0
- package/dist/theglobalfuel/components/viz/SkillBar.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/Sparkline.d.ts +16 -0
- package/dist/theglobalfuel/components/viz/Sparkline.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/StatCard.d.ts +22 -0
- package/dist/theglobalfuel/components/viz/StatCard.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/StepProgress.d.ts +17 -0
- package/dist/theglobalfuel/components/viz/StepProgress.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/Timeline.d.ts +21 -0
- package/dist/theglobalfuel/components/viz/Timeline.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/index.d.ts +35 -0
- package/dist/theglobalfuel/components/viz/index.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/lib/Avatar.d.ts +15 -0
- package/dist/theglobalfuel/components/viz/lib/Avatar.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/lib/CartesianFrame.d.ts +44 -0
- package/dist/theglobalfuel/components/viz/lib/CartesianFrame.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/lib/ResponsiveSvg.d.ts +27 -0
- package/dist/theglobalfuel/components/viz/lib/ResponsiveSvg.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/lib/format.d.ts +10 -0
- package/dist/theglobalfuel/components/viz/lib/format.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/lib/geometry.d.ts +41 -0
- package/dist/theglobalfuel/components/viz/lib/geometry.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/lib/hooks.d.ts +18 -0
- package/dist/theglobalfuel/components/viz/lib/hooks.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/lib/palette.d.ts +31 -0
- package/dist/theglobalfuel/components/viz/lib/palette.d.ts.map +1 -0
- package/dist/theglobalfuel/components/viz/lib/types.d.ts +27 -0
- package/dist/theglobalfuel/components/viz/lib/types.d.ts.map +1 -0
- package/dist/theglobalfuel/context/TheGlobalFuelContext.d.ts +16 -0
- package/dist/theglobalfuel/context/TheGlobalFuelContext.d.ts.map +1 -0
- package/dist/theglobalfuel/context/index.d.ts +6 -0
- package/dist/theglobalfuel/context/index.d.ts.map +1 -0
- package/dist/theglobalfuel/hooks/index.d.ts +15 -0
- package/dist/theglobalfuel/hooks/index.d.ts.map +1 -0
- package/dist/theglobalfuel/hooks/index.js +3 -0
- package/dist/theglobalfuel/hooks/useCursorPager.d.ts +26 -0
- package/dist/theglobalfuel/hooks/useCursorPager.d.ts.map +1 -0
- package/dist/theglobalfuel/hooks/useNotify.d.ts +23 -0
- package/dist/theglobalfuel/hooks/useNotify.d.ts.map +1 -0
- package/dist/theglobalfuel/hooks/useTheAnalytics.d.ts +38 -0
- package/dist/theglobalfuel/hooks/useTheAnalytics.d.ts.map +1 -0
- package/dist/theglobalfuel/hooks/useTheAnalytics.js +1 -0
- package/dist/theglobalfuel/hooks/useTheAnalytics.js.map +1 -1
- package/dist/theglobalfuel/hooks/useTheComments.d.ts +36 -0
- package/dist/theglobalfuel/hooks/useTheComments.d.ts.map +1 -0
- package/dist/theglobalfuel/hooks/useTheFiles.d.ts +47 -0
- package/dist/theglobalfuel/hooks/useTheFiles.d.ts.map +1 -0
- package/dist/theglobalfuel/hooks/useTheGlobalFuelApi.d.ts +79 -0
- package/dist/theglobalfuel/hooks/useTheGlobalFuelApi.d.ts.map +1 -0
- package/dist/theglobalfuel/hooks/useTheGlobalFuelApi.js +2 -9
- package/dist/theglobalfuel/hooks/useTheGlobalFuelApi.js.map +1 -1
- package/dist/theglobalfuel/hooks/useTheNativeControls.d.ts +20 -0
- package/dist/theglobalfuel/hooks/useTheNativeControls.d.ts.map +1 -0
- package/dist/theglobalfuel/hooks/useTheNativeControls.js +22 -0
- package/dist/theglobalfuel/hooks/useTheNativeControls.js.map +1 -0
- package/dist/theglobalfuel/hooks/useThePageView.d.ts +10 -0
- package/dist/theglobalfuel/hooks/useThePageView.d.ts.map +1 -0
- package/dist/theglobalfuel/hooks/useThePageView.js +13 -0
- package/dist/theglobalfuel/hooks/useThePageView.js.map +1 -0
- package/dist/theglobalfuel/hooks/useTheTags.d.ts +44 -0
- package/dist/theglobalfuel/hooks/useTheTags.d.ts.map +1 -0
- package/dist/theglobalfuel/hooks/useTheTranslation.d.ts +4 -0
- package/dist/theglobalfuel/hooks/useTheTranslation.d.ts.map +1 -0
- package/dist/theglobalfuel/hooks/useTheTranslation.js +12 -0
- package/dist/theglobalfuel/hooks/useTheTranslation.js.map +1 -0
- package/dist/theglobalfuel/index.d.ts +11 -0
- package/dist/theglobalfuel/index.d.ts.map +1 -0
- package/dist/theglobalfuel/pages/assets/AssetDetailPage.d.ts +13 -0
- package/dist/theglobalfuel/pages/assets/AssetDetailPage.d.ts.map +1 -0
- package/dist/theglobalfuel/pages/assets/AssetDetailPage.js +452 -415
- package/dist/theglobalfuel/pages/assets/AssetDetailPage.js.map +1 -1
- package/dist/theglobalfuel/pages/assets/AssetsPage.d.ts +10 -0
- package/dist/theglobalfuel/pages/assets/AssetsPage.d.ts.map +1 -0
- package/dist/theglobalfuel/pages/assets/AssetsPage.js +138 -135
- package/dist/theglobalfuel/pages/assets/AssetsPage.js.map +1 -1
- package/dist/theglobalfuel/pages/compliance/CompliancePage.d.ts +11 -0
- package/dist/theglobalfuel/pages/compliance/CompliancePage.d.ts.map +1 -0
- package/dist/theglobalfuel/pages/compliance/CompliancePage.js +233 -229
- package/dist/theglobalfuel/pages/compliance/CompliancePage.js.map +1 -1
- package/dist/theglobalfuel/pages/contracts/ContractDetailPage.d.ts +9 -0
- package/dist/theglobalfuel/pages/contracts/ContractDetailPage.d.ts.map +1 -0
- package/dist/theglobalfuel/pages/contracts/ContractDetailPage.js +410 -389
- package/dist/theglobalfuel/pages/contracts/ContractDetailPage.js.map +1 -1
- package/dist/theglobalfuel/pages/contracts/ContractsPage.d.ts +8 -0
- package/dist/theglobalfuel/pages/contracts/ContractsPage.d.ts.map +1 -0
- package/dist/theglobalfuel/pages/contracts/ContractsPage.js +140 -137
- package/dist/theglobalfuel/pages/contracts/ContractsPage.js.map +1 -1
- package/dist/theglobalfuel/pages/dashboard/DashboardPage.d.ts +17 -0
- package/dist/theglobalfuel/pages/dashboard/DashboardPage.d.ts.map +1 -0
- package/dist/theglobalfuel/pages/dashboard/DashboardPage.js +83 -83
- package/dist/theglobalfuel/pages/dashboard/DashboardPage.js.map +1 -1
- package/dist/theglobalfuel/pages/emissions/EmissionsPage.d.ts +13 -0
- package/dist/theglobalfuel/pages/emissions/EmissionsPage.d.ts.map +1 -0
- package/dist/theglobalfuel/pages/emissions/EmissionsPage.js +154 -150
- package/dist/theglobalfuel/pages/emissions/EmissionsPage.js.map +1 -1
- package/dist/theglobalfuel/pages/inventory/InventoryPage.d.ts +11 -0
- package/dist/theglobalfuel/pages/inventory/InventoryPage.d.ts.map +1 -0
- package/dist/theglobalfuel/pages/inventory/InventoryPage.js +151 -147
- package/dist/theglobalfuel/pages/inventory/InventoryPage.js.map +1 -1
- package/dist/theglobalfuel/pages/production/ProductionPage.d.ts +11 -0
- package/dist/theglobalfuel/pages/production/ProductionPage.d.ts.map +1 -0
- package/dist/theglobalfuel/pages/production/ProductionPage.js +175 -171
- package/dist/theglobalfuel/pages/production/ProductionPage.js.map +1 -1
- package/dist/theglobalfuel/pages/provenance/ProvenancePage.d.ts +23 -0
- package/dist/theglobalfuel/pages/provenance/ProvenancePage.d.ts.map +1 -0
- package/dist/theglobalfuel/pages/provenance/ProvenancePage.js +153 -146
- package/dist/theglobalfuel/pages/provenance/ProvenancePage.js.map +1 -1
- package/dist/theglobalfuel/pages/reserves/ReservesPage.d.ts +10 -0
- package/dist/theglobalfuel/pages/reserves/ReservesPage.d.ts.map +1 -0
- package/dist/theglobalfuel/pages/reserves/ReservesPage.js +168 -164
- package/dist/theglobalfuel/pages/reserves/ReservesPage.js.map +1 -1
- package/dist/theglobalfuel/pages/shipments/ShipmentsPage.d.ts +11 -0
- package/dist/theglobalfuel/pages/shipments/ShipmentsPage.d.ts.map +1 -0
- package/dist/theglobalfuel/pages/shipments/ShipmentsPage.js +179 -175
- package/dist/theglobalfuel/pages/shipments/ShipmentsPage.js.map +1 -1
- package/dist/theglobalfuel/services/assistantApi.d.ts +25 -0
- package/dist/theglobalfuel/services/assistantApi.d.ts.map +1 -0
- package/dist/theglobalfuel/services/assistantApi.js.map +1 -1
- package/dist/theglobalfuel/services/createSandboxAssistantTransport.d.ts +38 -0
- package/dist/theglobalfuel/services/createSandboxAssistantTransport.d.ts.map +1 -0
- package/dist/theglobalfuel/services/createSandboxAssistantTransport.js.map +1 -1
- package/dist/theglobalfuel/services/index.d.ts +7 -0
- package/dist/theglobalfuel/services/index.d.ts.map +1 -0
- package/dist/theglobalfuel/types/assistant.d.ts +65 -0
- package/dist/theglobalfuel/types/assistant.d.ts.map +1 -0
- package/dist/theglobalfuel/types/index.d.ts +376 -0
- package/dist/theglobalfuel/types/index.d.ts.map +1 -0
- package/dist/theglobalfuel/utils/cn.d.ts +4 -0
- package/dist/theglobalfuel/utils/cn.d.ts.map +1 -0
- package/dist/theglobalfuel/utils/formatters.d.ts +44 -0
- package/dist/theglobalfuel/utils/formatters.d.ts.map +1 -0
- package/dist/theglobalfuel/utils/i18n.d.ts +5 -0
- package/dist/theglobalfuel/utils/i18n.d.ts.map +1 -0
- package/dist/theglobalfuel/utils/i18n.js +15 -0
- package/dist/theglobalfuel/utils/i18n.js.map +1 -0
- package/dist/theglobalfuel/utils/index.d.ts +10 -0
- package/dist/theglobalfuel/utils/index.d.ts.map +1 -0
- package/dist/theglobalfuel/utils/navigation.d.ts +14 -0
- package/dist/theglobalfuel/utils/navigation.d.ts.map +1 -0
- package/dist/theglobalfuel/utils/pageContext.d.ts +26 -0
- package/dist/theglobalfuel/utils/pageContext.d.ts.map +1 -0
- package/dist/theglobalfuel/utils/transitions.d.ts +17 -0
- package/dist/theglobalfuel/utils/transitions.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContractsPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/contracts/ContractsPage.tsx"],"sourcesContent":["/**\n * Offtake contracts — list, filter, and create commodity purchase/sale contracts.\n * @module theglobalfuel/pages/contracts\n *\n * Reads `theListContracts`; writes `theCreateContract`.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, FileSignature } from 'lucide-react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataTable, type Column } from '../../components/DataTable';\nimport { FilterTabs, type FilterOption } from '../../components/FilterTabs';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Pagination } from '../../components/Pagination';\nimport { MiniBar } from '../../components/MiniBar';\nimport { useTheGlobalFuel } from '../../context';\nimport { useTheContracts, useTheCreateContract, useCursorPager, useNotify, useTheAnalytics } from '../../hooks';\nimport { formatEnumLabel, formatMoney, formatUnit, formatVolume } from '../../utils/formatters';\nimport { toBackendDate } from '../../utils';\nimport type {\n TheOfftakeContract,\n TheContractStatus,\n TheContractSide,\n TheCommodityType,\n ThePricingBasis,\n TheUnit,\n} from '../../types';\n\nconst STATUS_FILTERS: FilterOption<TheContractStatus | 'ALL'>[] = [\n { value: 'ALL', label: 'All' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'NEGOTIATION', label: 'Negotiation' },\n { value: 'SIGNED', label: 'Signed' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'COMPLETED', label: 'Completed' },\n { value: 'SUSPENDED', label: 'Suspended' },\n { value: 'TERMINATED', label: 'Terminated' },\n];\n\nconst SIDES: TheContractSide[] = ['BUY', 'SELL'];\nconst PRICING_BASES: ThePricingBasis[] = ['FIXED', 'INDEX_LINKED', 'FORMULA', 'SPOT'];\nconst COMMODITIES: TheCommodityType[] = [\n 'CRUDE_OIL',\n 'NATURAL_GAS',\n 'LNG',\n 'COAL',\n 'ELECTRICITY',\n 'HYDROGEN',\n 'BIOFUEL',\n 'IRON_ORE',\n 'COPPER',\n 'BAUXITE',\n 'GOLD',\n 'LITHIUM',\n 'RARE_EARTH',\n];\nconst UNITS: TheUnit[] = ['BARRELS', 'CUBIC_METERS', 'TONNES', 'KILOGRAMS', 'MWH', 'GJ', 'MCF'];\n\nconst PAGE_SIZE = 25;\n\nconst clampPercent = (value: number): number => Math.max(0, Math.min(100, value));\n\n/** Fraction of a contract's volume that has been delivered (0–100). */\nconst deliveryPct = (c: TheOfftakeContract): number =>\n c.contractedVolume > 0 ? clampPercent((c.deliveredVolume / c.contractedVolume) * 100) : 0;\n\ninterface CreateFormState {\n reference: string;\n counterparty: string;\n commodity: TheCommodityType;\n side: TheContractSide;\n pricingBasis: ThePricingBasis;\n pricePerUnit: string;\n priceIndex: string;\n currency: string;\n contractedVolume: string;\n unit: TheUnit;\n deliveryLocation: string;\n startDate: string;\n endDate: string;\n notes: string;\n}\n\nconst EMPTY_FORM: CreateFormState = {\n reference: '',\n counterparty: '',\n commodity: 'CRUDE_OIL',\n side: 'SELL',\n pricingBasis: 'FIXED',\n pricePerUnit: '',\n priceIndex: '',\n currency: 'USD',\n contractedVolume: '',\n unit: 'BARRELS',\n deliveryLocation: '',\n startDate: '',\n endDate: '',\n notes: '',\n};\n\nexport function ContractsPage() {\n const { navigateTo } = useTheGlobalFuel();\n const notify = useNotify();\n const { trackContractCreateClicked, trackContractCreated } = useTheAnalytics();\n const [status, setStatus] = useState<TheContractStatus | 'ALL'>('ALL');\n const [side, setSide] = useState<TheContractSide | 'ALL'>('ALL');\n const [commodity, setCommodity] = useState<TheCommodityType | 'ALL'>('ALL');\n const pager = useCursorPager();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<CreateFormState>(EMPTY_FORM);\n const [formError, setFormError] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useTheContracts({\n status: status === 'ALL' ? undefined : status,\n side: side === 'ALL' ? undefined : side,\n commodity: commodity === 'ALL' ? undefined : commodity,\n pagination: { limit: PAGE_SIZE, offset: pager.page * PAGE_SIZE },\n });\n const createContract = useTheCreateContract();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n\n const columns: Column<TheOfftakeContract>[] = [\n {\n key: 'reference',\n header: 'Contract',\n render: (c) => (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n <FileSignature className=\"h-4 w-4\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate font-semibold text-text-primary\">{c.reference}</p>\n <p className=\"truncate text-xs text-text-tertiary\">{c.counterparty}</p>\n </div>\n </div>\n ),\n },\n {\n key: 'side',\n header: 'Side',\n render: (c) => <StatusBadge status={c.side} />,\n },\n {\n key: 'commodity',\n header: 'Commodity',\n hideOnMobile: true,\n render: (c) => <span className=\"text-text-secondary\">{formatEnumLabel(c.commodity)}</span>,\n },\n {\n key: 'status',\n header: 'Status',\n render: (c) => <StatusBadge status={c.status} />,\n },\n {\n key: 'price',\n header: 'Price',\n align: 'right',\n hideOnMobile: true,\n sortValue: (c) => c.pricePerUnit,\n render: (c) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatMoney(c.pricePerUnit, c.currency)}\n <span className=\"text-text-tertiary\">/{formatUnit(c.unit)}</span>\n </span>\n ),\n },\n {\n key: 'delivery',\n header: 'Delivered',\n sortValue: (c) => deliveryPct(c),\n render: (c) => {\n const pct = deliveryPct(c);\n return (\n <div className=\"min-w-[9rem]\">\n <MiniBar\n value={pct}\n barClassName=\"bg-[var(--color-status-success-text)]\"\n className=\"mb-1\"\n />\n <p className=\"text-xs tabular-nums text-text-tertiary\">\n {formatVolume(c.deliveredVolume, c.unit)} / {formatVolume(c.contractedVolume, c.unit)}\n </p>\n </div>\n );\n },\n },\n {\n key: 'updated',\n header: 'Updated',\n align: 'right',\n hideOnMobile: true,\n render: (c) => (\n <span className=\"text-text-tertiary\">\n {new Date(c.updatedAt).toLocaleDateString(undefined, {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n })}\n </span>\n ),\n },\n ];\n\n const resetForm = () => {\n setForm(EMPTY_FORM);\n setFormError(null);\n };\n\n const handleCreate = async () => {\n if (!form.reference.trim()) {\n setFormError('Contract reference is required.');\n return;\n }\n if (!form.counterparty.trim()) {\n setFormError('Counterparty is required.');\n return;\n }\n setFormError(null);\n trackContractCreateClicked();\n try {\n const created = await createContract.mutateAsync({\n reference: form.reference.trim(),\n counterparty: form.counterparty.trim(),\n commodity: form.commodity,\n side: form.side,\n pricingBasis: form.pricingBasis,\n pricePerUnit: form.pricePerUnit ? Number(form.pricePerUnit) : null,\n priceIndex: form.priceIndex.trim() || null,\n currency: form.currency.trim().toUpperCase() || 'USD',\n contractedVolume: form.contractedVolume ? Number(form.contractedVolume) : null,\n unit: form.unit,\n deliveryLocation: form.deliveryLocation.trim() || null,\n startDate: toBackendDate(form.startDate) ?? null,\n endDate: toBackendDate(form.endDate) ?? null,\n notes: form.notes.trim() || null,\n });\n trackContractCreated(created.id);\n notify.success('Contract created');\n setDialogOpen(false);\n resetForm();\n navigateTo(`contracts/${created.id}`);\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create contract.');\n notify.fromError(err);\n }\n };\n\n return (\n <PageLayout\n title=\"Offtake Contracts\"\n description=\"Commodity purchase & sale agreements — pricing, contracted volume and delivery progress.\"\n actions={\n <Button onClick={() => setDialogOpen(true)} data-rybbit-event=\"theglobalfuel.contract.create_clicked\">\n <Plus className=\"mr-1.5 h-4 w-4\" /> New contract\n </Button>\n }\n >\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <FilterTabs\n options={STATUS_FILTERS}\n value={status}\n onChange={(v) => {\n setStatus(v);\n pager.reset();\n }}\n />\n <Select\n value={side}\n onValueChange={(v) => {\n setSide(v as TheContractSide | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-40\" aria-label=\"Filter by side\">\n <SelectValue placeholder=\"All sides\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All sides</SelectItem>\n {SIDES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select\n value={commodity}\n onValueChange={(v) => {\n setCommodity(v as TheCommodityType | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-48\" aria-label=\"Filter by commodity\">\n <SelectValue placeholder=\"All commodities\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All commodities</SelectItem>\n {COMMODITIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading contracts…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load contracts.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<FileSignature className=\"h-10 w-10\" />}\n title=\"No contracts yet\"\n description={\n status === 'ALL' && side === 'ALL' && commodity === 'ALL'\n ? 'Create your first offtake contract to track pricing, volume and delivery.'\n : 'No contracts match these filters.'\n }\n action={\n <Button onClick={() => setDialogOpen(true)} data-rybbit-event=\"theglobalfuel.contract.create_clicked\">\n <Plus className=\"mr-1.5 h-4 w-4\" /> New contract\n </Button>\n }\n />\n ) : (\n <>\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(c) => c.id}\n onRowClick={(c) => navigateTo(`contracts/${c.id}`)}\n rowLabel={(c) => `Open ${c.reference}`}\n />\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={rows.length}\n hasMore={data?.pageInfo?.hasMore ?? false}\n onPageChange={pager.onPageChange}\n />\n </>\n )}\n\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n setDialogOpen(open);\n if (!open) resetForm();\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New offtake contract</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Register a commodity purchase or sale agreement with a counterparty.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <form\n onSubmit={(e) => {\n e.preventDefault();\n void handleCreate();\n }}\n >\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"reference\">Reference *</Label>\n <Input\n id=\"reference\"\n value={form.reference}\n onChange={(e) => setForm({ ...form, reference: e.target.value })}\n placeholder=\"OFT-2026-0142\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"counterparty\">Counterparty *</Label>\n <Input\n id=\"counterparty\"\n value={form.counterparty}\n onChange={(e) => setForm({ ...form, counterparty: e.target.value })}\n placeholder=\"Vitol S.A.\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"commodity\">Commodity *</Label>\n <Select\n value={form.commodity}\n onValueChange={(v) => setForm({ ...form, commodity: v as TheCommodityType })}\n >\n <SelectTrigger id=\"commodity\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {COMMODITIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"side\">Side</Label>\n <Select\n value={form.side}\n onValueChange={(v) => setForm({ ...form, side: v as TheContractSide })}\n >\n <SelectTrigger id=\"side\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SIDES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"pricingBasis\">Pricing basis</Label>\n <Select\n value={form.pricingBasis}\n onValueChange={(v) => setForm({ ...form, pricingBasis: v as ThePricingBasis })}\n >\n <SelectTrigger id=\"pricingBasis\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PRICING_BASES.map((p) => (\n <SelectItem key={p} value={p}>\n {formatEnumLabel(p)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"priceIndex\">Price index</Label>\n <Input\n id=\"priceIndex\"\n value={form.priceIndex}\n onChange={(e) => setForm({ ...form, priceIndex: e.target.value })}\n placeholder=\"Brent, TTF, Henry Hub\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-3\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"pricePerUnit\">Price / unit</Label>\n <Input\n id=\"pricePerUnit\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.pricePerUnit}\n onChange={(e) => setForm({ ...form, pricePerUnit: e.target.value })}\n placeholder=\"82.50\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"currency\">Currency</Label>\n <Input\n id=\"currency\"\n value={form.currency}\n onChange={(e) => setForm({ ...form, currency: e.target.value })}\n placeholder=\"USD\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"unit\">Unit</Label>\n <Select\n value={form.unit}\n onValueChange={(v) => setForm({ ...form, unit: v as TheUnit })}\n >\n <SelectTrigger id=\"unit\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {UNITS.map((u) => (\n <SelectItem key={u} value={u}>\n {formatUnit(u)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"contractedVolume\">Contracted volume</Label>\n <Input\n id=\"contractedVolume\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.contractedVolume}\n onChange={(e) => setForm({ ...form, contractedVolume: e.target.value })}\n placeholder=\"500000\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"deliveryLocation\">Delivery location</Label>\n <Input\n id=\"deliveryLocation\"\n value={form.deliveryLocation}\n onChange={(e) => setForm({ ...form, deliveryLocation: e.target.value })}\n placeholder=\"Rotterdam\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"startDate\">Start date</Label>\n <Input\n id=\"startDate\"\n type=\"date\"\n value={form.startDate}\n onChange={(e) => setForm({ ...form, startDate: e.target.value })}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"endDate\">End date</Label>\n <Input\n id=\"endDate\"\n type=\"date\"\n value={form.endDate}\n onChange={(e) => setForm({ ...form, endDate: e.target.value })}\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"notes\">Notes</Label>\n <Textarea\n id=\"notes\"\n rows={2}\n value={form.notes}\n onChange={(e) => setForm({ ...form, notes: e.target.value })}\n placeholder=\"Optional context about this contract.\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setDialogOpen(false);\n resetForm();\n }}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={createContract.isPending}>\n {createContract.isPending ? 'Creating…' : 'Create contract'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ContractsPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/contracts/ContractsPage.tsx"],"sourcesContent":["/**\n * Offtake contracts — list, filter, and create commodity purchase/sale contracts.\n * @module theglobalfuel/pages/contracts\n *\n * Reads `theListContracts`; writes `theCreateContract`.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, FileSignature } from 'lucide-react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataTable, type Column } from '../../components/DataTable';\nimport { FilterTabs, type FilterOption } from '../../components/FilterTabs';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Pagination } from '../../components/Pagination';\nimport { MiniBar } from '../../components/MiniBar';\nimport { useTheGlobalFuel } from '../../context';\nimport {\n useTheContracts,\n useTheCreateContract,\n useCursorPager,\n useNotify,\n useTheAnalytics,\n useThePageView,\n useTheNativeControls,\n useTheTranslation,\n} from '../../hooks';\nimport { formatEnumLabel, formatMoney, formatUnit, formatVolume } from '../../utils/formatters';\nimport { toBackendDate } from '../../utils';\nimport type {\n TheOfftakeContract,\n TheContractStatus,\n TheContractSide,\n TheCommodityType,\n ThePricingBasis,\n TheUnit,\n} from '../../types';\n\nconst STATUS_FILTERS: FilterOption<TheContractStatus | 'ALL'>[] = [\n { value: 'ALL', label: 'All' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'NEGOTIATION', label: 'Negotiation' },\n { value: 'SIGNED', label: 'Signed' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'COMPLETED', label: 'Completed' },\n { value: 'SUSPENDED', label: 'Suspended' },\n { value: 'TERMINATED', label: 'Terminated' },\n];\n\nconst SIDES: TheContractSide[] = ['BUY', 'SELL'];\nconst PRICING_BASES: ThePricingBasis[] = ['FIXED', 'INDEX_LINKED', 'FORMULA', 'SPOT'];\nconst COMMODITIES: TheCommodityType[] = [\n 'CRUDE_OIL',\n 'NATURAL_GAS',\n 'LNG',\n 'COAL',\n 'ELECTRICITY',\n 'HYDROGEN',\n 'BIOFUEL',\n 'IRON_ORE',\n 'COPPER',\n 'BAUXITE',\n 'GOLD',\n 'LITHIUM',\n 'RARE_EARTH',\n];\nconst UNITS: TheUnit[] = ['BARRELS', 'CUBIC_METERS', 'TONNES', 'KILOGRAMS', 'MWH', 'GJ', 'MCF'];\n\nconst PAGE_SIZE = 25;\n\nconst clampPercent = (value: number): number => Math.max(0, Math.min(100, value));\n\n/** Fraction of a contract's volume that has been delivered (0–100). */\nconst deliveryPct = (c: TheOfftakeContract): number =>\n c.contractedVolume > 0 ? clampPercent((c.deliveredVolume / c.contractedVolume) * 100) : 0;\n\ninterface CreateFormState {\n reference: string;\n counterparty: string;\n commodity: TheCommodityType;\n side: TheContractSide;\n pricingBasis: ThePricingBasis;\n pricePerUnit: string;\n priceIndex: string;\n currency: string;\n contractedVolume: string;\n unit: TheUnit;\n deliveryLocation: string;\n startDate: string;\n endDate: string;\n notes: string;\n}\n\nconst EMPTY_FORM: CreateFormState = {\n reference: '',\n counterparty: '',\n commodity: 'CRUDE_OIL',\n side: 'SELL',\n pricingBasis: 'FIXED',\n pricePerUnit: '',\n priceIndex: '',\n currency: 'USD',\n contractedVolume: '',\n unit: 'BARRELS',\n deliveryLocation: '',\n startDate: '',\n endDate: '',\n notes: '',\n};\n\nexport function ContractsPage() {\n useThePageView('contracts');\n const t = useTheTranslation();\n const { navigateTo } = useTheGlobalFuel();\n const notify = useNotify();\n const { haptic } = useTheNativeControls();\n const { trackContractCreateClicked, trackContractCreated } = useTheAnalytics();\n const [status, setStatus] = useState<TheContractStatus | 'ALL'>('ALL');\n const [side, setSide] = useState<TheContractSide | 'ALL'>('ALL');\n const [commodity, setCommodity] = useState<TheCommodityType | 'ALL'>('ALL');\n const pager = useCursorPager();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<CreateFormState>(EMPTY_FORM);\n const [formError, setFormError] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useTheContracts({\n status: status === 'ALL' ? undefined : status,\n side: side === 'ALL' ? undefined : side,\n commodity: commodity === 'ALL' ? undefined : commodity,\n pagination: { limit: PAGE_SIZE, offset: pager.page * PAGE_SIZE },\n });\n const createContract = useTheCreateContract();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n\n const columns: Column<TheOfftakeContract>[] = [\n {\n key: 'reference',\n header: 'Contract',\n render: (c) => (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n <FileSignature className=\"h-4 w-4\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate font-semibold text-text-primary\">{c.reference}</p>\n <p className=\"truncate text-xs text-text-tertiary\">{c.counterparty}</p>\n </div>\n </div>\n ),\n },\n {\n key: 'side',\n header: 'Side',\n render: (c) => <StatusBadge status={c.side} />,\n },\n {\n key: 'commodity',\n header: 'Commodity',\n hideOnMobile: true,\n render: (c) => <span className=\"text-text-secondary\">{formatEnumLabel(c.commodity)}</span>,\n },\n {\n key: 'status',\n header: 'Status',\n render: (c) => <StatusBadge status={c.status} />,\n },\n {\n key: 'price',\n header: 'Price',\n align: 'right',\n hideOnMobile: true,\n sortValue: (c) => c.pricePerUnit,\n render: (c) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatMoney(c.pricePerUnit, c.currency)}\n <span className=\"text-text-tertiary\">/{formatUnit(c.unit)}</span>\n </span>\n ),\n },\n {\n key: 'delivery',\n header: 'Delivered',\n sortValue: (c) => deliveryPct(c),\n render: (c) => {\n const pct = deliveryPct(c);\n return (\n <div className=\"min-w-[9rem]\">\n <MiniBar\n value={pct}\n barClassName=\"bg-[var(--color-status-success-text)]\"\n className=\"mb-1\"\n />\n <p className=\"text-xs tabular-nums text-text-tertiary\">\n {formatVolume(c.deliveredVolume, c.unit)} / {formatVolume(c.contractedVolume, c.unit)}\n </p>\n </div>\n );\n },\n },\n {\n key: 'updated',\n header: 'Updated',\n align: 'right',\n hideOnMobile: true,\n render: (c) => (\n <span className=\"text-text-tertiary\">\n {new Date(c.updatedAt).toLocaleDateString(undefined, {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n })}\n </span>\n ),\n },\n ];\n\n const resetForm = () => {\n setForm(EMPTY_FORM);\n setFormError(null);\n };\n\n const handleCreate = async () => {\n if (!form.reference.trim()) {\n setFormError('Contract reference is required.');\n return;\n }\n if (!form.counterparty.trim()) {\n setFormError('Counterparty is required.');\n return;\n }\n setFormError(null);\n haptic('light');\n trackContractCreateClicked();\n try {\n const created = await createContract.mutateAsync({\n reference: form.reference.trim(),\n counterparty: form.counterparty.trim(),\n commodity: form.commodity,\n side: form.side,\n pricingBasis: form.pricingBasis,\n pricePerUnit: form.pricePerUnit ? Number(form.pricePerUnit) : null,\n priceIndex: form.priceIndex.trim() || null,\n currency: form.currency.trim().toUpperCase() || 'USD',\n contractedVolume: form.contractedVolume ? Number(form.contractedVolume) : null,\n unit: form.unit,\n deliveryLocation: form.deliveryLocation.trim() || null,\n startDate: toBackendDate(form.startDate) ?? null,\n endDate: toBackendDate(form.endDate) ?? null,\n notes: form.notes.trim() || null,\n });\n trackContractCreated(created.id);\n notify.success('Contract created');\n setDialogOpen(false);\n resetForm();\n navigateTo(`contracts/${created.id}`);\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create contract.');\n notify.fromError(err);\n }\n };\n\n return (\n <PageLayout\n title={t('theglobalfuel.pages.contracts.title', 'Offtake Contracts')}\n description={t(\n 'theglobalfuel.pages.contracts.description',\n 'Commodity purchase & sale agreements — pricing, contracted volume and delivery progress.'\n )}\n dataTour=\"theglobalfuel-contracts-page\"\n actions={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New contract\n </Button>\n }\n >\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <FilterTabs\n options={STATUS_FILTERS}\n value={status}\n onChange={(v) => {\n setStatus(v);\n pager.reset();\n }}\n />\n <Select\n value={side}\n onValueChange={(v) => {\n setSide(v as TheContractSide | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-40\" aria-label=\"Filter by side\">\n <SelectValue placeholder=\"All sides\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All sides</SelectItem>\n {SIDES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select\n value={commodity}\n onValueChange={(v) => {\n setCommodity(v as TheCommodityType | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-48\" aria-label=\"Filter by commodity\">\n <SelectValue placeholder=\"All commodities\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All commodities</SelectItem>\n {COMMODITIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading contracts…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load contracts.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<FileSignature className=\"h-10 w-10\" />}\n title=\"No contracts yet\"\n description={\n status === 'ALL' && side === 'ALL' && commodity === 'ALL'\n ? 'Create your first offtake contract to track pricing, volume and delivery.'\n : 'No contracts match these filters.'\n }\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New contract\n </Button>\n }\n />\n ) : (\n <>\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(c) => c.id}\n onRowClick={(c) => navigateTo(`contracts/${c.id}`)}\n rowLabel={(c) => `Open ${c.reference}`}\n />\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={rows.length}\n hasMore={data?.pageInfo?.hasMore ?? false}\n onPageChange={pager.onPageChange}\n />\n </>\n )}\n\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n setDialogOpen(open);\n if (!open) resetForm();\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New offtake contract</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Register a commodity purchase or sale agreement with a counterparty.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <form\n onSubmit={(e) => {\n e.preventDefault();\n void handleCreate();\n }}\n >\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"reference\">Reference *</Label>\n <Input\n id=\"reference\"\n value={form.reference}\n onChange={(e) => setForm({ ...form, reference: e.target.value })}\n placeholder=\"OFT-2026-0142\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"counterparty\">Counterparty *</Label>\n <Input\n id=\"counterparty\"\n value={form.counterparty}\n onChange={(e) => setForm({ ...form, counterparty: e.target.value })}\n placeholder=\"Vitol S.A.\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"commodity\">Commodity *</Label>\n <Select\n value={form.commodity}\n onValueChange={(v) => setForm({ ...form, commodity: v as TheCommodityType })}\n >\n <SelectTrigger id=\"commodity\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {COMMODITIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"side\">Side</Label>\n <Select\n value={form.side}\n onValueChange={(v) => setForm({ ...form, side: v as TheContractSide })}\n >\n <SelectTrigger id=\"side\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SIDES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"pricingBasis\">Pricing basis</Label>\n <Select\n value={form.pricingBasis}\n onValueChange={(v) => setForm({ ...form, pricingBasis: v as ThePricingBasis })}\n >\n <SelectTrigger id=\"pricingBasis\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PRICING_BASES.map((p) => (\n <SelectItem key={p} value={p}>\n {formatEnumLabel(p)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"priceIndex\">Price index</Label>\n <Input\n id=\"priceIndex\"\n value={form.priceIndex}\n onChange={(e) => setForm({ ...form, priceIndex: e.target.value })}\n placeholder=\"Brent, TTF, Henry Hub\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-3\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"pricePerUnit\">Price / unit</Label>\n <Input\n id=\"pricePerUnit\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.pricePerUnit}\n onChange={(e) => setForm({ ...form, pricePerUnit: e.target.value })}\n placeholder=\"82.50\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"currency\">Currency</Label>\n <Input\n id=\"currency\"\n value={form.currency}\n onChange={(e) => setForm({ ...form, currency: e.target.value })}\n placeholder=\"USD\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"unit\">Unit</Label>\n <Select\n value={form.unit}\n onValueChange={(v) => setForm({ ...form, unit: v as TheUnit })}\n >\n <SelectTrigger id=\"unit\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {UNITS.map((u) => (\n <SelectItem key={u} value={u}>\n {formatUnit(u)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"contractedVolume\">Contracted volume</Label>\n <Input\n id=\"contractedVolume\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.contractedVolume}\n onChange={(e) => setForm({ ...form, contractedVolume: e.target.value })}\n placeholder=\"500000\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"deliveryLocation\">Delivery location</Label>\n <Input\n id=\"deliveryLocation\"\n value={form.deliveryLocation}\n onChange={(e) => setForm({ ...form, deliveryLocation: e.target.value })}\n placeholder=\"Rotterdam\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"startDate\">Start date</Label>\n <Input\n id=\"startDate\"\n type=\"date\"\n value={form.startDate}\n onChange={(e) => setForm({ ...form, startDate: e.target.value })}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"endDate\">End date</Label>\n <Input\n id=\"endDate\"\n type=\"date\"\n value={form.endDate}\n onChange={(e) => setForm({ ...form, endDate: e.target.value })}\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"notes\">Notes</Label>\n <Textarea\n id=\"notes\"\n rows={2}\n value={form.notes}\n onChange={(e) => setForm({ ...form, notes: e.target.value })}\n placeholder=\"Optional context about this contract.\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setDialogOpen(false);\n resetForm();\n }}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={createContract.isPending}>\n {createContract.isPending ? 'Creating…' : 'Create contract'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard — TheGlobalFuel resources operating-system overview.
|
|
3
|
+
* @module theglobalfuel/pages/dashboard
|
|
4
|
+
*
|
|
5
|
+
* The hero landing (eager-loaded). Every figure is aggregated client-side from
|
|
6
|
+
* the real `the*` list endpoints — no mock data. The page opens with the domain
|
|
7
|
+
* KPI grid (registry / commerce / sustainability), then a rich analytics band:
|
|
8
|
+
* - a PRODUCTION TREND area chart (metered output bucketed by month),
|
|
9
|
+
* - a COMMODITY MIX donut (share of assets by commodity), and
|
|
10
|
+
* - an EMISSIONS-BY-SCOPE donut (tonnes CO₂e per GHG scope);
|
|
11
|
+
* a COMMODITY PORTFOLIO grid (one glass card per commodity present, with real
|
|
12
|
+
* asset counts, summed capacity and a production sparkline); an ASSETS-BY-
|
|
13
|
+
* LIFECYCLE distribution; and recent-activity tables. All charts derive from
|
|
14
|
+
* the fetched arrays and degrade to pre-launch empty states.
|
|
15
|
+
*/
|
|
16
|
+
export declare function DashboardPage(): import("react").JSX.Element;
|
|
17
|
+
//# sourceMappingURL=DashboardPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DashboardPage.d.ts","sourceRoot":"","sources":["../../../../src/theglobalfuel/pages/dashboard/DashboardPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA6cH,wBAAgB,aAAa,gCAgpB5B"}
|
|
@@ -15,9 +15,10 @@ import { DonutChart as b } from "../../components/viz/DonutChart.js";
|
|
|
15
15
|
import "../../components/viz/index.js";
|
|
16
16
|
import "../../context/index.js";
|
|
17
17
|
import { useTheAssets as ne, useTheComplianceCerts as re, useTheContracts as ie, useTheEmissionRecords as ae, useTheInventoryLots as oe, useTheProductionRecords as se, useTheShipments as ce } from "../../hooks/useTheGlobalFuelApi.js";
|
|
18
|
-
import {
|
|
18
|
+
import { useThePageView as le } from "../../hooks/useThePageView.js";
|
|
19
|
+
import { useTheTranslation as ue } from "../../hooks/useTheTranslation.js";
|
|
19
20
|
import "../../hooks/index.js";
|
|
20
|
-
import {
|
|
21
|
+
import { useMemo as x } from "react";
|
|
21
22
|
import { Activity as de, ArrowRight as S, ArrowUpRight as C, Boxes as fe, ClipboardList as pe, Factory as me, Fuel as he, Gauge as ge, GitBranch as _e, Layers as ve, ScrollText as ye, ShieldCheck as be, Ship as xe } from "lucide-react";
|
|
22
23
|
import { jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
23
24
|
import { GlassCard as E, Spinner as D } from "@burdenoff/fe-libs/ui";
|
|
@@ -323,44 +324,41 @@ function De({ card: e, onOpen: t }) {
|
|
|
323
324
|
});
|
|
324
325
|
}
|
|
325
326
|
function L() {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
y();
|
|
329
|
-
}, [y]);
|
|
330
|
-
let C = ne({ pagination: { limit: 200 } }), E = ie({ pagination: { limit: 50 } }), D = ce(void 0, "IN_TRANSIT"), O = ae({ pagination: { limit: 200 } }), k = oe({ pagination: { limit: 50 } }), M = re(), N = se({ pagination: { limit: 200 } }), L = x(() => C.data?.items ?? [], [C.data]), R = x(() => E.data?.items ?? [], [E.data]), z = x(() => D.data?.items ?? [], [D.data]), B = x(() => O.data?.items ?? [], [O.data]), V = x(() => k.data?.items ?? [], [k.data]), H = x(() => M.data?.items ?? [], [M.data]), U = x(() => N.data?.items ?? [], [N.data]), W = L.filter((e) => e.status === "PRODUCING").length, Oe = R.filter((e) => e.status === "ACTIVE").length, G = B.reduce((e, t) => e + (t.co2eTonnes ?? 0), 0), ke = B.filter((e) => e.verified).length, Ae = V.filter((e) => e.status === "AVAILABLE").length, je = U.reduce((e, t) => e + (t.volume ?? 0), 0), Me = H.filter((e) => e.status === "PENDING").length, Ne = H.filter((e) => e.expiresAt != null && (d(e.expiresAt) || A(e.expiresAt))).length, K = H.filter((e) => e.status === "PENDING" || e.expiresAt != null && (d(e.expiresAt) || A(e.expiresAt))).length, q = (e, t) => t ? `${e.length}+` : o(e.length), J = x(() => P(Te(U, (e) => e.periodEnd, (e) => e.volume ?? 0)), [U]), Y = x(() => F(L, (e) => e.commodity), [L]), X = x(() => {
|
|
327
|
+
le("dashboard");
|
|
328
|
+
let { navigateTo: t, currentUser: s } = e(), y = ne({ pagination: { limit: 200 } }), C = ie({ pagination: { limit: 50 } }), E = ce(void 0, "IN_TRANSIT"), D = ae({ pagination: { limit: 200 } }), O = oe({ pagination: { limit: 50 } }), k = re(), M = se({ pagination: { limit: 200 } }), N = x(() => y.data?.items ?? [], [y.data]), L = x(() => C.data?.items ?? [], [C.data]), R = x(() => E.data?.items ?? [], [E.data]), z = x(() => D.data?.items ?? [], [D.data]), B = x(() => O.data?.items ?? [], [O.data]), V = x(() => k.data?.items ?? [], [k.data]), H = x(() => M.data?.items ?? [], [M.data]), U = N.filter((e) => e.status === "PRODUCING").length, W = L.filter((e) => e.status === "ACTIVE").length, G = z.reduce((e, t) => e + (t.co2eTonnes ?? 0), 0), Oe = z.filter((e) => e.verified).length, ke = B.filter((e) => e.status === "AVAILABLE").length, Ae = H.reduce((e, t) => e + (t.volume ?? 0), 0), je = V.filter((e) => e.status === "PENDING").length, Me = V.filter((e) => e.expiresAt != null && (d(e.expiresAt) || A(e.expiresAt))).length, K = V.filter((e) => e.status === "PENDING" || e.expiresAt != null && (d(e.expiresAt) || A(e.expiresAt))).length, q = (e, t) => t ? `${e.length}+` : o(e.length), J = x(() => P(Te(H, (e) => e.periodEnd, (e) => e.volume ?? 0)), [H]), Y = x(() => F(N, (e) => e.commodity), [N]), X = x(() => {
|
|
331
329
|
let e = ee(Y.length), t = /* @__PURE__ */ new Map();
|
|
332
330
|
return Y.forEach((n, r) => t.set(n.key, e[r])), t;
|
|
333
331
|
}, [Y]), Z = x(() => Y.map((e) => ({
|
|
334
332
|
label: a(e.key),
|
|
335
333
|
value: e.count,
|
|
336
334
|
color: X.get(e.key)
|
|
337
|
-
})), [Y, X]),
|
|
338
|
-
if (
|
|
335
|
+
})), [Y, X]), Ne = x(() => {
|
|
336
|
+
if (z.length === 0) return [];
|
|
339
337
|
let e = {
|
|
340
338
|
SCOPE_1: 0,
|
|
341
339
|
SCOPE_2: 0,
|
|
342
340
|
SCOPE_3: 0
|
|
343
341
|
};
|
|
344
|
-
for (let t of
|
|
342
|
+
for (let t of z) e[t.scope] += t.co2eTonnes ?? 0;
|
|
345
343
|
return we.filter((t) => e[t] > 0).map((t) => ({
|
|
346
344
|
label: a(t),
|
|
347
345
|
value: e[t],
|
|
348
346
|
color: Ce[t]
|
|
349
347
|
}));
|
|
350
|
-
}, [
|
|
348
|
+
}, [z]), Pe = x(() => F(N, (e) => e.status).map((e) => ({
|
|
351
349
|
key: e.key,
|
|
352
350
|
label: /* @__PURE__ */ w(f, { status: e.key }),
|
|
353
351
|
value: o(e.count),
|
|
354
352
|
pct: e.pct,
|
|
355
353
|
barClassName: Se[e.key] ?? "bg-action-primary-bg"
|
|
356
|
-
})), [
|
|
354
|
+
})), [N]), Fe = x(() => {
|
|
357
355
|
let e = /* @__PURE__ */ new Map();
|
|
358
|
-
for (let t of
|
|
356
|
+
for (let t of N) e.set(t.id, t.commodity);
|
|
359
357
|
return e;
|
|
360
|
-
}, [
|
|
358
|
+
}, [N]), Ie = x(() => {
|
|
361
359
|
if (Y.length === 0) return [];
|
|
362
360
|
let e = /* @__PURE__ */ new Map();
|
|
363
|
-
for (let t of
|
|
361
|
+
for (let t of N) {
|
|
364
362
|
let n = e.get(t.commodity) ?? {
|
|
365
363
|
count: 0,
|
|
366
364
|
producing: 0,
|
|
@@ -370,8 +368,8 @@ function L() {
|
|
|
370
368
|
n.count += 1, t.status === "PRODUCING" && (n.producing += 1), n.capacity += t.capacityPerDay ?? 0, t.capacityUnit && n.units.set(t.capacityUnit, (n.units.get(t.capacityUnit) ?? 0) + 1), e.set(t.commodity, n);
|
|
371
369
|
}
|
|
372
370
|
let t = /* @__PURE__ */ new Map();
|
|
373
|
-
for (let e of
|
|
374
|
-
let n =
|
|
371
|
+
for (let e of H) {
|
|
372
|
+
let n = Fe.get(e.assetId);
|
|
375
373
|
if (!n) continue;
|
|
376
374
|
let r = new Date(e.periodEnd);
|
|
377
375
|
if (Number.isNaN(r.getTime())) continue;
|
|
@@ -402,16 +400,16 @@ function L() {
|
|
|
402
400
|
};
|
|
403
401
|
});
|
|
404
402
|
}, [
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
403
|
+
N,
|
|
404
|
+
H,
|
|
405
|
+
Fe,
|
|
408
406
|
Y,
|
|
409
407
|
X
|
|
410
|
-
]),
|
|
408
|
+
]), Le = x(() => {
|
|
411
409
|
let e = /* @__PURE__ */ new Map();
|
|
412
|
-
for (let t of
|
|
410
|
+
for (let t of N) e.set(t.id, t.name);
|
|
413
411
|
return e;
|
|
414
|
-
}, [
|
|
412
|
+
}, [N]), Re = x(() => [...L].sort((e, t) => new Date(t.createdAt).getTime() - new Date(e.createdAt).getTime()).slice(0, 6), [L]), Q = x(() => [...H].sort((e, t) => new Date(t.periodEnd).getTime() - new Date(e.periodEnd).getTime()).slice(0, 6), [H]), ze = [
|
|
415
413
|
{
|
|
416
414
|
key: "reference",
|
|
417
415
|
header: "Reference",
|
|
@@ -468,13 +466,13 @@ function L() {
|
|
|
468
466
|
children: c(e.createdAt)
|
|
469
467
|
})
|
|
470
468
|
}
|
|
471
|
-
],
|
|
469
|
+
], Be = [
|
|
472
470
|
{
|
|
473
471
|
key: "asset",
|
|
474
472
|
header: "Asset",
|
|
475
473
|
render: (e) => /* @__PURE__ */ w("span", {
|
|
476
474
|
className: "font-medium text-text-primary",
|
|
477
|
-
children:
|
|
475
|
+
children: Le.get(e.assetId) ?? "Unknown asset"
|
|
478
476
|
})
|
|
479
477
|
},
|
|
480
478
|
{
|
|
@@ -519,78 +517,80 @@ function L() {
|
|
|
519
517
|
children: c(e.createdAt)
|
|
520
518
|
})
|
|
521
519
|
}
|
|
522
|
-
],
|
|
523
|
-
return
|
|
524
|
-
title:
|
|
520
|
+
], Ve = s?.firstName || s?.name || "there", He = ue(), Ue = He("theglobalfuel.pages.dashboard.subtitle", "Welcome back, {name} — your energy, mineral & commodity resource control room.", { name: Ve }), We = y.isLoading && C.isLoading && D.isLoading && O.isLoading && k.isLoading, $ = He("theglobalfuel.pages.dashboard.title", "TheGlobalFuel");
|
|
521
|
+
return We ? /* @__PURE__ */ w(n, {
|
|
522
|
+
title: $,
|
|
525
523
|
titleGradient: !0,
|
|
526
524
|
aurora: !0,
|
|
527
|
-
description:
|
|
525
|
+
description: Ue,
|
|
526
|
+
dataTour: "theglobalfuel-dashboard-page",
|
|
528
527
|
children: /* @__PURE__ */ w(g, { label: "Loading your resource portfolio…" })
|
|
529
528
|
}) : /* @__PURE__ */ T(n, {
|
|
530
|
-
title:
|
|
529
|
+
title: $,
|
|
531
530
|
titleGradient: !0,
|
|
532
531
|
aurora: !0,
|
|
533
|
-
description:
|
|
532
|
+
description: Ue,
|
|
533
|
+
dataTour: "theglobalfuel-dashboard-page",
|
|
534
534
|
children: [
|
|
535
535
|
/* @__PURE__ */ T("div", {
|
|
536
536
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6",
|
|
537
537
|
children: [
|
|
538
538
|
/* @__PURE__ */ w(r, {
|
|
539
539
|
icon: /* @__PURE__ */ w(ve, { className: "h-5 w-5" }),
|
|
540
|
-
value: q(
|
|
540
|
+
value: q(N, y.data?.pageInfo?.hasMore),
|
|
541
541
|
label: "Resource assets",
|
|
542
542
|
featured: !0,
|
|
543
543
|
footer: /* @__PURE__ */ T("div", {
|
|
544
544
|
className: "space-y-2",
|
|
545
545
|
children: [/* @__PURE__ */ w(p, {
|
|
546
|
-
value:
|
|
546
|
+
value: N.length ? U / N.length * 100 : 0,
|
|
547
547
|
height: 4,
|
|
548
548
|
barClassName: "bg-status-success-text"
|
|
549
549
|
}), /* @__PURE__ */ T("p", {
|
|
550
550
|
className: "text-xs text-text-tertiary",
|
|
551
551
|
children: [/* @__PURE__ */ w("span", {
|
|
552
552
|
className: "tabular-nums text-text-secondary",
|
|
553
|
-
children:
|
|
553
|
+
children: U
|
|
554
554
|
}), " producing"]
|
|
555
555
|
})]
|
|
556
556
|
})
|
|
557
557
|
}),
|
|
558
558
|
/* @__PURE__ */ w(r, {
|
|
559
559
|
icon: /* @__PURE__ */ w(ye, { className: "h-5 w-5" }),
|
|
560
|
-
value: q(
|
|
560
|
+
value: q(L, C.data?.pageInfo?.hasMore),
|
|
561
561
|
label: "Offtake contracts",
|
|
562
562
|
footer: /* @__PURE__ */ T("div", {
|
|
563
563
|
className: "space-y-2",
|
|
564
564
|
children: [/* @__PURE__ */ w(p, {
|
|
565
|
-
value:
|
|
565
|
+
value: L.length ? W / L.length * 100 : 0,
|
|
566
566
|
height: 4,
|
|
567
567
|
barClassName: "bg-action-primary-bg"
|
|
568
568
|
}), /* @__PURE__ */ T("p", {
|
|
569
569
|
className: "text-xs text-text-tertiary",
|
|
570
570
|
children: [/* @__PURE__ */ w("span", {
|
|
571
571
|
className: "tabular-nums text-text-secondary",
|
|
572
|
-
children:
|
|
572
|
+
children: W
|
|
573
573
|
}), " active"]
|
|
574
574
|
})]
|
|
575
575
|
})
|
|
576
576
|
}),
|
|
577
577
|
/* @__PURE__ */ w(r, {
|
|
578
578
|
icon: /* @__PURE__ */ w(xe, { className: "h-5 w-5" }),
|
|
579
|
-
value:
|
|
579
|
+
value: E.isError ? "—" : o(R.length),
|
|
580
580
|
label: "Shipments in transit",
|
|
581
581
|
footer: /* @__PURE__ */ w("p", {
|
|
582
582
|
className: "text-xs text-text-tertiary",
|
|
583
|
-
children:
|
|
583
|
+
children: R.length > 0 ? "In motion across carriers" : "No active movements"
|
|
584
584
|
})
|
|
585
585
|
}),
|
|
586
586
|
/* @__PURE__ */ w(r, {
|
|
587
587
|
icon: /* @__PURE__ */ w(me, { className: "h-5 w-5" }),
|
|
588
|
-
value:
|
|
588
|
+
value: D.isError ? "—" : l(G),
|
|
589
589
|
label: "Emissions logged",
|
|
590
590
|
footer: /* @__PURE__ */ T("div", {
|
|
591
591
|
className: "space-y-2",
|
|
592
592
|
children: [/* @__PURE__ */ w(p, {
|
|
593
|
-
value:
|
|
593
|
+
value: z.length ? Oe / z.length * 100 : 0,
|
|
594
594
|
height: 4,
|
|
595
595
|
barClassName: "bg-status-success-text"
|
|
596
596
|
}), /* @__PURE__ */ T("p", {
|
|
@@ -598,7 +598,7 @@ function L() {
|
|
|
598
598
|
children: [
|
|
599
599
|
/* @__PURE__ */ w("span", {
|
|
600
600
|
className: "tabular-nums text-text-secondary",
|
|
601
|
-
children:
|
|
601
|
+
children: Oe
|
|
602
602
|
}),
|
|
603
603
|
" ",
|
|
604
604
|
"verified"
|
|
@@ -608,12 +608,12 @@ function L() {
|
|
|
608
608
|
}),
|
|
609
609
|
/* @__PURE__ */ w(r, {
|
|
610
610
|
icon: /* @__PURE__ */ w(fe, { className: "h-5 w-5" }),
|
|
611
|
-
value:
|
|
611
|
+
value: O.isError ? "—" : o(ke),
|
|
612
612
|
label: "Inventory available",
|
|
613
613
|
footer: /* @__PURE__ */ T("div", {
|
|
614
614
|
className: "space-y-2",
|
|
615
615
|
children: [/* @__PURE__ */ w(p, {
|
|
616
|
-
value:
|
|
616
|
+
value: B.length ? ke / B.length * 100 : 0,
|
|
617
617
|
height: 4,
|
|
618
618
|
barClassName: "bg-action-primary-bg"
|
|
619
619
|
}), /* @__PURE__ */ T("p", {
|
|
@@ -621,7 +621,7 @@ function L() {
|
|
|
621
621
|
children: [
|
|
622
622
|
/* @__PURE__ */ w("span", {
|
|
623
623
|
className: "tabular-nums text-text-secondary",
|
|
624
|
-
children: q(
|
|
624
|
+
children: q(B, O.data?.pageInfo?.hasMore)
|
|
625
625
|
}),
|
|
626
626
|
" ",
|
|
627
627
|
"lots total"
|
|
@@ -631,12 +631,12 @@ function L() {
|
|
|
631
631
|
}),
|
|
632
632
|
/* @__PURE__ */ w(r, {
|
|
633
633
|
icon: /* @__PURE__ */ w(be, { className: "h-5 w-5" }),
|
|
634
|
-
value:
|
|
634
|
+
value: k.isError ? "—" : o(K),
|
|
635
635
|
label: "Certs need attention",
|
|
636
|
-
accent: K > 0 ? "warning" :
|
|
636
|
+
accent: K > 0 ? "warning" : V.length > 0 ? "success" : void 0,
|
|
637
637
|
footer: /* @__PURE__ */ w("p", {
|
|
638
638
|
className: K > 0 ? "text-xs font-medium text-status-warning-text" : "text-xs text-text-tertiary",
|
|
639
|
-
children:
|
|
639
|
+
children: V.length === 0 ? "No certifications tracked yet" : K > 0 ? `${je} pending · ${Me} expiring` : "All certifications current"
|
|
640
640
|
})
|
|
641
641
|
})
|
|
642
642
|
]
|
|
@@ -652,12 +652,12 @@ function L() {
|
|
|
652
652
|
label: "Production",
|
|
653
653
|
onClick: () => t("production")
|
|
654
654
|
},
|
|
655
|
-
isLoading:
|
|
656
|
-
isError:
|
|
657
|
-
onRetry: () =>
|
|
655
|
+
isLoading: M.isLoading,
|
|
656
|
+
isError: M.isError,
|
|
657
|
+
onRetry: () => M.refetch(),
|
|
658
658
|
isEmpty: J.length === 0,
|
|
659
659
|
emptyLabel: "No production logged yet — record output to build the trend.",
|
|
660
|
-
footer: J.length > 0 ? `${o(
|
|
660
|
+
footer: J.length > 0 ? `${o(Ae, { maximumFractionDigits: 0 })} total volume across ${q(H, M.data?.pageInfo?.hasMore)} records` : void 0,
|
|
661
661
|
children: /* @__PURE__ */ w(te, {
|
|
662
662
|
series: J,
|
|
663
663
|
height: 220,
|
|
@@ -671,18 +671,18 @@ function L() {
|
|
|
671
671
|
label: "Assets",
|
|
672
672
|
onClick: () => t("assets")
|
|
673
673
|
},
|
|
674
|
-
isLoading:
|
|
675
|
-
isError:
|
|
676
|
-
onRetry: () =>
|
|
674
|
+
isLoading: y.isLoading,
|
|
675
|
+
isError: y.isError,
|
|
676
|
+
onRetry: () => y.refetch(),
|
|
677
677
|
isEmpty: Z.length === 0,
|
|
678
678
|
emptyLabel: "No assets registered yet.",
|
|
679
|
-
footer: Z.length > 0 ? `${q(
|
|
679
|
+
footer: Z.length > 0 ? `${q(N, y.data?.pageInfo?.hasMore)} assets · ${Z.length} ${Z.length === 1 ? "commodity" : "commodities"}` : void 0,
|
|
680
680
|
children: /* @__PURE__ */ w("div", {
|
|
681
681
|
className: "flex items-center justify-center py-2",
|
|
682
682
|
children: /* @__PURE__ */ w(b, {
|
|
683
683
|
segments: Z,
|
|
684
684
|
size: 168,
|
|
685
|
-
centerLabel: o(
|
|
685
|
+
centerLabel: o(N.length),
|
|
686
686
|
centerCaption: "assets",
|
|
687
687
|
valueFormatter: (e) => o(e),
|
|
688
688
|
title: "Assets by commodity"
|
|
@@ -693,17 +693,17 @@ function L() {
|
|
|
693
693
|
/* @__PURE__ */ w(_, {
|
|
694
694
|
title: "Commodity portfolio",
|
|
695
695
|
description: "One model, every commodity — assets, capacity and output across your book.",
|
|
696
|
-
children:
|
|
696
|
+
children: y.isLoading ? /* @__PURE__ */ w(g, { label: "Loading commodities…" }) : y.isError ? /* @__PURE__ */ w(h, {
|
|
697
697
|
message: "Couldn't load your commodity portfolio.",
|
|
698
|
-
onRetry: () =>
|
|
699
|
-
}) :
|
|
698
|
+
onRetry: () => y.refetch()
|
|
699
|
+
}) : Ie.length === 0 ? /* @__PURE__ */ w(v, {
|
|
700
700
|
illustration: "empty-data",
|
|
701
701
|
icon: /* @__PURE__ */ w(ve, { className: "h-10 w-10" }),
|
|
702
702
|
title: "No commodities yet",
|
|
703
703
|
description: "Register your first resource asset to build out your commodity portfolio."
|
|
704
704
|
}) : /* @__PURE__ */ w("div", {
|
|
705
705
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4",
|
|
706
|
-
children:
|
|
706
|
+
children: Ie.map((e) => /* @__PURE__ */ w(De, {
|
|
707
707
|
card: e,
|
|
708
708
|
onOpen: () => t("assets")
|
|
709
709
|
}, e.key))
|
|
@@ -717,12 +717,12 @@ function L() {
|
|
|
717
717
|
icon: /* @__PURE__ */ w(_e, { className: "h-4 w-4" }),
|
|
718
718
|
linkLabel: "Assets",
|
|
719
719
|
onLink: () => t("assets"),
|
|
720
|
-
isLoading:
|
|
721
|
-
isError:
|
|
722
|
-
onRetry: () =>
|
|
720
|
+
isLoading: y.isLoading,
|
|
721
|
+
isError: y.isError,
|
|
722
|
+
onRetry: () => y.refetch(),
|
|
723
723
|
emptyLabel: "No assets to profile yet.",
|
|
724
|
-
bars:
|
|
725
|
-
footer:
|
|
724
|
+
bars: Pe,
|
|
725
|
+
footer: N.length > 0 ? `${U} of ${q(N, y.data?.pageInfo?.hasMore)} currently producing` : void 0
|
|
726
726
|
}), /* @__PURE__ */ w(I, {
|
|
727
727
|
title: "Emissions by scope",
|
|
728
728
|
caption: "GHG Protocol Scope 1 / 2 / 3 — tonnes CO₂e logged.",
|
|
@@ -731,16 +731,16 @@ function L() {
|
|
|
731
731
|
label: "Emissions",
|
|
732
732
|
onClick: () => t("emissions")
|
|
733
733
|
},
|
|
734
|
-
isLoading:
|
|
735
|
-
isError:
|
|
736
|
-
onRetry: () =>
|
|
737
|
-
isEmpty:
|
|
734
|
+
isLoading: D.isLoading,
|
|
735
|
+
isError: D.isError,
|
|
736
|
+
onRetry: () => D.refetch(),
|
|
737
|
+
isEmpty: Ne.length === 0,
|
|
738
738
|
emptyLabel: "No emission records logged yet.",
|
|
739
|
-
footer:
|
|
739
|
+
footer: z.length > 0 ? `${l(G)} across ${q(z, D.data?.pageInfo?.hasMore)} records` : void 0,
|
|
740
740
|
children: /* @__PURE__ */ w("div", {
|
|
741
741
|
className: "flex items-center justify-center py-2",
|
|
742
742
|
children: /* @__PURE__ */ w(b, {
|
|
743
|
-
segments:
|
|
743
|
+
segments: Ne,
|
|
744
744
|
size: 168,
|
|
745
745
|
centerLabel: o(G, {
|
|
746
746
|
notation: "compact",
|
|
@@ -762,17 +762,17 @@ function L() {
|
|
|
762
762
|
className: "inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline",
|
|
763
763
|
children: ["All contracts ", /* @__PURE__ */ w(S, { className: "h-4 w-4" })]
|
|
764
764
|
}),
|
|
765
|
-
children:
|
|
765
|
+
children: C.isLoading ? /* @__PURE__ */ w(g, { label: "Loading contracts…" }) : C.isError ? /* @__PURE__ */ w(h, {
|
|
766
766
|
message: "Couldn't load contracts.",
|
|
767
|
-
onRetry: () =>
|
|
768
|
-
}) :
|
|
767
|
+
onRetry: () => C.refetch()
|
|
768
|
+
}) : Re.length === 0 ? /* @__PURE__ */ w(v, {
|
|
769
769
|
illustration: "empty-data",
|
|
770
770
|
icon: /* @__PURE__ */ w(ye, { className: "h-10 w-10" }),
|
|
771
771
|
title: "No contracts yet",
|
|
772
772
|
description: "Draft your first offtake contract to start tracking commodity trade."
|
|
773
773
|
}) : /* @__PURE__ */ w(m, {
|
|
774
|
-
columns:
|
|
775
|
-
rows:
|
|
774
|
+
columns: ze,
|
|
775
|
+
rows: Re,
|
|
776
776
|
rowKey: (e) => e.id,
|
|
777
777
|
onRowClick: (e) => t(`contracts/${e.id}`),
|
|
778
778
|
rowLabel: (e) => `Open contract ${e.reference}`
|
|
@@ -787,20 +787,20 @@ function L() {
|
|
|
787
787
|
className: "inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline",
|
|
788
788
|
children: ["All production ", /* @__PURE__ */ w(S, { className: "h-4 w-4" })]
|
|
789
789
|
}),
|
|
790
|
-
children:
|
|
790
|
+
children: M.isLoading ? /* @__PURE__ */ w(g, { label: "Loading production…" }) : M.isError ? /* @__PURE__ */ w(h, {
|
|
791
791
|
message: "Couldn't load production records.",
|
|
792
|
-
onRetry: () =>
|
|
793
|
-
}) :
|
|
792
|
+
onRetry: () => M.refetch()
|
|
793
|
+
}) : Q.length === 0 ? /* @__PURE__ */ w(v, {
|
|
794
794
|
illustration: "empty-data",
|
|
795
795
|
icon: /* @__PURE__ */ w(pe, { className: "h-10 w-10" }),
|
|
796
796
|
title: "No production logged yet",
|
|
797
797
|
description: "Record production against an asset to build its output history."
|
|
798
798
|
}) : /* @__PURE__ */ w(m, {
|
|
799
|
-
columns:
|
|
800
|
-
rows:
|
|
799
|
+
columns: Be,
|
|
800
|
+
rows: Q,
|
|
801
801
|
rowKey: (e) => e.id,
|
|
802
802
|
onRowClick: (e) => t(`assets/${e.assetId}`),
|
|
803
|
-
rowLabel: (e) => `Open ${
|
|
803
|
+
rowLabel: (e) => `Open ${Le.get(e.assetId) ?? "asset"}`
|
|
804
804
|
})
|
|
805
805
|
})
|
|
806
806
|
]
|