@burdenoff/microfe-theglobalfuel 2026.1022.1 → 2026.1026.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.
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/theglobalfuel/components/DataTable.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAgD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKrF,MAAM,WAAW,MAAM,CAAC,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,CAAC;CACzC;AAED,UAAU,cAAc,CAAC,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACrB,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC;IAC9B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAC;CACpD;AAoBD,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAC3B,OAAO,EACP,IAAI,EACJ,MAAM,EACN,UAAU,EACV,QAAQ,EACR,SAAS,EACT,WAAW,GACZ,EAAE,cAAc,CAAC,CAAC,CAAC,+BA+MnB"}
1
+ {"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/theglobalfuel/components/DataTable.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAgD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKrF,MAAM,WAAW,MAAM,CAAC,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,CAAC;CACzC;AAED,UAAU,cAAc,CAAC,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACrB,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC;IAC9B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAC;CACpD;AAoBD,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAC3B,OAAO,EACP,IAAI,EACJ,MAAM,EACN,UAAU,EACV,QAAQ,EACR,SAAS,EACT,WAAW,GACZ,EAAE,cAAc,CAAC,CAAC,CAAC,+BAgNnB"}
@@ -63,7 +63,7 @@ function p({ columns: p, rows: m, rowKey: h, onRowClick: g, rowLabel: _, classNa
63
63
  onClick: n ? () => w(t.key) : void 0,
64
64
  onKeyDown: n ? (e) => d(e, () => w(t.key)) : void 0,
65
65
  "aria-sort": r ? b?.dir === "asc" ? "ascending" : "descending" : void 0,
66
- className: e("px-4 py-3 font-medium text-text-secondary whitespace-nowrap", f[t.align ?? "left"], t.hideOnMobile && "hidden md:table-cell", n && "cursor-pointer select-none hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]"),
66
+ className: e("px-4 py-3 font-medium text-text-secondary whitespace-nowrap", f[t.align ?? "left"], t.hideOnMobile && "hidden md:table-cell", t.className, n && "cursor-pointer select-none hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]"),
67
67
  children: /* @__PURE__ */ l("span", {
68
68
  className: e("inline-flex items-center gap-1", t.align === "right" && "flex-row-reverse"),
69
69
  children: [t.header, n && (r ? b?.dir === "asc" ? /* @__PURE__ */ c(o, { className: "h-3.5 w-3.5 text-action-primary-bg" }) : /* @__PURE__ */ c(i, { className: "h-3.5 w-3.5 text-action-primary-bg" }) : /* @__PURE__ */ c(s, { className: "h-3.5 w-3.5 opacity-40" }))]
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.js","names":[],"sources":["../../../src/theglobalfuel/components/DataTable.tsx"],"sourcesContent":["/**\n * DataTable — a lightweight, semantic-token table for list pages.\n * @module theglobalfuel/components\n *\n * Deliberately minimal (no external table lib). Columns declare a header, a\n * render fn, optional alignment, and optionally a `sortValue` to make the column\n * click-sortable.\n *\n * Responsive strategy:\n * - At `md` and up it renders a horizontally-scrollable table wrapped in a\n * GlassCard (the classic desktop layout).\n * - Below `md` it renders each row as a native-feeling, stacked \"card\": the\n * first column becomes the card's headline (with a chevron affordance when\n * the row is clickable) and the remaining columns render as label→value\n * pairs. Sort + click behavior carry over, so every list page is usable on\n * mobile with zero page-level changes.\n */\n\nimport { useId, useMemo, useState, type KeyboardEvent, type ReactNode } from 'react';\nimport { ChevronUp, ChevronDown, ChevronsUpDown, ChevronRight } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\nexport interface Column<T> {\n key: string;\n header: ReactNode;\n render: (row: T) => ReactNode;\n align?: 'left' | 'right' | 'center';\n className?: string;\n /** Hide below the `md` breakpoint for a mobile-friendly layout. */\n hideOnMobile?: boolean;\n /** Provide to make this column click-sortable (returns a comparable value). */\n sortValue?: (row: T) => string | number;\n}\n\ninterface DataTableProps<T> {\n columns: Column<T>[];\n rows: T[];\n rowKey: (row: T) => string;\n onRowClick?: (row: T) => void;\n /** Accessible label for a clickable row (e.g. `(a) => `Open ${a.name}``). */\n rowLabel?: (row: T) => string;\n className?: string;\n /** Default sort: a column key + direction. */\n defaultSort?: { key: string; dir: 'asc' | 'desc' };\n}\n\n/** Enter/Space activate — only when the event originates on the element itself\n * (not on an interactive descendant like a Select or Button inside a cell). */\nconst activateOnKey = (e: KeyboardEvent, fn: () => void) => {\n if (e.target !== e.currentTarget) return;\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n fn();\n }\n};\n\nconst alignClass = {\n left: 'text-left',\n right: 'text-right',\n center: 'text-center',\n} as const;\n\ntype Sort = { key: string; dir: 'asc' | 'desc' };\n\nexport function DataTable<T>({\n columns,\n rows,\n rowKey,\n onRowClick,\n rowLabel,\n className,\n defaultSort,\n}: DataTableProps<T>) {\n const [sort, setSort] = useState<Sort | null>(defaultSort ?? null);\n const sortSelectId = useId();\n\n const sortedRows = useMemo(() => {\n if (!sort) return rows;\n const col = columns.find((c) => c.key === sort.key);\n if (!col?.sortValue) return rows;\n const dir = sort.dir === 'asc' ? 1 : -1;\n return [...rows].sort((a, b) => {\n const va = col.sortValue!(a);\n const vb = col.sortValue!(b);\n if (va < vb) return -1 * dir;\n if (va > vb) return 1 * dir;\n return 0;\n });\n }, [rows, sort, columns]);\n\n const toggleSort = (key: string) => {\n setSort((prev) =>\n prev?.key === key ? { key, dir: prev.dir === 'asc' ? 'desc' : 'asc' } : { key, dir: 'asc' }\n );\n };\n\n const flipDir = () =>\n setSort((prev) => (prev ? { key: prev.key, dir: prev.dir === 'asc' ? 'desc' : 'asc' } : prev));\n\n const sortableColumns = useMemo(() => columns.filter((c) => c.sortValue), [columns]);\n\n const rowInteractive = (row: T) =>\n onRowClick\n ? {\n role: 'button' as const,\n tabIndex: 0,\n 'aria-label': rowLabel?.(row),\n onClick: () => onRowClick(row),\n onKeyDown: (e: KeyboardEvent) => activateOnKey(e, () => onRowClick(row)),\n }\n : {};\n\n const [headCol, ...restCols] = columns;\n\n return (\n <div className={className}>\n {/* ── md and up: full table ─────────────────────────────────────── */}\n <GlassCard treatment=\"plain\" className=\"hidden overflow-hidden md:block\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam\">\n {columns.map((col) => {\n const sortable = Boolean(col.sortValue);\n const active = sort?.key === col.key;\n return (\n <th\n key={col.key}\n scope=\"col\"\n role={sortable ? 'button' : undefined}\n tabIndex={sortable ? 0 : undefined}\n onClick={sortable ? () => toggleSort(col.key) : undefined}\n onKeyDown={\n sortable ? (e) => activateOnKey(e, () => toggleSort(col.key)) : undefined\n }\n aria-sort={\n active ? (sort?.dir === 'asc' ? 'ascending' : 'descending') : undefined\n }\n className={cn(\n 'px-4 py-3 font-medium text-text-secondary whitespace-nowrap',\n alignClass[col.align ?? 'left'],\n col.hideOnMobile && 'hidden md:table-cell',\n sortable &&\n 'cursor-pointer select-none hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]'\n )}\n >\n <span\n className={cn(\n 'inline-flex items-center gap-1',\n col.align === 'right' && 'flex-row-reverse'\n )}\n >\n {col.header}\n {sortable &&\n (active ? (\n sort?.dir === 'asc' ? (\n <ChevronUp className=\"h-3.5 w-3.5 text-action-primary-bg\" />\n ) : (\n <ChevronDown className=\"h-3.5 w-3.5 text-action-primary-bg\" />\n )\n ) : (\n <ChevronsUpDown className=\"h-3.5 w-3.5 opacity-40\" />\n ))}\n </span>\n </th>\n );\n })}\n </tr>\n </thead>\n <tbody>\n {sortedRows.map((row) => (\n <tr\n key={rowKey(row)}\n {...rowInteractive(row)}\n className={cn(\n 'group border-b border-border-seam/60 last:border-0',\n onRowClick &&\n 'cursor-pointer transition-colors hover:bg-bg-sunken/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--color-focus-ring)]'\n )}\n >\n {columns.map((col) => (\n <td\n key={col.key}\n className={cn(\n 'px-4 py-3 text-text-primary align-middle',\n alignClass[col.align ?? 'left'],\n col.hideOnMobile && 'hidden md:table-cell',\n col.className\n )}\n >\n {col.render(row)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </GlassCard>\n\n {/* ── below md: stacked cards ───────────────────────────────────── */}\n <div className=\"space-y-2.5 md:hidden\">\n {sortableColumns.length > 0 && (\n <div className=\"flex items-center justify-end gap-1.5 px-0.5\">\n <label htmlFor={sortSelectId} className=\"text-xs text-text-tertiary\">\n Sort\n </label>\n <select\n id={sortSelectId}\n value={sort?.key ?? ''}\n onChange={(e) =>\n setSort(e.target.value ? { key: e.target.value, dir: sort?.dir ?? 'asc' } : null)\n }\n className=\"rounded-md border border-border-subtle bg-bg-surface px-2 py-1 text-xs text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">Default order</option>\n {sortableColumns.map((col) => (\n <option key={col.key} value={col.key}>\n {typeof col.header === 'string' ? col.header : col.key}\n </option>\n ))}\n </select>\n {sort && (\n <button\n type=\"button\"\n onClick={flipDir}\n aria-label={sort.dir === 'asc' ? 'Sort ascending' : 'Sort descending'}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded-md border border-border-subtle bg-bg-surface text-text-secondary transition-colors hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n {sort.dir === 'asc' ? (\n <ChevronUp className=\"h-4 w-4\" />\n ) : (\n <ChevronDown className=\"h-4 w-4\" />\n )}\n </button>\n )}\n </div>\n )}\n\n {sortedRows.map((row) => (\n <div\n key={rowKey(row)}\n {...rowInteractive(row)}\n className={cn(\n 'rounded-xl border border-border-subtle bg-bg-surface p-4',\n onRowClick &&\n 'cursor-pointer transition-colors hover:bg-bg-sunken/40 active:bg-bg-sunken/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]'\n )}\n >\n {headCol && (\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1\">{headCol.render(row)}</div>\n {onRowClick && (\n <ChevronRight\n className=\"mt-0.5 h-4 w-4 shrink-0 text-text-tertiary\"\n aria-hidden\n />\n )}\n </div>\n )}\n {restCols.length > 0 && (\n <dl className=\"mt-3 grid grid-cols-2 gap-x-4 gap-y-2.5 border-t border-border-subtle/70 pt-3\">\n {restCols.map((col) => (\n <div key={col.key} className=\"min-w-0\">\n <dt className=\"text-[11px] uppercase tracking-wide text-text-tertiary\">\n {col.header}\n </dt>\n <dd className=\"mt-0.5 text-sm text-text-primary break-words\">\n {col.render(row)}\n </dd>\n </div>\n ))}\n </dl>\n )}\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DataTable.js","names":[],"sources":["../../../src/theglobalfuel/components/DataTable.tsx"],"sourcesContent":["/**\n * DataTable — a lightweight, semantic-token table for list pages.\n * @module theglobalfuel/components\n *\n * Deliberately minimal (no external table lib). Columns declare a header, a\n * render fn, optional alignment, and optionally a `sortValue` to make the column\n * click-sortable.\n *\n * Responsive strategy:\n * - At `md` and up it renders a horizontally-scrollable table wrapped in a\n * GlassCard (the classic desktop layout).\n * - Below `md` it renders each row as a native-feeling, stacked \"card\": the\n * first column becomes the card's headline (with a chevron affordance when\n * the row is clickable) and the remaining columns render as label→value\n * pairs. Sort + click behavior carry over, so every list page is usable on\n * mobile with zero page-level changes.\n */\n\nimport { useId, useMemo, useState, type KeyboardEvent, type ReactNode } from 'react';\nimport { ChevronUp, ChevronDown, ChevronsUpDown, ChevronRight } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\nexport interface Column<T> {\n key: string;\n header: ReactNode;\n render: (row: T) => ReactNode;\n align?: 'left' | 'right' | 'center';\n className?: string;\n /** Hide below the `md` breakpoint for a mobile-friendly layout. */\n hideOnMobile?: boolean;\n /** Provide to make this column click-sortable (returns a comparable value). */\n sortValue?: (row: T) => string | number;\n}\n\ninterface DataTableProps<T> {\n columns: Column<T>[];\n rows: T[];\n rowKey: (row: T) => string;\n onRowClick?: (row: T) => void;\n /** Accessible label for a clickable row (e.g. `(a) => `Open ${a.name}``). */\n rowLabel?: (row: T) => string;\n className?: string;\n /** Default sort: a column key + direction. */\n defaultSort?: { key: string; dir: 'asc' | 'desc' };\n}\n\n/** Enter/Space activate — only when the event originates on the element itself\n * (not on an interactive descendant like a Select or Button inside a cell). */\nconst activateOnKey = (e: KeyboardEvent, fn: () => void) => {\n if (e.target !== e.currentTarget) return;\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n fn();\n }\n};\n\nconst alignClass = {\n left: 'text-left',\n right: 'text-right',\n center: 'text-center',\n} as const;\n\ntype Sort = { key: string; dir: 'asc' | 'desc' };\n\nexport function DataTable<T>({\n columns,\n rows,\n rowKey,\n onRowClick,\n rowLabel,\n className,\n defaultSort,\n}: DataTableProps<T>) {\n const [sort, setSort] = useState<Sort | null>(defaultSort ?? null);\n const sortSelectId = useId();\n\n const sortedRows = useMemo(() => {\n if (!sort) return rows;\n const col = columns.find((c) => c.key === sort.key);\n if (!col?.sortValue) return rows;\n const dir = sort.dir === 'asc' ? 1 : -1;\n return [...rows].sort((a, b) => {\n const va = col.sortValue!(a);\n const vb = col.sortValue!(b);\n if (va < vb) return -1 * dir;\n if (va > vb) return 1 * dir;\n return 0;\n });\n }, [rows, sort, columns]);\n\n const toggleSort = (key: string) => {\n setSort((prev) =>\n prev?.key === key ? { key, dir: prev.dir === 'asc' ? 'desc' : 'asc' } : { key, dir: 'asc' }\n );\n };\n\n const flipDir = () =>\n setSort((prev) => (prev ? { key: prev.key, dir: prev.dir === 'asc' ? 'desc' : 'asc' } : prev));\n\n const sortableColumns = useMemo(() => columns.filter((c) => c.sortValue), [columns]);\n\n const rowInteractive = (row: T) =>\n onRowClick\n ? {\n role: 'button' as const,\n tabIndex: 0,\n 'aria-label': rowLabel?.(row),\n onClick: () => onRowClick(row),\n onKeyDown: (e: KeyboardEvent) => activateOnKey(e, () => onRowClick(row)),\n }\n : {};\n\n const [headCol, ...restCols] = columns;\n\n return (\n <div className={className}>\n {/* ── md and up: full table ─────────────────────────────────────── */}\n <GlassCard treatment=\"plain\" className=\"hidden overflow-hidden md:block\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam\">\n {columns.map((col) => {\n const sortable = Boolean(col.sortValue);\n const active = sort?.key === col.key;\n return (\n <th\n key={col.key}\n scope=\"col\"\n role={sortable ? 'button' : undefined}\n tabIndex={sortable ? 0 : undefined}\n onClick={sortable ? () => toggleSort(col.key) : undefined}\n onKeyDown={\n sortable ? (e) => activateOnKey(e, () => toggleSort(col.key)) : undefined\n }\n aria-sort={\n active ? (sort?.dir === 'asc' ? 'ascending' : 'descending') : undefined\n }\n className={cn(\n 'px-4 py-3 font-medium text-text-secondary whitespace-nowrap',\n alignClass[col.align ?? 'left'],\n col.hideOnMobile && 'hidden md:table-cell',\n col.className,\n sortable &&\n 'cursor-pointer select-none hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]'\n )}\n >\n <span\n className={cn(\n 'inline-flex items-center gap-1',\n col.align === 'right' && 'flex-row-reverse'\n )}\n >\n {col.header}\n {sortable &&\n (active ? (\n sort?.dir === 'asc' ? (\n <ChevronUp className=\"h-3.5 w-3.5 text-action-primary-bg\" />\n ) : (\n <ChevronDown className=\"h-3.5 w-3.5 text-action-primary-bg\" />\n )\n ) : (\n <ChevronsUpDown className=\"h-3.5 w-3.5 opacity-40\" />\n ))}\n </span>\n </th>\n );\n })}\n </tr>\n </thead>\n <tbody>\n {sortedRows.map((row) => (\n <tr\n key={rowKey(row)}\n {...rowInteractive(row)}\n className={cn(\n 'group border-b border-border-seam/60 last:border-0',\n onRowClick &&\n 'cursor-pointer transition-colors hover:bg-bg-sunken/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--color-focus-ring)]'\n )}\n >\n {columns.map((col) => (\n <td\n key={col.key}\n className={cn(\n 'px-4 py-3 text-text-primary align-middle',\n alignClass[col.align ?? 'left'],\n col.hideOnMobile && 'hidden md:table-cell',\n col.className\n )}\n >\n {col.render(row)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </GlassCard>\n\n {/* ── below md: stacked cards ───────────────────────────────────── */}\n <div className=\"space-y-2.5 md:hidden\">\n {sortableColumns.length > 0 && (\n <div className=\"flex items-center justify-end gap-1.5 px-0.5\">\n <label htmlFor={sortSelectId} className=\"text-xs text-text-tertiary\">\n Sort\n </label>\n <select\n id={sortSelectId}\n value={sort?.key ?? ''}\n onChange={(e) =>\n setSort(e.target.value ? { key: e.target.value, dir: sort?.dir ?? 'asc' } : null)\n }\n className=\"rounded-md border border-border-subtle bg-bg-surface px-2 py-1 text-xs text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">Default order</option>\n {sortableColumns.map((col) => (\n <option key={col.key} value={col.key}>\n {typeof col.header === 'string' ? col.header : col.key}\n </option>\n ))}\n </select>\n {sort && (\n <button\n type=\"button\"\n onClick={flipDir}\n aria-label={sort.dir === 'asc' ? 'Sort ascending' : 'Sort descending'}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded-md border border-border-subtle bg-bg-surface text-text-secondary transition-colors hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n {sort.dir === 'asc' ? (\n <ChevronUp className=\"h-4 w-4\" />\n ) : (\n <ChevronDown className=\"h-4 w-4\" />\n )}\n </button>\n )}\n </div>\n )}\n\n {sortedRows.map((row) => (\n <div\n key={rowKey(row)}\n {...rowInteractive(row)}\n className={cn(\n 'rounded-xl border border-border-subtle bg-bg-surface p-4',\n onRowClick &&\n 'cursor-pointer transition-colors hover:bg-bg-sunken/40 active:bg-bg-sunken/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]'\n )}\n >\n {headCol && (\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1\">{headCol.render(row)}</div>\n {onRowClick && (\n <ChevronRight\n className=\"mt-0.5 h-4 w-4 shrink-0 text-text-tertiary\"\n aria-hidden\n />\n )}\n </div>\n )}\n {restCols.length > 0 && (\n <dl className=\"mt-3 grid grid-cols-2 gap-x-4 gap-y-2.5 border-t border-border-subtle/70 pt-3\">\n {restCols.map((col) => (\n <div key={col.key} className=\"min-w-0\">\n <dt className=\"text-[11px] uppercase tracking-wide text-text-tertiary\">\n {col.header}\n </dt>\n <dd className=\"mt-0.5 text-sm text-text-primary break-words\">\n {col.render(row)}\n </dd>\n </div>\n ))}\n </dl>\n )}\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -14,7 +14,7 @@ function r({ options: r, value: i, onChange: a, className: o }) {
14
14
  onClick: () => a(r.value),
15
15
  className: e("rounded-lg px-3 py-1.5 text-sm font-medium transition-colors", o ? "bg-action-primary-bg text-action-primary-text" : "text-text-secondary hover:bg-bg-sunken hover:text-text-primary"),
16
16
  children: [r.label, typeof r.count == "number" && /* @__PURE__ */ t("span", {
17
- className: e("ml-1.5 rounded-full px-1.5 py-0.5 text-xs tabular-nums", o ? "bg-black/10 dark:bg-white/15" : "bg-bg-sunken"),
17
+ className: e("ml-1.5 rounded-full px-1.5 py-0.5 text-xs tabular-nums", o ? "bg-bg-overlay" : "bg-bg-sunken"),
18
18
  children: r.count
19
19
  })]
20
20
  }, r.value);
@@ -1 +1 @@
1
- {"version":3,"file":"FilterTabs.js","names":[],"sources":["../../../src/theglobalfuel/components/FilterTabs.tsx"],"sourcesContent":["/**\n * FilterTabs — a segmented status/enum filter control.\n * @module theglobalfuel/components\n */\n\nimport { cn } from '../utils/cn';\n\nexport interface FilterOption<V extends string> {\n value: V;\n label: string;\n count?: number;\n}\n\ninterface FilterTabsProps<V extends string> {\n options: FilterOption<V>[];\n value: V;\n onChange: (value: V) => void;\n className?: string;\n}\n\nexport function FilterTabs<V extends string>({\n options,\n value,\n onChange,\n className,\n}: FilterTabsProps<V>) {\n return (\n <div\n role=\"tablist\"\n className={cn(\n 'inline-flex flex-wrap items-center gap-1 rounded-xl border border-border-seam bg-bg-surface p-1',\n className\n )}\n >\n {options.map((opt) => {\n const active = opt.value === value;\n return (\n <button\n key={opt.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n onClick={() => onChange(opt.value)}\n className={cn(\n 'rounded-lg px-3 py-1.5 text-sm font-medium transition-colors',\n active\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n {opt.label}\n {typeof opt.count === 'number' && (\n <span\n className={cn(\n 'ml-1.5 rounded-full px-1.5 py-0.5 text-xs tabular-nums',\n active ? 'bg-black/10 dark:bg-white/15' : 'bg-bg-sunken'\n )}\n >\n {opt.count}\n </span>\n )}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;AAoBA,SAAgB,EAA6B,EAC3C,YACA,UACA,aACA,gBACqB;AACrB,QACE,kBAAC,OAAD;EACE,MAAK;EACL,WAAW,EACT,mGACA,EACD;YAEA,EAAQ,KAAK,MAAQ;GACpB,IAAM,IAAS,EAAI,UAAU;AAC7B,UACE,kBAAC,UAAD;IAEE,MAAK;IACL,MAAK;IACL,iBAAe;IACf,eAAe,EAAS,EAAI,MAAM;IAClC,WAAW,EACT,gEACA,IACI,kDACA,iEACL;cAXH,CAaG,EAAI,OACJ,OAAO,EAAI,SAAU,YACpB,kBAAC,QAAD;KACE,WAAW,EACT,0DACA,IAAS,iCAAiC,eAC3C;eAEA,EAAI;KACA,CAAA,CAEF;MAvBF,EAAI,MAuBF;IAEX;EACE,CAAA"}
1
+ {"version":3,"file":"FilterTabs.js","names":[],"sources":["../../../src/theglobalfuel/components/FilterTabs.tsx"],"sourcesContent":["/**\n * FilterTabs — a segmented status/enum filter control.\n * @module theglobalfuel/components\n */\n\nimport { cn } from '../utils/cn';\n\nexport interface FilterOption<V extends string> {\n value: V;\n label: string;\n count?: number;\n}\n\ninterface FilterTabsProps<V extends string> {\n options: FilterOption<V>[];\n value: V;\n onChange: (value: V) => void;\n className?: string;\n}\n\nexport function FilterTabs<V extends string>({\n options,\n value,\n onChange,\n className,\n}: FilterTabsProps<V>) {\n return (\n <div\n role=\"tablist\"\n className={cn(\n 'inline-flex flex-wrap items-center gap-1 rounded-xl border border-border-seam bg-bg-surface p-1',\n className\n )}\n >\n {options.map((opt) => {\n const active = opt.value === value;\n return (\n <button\n key={opt.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n onClick={() => onChange(opt.value)}\n className={cn(\n 'rounded-lg px-3 py-1.5 text-sm font-medium transition-colors',\n active\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n {opt.label}\n {typeof opt.count === 'number' && (\n <span\n className={cn(\n 'ml-1.5 rounded-full px-1.5 py-0.5 text-xs tabular-nums',\n active ? 'bg-bg-overlay' : 'bg-bg-sunken'\n )}\n >\n {opt.count}\n </span>\n )}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;AAoBA,SAAgB,EAA6B,EAC3C,YACA,UACA,aACA,gBACqB;AACrB,QACE,kBAAC,OAAD;EACE,MAAK;EACL,WAAW,EACT,mGACA,EACD;YAEA,EAAQ,KAAK,MAAQ;GACpB,IAAM,IAAS,EAAI,UAAU;AAC7B,UACE,kBAAC,UAAD;IAEE,MAAK;IACL,MAAK;IACL,iBAAe;IACf,eAAe,EAAS,EAAI,MAAM;IAClC,WAAW,EACT,gEACA,IACI,kDACA,iEACL;cAXH,CAaG,EAAI,OACJ,OAAO,EAAI,SAAU,YACpB,kBAAC,QAAD;KACE,WAAW,EACT,0DACA,IAAS,kBAAkB,eAC5B;eAEA,EAAI;KACA,CAAA,CAEF;MAvBF,EAAI,MAuBF;IAEX;EACE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"ContractsPage.d.ts","sourceRoot":"","sources":["../../../../src/theglobalfuel/pages/contracts/ContractsPage.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2HH,wBAAgB,aAAa,gCAue5B"}
1
+ {"version":3,"file":"ContractsPage.d.ts","sourceRoot":"","sources":["../../../../src/theglobalfuel/pages/contracts/ContractsPage.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2HH,wBAAgB,aAAa,gCA4e5B"}
@@ -113,6 +113,7 @@ function R() {
113
113
  {
114
114
  key: "reference",
115
115
  header: "Contract",
116
+ className: "min-w-[16rem]",
116
117
  render: (e) => /* @__PURE__ */ v("div", {
117
118
  className: "flex items-center gap-3",
118
119
  children: [/* @__PURE__ */ _("div", {
@@ -122,9 +123,11 @@ function R() {
122
123
  className: "min-w-0",
123
124
  children: [/* @__PURE__ */ _("p", {
124
125
  className: "truncate font-semibold text-text-primary",
126
+ title: e.reference,
125
127
  children: e.reference
126
128
  }), /* @__PURE__ */ _("p", {
127
129
  className: "truncate text-xs text-text-tertiary",
130
+ title: e.counterparty,
128
131
  children: e.counterparty
129
132
  })]
130
133
  })]
@@ -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 {\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-action-primary-bg\">\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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"}
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 className: 'min-w-[16rem]',\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-action-primary-bg\">\n <FileSignature className=\"h-4 w-4\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate font-semibold text-text-primary\" title={c.reference}>\n {c.reference}\n </p>\n <p className=\"truncate text-xs text-text-tertiary\" title={c.counterparty}>\n {c.counterparty}\n </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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ShipmentsPage.d.ts","sourceRoot":"","sources":["../../../../src/theglobalfuel/pages/shipments/ShipmentsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA+KH,wBAAgB,aAAa,gCAwrB5B"}
1
+ {"version":3,"file":"ShipmentsPage.d.ts","sourceRoot":"","sources":["../../../../src/theglobalfuel/pages/shipments/ShipmentsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA+KH,wBAAgB,aAAa,gCAqsB5B"}
@@ -179,10 +179,12 @@ function T() {
179
179
  {
180
180
  key: "reference",
181
181
  header: "Shipment",
182
+ className: "min-w-[14rem]",
182
183
  render: (e) => /* @__PURE__ */ m("div", {
183
184
  className: "min-w-0",
184
185
  children: [/* @__PURE__ */ p("p", {
185
186
  className: "truncate font-semibold text-text-primary",
187
+ title: e.reference,
186
188
  children: e.reference
187
189
  }), /* @__PURE__ */ p("p", {
188
190
  className: "truncate text-xs text-text-tertiary md:hidden",
@@ -194,15 +196,18 @@ function T() {
194
196
  key: "contract",
195
197
  header: "Contract",
196
198
  hideOnMobile: !0,
199
+ className: "min-w-[16rem]",
197
200
  render: (e) => {
198
201
  let t = W.get(e.contractId);
199
202
  return t ? /* @__PURE__ */ m("div", {
200
203
  className: "min-w-0",
201
204
  children: [/* @__PURE__ */ p("p", {
202
205
  className: "truncate font-medium text-text-primary",
206
+ title: t.reference,
203
207
  children: t.reference
204
208
  }), /* @__PURE__ */ p("p", {
205
209
  className: "truncate text-xs text-text-tertiary",
210
+ title: t.counterparty,
206
211
  children: t.counterparty
207
212
  })]
208
213
  }) : /* @__PURE__ */ p("span", {
@@ -241,6 +246,7 @@ function T() {
241
246
  key: "route",
242
247
  header: "Route",
243
248
  hideOnMobile: !0,
249
+ className: "min-w-[16rem]",
244
250
  render: (e) => {
245
251
  let t = e.origin?.trim(), n = e.destination?.trim();
246
252
  return !t && !n ? /* @__PURE__ */ p("span", {
@@ -251,11 +257,13 @@ function T() {
251
257
  children: [
252
258
  /* @__PURE__ */ p("span", {
253
259
  className: "truncate",
260
+ title: t ?? void 0,
254
261
  children: t ?? "—"
255
262
  }),
256
263
  /* @__PURE__ */ p(Se, { className: "h-3.5 w-3.5 shrink-0 text-text-tertiary" }),
257
264
  /* @__PURE__ */ p("span", {
258
265
  className: "truncate",
266
+ title: n ?? void 0,
259
267
  children: n ?? "—"
260
268
  })
261
269
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"ShipmentsPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/shipments/ShipmentsPage.tsx"],"sourcesContent":["/**\n * Shipments — schedule and track cargo movements against offtake contracts.\n * @module theglobalfuel/pages/shipments\n *\n * Reads `theListShipments` (a cursor connection — `{ items, pageInfo }`, filtered\n * by contract + status) and `theListContracts` (to resolve contract references +\n * populate the picker); writes `theScheduleShipment`, `theDeliverShipment` and\n * lifecycle transitions via `theTransitionShipment`.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, Ship, CalendarClock, Truck, PackageCheck, ArrowRight, MapPin } 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 { FileLink } from '../../components/FileLink';\nimport { EvidenceUpload } from '../../components/EvidenceUpload';\nimport { Pagination } from '../../components/Pagination';\nimport { AllocationBar, PathSteps, type PathStep, type Segment } from '../../components';\nimport {\n useNotify,\n useTheShipments,\n useTheContracts,\n useTheScheduleShipment,\n useTheDeliverShipment,\n useTheTransitionShipment,\n useCursorPager,\n type UploadedTheFile,\n useThePageView,\n useTheTranslation,\n} from '../../hooks';\nimport { formatEnumLabel, formatDate, formatVolume } from '../../utils/formatters';\nimport {\n toBackendDate,\n SHIPMENT_TRANSITIONS,\n SHIPMENT_DELIVERABLE_FROM,\n nextStatuses,\n} from '../../utils';\nimport type {\n TheShipment,\n TheShipmentStatus,\n TheTransportMode,\n TheUnit,\n TheOfftakeContract,\n} from '../../types';\n\nconst STATUS_FILTERS: Array<{ value: TheShipmentStatus | 'ALL'; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'SCHEDULED', label: 'Scheduled' },\n { value: 'LOADING', label: 'Loading' },\n { value: 'IN_TRANSIT', label: 'In transit' },\n { value: 'DELIVERED', label: 'Delivered' },\n { value: 'CANCELLED', label: 'Cancelled' },\n];\n\nconst TRANSPORT_MODES: TheTransportMode[] = [\n 'PIPELINE',\n 'TANKER',\n 'VESSEL_BULK',\n 'RAIL',\n 'TRUCK',\n 'GRID',\n];\n\nconst UNITS: TheUnit[] = ['BARRELS', 'CUBIC_METERS', 'TONNES', 'KILOGRAMS', 'MWH', 'GJ', 'MCF'];\n\nconst PAGE_SIZE = 25;\n\n/** Lifecycle order for the status-distribution bar + legend. */\nconst STATUS_ORDER: TheShipmentStatus[] = [\n 'SCHEDULED',\n 'LOADING',\n 'IN_TRANSIT',\n 'DELIVERED',\n 'CANCELLED',\n];\n\nconst STATUS_LABEL: Record<TheShipmentStatus, string> = {\n SCHEDULED: 'Scheduled',\n LOADING: 'Loading',\n IN_TRANSIT: 'In transit',\n DELIVERED: 'Delivered',\n CANCELLED: 'Cancelled',\n};\n\n/**\n * Tokenized AllocationBar color per shipment status — aligned to the StatusBadge\n * palette (neutral → info → warning → success → danger). All are semantic CSS\n * variables so the bar themes automatically.\n */\nconst STATUS_SEGMENT_COLOR: Record<TheShipmentStatus, string> = {\n SCHEDULED: 'var(--color-text-muted)',\n LOADING: 'var(--color-accent-blue)',\n IN_TRANSIT: 'var(--color-status-warning-text)',\n DELIVERED: 'var(--color-status-success-text)',\n CANCELLED: 'var(--color-status-error-text)',\n};\n\n/**\n * Build an origin → mode → destination route flow for a shipment, with node\n * states derived from its lifecycle status. Origin/destination are free-text\n * strings — never plotted on a map. Only call with shipments that carry both.\n */\nconst routeSteps = (s: TheShipment): PathStep[] => {\n const cancelled = s.status === 'CANCELLED';\n const delivered = s.status === 'DELIVERED';\n const inTransit = s.status === 'IN_TRANSIT';\n const departed = delivered || inTransit;\n const midMeta = cancelled\n ? 'Cancelled'\n : delivered\n ? 'Delivered'\n : inTransit\n ? 'In transit'\n : formatEnumLabel(s.status);\n return [\n {\n label: (s.origin ?? '').trim(),\n meta: 'Origin',\n state: cancelled ? 'todo' : departed ? 'done' : 'active',\n },\n {\n label: formatEnumLabel(s.mode),\n meta: midMeta,\n state: cancelled ? 'locked' : delivered ? 'done' : inTransit ? 'active' : 'todo',\n },\n {\n label: (s.destination ?? '').trim(),\n meta: 'Destination',\n state: cancelled ? 'locked' : delivered ? 'done' : 'todo',\n },\n ];\n};\n\ninterface ScheduleFormState {\n contractId: string;\n reference: string;\n mode: TheTransportMode;\n carrier: string;\n trackingId: string;\n origin: string;\n destination: string;\n volume: string;\n unit: TheUnit;\n scheduledAt: string;\n notes: string;\n}\n\nconst EMPTY_FORM: ScheduleFormState = {\n contractId: '',\n reference: '',\n mode: 'TANKER',\n carrier: '',\n trackingId: '',\n origin: '',\n destination: '',\n volume: '',\n unit: 'BARRELS',\n scheduledAt: '',\n notes: '',\n};\n\nexport function ShipmentsPage() {\n useThePageView('shipments');\n const t = useTheTranslation();\n const [status, setStatus] = useState<TheShipmentStatus | 'ALL'>('ALL');\n const [contractId, setContractId] = useState<string | 'ALL'>('ALL');\n const pager = useCursorPager();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<ScheduleFormState>(EMPTY_FORM);\n const [doc, setDoc] = useState<UploadedTheFile | null>(null);\n const [formError, setFormError] = useState<string | null>(null);\n // Track the shipment whose transition is in flight so only that row's Select\n // disables (transitionShipment.isPending is shared across all rows).\n const [transitioningId, setTransitioningId] = useState<string | null>(null);\n // The shipment whose route flow is traced in the logistics panel (falls back\n // to the first routeable shipment when unset or no longer present).\n const [tracedId, setTracedId] = useState<string | null>(null);\n\n const notify = useNotify();\n\n const scopedContractId = contractId === 'ALL' ? undefined : contractId;\n\n // Table query — respects both the contract scope and the status filter, and is\n // cursor-paginated to PAGE_SIZE.\n const { data, isLoading, isError, refetch } = useTheShipments(\n scopedContractId,\n status === 'ALL' ? undefined : status,\n { limit: PAGE_SIZE, offset: pager.page * PAGE_SIZE }\n );\n // Metrics query — same contract scope but ignores the status filter so the\n // header counts stay stable as the table is narrowed. A broad limit keeps the\n // KPI status mix representative (the table itself is paginated to PAGE_SIZE).\n const metricsQuery = useTheShipments(scopedContractId, undefined, { limit: 200 });\n\n // Contracts drive the picker + let us resolve a shipment's contract reference.\n const contractsQuery = useTheContracts({ pagination: { limit: 100 } });\n const contractItems = useMemo(() => contractsQuery.data?.items ?? [], [contractsQuery.data]);\n const contractMap = useMemo(() => {\n const map = new Map<string, TheOfftakeContract>();\n for (const c of contractItems) map.set(c.id, c);\n return map;\n }, [contractItems]);\n\n const scheduleShipment = useTheScheduleShipment();\n const deliverShipment = useTheDeliverShipment();\n const transitionShipment = useTheTransitionShipment();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n const metricsRows = useMemo(() => metricsQuery.data?.items ?? [], [metricsQuery.data]);\n\n // ── Header metrics (derived from the contract-scoped, status-agnostic list) ──\n const scheduledCount = metricsRows.filter((s) => s.status === 'SCHEDULED').length;\n const inTransitCount = metricsRows.filter((s) => s.status === 'IN_TRANSIT').length;\n const deliveredCount = metricsRows.filter((s) => s.status === 'DELIVERED').length;\n\n const statusCounts = useMemo(() => {\n const counts: Record<string, number> = {};\n for (const s of metricsRows) counts[s.status] = (counts[s.status] ?? 0) + 1;\n return counts;\n }, [metricsRows]);\n\n const filterOptions: FilterOption<TheShipmentStatus | 'ALL'>[] = STATUS_FILTERS.map((opt) => ({\n value: opt.value,\n label: opt.label,\n count: opt.value === 'ALL' ? metricsRows.length : (statusCounts[opt.value] ?? 0),\n }));\n\n // ── Logistics viz (derived from the broad, contract-scoped metrics list) ──\n // Status distribution → AllocationBar segments (lifecycle-ordered, tokenized).\n const statusSegments = useMemo<Segment[]>(\n () =>\n STATUS_ORDER.filter((st) => (statusCounts[st] ?? 0) > 0).map((st) => ({\n label: STATUS_LABEL[st],\n value: statusCounts[st] ?? 0,\n color: STATUS_SEGMENT_COLOR[st],\n })),\n [statusCounts]\n );\n\n // Shipments that carry both an origin and a destination can be route-traced.\n const routeableShipments = useMemo(\n () => metricsRows.filter((s) => (s.origin ?? '').trim() && (s.destination ?? '').trim()),\n [metricsRows]\n );\n\n // Distinct origin → destination lanes across the routeable set.\n const distinctLanes = useMemo(() => {\n const lanes = new Set<string>();\n for (const s of routeableShipments) {\n lanes.add(`${(s.origin ?? '').trim()} → ${(s.destination ?? '').trim()}`);\n }\n return lanes.size;\n }, [routeableShipments]);\n\n const tracedShipment = useMemo(\n () => routeableShipments.find((s) => s.id === tracedId) ?? routeableShipments[0] ?? null,\n [routeableShipments, tracedId]\n );\n\n const resetForm = () => {\n setForm(EMPTY_FORM);\n setDoc(null);\n setFormError(null);\n };\n\n const handleSchedule = async () => {\n if (!form.contractId) {\n setFormError('Select the contract this shipment fulfils.');\n return;\n }\n if (!form.reference.trim()) {\n setFormError('A shipment reference is required.');\n return;\n }\n const volume = Number(form.volume);\n if (!form.volume || Number.isNaN(volume) || volume <= 0) {\n setFormError('Enter a volume greater than zero.');\n notify.error('Enter a volume greater than zero.');\n return;\n }\n setFormError(null);\n try {\n await scheduleShipment.mutateAsync({\n contractId: form.contractId,\n reference: form.reference.trim(),\n mode: form.mode,\n carrier: form.carrier.trim() || null,\n trackingId: form.trackingId.trim() || null,\n origin: form.origin.trim() || null,\n destination: form.destination.trim() || null,\n volume,\n unit: form.unit,\n scheduledAt: toBackendDate(form.scheduledAt) ?? null,\n documentFileId: doc?.fileId ?? null,\n notes: form.notes.trim() || null,\n });\n notify.success('Shipment scheduled');\n setDialogOpen(false);\n resetForm();\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to schedule shipment.');\n notify.fromError(err);\n }\n };\n\n const columns: Column<TheShipment>[] = [\n {\n key: 'reference',\n header: 'Shipment',\n render: (s) => (\n <div className=\"min-w-0\">\n <p className=\"truncate font-semibold text-text-primary\">{s.reference}</p>\n <p className=\"truncate text-xs text-text-tertiary md:hidden\">{formatEnumLabel(s.mode)}</p>\n </div>\n ),\n },\n {\n key: 'contract',\n header: 'Contract',\n hideOnMobile: true,\n render: (s) => {\n const contract = contractMap.get(s.contractId);\n return contract ? (\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium text-text-primary\">{contract.reference}</p>\n <p className=\"truncate text-xs text-text-tertiary\">{contract.counterparty}</p>\n </div>\n ) : (\n <span className=\"font-mono text-xs text-text-tertiary\">{s.contractId.slice(0, 8)}</span>\n );\n },\n },\n {\n key: 'mode',\n header: 'Mode',\n hideOnMobile: true,\n render: (s) => <span className=\"text-text-secondary\">{formatEnumLabel(s.mode)}</span>,\n },\n {\n key: 'status',\n header: 'Status',\n render: (s) => <StatusBadge status={s.status} />,\n },\n {\n key: 'trackingId',\n header: 'Tracking ID',\n hideOnMobile: true,\n render: (s) =>\n s.trackingId ? (\n <span className=\"truncate font-mono text-xs text-text-secondary\">{s.trackingId}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'route',\n header: 'Route',\n hideOnMobile: true,\n render: (s) => {\n const origin = s.origin?.trim();\n const destination = s.destination?.trim();\n if (!origin && !destination) return <span className=\"text-text-tertiary\">—</span>;\n return (\n <span className=\"inline-flex items-center gap-1.5 text-text-secondary\">\n <span className=\"truncate\">{origin ?? '—'}</span>\n <ArrowRight className=\"h-3.5 w-3.5 shrink-0 text-text-tertiary\" />\n <span className=\"truncate\">{destination ?? '—'}</span>\n </span>\n );\n },\n },\n {\n key: 'volume',\n header: 'Volume',\n align: 'right',\n sortValue: (s) => s.volume,\n render: (s) => (\n <span className=\"tabular-nums text-text-primary\">{formatVolume(s.volume, s.unit)}</span>\n ),\n },\n {\n key: 'scheduledAt',\n header: 'Scheduled',\n align: 'right',\n hideOnMobile: true,\n sortValue: (s) => s.scheduledAt ?? '',\n render: (s) => <span className=\"text-text-tertiary\">{formatDate(s.scheduledAt)}</span>,\n },\n {\n key: 'document',\n header: 'Document',\n hideOnMobile: true,\n render: (s) =>\n s.document?.id ? (\n <FileLink fileId={s.document.id} />\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'action',\n header: '',\n align: 'right',\n render: (s) => {\n // Lifecycle transitions reachable via theTransitionShipment (SCHEDULED →\n // LOADING → IN_TRANSIT → CANCELLED). DELIVERED is NOT offered here — it is\n // reached through \"Mark delivered\", which additionally rolls volume into\n // the contract. Terminal states (DELIVERED / CANCELLED) expose neither.\n const nexts = nextStatuses(SHIPMENT_TRANSITIONS, s.status);\n const canDeliver = SHIPMENT_DELIVERABLE_FROM.includes(s.status);\n const rowBusy = transitioningId === s.id;\n if (nexts.length === 0 && !canDeliver) {\n return <span className=\"text-text-tertiary\">—</span>;\n }\n return (\n <div className=\"flex items-center justify-end gap-2\">\n {nexts.length > 0 && (\n <Select\n value={s.status}\n disabled={rowBusy}\n onValueChange={(v) => {\n if (v === s.status) return;\n setTransitioningId(s.id);\n transitionShipment.mutate(\n { id: s.id, status: v as TheShipmentStatus },\n {\n onSuccess: () => notify.success('Shipment updated'),\n onError: (e) => notify.fromError(e),\n onSettled: () => setTransitioningId(null),\n }\n );\n }}\n >\n <SelectTrigger\n className=\"h-8 w-36\"\n aria-label={`Change status for shipment ${s.reference}`}\n >\n <SelectValue placeholder={formatEnumLabel(s.status)} />\n </SelectTrigger>\n <SelectContent>\n {nexts.map((st) => (\n <SelectItem key={st} value={st}>\n {formatEnumLabel(st)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n {canDeliver && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled={deliverShipment.isPending || rowBusy}\n onClick={() =>\n deliverShipment.mutate(s.id, {\n onSuccess: () => notify.success('Shipment delivered'),\n onError: (e) => notify.fromError(e),\n })\n }\n >\n <PackageCheck className=\"mr-1.5 h-4 w-4\" /> Mark delivered\n </Button>\n )}\n </div>\n );\n },\n },\n ];\n\n const isFiltered = status !== 'ALL' || contractId !== 'ALL';\n\n return (\n <PageLayout\n title={t('theglobalfuel.pages.shipments.title', 'Shipments')}\n description={t(\n 'theglobalfuel.pages.shipments.description',\n 'Cargo movements delivering offtake contracts — pipelines, tankers, vessels, rail & grid.'\n )}\n dataTour=\"theglobalfuel-shipments-page\"\n actions={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Schedule shipment\n </Button>\n }\n >\n {/* Header metrics — status mix within the current contract scope. */}\n <div className=\"mb-4 grid grid-cols-2 gap-4 lg:grid-cols-4\">\n <MetricsCard\n featured\n icon={<Ship className=\"h-5 w-5\" />}\n value={metricsRows.length}\n label=\"Total shipments\"\n />\n <MetricsCard\n icon={<CalendarClock className=\"h-5 w-5\" />}\n value={scheduledCount}\n label=\"Scheduled\"\n />\n <MetricsCard\n accent=\"warning\"\n icon={<Truck className=\"h-5 w-5\" />}\n value={inTransitCount}\n label=\"In transit\"\n />\n <MetricsCard\n accent=\"success\"\n icon={<PackageCheck className=\"h-5 w-5\" />}\n value={deliveredCount}\n label=\"Delivered\"\n />\n </div>\n\n {/* Logistics — status distribution + per-shipment route flow (broad, contract-scoped). */}\n <div className=\"mb-6 grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <div className=\"flex flex-col gap-4 rounded-[var(--radius-card)] border border-border-subtle bg-bg-surface p-5 shadow-elevation-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <h3 className=\"text-sm font-semibold text-text-secondary\">Status distribution</h3>\n <Ship className=\"h-4 w-4 shrink-0 text-text-muted\" aria-hidden=\"true\" />\n </div>\n {statusSegments.length > 0 ? (\n <AllocationBar\n segments={statusSegments}\n height={14}\n label=\"By status\"\n rightLabel={`${metricsRows.length} shipment${metricsRows.length === 1 ? '' : 's'}`}\n />\n ) : (\n <p className=\"py-6 text-sm text-text-tertiary\">\n No shipments yet — schedule one to see the status mix.\n </p>\n )}\n </div>\n\n <div className=\"flex flex-col gap-3 rounded-[var(--radius-card)] border border-border-subtle bg-bg-surface p-5 shadow-elevation-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <h3 className=\"text-sm font-semibold text-text-secondary\">Route flow</h3>\n <span className=\"inline-flex items-center gap-1.5 text-xs text-text-tertiary\">\n <MapPin className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n {distinctLanes} lane{distinctLanes === 1 ? '' : 's'}\n </span>\n </div>\n {tracedShipment ? (\n <>\n <Select value={tracedShipment.id} onValueChange={setTracedId}>\n <SelectTrigger aria-label=\"Trace a shipment route\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {routeableShipments.map((s) => (\n <SelectItem key={s.id} value={s.id}>\n {s.reference} · {(s.origin ?? '').trim()} → {(s.destination ?? '').trim()}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <PathSteps steps={routeSteps(tracedShipment)} />\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1.5 text-xs text-text-tertiary\">\n <StatusBadge status={tracedShipment.status} />\n <span>{formatEnumLabel(tracedShipment.mode)}</span>\n <span className=\"tabular-nums text-text-secondary\">\n {formatVolume(tracedShipment.volume, tracedShipment.unit)}\n </span>\n {tracedShipment.scheduledAt ? (\n <span className=\"tabular-nums\">\n Sched {formatDate(tracedShipment.scheduledAt)}\n </span>\n ) : null}\n </div>\n </>\n ) : (\n <p className=\"py-6 text-sm text-text-tertiary\">\n Add an origin and destination to a shipment to trace its route.\n </p>\n )}\n </div>\n </div>\n\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <FilterTabs\n options={filterOptions}\n value={status}\n onChange={(v) => {\n setStatus(v);\n pager.reset();\n }}\n />\n <Select\n value={contractId}\n onValueChange={(v) => {\n setContractId(v as string | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-56\" aria-label=\"Filter by contract\">\n <SelectValue placeholder=\"All contracts\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All contracts</SelectItem>\n {contractItems.map((c) => (\n <SelectItem key={c.id} value={c.id}>\n {c.reference} · {c.counterparty}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading shipments…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load shipments.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Ship className=\"h-10 w-10\" />}\n title={isFiltered ? 'No matching shipments' : 'No shipments yet'}\n description={\n isFiltered\n ? 'No shipments match these filters. Try a different status or contract.'\n : 'Schedule your first shipment to start tracking cargo against your offtake contracts.'\n }\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Schedule shipment\n </Button>\n }\n />\n ) : (\n <>\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(s) => s.id}\n defaultSort={{ key: 'scheduledAt', dir: 'desc' }}\n />\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={rows.length}\n hasMore={data?.pageInfo?.hasMore ?? false}\n onPageChange={pager.onPageChange}\n />\n </>\n )}\n\n {/* Schedule shipment dialog */}\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n setDialogOpen(open);\n if (!open) resetForm();\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Schedule shipment</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Book a cargo movement against an offtake contract and track it to delivery.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <form\n onSubmit={(e) => {\n e.preventDefault();\n void handleSchedule();\n }}\n >\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipContract\">Contract *</Label>\n <Select\n value={form.contractId}\n onValueChange={(v) => {\n // Default the unit to the contract's unit for a sensible start.\n const contract = contractMap.get(v);\n setForm((prev) => ({\n ...prev,\n contractId: v,\n unit: contract?.unit ?? prev.unit,\n }));\n }}\n >\n <SelectTrigger id=\"shipContract\">\n <SelectValue placeholder=\"Select a contract\" />\n </SelectTrigger>\n <SelectContent>\n {contractItems.length === 0 ? (\n <SelectItem value=\"none\" disabled>\n No contracts available\n </SelectItem>\n ) : (\n contractItems.map((c) => (\n <SelectItem key={c.id} value={c.id}>\n {c.reference} · {c.counterparty}\n </SelectItem>\n ))\n )}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipRef\">Reference *</Label>\n <Input\n id=\"shipRef\"\n value={form.reference}\n onChange={(e) => setForm({ ...form, reference: e.target.value })}\n placeholder=\"SHP-2026-0142\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipMode\">Mode</Label>\n <Select\n value={form.mode}\n onValueChange={(v) => setForm({ ...form, mode: v as TheTransportMode })}\n >\n <SelectTrigger id=\"shipMode\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TRANSPORT_MODES.map((m) => (\n <SelectItem key={m} value={m}>\n {formatEnumLabel(m)}\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=\"shipOrigin\">Origin</Label>\n <Input\n id=\"shipOrigin\"\n value={form.origin}\n onChange={(e) => setForm({ ...form, origin: e.target.value })}\n placeholder=\"Ras Tanura Terminal\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipDest\">Destination</Label>\n <Input\n id=\"shipDest\"\n value={form.destination}\n onChange={(e) => setForm({ ...form, destination: e.target.value })}\n placeholder=\"Rotterdam\"\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=\"shipVolume\">Volume *</Label>\n <Input\n id=\"shipVolume\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.volume}\n onChange={(e) => setForm({ ...form, volume: e.target.value })}\n placeholder=\"500000\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipUnit\">Unit</Label>\n <Select\n value={form.unit}\n onValueChange={(v) => setForm({ ...form, unit: v as TheUnit })}\n >\n <SelectTrigger id=\"shipUnit\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {UNITS.map((u) => (\n <SelectItem key={u} value={u}>\n {formatEnumLabel(u)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipScheduled\">Scheduled date</Label>\n <Input\n id=\"shipScheduled\"\n type=\"date\"\n value={form.scheduledAt}\n onChange={(e) => setForm({ ...form, scheduledAt: e.target.value })}\n />\n </div>\n </div>\n\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipCarrier\">Carrier</Label>\n <Input\n id=\"shipCarrier\"\n value={form.carrier}\n onChange={(e) => setForm({ ...form, carrier: e.target.value })}\n placeholder=\"Frontline Ltd.\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipTrackingId\">Tracking ID</Label>\n <Input\n id=\"shipTrackingId\"\n value={form.trackingId}\n onChange={(e) => setForm({ ...form, trackingId: e.target.value })}\n placeholder=\"Carrier waybill / B-L number\"\n />\n </div>\n </div>\n\n <EvidenceUpload\n id=\"shipDocument\"\n label=\"Bill of lading (optional)\"\n value={doc}\n onChange={setDoc}\n hint=\"Attach the bill of lading or shipping document (PDF or image).\"\n />\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipNotes\">Notes</Label>\n <Textarea\n id=\"shipNotes\"\n value={form.notes}\n onChange={(e) => setForm({ ...form, notes: e.target.value })}\n placeholder=\"Optional context — laycan window, inspector, terms.\"\n rows={2}\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={scheduleShipment.isPending}>\n {scheduleShipment.isPending ? 'Scheduling…' : 'Schedule shipment'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ShipmentsPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/shipments/ShipmentsPage.tsx"],"sourcesContent":["/**\n * Shipments — schedule and track cargo movements against offtake contracts.\n * @module theglobalfuel/pages/shipments\n *\n * Reads `theListShipments` (a cursor connection — `{ items, pageInfo }`, filtered\n * by contract + status) and `theListContracts` (to resolve contract references +\n * populate the picker); writes `theScheduleShipment`, `theDeliverShipment` and\n * lifecycle transitions via `theTransitionShipment`.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, Ship, CalendarClock, Truck, PackageCheck, ArrowRight, MapPin } 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 { FileLink } from '../../components/FileLink';\nimport { EvidenceUpload } from '../../components/EvidenceUpload';\nimport { Pagination } from '../../components/Pagination';\nimport { AllocationBar, PathSteps, type PathStep, type Segment } from '../../components';\nimport {\n useNotify,\n useTheShipments,\n useTheContracts,\n useTheScheduleShipment,\n useTheDeliverShipment,\n useTheTransitionShipment,\n useCursorPager,\n type UploadedTheFile,\n useThePageView,\n useTheTranslation,\n} from '../../hooks';\nimport { formatEnumLabel, formatDate, formatVolume } from '../../utils/formatters';\nimport {\n toBackendDate,\n SHIPMENT_TRANSITIONS,\n SHIPMENT_DELIVERABLE_FROM,\n nextStatuses,\n} from '../../utils';\nimport type {\n TheShipment,\n TheShipmentStatus,\n TheTransportMode,\n TheUnit,\n TheOfftakeContract,\n} from '../../types';\n\nconst STATUS_FILTERS: Array<{ value: TheShipmentStatus | 'ALL'; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'SCHEDULED', label: 'Scheduled' },\n { value: 'LOADING', label: 'Loading' },\n { value: 'IN_TRANSIT', label: 'In transit' },\n { value: 'DELIVERED', label: 'Delivered' },\n { value: 'CANCELLED', label: 'Cancelled' },\n];\n\nconst TRANSPORT_MODES: TheTransportMode[] = [\n 'PIPELINE',\n 'TANKER',\n 'VESSEL_BULK',\n 'RAIL',\n 'TRUCK',\n 'GRID',\n];\n\nconst UNITS: TheUnit[] = ['BARRELS', 'CUBIC_METERS', 'TONNES', 'KILOGRAMS', 'MWH', 'GJ', 'MCF'];\n\nconst PAGE_SIZE = 25;\n\n/** Lifecycle order for the status-distribution bar + legend. */\nconst STATUS_ORDER: TheShipmentStatus[] = [\n 'SCHEDULED',\n 'LOADING',\n 'IN_TRANSIT',\n 'DELIVERED',\n 'CANCELLED',\n];\n\nconst STATUS_LABEL: Record<TheShipmentStatus, string> = {\n SCHEDULED: 'Scheduled',\n LOADING: 'Loading',\n IN_TRANSIT: 'In transit',\n DELIVERED: 'Delivered',\n CANCELLED: 'Cancelled',\n};\n\n/**\n * Tokenized AllocationBar color per shipment status — aligned to the StatusBadge\n * palette (neutral → info → warning → success → danger). All are semantic CSS\n * variables so the bar themes automatically.\n */\nconst STATUS_SEGMENT_COLOR: Record<TheShipmentStatus, string> = {\n SCHEDULED: 'var(--color-text-muted)',\n LOADING: 'var(--color-accent-blue)',\n IN_TRANSIT: 'var(--color-status-warning-text)',\n DELIVERED: 'var(--color-status-success-text)',\n CANCELLED: 'var(--color-status-error-text)',\n};\n\n/**\n * Build an origin → mode → destination route flow for a shipment, with node\n * states derived from its lifecycle status. Origin/destination are free-text\n * strings — never plotted on a map. Only call with shipments that carry both.\n */\nconst routeSteps = (s: TheShipment): PathStep[] => {\n const cancelled = s.status === 'CANCELLED';\n const delivered = s.status === 'DELIVERED';\n const inTransit = s.status === 'IN_TRANSIT';\n const departed = delivered || inTransit;\n const midMeta = cancelled\n ? 'Cancelled'\n : delivered\n ? 'Delivered'\n : inTransit\n ? 'In transit'\n : formatEnumLabel(s.status);\n return [\n {\n label: (s.origin ?? '').trim(),\n meta: 'Origin',\n state: cancelled ? 'todo' : departed ? 'done' : 'active',\n },\n {\n label: formatEnumLabel(s.mode),\n meta: midMeta,\n state: cancelled ? 'locked' : delivered ? 'done' : inTransit ? 'active' : 'todo',\n },\n {\n label: (s.destination ?? '').trim(),\n meta: 'Destination',\n state: cancelled ? 'locked' : delivered ? 'done' : 'todo',\n },\n ];\n};\n\ninterface ScheduleFormState {\n contractId: string;\n reference: string;\n mode: TheTransportMode;\n carrier: string;\n trackingId: string;\n origin: string;\n destination: string;\n volume: string;\n unit: TheUnit;\n scheduledAt: string;\n notes: string;\n}\n\nconst EMPTY_FORM: ScheduleFormState = {\n contractId: '',\n reference: '',\n mode: 'TANKER',\n carrier: '',\n trackingId: '',\n origin: '',\n destination: '',\n volume: '',\n unit: 'BARRELS',\n scheduledAt: '',\n notes: '',\n};\n\nexport function ShipmentsPage() {\n useThePageView('shipments');\n const t = useTheTranslation();\n const [status, setStatus] = useState<TheShipmentStatus | 'ALL'>('ALL');\n const [contractId, setContractId] = useState<string | 'ALL'>('ALL');\n const pager = useCursorPager();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<ScheduleFormState>(EMPTY_FORM);\n const [doc, setDoc] = useState<UploadedTheFile | null>(null);\n const [formError, setFormError] = useState<string | null>(null);\n // Track the shipment whose transition is in flight so only that row's Select\n // disables (transitionShipment.isPending is shared across all rows).\n const [transitioningId, setTransitioningId] = useState<string | null>(null);\n // The shipment whose route flow is traced in the logistics panel (falls back\n // to the first routeable shipment when unset or no longer present).\n const [tracedId, setTracedId] = useState<string | null>(null);\n\n const notify = useNotify();\n\n const scopedContractId = contractId === 'ALL' ? undefined : contractId;\n\n // Table query — respects both the contract scope and the status filter, and is\n // cursor-paginated to PAGE_SIZE.\n const { data, isLoading, isError, refetch } = useTheShipments(\n scopedContractId,\n status === 'ALL' ? undefined : status,\n { limit: PAGE_SIZE, offset: pager.page * PAGE_SIZE }\n );\n // Metrics query — same contract scope but ignores the status filter so the\n // header counts stay stable as the table is narrowed. A broad limit keeps the\n // KPI status mix representative (the table itself is paginated to PAGE_SIZE).\n const metricsQuery = useTheShipments(scopedContractId, undefined, { limit: 200 });\n\n // Contracts drive the picker + let us resolve a shipment's contract reference.\n const contractsQuery = useTheContracts({ pagination: { limit: 100 } });\n const contractItems = useMemo(() => contractsQuery.data?.items ?? [], [contractsQuery.data]);\n const contractMap = useMemo(() => {\n const map = new Map<string, TheOfftakeContract>();\n for (const c of contractItems) map.set(c.id, c);\n return map;\n }, [contractItems]);\n\n const scheduleShipment = useTheScheduleShipment();\n const deliverShipment = useTheDeliverShipment();\n const transitionShipment = useTheTransitionShipment();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n const metricsRows = useMemo(() => metricsQuery.data?.items ?? [], [metricsQuery.data]);\n\n // ── Header metrics (derived from the contract-scoped, status-agnostic list) ──\n const scheduledCount = metricsRows.filter((s) => s.status === 'SCHEDULED').length;\n const inTransitCount = metricsRows.filter((s) => s.status === 'IN_TRANSIT').length;\n const deliveredCount = metricsRows.filter((s) => s.status === 'DELIVERED').length;\n\n const statusCounts = useMemo(() => {\n const counts: Record<string, number> = {};\n for (const s of metricsRows) counts[s.status] = (counts[s.status] ?? 0) + 1;\n return counts;\n }, [metricsRows]);\n\n const filterOptions: FilterOption<TheShipmentStatus | 'ALL'>[] = STATUS_FILTERS.map((opt) => ({\n value: opt.value,\n label: opt.label,\n count: opt.value === 'ALL' ? metricsRows.length : (statusCounts[opt.value] ?? 0),\n }));\n\n // ── Logistics viz (derived from the broad, contract-scoped metrics list) ──\n // Status distribution → AllocationBar segments (lifecycle-ordered, tokenized).\n const statusSegments = useMemo<Segment[]>(\n () =>\n STATUS_ORDER.filter((st) => (statusCounts[st] ?? 0) > 0).map((st) => ({\n label: STATUS_LABEL[st],\n value: statusCounts[st] ?? 0,\n color: STATUS_SEGMENT_COLOR[st],\n })),\n [statusCounts]\n );\n\n // Shipments that carry both an origin and a destination can be route-traced.\n const routeableShipments = useMemo(\n () => metricsRows.filter((s) => (s.origin ?? '').trim() && (s.destination ?? '').trim()),\n [metricsRows]\n );\n\n // Distinct origin → destination lanes across the routeable set.\n const distinctLanes = useMemo(() => {\n const lanes = new Set<string>();\n for (const s of routeableShipments) {\n lanes.add(`${(s.origin ?? '').trim()} → ${(s.destination ?? '').trim()}`);\n }\n return lanes.size;\n }, [routeableShipments]);\n\n const tracedShipment = useMemo(\n () => routeableShipments.find((s) => s.id === tracedId) ?? routeableShipments[0] ?? null,\n [routeableShipments, tracedId]\n );\n\n const resetForm = () => {\n setForm(EMPTY_FORM);\n setDoc(null);\n setFormError(null);\n };\n\n const handleSchedule = async () => {\n if (!form.contractId) {\n setFormError('Select the contract this shipment fulfils.');\n return;\n }\n if (!form.reference.trim()) {\n setFormError('A shipment reference is required.');\n return;\n }\n const volume = Number(form.volume);\n if (!form.volume || Number.isNaN(volume) || volume <= 0) {\n setFormError('Enter a volume greater than zero.');\n notify.error('Enter a volume greater than zero.');\n return;\n }\n setFormError(null);\n try {\n await scheduleShipment.mutateAsync({\n contractId: form.contractId,\n reference: form.reference.trim(),\n mode: form.mode,\n carrier: form.carrier.trim() || null,\n trackingId: form.trackingId.trim() || null,\n origin: form.origin.trim() || null,\n destination: form.destination.trim() || null,\n volume,\n unit: form.unit,\n scheduledAt: toBackendDate(form.scheduledAt) ?? null,\n documentFileId: doc?.fileId ?? null,\n notes: form.notes.trim() || null,\n });\n notify.success('Shipment scheduled');\n setDialogOpen(false);\n resetForm();\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to schedule shipment.');\n notify.fromError(err);\n }\n };\n\n const columns: Column<TheShipment>[] = [\n {\n key: 'reference',\n header: 'Shipment',\n className: 'min-w-[14rem]',\n render: (s) => (\n <div className=\"min-w-0\">\n <p className=\"truncate font-semibold text-text-primary\" title={s.reference}>\n {s.reference}\n </p>\n <p className=\"truncate text-xs text-text-tertiary md:hidden\">{formatEnumLabel(s.mode)}</p>\n </div>\n ),\n },\n {\n key: 'contract',\n header: 'Contract',\n hideOnMobile: true,\n className: 'min-w-[16rem]',\n render: (s) => {\n const contract = contractMap.get(s.contractId);\n return contract ? (\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium text-text-primary\" title={contract.reference}>\n {contract.reference}\n </p>\n <p className=\"truncate text-xs text-text-tertiary\" title={contract.counterparty}>\n {contract.counterparty}\n </p>\n </div>\n ) : (\n <span className=\"font-mono text-xs text-text-tertiary\">{s.contractId.slice(0, 8)}</span>\n );\n },\n },\n {\n key: 'mode',\n header: 'Mode',\n hideOnMobile: true,\n render: (s) => <span className=\"text-text-secondary\">{formatEnumLabel(s.mode)}</span>,\n },\n {\n key: 'status',\n header: 'Status',\n render: (s) => <StatusBadge status={s.status} />,\n },\n {\n key: 'trackingId',\n header: 'Tracking ID',\n hideOnMobile: true,\n render: (s) =>\n s.trackingId ? (\n <span className=\"truncate font-mono text-xs text-text-secondary\">{s.trackingId}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'route',\n header: 'Route',\n hideOnMobile: true,\n className: 'min-w-[16rem]',\n render: (s) => {\n const origin = s.origin?.trim();\n const destination = s.destination?.trim();\n if (!origin && !destination) return <span className=\"text-text-tertiary\">—</span>;\n return (\n <span className=\"inline-flex items-center gap-1.5 text-text-secondary\">\n <span className=\"truncate\" title={origin ?? undefined}>\n {origin ?? '—'}\n </span>\n <ArrowRight className=\"h-3.5 w-3.5 shrink-0 text-text-tertiary\" />\n <span className=\"truncate\" title={destination ?? undefined}>\n {destination ?? '—'}\n </span>\n </span>\n );\n },\n },\n {\n key: 'volume',\n header: 'Volume',\n align: 'right',\n sortValue: (s) => s.volume,\n render: (s) => (\n <span className=\"tabular-nums text-text-primary\">{formatVolume(s.volume, s.unit)}</span>\n ),\n },\n {\n key: 'scheduledAt',\n header: 'Scheduled',\n align: 'right',\n hideOnMobile: true,\n sortValue: (s) => s.scheduledAt ?? '',\n render: (s) => <span className=\"text-text-tertiary\">{formatDate(s.scheduledAt)}</span>,\n },\n {\n key: 'document',\n header: 'Document',\n hideOnMobile: true,\n render: (s) =>\n s.document?.id ? (\n <FileLink fileId={s.document.id} />\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'action',\n header: '',\n align: 'right',\n render: (s) => {\n // Lifecycle transitions reachable via theTransitionShipment (SCHEDULED →\n // LOADING → IN_TRANSIT → CANCELLED). DELIVERED is NOT offered here — it is\n // reached through \"Mark delivered\", which additionally rolls volume into\n // the contract. Terminal states (DELIVERED / CANCELLED) expose neither.\n const nexts = nextStatuses(SHIPMENT_TRANSITIONS, s.status);\n const canDeliver = SHIPMENT_DELIVERABLE_FROM.includes(s.status);\n const rowBusy = transitioningId === s.id;\n if (nexts.length === 0 && !canDeliver) {\n return <span className=\"text-text-tertiary\">—</span>;\n }\n return (\n <div className=\"flex items-center justify-end gap-2\">\n {nexts.length > 0 && (\n <Select\n value={s.status}\n disabled={rowBusy}\n onValueChange={(v) => {\n if (v === s.status) return;\n setTransitioningId(s.id);\n transitionShipment.mutate(\n { id: s.id, status: v as TheShipmentStatus },\n {\n onSuccess: () => notify.success('Shipment updated'),\n onError: (e) => notify.fromError(e),\n onSettled: () => setTransitioningId(null),\n }\n );\n }}\n >\n <SelectTrigger\n className=\"h-8 w-36\"\n aria-label={`Change status for shipment ${s.reference}`}\n >\n <SelectValue placeholder={formatEnumLabel(s.status)} />\n </SelectTrigger>\n <SelectContent>\n {nexts.map((st) => (\n <SelectItem key={st} value={st}>\n {formatEnumLabel(st)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n {canDeliver && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled={deliverShipment.isPending || rowBusy}\n onClick={() =>\n deliverShipment.mutate(s.id, {\n onSuccess: () => notify.success('Shipment delivered'),\n onError: (e) => notify.fromError(e),\n })\n }\n >\n <PackageCheck className=\"mr-1.5 h-4 w-4\" /> Mark delivered\n </Button>\n )}\n </div>\n );\n },\n },\n ];\n\n const isFiltered = status !== 'ALL' || contractId !== 'ALL';\n\n return (\n <PageLayout\n title={t('theglobalfuel.pages.shipments.title', 'Shipments')}\n description={t(\n 'theglobalfuel.pages.shipments.description',\n 'Cargo movements delivering offtake contracts — pipelines, tankers, vessels, rail & grid.'\n )}\n dataTour=\"theglobalfuel-shipments-page\"\n actions={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Schedule shipment\n </Button>\n }\n >\n {/* Header metrics — status mix within the current contract scope. */}\n <div className=\"mb-4 grid grid-cols-2 gap-4 lg:grid-cols-4\">\n <MetricsCard\n featured\n icon={<Ship className=\"h-5 w-5\" />}\n value={metricsRows.length}\n label=\"Total shipments\"\n />\n <MetricsCard\n icon={<CalendarClock className=\"h-5 w-5\" />}\n value={scheduledCount}\n label=\"Scheduled\"\n />\n <MetricsCard\n accent=\"warning\"\n icon={<Truck className=\"h-5 w-5\" />}\n value={inTransitCount}\n label=\"In transit\"\n />\n <MetricsCard\n accent=\"success\"\n icon={<PackageCheck className=\"h-5 w-5\" />}\n value={deliveredCount}\n label=\"Delivered\"\n />\n </div>\n\n {/* Logistics — status distribution + per-shipment route flow (broad, contract-scoped). */}\n <div className=\"mb-6 grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <div className=\"flex flex-col gap-4 rounded-[var(--radius-card)] border border-border-subtle bg-bg-surface p-5 shadow-elevation-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <h3 className=\"text-sm font-semibold text-text-secondary\">Status distribution</h3>\n <Ship className=\"h-4 w-4 shrink-0 text-text-muted\" aria-hidden=\"true\" />\n </div>\n {statusSegments.length > 0 ? (\n <AllocationBar\n segments={statusSegments}\n height={14}\n label=\"By status\"\n rightLabel={`${metricsRows.length} shipment${metricsRows.length === 1 ? '' : 's'}`}\n />\n ) : (\n <p className=\"py-6 text-sm text-text-tertiary\">\n No shipments yet — schedule one to see the status mix.\n </p>\n )}\n </div>\n\n <div className=\"flex flex-col gap-3 rounded-[var(--radius-card)] border border-border-subtle bg-bg-surface p-5 shadow-elevation-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <h3 className=\"text-sm font-semibold text-text-secondary\">Route flow</h3>\n <span className=\"inline-flex items-center gap-1.5 text-xs text-text-tertiary\">\n <MapPin className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n {distinctLanes} lane{distinctLanes === 1 ? '' : 's'}\n </span>\n </div>\n {tracedShipment ? (\n <>\n <Select value={tracedShipment.id} onValueChange={setTracedId}>\n <SelectTrigger aria-label=\"Trace a shipment route\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {routeableShipments.map((s) => (\n <SelectItem key={s.id} value={s.id}>\n {s.reference} · {(s.origin ?? '').trim()} → {(s.destination ?? '').trim()}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <PathSteps steps={routeSteps(tracedShipment)} />\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1.5 text-xs text-text-tertiary\">\n <StatusBadge status={tracedShipment.status} />\n <span>{formatEnumLabel(tracedShipment.mode)}</span>\n <span className=\"tabular-nums text-text-secondary\">\n {formatVolume(tracedShipment.volume, tracedShipment.unit)}\n </span>\n {tracedShipment.scheduledAt ? (\n <span className=\"tabular-nums\">\n Sched {formatDate(tracedShipment.scheduledAt)}\n </span>\n ) : null}\n </div>\n </>\n ) : (\n <p className=\"py-6 text-sm text-text-tertiary\">\n Add an origin and destination to a shipment to trace its route.\n </p>\n )}\n </div>\n </div>\n\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <FilterTabs\n options={filterOptions}\n value={status}\n onChange={(v) => {\n setStatus(v);\n pager.reset();\n }}\n />\n <Select\n value={contractId}\n onValueChange={(v) => {\n setContractId(v as string | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-56\" aria-label=\"Filter by contract\">\n <SelectValue placeholder=\"All contracts\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All contracts</SelectItem>\n {contractItems.map((c) => (\n <SelectItem key={c.id} value={c.id}>\n {c.reference} · {c.counterparty}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading shipments…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load shipments.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Ship className=\"h-10 w-10\" />}\n title={isFiltered ? 'No matching shipments' : 'No shipments yet'}\n description={\n isFiltered\n ? 'No shipments match these filters. Try a different status or contract.'\n : 'Schedule your first shipment to start tracking cargo against your offtake contracts.'\n }\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Schedule shipment\n </Button>\n }\n />\n ) : (\n <>\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(s) => s.id}\n defaultSort={{ key: 'scheduledAt', dir: 'desc' }}\n />\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={rows.length}\n hasMore={data?.pageInfo?.hasMore ?? false}\n onPageChange={pager.onPageChange}\n />\n </>\n )}\n\n {/* Schedule shipment dialog */}\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n setDialogOpen(open);\n if (!open) resetForm();\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Schedule shipment</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Book a cargo movement against an offtake contract and track it to delivery.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <form\n onSubmit={(e) => {\n e.preventDefault();\n void handleSchedule();\n }}\n >\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipContract\">Contract *</Label>\n <Select\n value={form.contractId}\n onValueChange={(v) => {\n // Default the unit to the contract's unit for a sensible start.\n const contract = contractMap.get(v);\n setForm((prev) => ({\n ...prev,\n contractId: v,\n unit: contract?.unit ?? prev.unit,\n }));\n }}\n >\n <SelectTrigger id=\"shipContract\">\n <SelectValue placeholder=\"Select a contract\" />\n </SelectTrigger>\n <SelectContent>\n {contractItems.length === 0 ? (\n <SelectItem value=\"none\" disabled>\n No contracts available\n </SelectItem>\n ) : (\n contractItems.map((c) => (\n <SelectItem key={c.id} value={c.id}>\n {c.reference} · {c.counterparty}\n </SelectItem>\n ))\n )}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipRef\">Reference *</Label>\n <Input\n id=\"shipRef\"\n value={form.reference}\n onChange={(e) => setForm({ ...form, reference: e.target.value })}\n placeholder=\"SHP-2026-0142\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipMode\">Mode</Label>\n <Select\n value={form.mode}\n onValueChange={(v) => setForm({ ...form, mode: v as TheTransportMode })}\n >\n <SelectTrigger id=\"shipMode\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TRANSPORT_MODES.map((m) => (\n <SelectItem key={m} value={m}>\n {formatEnumLabel(m)}\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=\"shipOrigin\">Origin</Label>\n <Input\n id=\"shipOrigin\"\n value={form.origin}\n onChange={(e) => setForm({ ...form, origin: e.target.value })}\n placeholder=\"Ras Tanura Terminal\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipDest\">Destination</Label>\n <Input\n id=\"shipDest\"\n value={form.destination}\n onChange={(e) => setForm({ ...form, destination: e.target.value })}\n placeholder=\"Rotterdam\"\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=\"shipVolume\">Volume *</Label>\n <Input\n id=\"shipVolume\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={form.volume}\n onChange={(e) => setForm({ ...form, volume: e.target.value })}\n placeholder=\"500000\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipUnit\">Unit</Label>\n <Select\n value={form.unit}\n onValueChange={(v) => setForm({ ...form, unit: v as TheUnit })}\n >\n <SelectTrigger id=\"shipUnit\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {UNITS.map((u) => (\n <SelectItem key={u} value={u}>\n {formatEnumLabel(u)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipScheduled\">Scheduled date</Label>\n <Input\n id=\"shipScheduled\"\n type=\"date\"\n value={form.scheduledAt}\n onChange={(e) => setForm({ ...form, scheduledAt: e.target.value })}\n />\n </div>\n </div>\n\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipCarrier\">Carrier</Label>\n <Input\n id=\"shipCarrier\"\n value={form.carrier}\n onChange={(e) => setForm({ ...form, carrier: e.target.value })}\n placeholder=\"Frontline Ltd.\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipTrackingId\">Tracking ID</Label>\n <Input\n id=\"shipTrackingId\"\n value={form.trackingId}\n onChange={(e) => setForm({ ...form, trackingId: e.target.value })}\n placeholder=\"Carrier waybill / B-L number\"\n />\n </div>\n </div>\n\n <EvidenceUpload\n id=\"shipDocument\"\n label=\"Bill of lading (optional)\"\n value={doc}\n onChange={setDoc}\n hint=\"Attach the bill of lading or shipping document (PDF or image).\"\n />\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"shipNotes\">Notes</Label>\n <Textarea\n id=\"shipNotes\"\n value={form.notes}\n onChange={(e) => setForm({ ...form, notes: e.target.value })}\n placeholder=\"Optional context — laycan window, inspector, terms.\"\n rows={2}\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={scheduleShipment.isPending}>\n {scheduleShipment.isPending ? 'Scheduling…' : 'Schedule shipment'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-theglobalfuel",
3
- "version": "2026.1022.1",
3
+ "version": "2026.1026.2",
4
4
  "description": "Burdenoff TheGlobalFuel Microfrontend — Energy, Mineral & Commodity Resource operating system",
5
5
  "type": "module",
6
6
  "files": [