@burdenoff/microfe-theglobalfuel 2026.804.1 → 2026.804.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.
@@ -0,0 +1,496 @@
1
+ import { cn as e } from "../../utils/cn.js";
2
+ import { PageLayout as t } from "../../components/PageLayout.js";
3
+ import { MetricsCard as n } from "../../components/MetricsCard.js";
4
+ import { formatDate as r, formatDateTime as i, formatEnumLabel as a, formatNumber as o, toBackendDate as s } from "../../utils/formatters.js";
5
+ import { StatusBadge as c } from "../../components/StatusBadge.js";
6
+ import { DataTable as l } from "../../components/DataTable.js";
7
+ import { ErrorView as u, LoadingView as d } from "../../components/StateViews.js";
8
+ import { EmptyState as f } from "../../components/EmptyState.js";
9
+ import { useTheEsgDisclosures as ee, useTheFinalizeEsgDisclosure as te, useTheGenerateEsgDisclosure as ne } from "../../hooks/useTheGlobalFuelApi.js";
10
+ import { useNotify as re } from "../../hooks/useNotify.js";
11
+ import { useThePageView as ie } from "../../hooks/useThePageView.js";
12
+ import { useTheTranslation as ae } from "../../hooks/useTheTranslation.js";
13
+ import "../../hooks/index.js";
14
+ import { toCsv as oe } from "../../utils/csv.js";
15
+ import { downloadTextFile as se } from "../../utils/provenance.js";
16
+ import "../../components/index.js";
17
+ import { useMemo as p, useState as m } from "react";
18
+ import { Cloud as h, Download as g, FileCheck2 as _, Lock as v, Plus as y } from "lucide-react";
19
+ import { Fragment as ce, jsx as b, jsxs as x } from "react/jsx-runtime";
20
+ import { Button as S, GlassCard as C, Input as w, Label as T, ResponsiveDialog as le, ResponsiveDialogContent as ue, ResponsiveDialogDescription as de, ResponsiveDialogFooter as fe, ResponsiveDialogHeader as pe, ResponsiveDialogTitle as me, Select as he, SelectContent as E, SelectItem as D, SelectTrigger as O, SelectValue as k, Textarea as A } from "@burdenoff/fe-libs/ui";
21
+ //#region src/theglobalfuel/pages/esg-disclosures/EsgDisclosuresPage.tsx
22
+ var j = 25, M = [
23
+ "GRI",
24
+ "SASB",
25
+ "CSRD",
26
+ "SEC_CLIMATE",
27
+ "CDP"
28
+ ], N = {
29
+ GRI: "GRI — Global Reporting Initiative",
30
+ SASB: "SASB — Sustainability Accounting Standards Board",
31
+ CSRD: "CSRD — EU Corporate Sustainability Reporting Directive",
32
+ SEC_CLIMATE: "SEC Climate Disclosure",
33
+ CDP: "CDP — Carbon Disclosure Project"
34
+ }, P = () => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), F = () => (/* @__PURE__ */ new Date()).getUTCFullYear(), I = () => ({
35
+ framework: "GRI",
36
+ periodStart: `${F()}-01-01`,
37
+ periodEnd: `${F()}-12-31`,
38
+ notes: ""
39
+ }), L = (e) => {
40
+ try {
41
+ let t = JSON.parse(e);
42
+ return typeof t != "object" || !t ? null : t;
43
+ } catch {
44
+ return null;
45
+ }
46
+ };
47
+ function R() {
48
+ ie("esg-disclosures");
49
+ let F = ae(), R = re(), [ge, z] = m(!1), [B, V] = m(I), [H, U] = m(null), [W, G] = m(null), [K, q] = m(null), { data: J, isLoading: _e, isError: ve, refetch: ye } = ee({ pagination: { limit: j } }), Y = ne(), X = te(), Z = p(() => J?.items ?? [], [J]), Q = p(() => Z.find((e) => e.id === W) ?? Z[0] ?? null, [Z, W]), $ = p(() => Q ? L(Q.datapoints) : null, [Q]), be = async () => {
50
+ let e = s(B.periodStart), t = s(B.periodEnd);
51
+ if (!e || !t) {
52
+ U("Enter a valid reporting period.");
53
+ return;
54
+ }
55
+ if (t < e) {
56
+ U("The reporting period must end after it starts.");
57
+ return;
58
+ }
59
+ U(null);
60
+ try {
61
+ let n = await Y.mutateAsync({
62
+ framework: B.framework,
63
+ periodStart: e,
64
+ periodEnd: t,
65
+ notes: B.notes.trim() || null
66
+ });
67
+ R.success(`${B.framework} disclosure generated for the selected period`), G(n.id), z(!1);
68
+ } catch (e) {
69
+ U(e instanceof Error ? e.message : "Could not generate the disclosure.");
70
+ }
71
+ }, xe = async (e) => {
72
+ q(e.id);
73
+ try {
74
+ await X.mutateAsync(e.id), R.success("Disclosure finalized — locked as the reported-on-record snapshot.");
75
+ } catch (e) {
76
+ R.error(e instanceof Error ? e.message : "Could not finalize the disclosure.");
77
+ } finally {
78
+ q(null);
79
+ }
80
+ }, Se = (e) => {
81
+ let t = L(e.datapoints);
82
+ if (!t) {
83
+ R.error("This disclosure has no exportable datapoints.");
84
+ return;
85
+ }
86
+ let n = oe([
87
+ {
88
+ header: "Section",
89
+ value: (e) => e.section
90
+ },
91
+ {
92
+ header: "Datapoint",
93
+ value: (e) => e.item
94
+ },
95
+ {
96
+ header: "Value",
97
+ value: (e) => e.value
98
+ },
99
+ {
100
+ header: "Detail",
101
+ value: (e) => e.detail
102
+ }
103
+ ], [
104
+ ...t.emissionsByScope.map((e) => ({
105
+ section: "Emissions by scope",
106
+ item: a(e.scope),
107
+ value: e.co2eTonnes,
108
+ detail: `${e.recordCount} record(s)`
109
+ })),
110
+ {
111
+ section: "Emissions summary",
112
+ item: "Total CO2e (tonnes)",
113
+ value: t.totalCo2eTonnes,
114
+ detail: `${t.verifiedEmissionRecords}/${t.totalEmissionRecords} records verified`
115
+ },
116
+ ...t.complianceCertsByCategory.map((e) => ({
117
+ section: "Compliance by category",
118
+ item: a(e.category),
119
+ value: e.count,
120
+ detail: "certificate(s)"
121
+ })),
122
+ ...t.complianceCertsByStatus.map((e) => ({
123
+ section: "Compliance by status",
124
+ item: a(e.status),
125
+ value: e.count,
126
+ detail: "certificate(s)"
127
+ }))
128
+ ]);
129
+ se(`theglobalfuel-${e.framework.toLowerCase()}-disclosure-${e.periodStart.slice(0, 10)}.csv`, "text/csv", n) ? R.success("Disclosure datapoints exported.") : R.error("This browser can't download the export.");
130
+ };
131
+ return /* @__PURE__ */ x(t, {
132
+ title: F("theglobalfuel.pages.esgDisclosures.title", "ESG Disclosures"),
133
+ description: F("theglobalfuel.pages.esgDisclosures.description", "Framework-aligned disclosure snapshots computed from your live emission and compliance records."),
134
+ dataTour: "theglobalfuel-esg-disclosures-page",
135
+ actions: /* @__PURE__ */ x(S, {
136
+ onClick: () => z(!0),
137
+ children: [/* @__PURE__ */ b(y, { className: "mr-1.5 h-4 w-4" }), " Generate disclosure"]
138
+ }),
139
+ children: [_e ? /* @__PURE__ */ b(d, { label: "Loading ESG disclosures…" }) : ve ? /* @__PURE__ */ b(u, {
140
+ message: "Couldn't load ESG disclosures.",
141
+ onRetry: () => ye()
142
+ }) : Z.length === 0 ? /* @__PURE__ */ b(f, {
143
+ illustration: "empty-data",
144
+ icon: /* @__PURE__ */ b(h, { className: "h-10 w-10" }),
145
+ title: "No disclosures generated yet",
146
+ description: "Generate a GRI, SASB, CSRD, SEC or CDP-aligned disclosure snapshot from your live emissions and compliance records.",
147
+ action: /* @__PURE__ */ x(S, {
148
+ onClick: () => z(!0),
149
+ children: [/* @__PURE__ */ b(y, { className: "mr-1.5 h-4 w-4" }), " Generate disclosure"]
150
+ })
151
+ }) : /* @__PURE__ */ x("div", {
152
+ className: "grid grid-cols-1 gap-6 lg:grid-cols-[340px_1fr]",
153
+ children: [/* @__PURE__ */ b("div", {
154
+ className: "flex flex-col gap-3",
155
+ children: Z.map((t) => {
156
+ let n = Q?.id === t.id;
157
+ return /* @__PURE__ */ x("button", {
158
+ type: "button",
159
+ onClick: () => G(t.id),
160
+ "aria-pressed": n,
161
+ className: e("rounded-xl border p-4 text-left transition-colors", n ? "border-action-primary-bg bg-[var(--color-accent-soft)]" : "border-border-seam bg-bg-surface hover:bg-bg-sunken"),
162
+ children: [
163
+ /* @__PURE__ */ x("div", {
164
+ className: "flex items-start justify-between gap-3",
165
+ children: [/* @__PURE__ */ b("p", {
166
+ className: "text-sm font-semibold text-text-primary",
167
+ children: t.framework
168
+ }), /* @__PURE__ */ b(c, { status: t.status })]
169
+ }),
170
+ /* @__PURE__ */ x("p", {
171
+ className: "mt-1 text-xs text-text-secondary",
172
+ children: [
173
+ r(t.periodStart),
174
+ " → ",
175
+ r(t.periodEnd)
176
+ ]
177
+ }),
178
+ /* @__PURE__ */ x("p", {
179
+ className: "mt-0.5 text-xs text-text-tertiary",
180
+ children: ["Generated ", i(t.generatedAt)]
181
+ })
182
+ ]
183
+ }, t.id);
184
+ })
185
+ }), Q && /* @__PURE__ */ x("div", {
186
+ className: "flex flex-col gap-6",
187
+ children: [/* @__PURE__ */ x(C, {
188
+ treatment: "glass",
189
+ className: "p-5",
190
+ children: [/* @__PURE__ */ x("div", {
191
+ className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between",
192
+ children: [/* @__PURE__ */ x("div", {
193
+ className: "min-w-0",
194
+ children: [
195
+ /* @__PURE__ */ x("h2", {
196
+ className: "flex items-center gap-2 text-base font-semibold text-text-primary",
197
+ children: [/* @__PURE__ */ b(_, { className: "h-4 w-4 text-text-secondary" }), N[Q.framework]]
198
+ }),
199
+ /* @__PURE__ */ x("p", {
200
+ className: "mt-1 text-xs text-text-tertiary",
201
+ children: [
202
+ "Reporting period ",
203
+ r(Q.periodStart),
204
+ " →",
205
+ " ",
206
+ r(Q.periodEnd),
207
+ " · generated",
208
+ " ",
209
+ i(Q.generatedAt)
210
+ ]
211
+ }),
212
+ Q.notes && /* @__PURE__ */ b("p", {
213
+ className: "mt-2 text-sm text-text-secondary",
214
+ children: Q.notes
215
+ })
216
+ ]
217
+ }), /* @__PURE__ */ x("div", {
218
+ className: "flex shrink-0 items-center gap-2",
219
+ children: [/* @__PURE__ */ x(S, {
220
+ size: "sm",
221
+ variant: "outline",
222
+ onClick: () => Se(Q),
223
+ children: [/* @__PURE__ */ b(g, { className: "mr-2 h-4 w-4" }), " Export CSV"]
224
+ }), Q.status === "DRAFT" && /* @__PURE__ */ x(S, {
225
+ size: "sm",
226
+ onClick: () => void xe(Q),
227
+ disabled: K === Q.id,
228
+ children: [/* @__PURE__ */ b(v, { className: "mr-2 h-4 w-4" }), K === Q.id ? "Finalizing…" : "Finalize"]
229
+ })]
230
+ })]
231
+ }), /* @__PURE__ */ x("dl", {
232
+ className: "mt-4 grid grid-cols-2 gap-3 border-t border-border-seam pt-4 text-xs sm:grid-cols-4",
233
+ children: [
234
+ /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("dt", {
235
+ className: "text-text-tertiary",
236
+ children: "Status"
237
+ }), /* @__PURE__ */ b("dd", {
238
+ className: "mt-0.5",
239
+ children: /* @__PURE__ */ b(c, { status: Q.status })
240
+ })] }),
241
+ /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("dt", {
242
+ className: "text-text-tertiary",
243
+ children: "Generated"
244
+ }), /* @__PURE__ */ b("dd", {
245
+ className: "mt-0.5 text-text-secondary",
246
+ children: i(Q.generatedAt)
247
+ })] }),
248
+ /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("dt", {
249
+ className: "text-text-tertiary",
250
+ children: "Created"
251
+ }), /* @__PURE__ */ b("dd", {
252
+ className: "mt-0.5 text-text-secondary",
253
+ children: i(Q.createdAt)
254
+ })] }),
255
+ /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("dt", {
256
+ className: "text-text-tertiary",
257
+ children: "Last updated"
258
+ }), /* @__PURE__ */ b("dd", {
259
+ className: "mt-0.5 text-text-secondary",
260
+ children: i(Q.updatedAt)
261
+ })] })
262
+ ]
263
+ })]
264
+ }), $ ? /* @__PURE__ */ x(ce, { children: [
265
+ /* @__PURE__ */ x("div", {
266
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-3",
267
+ children: [
268
+ /* @__PURE__ */ b(n, {
269
+ featured: !0,
270
+ icon: /* @__PURE__ */ b(h, { className: "h-5 w-5" }),
271
+ value: o($.totalCo2eTonnes),
272
+ label: "Total CO₂e in period (tonnes)"
273
+ }),
274
+ /* @__PURE__ */ b(n, {
275
+ icon: /* @__PURE__ */ b(_, { className: "h-5 w-5" }),
276
+ value: `${o($.verifiedEmissionRecords)}/${o($.totalEmissionRecords)}`,
277
+ label: "Emission records third-party verified"
278
+ }),
279
+ /* @__PURE__ */ b(n, {
280
+ icon: /* @__PURE__ */ b(v, { className: "h-5 w-5" }),
281
+ value: o($.complianceCertsByCategory.reduce((e, t) => e + t.count, 0)),
282
+ label: "Permits, licences & certifications on file"
283
+ })
284
+ ]
285
+ }),
286
+ /* @__PURE__ */ x(C, {
287
+ treatment: "glass",
288
+ className: "p-5",
289
+ children: [
290
+ /* @__PURE__ */ b("h3", {
291
+ className: "text-sm font-semibold text-text-primary",
292
+ children: "Emissions by scope"
293
+ }),
294
+ /* @__PURE__ */ b("p", {
295
+ className: "mt-1 text-xs text-text-tertiary",
296
+ children: "Summed from live emission records overlapping the reporting period."
297
+ }),
298
+ /* @__PURE__ */ b("div", {
299
+ className: "mt-3",
300
+ children: $.emissionsByScope.length > 0 ? /* @__PURE__ */ b(l, {
301
+ columns: [
302
+ {
303
+ key: "scope",
304
+ header: "Scope",
305
+ render: (e) => /* @__PURE__ */ b(c, { status: e.scope })
306
+ },
307
+ {
308
+ key: "co2eTonnes",
309
+ header: "tCO2e",
310
+ render: (e) => /* @__PURE__ */ b("span", {
311
+ className: "tabular-nums",
312
+ children: o(e.co2eTonnes)
313
+ })
314
+ },
315
+ {
316
+ key: "recordCount",
317
+ header: "Records",
318
+ render: (e) => /* @__PURE__ */ b("span", {
319
+ className: "tabular-nums",
320
+ children: o(e.recordCount)
321
+ })
322
+ }
323
+ ],
324
+ rows: $.emissionsByScope,
325
+ rowKey: (e) => e.scope
326
+ }) : /* @__PURE__ */ b("p", {
327
+ className: "rounded-xl border border-dashed border-border-seam py-6 text-center text-sm text-text-secondary",
328
+ children: "No emission records overlap this reporting period."
329
+ })
330
+ })
331
+ ]
332
+ }),
333
+ /* @__PURE__ */ x("div", {
334
+ className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
335
+ children: [/* @__PURE__ */ x(C, {
336
+ treatment: "glass",
337
+ className: "p-5",
338
+ children: [/* @__PURE__ */ b("h3", {
339
+ className: "text-sm font-semibold text-text-primary",
340
+ children: "Compliance certificates by category"
341
+ }), /* @__PURE__ */ b("ul", {
342
+ className: "mt-3 space-y-2",
343
+ children: $.complianceCertsByCategory.length > 0 ? $.complianceCertsByCategory.map((e) => /* @__PURE__ */ x("li", {
344
+ className: "flex items-center justify-between text-sm",
345
+ children: [/* @__PURE__ */ b("span", {
346
+ className: "text-text-secondary",
347
+ children: a(e.category)
348
+ }), /* @__PURE__ */ b("span", {
349
+ className: "tabular-nums text-text-primary",
350
+ children: o(e.count)
351
+ })]
352
+ }, e.category)) : /* @__PURE__ */ b("li", {
353
+ className: "text-sm text-text-tertiary",
354
+ children: "No certificates on file."
355
+ })
356
+ })]
357
+ }), /* @__PURE__ */ x(C, {
358
+ treatment: "glass",
359
+ className: "p-5",
360
+ children: [/* @__PURE__ */ b("h3", {
361
+ className: "text-sm font-semibold text-text-primary",
362
+ children: "Compliance certificates by status"
363
+ }), /* @__PURE__ */ b("ul", {
364
+ className: "mt-3 space-y-2",
365
+ children: $.complianceCertsByStatus.length > 0 ? $.complianceCertsByStatus.map((e) => /* @__PURE__ */ x("li", {
366
+ className: "flex items-center justify-between text-sm",
367
+ children: [/* @__PURE__ */ b(c, { status: e.status }), /* @__PURE__ */ b("span", {
368
+ className: "tabular-nums text-text-primary",
369
+ children: o(e.count)
370
+ })]
371
+ }, e.status)) : /* @__PURE__ */ b("li", {
372
+ className: "text-sm text-text-tertiary",
373
+ children: "No certificates on file."
374
+ })
375
+ })]
376
+ })]
377
+ }),
378
+ /* @__PURE__ */ b("p", {
379
+ className: "text-xs text-text-tertiary",
380
+ children: "Datapoints are derived from this workspace's live operational records at generation time — never manually entered. Regenerate to capture records added since."
381
+ })
382
+ ] }) : /* @__PURE__ */ b(C, {
383
+ treatment: "glass",
384
+ className: "p-5",
385
+ children: /* @__PURE__ */ b("p", {
386
+ className: "text-sm text-text-secondary",
387
+ children: "This disclosure has no readable datapoints."
388
+ })
389
+ })]
390
+ })]
391
+ }), /* @__PURE__ */ b(le, {
392
+ open: ge,
393
+ onOpenChange: (e) => {
394
+ z(e), e || (V(I()), U(null));
395
+ },
396
+ children: /* @__PURE__ */ x(ue, { children: [/* @__PURE__ */ x(pe, { children: [/* @__PURE__ */ b(me, { children: "Generate ESG disclosure" }), /* @__PURE__ */ b(de, { children: "Computes a framework-aligned snapshot from your live emission and compliance records for the selected reporting period." })] }), /* @__PURE__ */ x("form", {
397
+ onSubmit: (e) => {
398
+ e.preventDefault(), be();
399
+ },
400
+ children: [/* @__PURE__ */ x("div", {
401
+ className: "grid gap-4 py-2",
402
+ children: [
403
+ /* @__PURE__ */ x("div", {
404
+ className: "grid gap-1.5",
405
+ children: [/* @__PURE__ */ b(T, {
406
+ htmlFor: "esgFramework",
407
+ children: "Framework"
408
+ }), /* @__PURE__ */ x(he, {
409
+ value: B.framework,
410
+ onValueChange: (e) => V({
411
+ ...B,
412
+ framework: e
413
+ }),
414
+ children: [/* @__PURE__ */ b(O, {
415
+ id: "esgFramework",
416
+ children: /* @__PURE__ */ b(k, {})
417
+ }), /* @__PURE__ */ b(E, { children: M.map((e) => /* @__PURE__ */ b(D, {
418
+ value: e,
419
+ children: N[e]
420
+ }, e)) })]
421
+ })]
422
+ }),
423
+ /* @__PURE__ */ x("div", {
424
+ className: "grid gap-2 sm:grid-cols-2",
425
+ children: [/* @__PURE__ */ x("div", {
426
+ className: "grid gap-1.5",
427
+ children: [/* @__PURE__ */ b(T, {
428
+ htmlFor: "esgPeriodStart",
429
+ children: "Period start *"
430
+ }), /* @__PURE__ */ b(w, {
431
+ id: "esgPeriodStart",
432
+ type: "date",
433
+ value: B.periodStart,
434
+ max: P(),
435
+ onChange: (e) => V({
436
+ ...B,
437
+ periodStart: e.target.value
438
+ }),
439
+ required: !0
440
+ })]
441
+ }), /* @__PURE__ */ x("div", {
442
+ className: "grid gap-1.5",
443
+ children: [/* @__PURE__ */ b(T, {
444
+ htmlFor: "esgPeriodEnd",
445
+ children: "Period end *"
446
+ }), /* @__PURE__ */ b(w, {
447
+ id: "esgPeriodEnd",
448
+ type: "date",
449
+ value: B.periodEnd,
450
+ onChange: (e) => V({
451
+ ...B,
452
+ periodEnd: e.target.value
453
+ }),
454
+ required: !0
455
+ })]
456
+ })]
457
+ }),
458
+ /* @__PURE__ */ x("div", {
459
+ className: "grid gap-1.5",
460
+ children: [/* @__PURE__ */ b(T, {
461
+ htmlFor: "esgNotes",
462
+ children: "Notes"
463
+ }), /* @__PURE__ */ b(A, {
464
+ id: "esgNotes",
465
+ value: B.notes,
466
+ onChange: (e) => V({
467
+ ...B,
468
+ notes: e.target.value
469
+ }),
470
+ placeholder: "Optional context for this reporting period…",
471
+ rows: 3
472
+ })]
473
+ }),
474
+ H && /* @__PURE__ */ b("p", {
475
+ className: "text-sm text-status-error-text",
476
+ children: H
477
+ })
478
+ ]
479
+ }), /* @__PURE__ */ x(fe, { children: [/* @__PURE__ */ b(S, {
480
+ type: "button",
481
+ variant: "outline",
482
+ onClick: () => z(!1),
483
+ children: "Cancel"
484
+ }), /* @__PURE__ */ b(S, {
485
+ type: "submit",
486
+ disabled: Y.isPending,
487
+ children: Y.isPending ? "Generating…" : "Generate disclosure"
488
+ })] })]
489
+ })] })
490
+ })]
491
+ });
492
+ }
493
+ //#endregion
494
+ export { R as EsgDisclosuresPage };
495
+
496
+ //# sourceMappingURL=EsgDisclosuresPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EsgDisclosuresPage.js","names":[],"sources":["../../../../src/theglobalfuel/pages/esg-disclosures/EsgDisclosuresPage.tsx"],"sourcesContent":["/**\n * ESG Disclosures — framework-aligned reporting built from live records.\n * @module theglobalfuel/pages/esg-disclosures\n *\n * Report builder over the `the*` ESG disclosure API: pick a framework\n * (GRI/SASB/CSRD/SEC climate/CDP) and a reporting period, and\n * `theGenerateEsgDisclosure` computes the datapoints live from this\n * workspace's own emission and compliance records — a disclosure is a derived\n * snapshot, never a manually-entered form. Drafts can be finalized into the\n * reported-on-record snapshot; every snapshot keeps its generation/audit\n * timestamps so the trail holds up. No mock data.\n */\n\nimport { useMemo, useState } from 'react';\nimport { FileCheck2, Download, Lock, Plus, Cloud } from 'lucide-react';\nimport {\n Button,\n GlassCard,\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 {\n PageLayout,\n LoadingView,\n ErrorView,\n EmptyState,\n StatusBadge,\n MetricsCard,\n DataTable,\n type Column,\n} from '../../components';\nimport {\n useTheEsgDisclosures,\n useTheGenerateEsgDisclosure,\n useTheFinalizeEsgDisclosure,\n useNotify,\n useThePageView,\n useTheTranslation,\n} from '../../hooks';\nimport { cn } from '../../utils/cn';\nimport {\n formatDate,\n formatDateTime,\n formatNumber,\n formatEnumLabel,\n toBackendDate,\n} from '../../utils/formatters';\nimport { toCsv, downloadTextFile } from '../../utils';\nimport type { TheEsgDisclosure, TheEsgDatapoints, TheEsgFramework } from '../../types';\n\nconst PAGE_SIZE = 25;\n\nconst FRAMEWORKS: TheEsgFramework[] = ['GRI', 'SASB', 'CSRD', 'SEC_CLIMATE', 'CDP'];\n\n/** Plain-language framework names for selects and detail headers. */\nconst FRAMEWORK_LABEL: Record<TheEsgFramework, string> = {\n GRI: 'GRI — Global Reporting Initiative',\n SASB: 'SASB — Sustainability Accounting Standards Board',\n CSRD: 'CSRD — EU Corporate Sustainability Reporting Directive',\n SEC_CLIMATE: 'SEC Climate Disclosure',\n CDP: 'CDP — Carbon Disclosure Project',\n};\n\nconst today = (): string => new Date().toISOString().slice(0, 10);\nconst currentYear = (): number => new Date().getUTCFullYear();\n\ninterface GenerateFormState {\n framework: TheEsgFramework;\n periodStart: string;\n periodEnd: string;\n notes: string;\n}\n\nconst emptyForm = (): GenerateFormState => ({\n framework: 'GRI',\n periodStart: `${currentYear()}-01-01`,\n periodEnd: `${currentYear()}-12-31`,\n notes: '',\n});\n\n/** Parse the JSON-encoded datapoints blob; returns null on any malformed input. */\nconst parseDatapoints = (raw: string): TheEsgDatapoints | null => {\n try {\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed !== 'object' || parsed === null) return null;\n return parsed as TheEsgDatapoints;\n } catch {\n return null;\n }\n};\n\nexport function EsgDisclosuresPage() {\n useThePageView('esg-disclosures');\n const t = useTheTranslation();\n const notify = useNotify();\n\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<GenerateFormState>(emptyForm);\n const [formError, setFormError] = useState<string | null>(null);\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [finalizingId, setFinalizingId] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useTheEsgDisclosures({\n pagination: { limit: PAGE_SIZE },\n });\n const generate = useTheGenerateEsgDisclosure();\n const finalize = useTheFinalizeEsgDisclosure();\n\n const disclosures = useMemo(() => data?.items ?? [], [data]);\n const selected = useMemo(\n () => disclosures.find((d) => d.id === selectedId) ?? disclosures[0] ?? null,\n [disclosures, selectedId]\n );\n const selectedDatapoints = useMemo(\n () => (selected ? parseDatapoints(selected.datapoints) : null),\n [selected]\n );\n\n const handleGenerate = async () => {\n const periodStart = toBackendDate(form.periodStart);\n const periodEnd = toBackendDate(form.periodEnd);\n if (!periodStart || !periodEnd) {\n setFormError('Enter a valid reporting period.');\n return;\n }\n if (periodEnd < periodStart) {\n setFormError('The reporting period must end after it starts.');\n return;\n }\n setFormError(null);\n try {\n const created = await generate.mutateAsync({\n framework: form.framework,\n periodStart,\n periodEnd,\n notes: form.notes.trim() || null,\n });\n notify.success(`${form.framework} disclosure generated for the selected period`);\n setSelectedId(created.id);\n setDialogOpen(false);\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Could not generate the disclosure.');\n }\n };\n\n const handleFinalize = async (disclosure: TheEsgDisclosure) => {\n setFinalizingId(disclosure.id);\n try {\n await finalize.mutateAsync(disclosure.id);\n notify.success('Disclosure finalized — locked as the reported-on-record snapshot.');\n } catch (err) {\n notify.error(err instanceof Error ? err.message : 'Could not finalize the disclosure.');\n } finally {\n setFinalizingId(null);\n }\n };\n\n const handleExport = (disclosure: TheEsgDisclosure) => {\n const datapoints = parseDatapoints(disclosure.datapoints);\n if (!datapoints) {\n notify.error('This disclosure has no exportable datapoints.');\n return;\n }\n const rows = [\n ...datapoints.emissionsByScope.map((s) => ({\n section: 'Emissions by scope',\n item: formatEnumLabel(s.scope),\n value: s.co2eTonnes,\n detail: `${s.recordCount} record(s)`,\n })),\n {\n section: 'Emissions summary',\n item: 'Total CO2e (tonnes)',\n value: datapoints.totalCo2eTonnes,\n detail: `${datapoints.verifiedEmissionRecords}/${datapoints.totalEmissionRecords} records verified`,\n },\n ...datapoints.complianceCertsByCategory.map((c) => ({\n section: 'Compliance by category',\n item: formatEnumLabel(c.category),\n value: c.count,\n detail: 'certificate(s)',\n })),\n ...datapoints.complianceCertsByStatus.map((s) => ({\n section: 'Compliance by status',\n item: formatEnumLabel(s.status),\n value: s.count,\n detail: 'certificate(s)',\n })),\n ];\n const csv = toCsv(\n [\n { header: 'Section', value: (r: (typeof rows)[number]) => r.section },\n { header: 'Datapoint', value: (r: (typeof rows)[number]) => r.item },\n { header: 'Value', value: (r: (typeof rows)[number]) => r.value },\n { header: 'Detail', value: (r: (typeof rows)[number]) => r.detail },\n ],\n rows\n );\n const filename = `theglobalfuel-${disclosure.framework.toLowerCase()}-disclosure-${disclosure.periodStart.slice(0, 10)}.csv`;\n const ok = downloadTextFile(filename, 'text/csv', csv);\n if (ok) notify.success('Disclosure datapoints exported.');\n else notify.error(\"This browser can't download the export.\");\n };\n\n const scopeColumns: Column<{ scope: string; co2eTonnes: number; recordCount: number }>[] = [\n {\n key: 'scope',\n header: 'Scope',\n render: (r) => <StatusBadge status={r.scope} />,\n },\n {\n key: 'co2eTonnes',\n header: 'tCO2e',\n render: (r) => <span className=\"tabular-nums\">{formatNumber(r.co2eTonnes)}</span>,\n },\n {\n key: 'recordCount',\n header: 'Records',\n render: (r) => <span className=\"tabular-nums\">{formatNumber(r.recordCount)}</span>,\n },\n ];\n\n const pageTitle = t('theglobalfuel.pages.esgDisclosures.title', 'ESG Disclosures');\n const description = t(\n 'theglobalfuel.pages.esgDisclosures.description',\n 'Framework-aligned disclosure snapshots computed from your live emission and compliance records.'\n );\n\n return (\n <PageLayout\n title={pageTitle}\n description={description}\n dataTour=\"theglobalfuel-esg-disclosures-page\"\n actions={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Generate disclosure\n </Button>\n }\n >\n {isLoading ? (\n <LoadingView label=\"Loading ESG disclosures…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load ESG disclosures.\" onRetry={() => refetch()} />\n ) : disclosures.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Cloud className=\"h-10 w-10\" />}\n title=\"No disclosures generated yet\"\n description=\"Generate a GRI, SASB, CSRD, SEC or CDP-aligned disclosure snapshot from your live emissions and compliance records.\"\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Generate disclosure\n </Button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-[340px_1fr]\">\n {/* Disclosure list */}\n <div className=\"flex flex-col gap-3\">\n {disclosures.map((d) => {\n const active = selected?.id === d.id;\n return (\n <button\n key={d.id}\n type=\"button\"\n onClick={() => setSelectedId(d.id)}\n aria-pressed={active}\n className={cn(\n 'rounded-xl border p-4 text-left transition-colors',\n active\n ? 'border-action-primary-bg bg-[var(--color-accent-soft)]'\n : 'border-border-seam bg-bg-surface hover:bg-bg-sunken'\n )}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <p className=\"text-sm font-semibold text-text-primary\">{d.framework}</p>\n <StatusBadge status={d.status} />\n </div>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {formatDate(d.periodStart)} → {formatDate(d.periodEnd)}\n </p>\n <p className=\"mt-0.5 text-xs text-text-tertiary\">\n Generated {formatDateTime(d.generatedAt)}\n </p>\n </button>\n );\n })}\n </div>\n\n {/* Selected disclosure detail */}\n {selected && (\n <div className=\"flex flex-col gap-6\">\n <GlassCard treatment=\"glass\" className=\"p-5\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"min-w-0\">\n <h2 className=\"flex items-center gap-2 text-base font-semibold text-text-primary\">\n <FileCheck2 className=\"h-4 w-4 text-text-secondary\" />\n {FRAMEWORK_LABEL[selected.framework]}\n </h2>\n <p className=\"mt-1 text-xs text-text-tertiary\">\n Reporting period {formatDate(selected.periodStart)} →{' '}\n {formatDate(selected.periodEnd)} · generated{' '}\n {formatDateTime(selected.generatedAt)}\n </p>\n {selected.notes && (\n <p className=\"mt-2 text-sm text-text-secondary\">{selected.notes}</p>\n )}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <Button size=\"sm\" variant=\"outline\" onClick={() => handleExport(selected)}>\n <Download className=\"mr-2 h-4 w-4\" /> Export CSV\n </Button>\n {selected.status === 'DRAFT' && (\n <Button\n size=\"sm\"\n onClick={() => void handleFinalize(selected)}\n disabled={finalizingId === selected.id}\n >\n <Lock className=\"mr-2 h-4 w-4\" />\n {finalizingId === selected.id ? 'Finalizing…' : 'Finalize'}\n </Button>\n )}\n </div>\n </div>\n\n {/* Audit trail */}\n <dl className=\"mt-4 grid grid-cols-2 gap-3 border-t border-border-seam pt-4 text-xs sm:grid-cols-4\">\n <div>\n <dt className=\"text-text-tertiary\">Status</dt>\n <dd className=\"mt-0.5\">\n <StatusBadge status={selected.status} />\n </dd>\n </div>\n <div>\n <dt className=\"text-text-tertiary\">Generated</dt>\n <dd className=\"mt-0.5 text-text-secondary\">\n {formatDateTime(selected.generatedAt)}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-tertiary\">Created</dt>\n <dd className=\"mt-0.5 text-text-secondary\">\n {formatDateTime(selected.createdAt)}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-tertiary\">Last updated</dt>\n <dd className=\"mt-0.5 text-text-secondary\">\n {formatDateTime(selected.updatedAt)}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n {selectedDatapoints ? (\n <>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n featured\n icon={<Cloud className=\"h-5 w-5\" />}\n value={formatNumber(selectedDatapoints.totalCo2eTonnes)}\n label=\"Total CO₂e in period (tonnes)\"\n />\n <MetricsCard\n icon={<FileCheck2 className=\"h-5 w-5\" />}\n value={`${formatNumber(selectedDatapoints.verifiedEmissionRecords)}/${formatNumber(\n selectedDatapoints.totalEmissionRecords\n )}`}\n label=\"Emission records third-party verified\"\n />\n <MetricsCard\n icon={<Lock className=\"h-5 w-5\" />}\n value={formatNumber(\n selectedDatapoints.complianceCertsByCategory.reduce(\n (sum, c) => sum + c.count,\n 0\n )\n )}\n label=\"Permits, licences & certifications on file\"\n />\n </div>\n\n <GlassCard treatment=\"glass\" className=\"p-5\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Emissions by scope</h3>\n <p className=\"mt-1 text-xs text-text-tertiary\">\n Summed from live emission records overlapping the reporting period.\n </p>\n <div className=\"mt-3\">\n {selectedDatapoints.emissionsByScope.length > 0 ? (\n <DataTable\n columns={scopeColumns}\n rows={selectedDatapoints.emissionsByScope}\n rowKey={(r) => r.scope}\n />\n ) : (\n <p className=\"rounded-xl border border-dashed border-border-seam py-6 text-center text-sm text-text-secondary\">\n No emission records overlap this reporting period.\n </p>\n )}\n </div>\n </GlassCard>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <GlassCard treatment=\"glass\" className=\"p-5\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n Compliance certificates by category\n </h3>\n <ul className=\"mt-3 space-y-2\">\n {selectedDatapoints.complianceCertsByCategory.length > 0 ? (\n selectedDatapoints.complianceCertsByCategory.map((c) => (\n <li\n key={c.category}\n className=\"flex items-center justify-between text-sm\"\n >\n <span className=\"text-text-secondary\">\n {formatEnumLabel(c.category)}\n </span>\n <span className=\"tabular-nums text-text-primary\">\n {formatNumber(c.count)}\n </span>\n </li>\n ))\n ) : (\n <li className=\"text-sm text-text-tertiary\">No certificates on file.</li>\n )}\n </ul>\n </GlassCard>\n\n <GlassCard treatment=\"glass\" className=\"p-5\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n Compliance certificates by status\n </h3>\n <ul className=\"mt-3 space-y-2\">\n {selectedDatapoints.complianceCertsByStatus.length > 0 ? (\n selectedDatapoints.complianceCertsByStatus.map((s) => (\n <li\n key={s.status}\n className=\"flex items-center justify-between text-sm\"\n >\n <StatusBadge status={s.status} />\n <span className=\"tabular-nums text-text-primary\">\n {formatNumber(s.count)}\n </span>\n </li>\n ))\n ) : (\n <li className=\"text-sm text-text-tertiary\">No certificates on file.</li>\n )}\n </ul>\n </GlassCard>\n </div>\n\n <p className=\"text-xs text-text-tertiary\">\n Datapoints are derived from this workspace&apos;s live operational records at\n generation time — never manually entered. Regenerate to capture records added\n since.\n </p>\n </>\n ) : (\n <GlassCard treatment=\"glass\" className=\"p-5\">\n <p className=\"text-sm text-text-secondary\">\n This disclosure has no readable datapoints.\n </p>\n </GlassCard>\n )}\n </div>\n )}\n </div>\n )}\n\n {/* Generate disclosure dialog */}\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n setDialogOpen(open);\n if (!open) {\n setForm(emptyForm());\n setFormError(null);\n }\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Generate ESG disclosure</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Computes a framework-aligned snapshot from your live emission and compliance records\n for the selected reporting period.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <form\n onSubmit={(e) => {\n e.preventDefault();\n void handleGenerate();\n }}\n >\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"esgFramework\">Framework</Label>\n <Select\n value={form.framework}\n onValueChange={(v) => setForm({ ...form, framework: v as TheEsgFramework })}\n >\n <SelectTrigger id=\"esgFramework\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {FRAMEWORKS.map((f) => (\n <SelectItem key={f} value={f}>\n {FRAMEWORK_LABEL[f]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"esgPeriodStart\">Period start *</Label>\n <Input\n id=\"esgPeriodStart\"\n type=\"date\"\n value={form.periodStart}\n max={today()}\n onChange={(e) => setForm({ ...form, periodStart: e.target.value })}\n required\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"esgPeriodEnd\">Period end *</Label>\n <Input\n id=\"esgPeriodEnd\"\n type=\"date\"\n value={form.periodEnd}\n onChange={(e) => setForm({ ...form, periodEnd: e.target.value })}\n required\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"esgNotes\">Notes</Label>\n <Textarea\n id=\"esgNotes\"\n value={form.notes}\n onChange={(e) => setForm({ ...form, notes: e.target.value })}\n placeholder=\"Optional context for this reporting period…\"\n rows={3}\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setDialogOpen(false)}>\n Cancel\n </Button>\n <Button type=\"submit\" disabled={generate.isPending}>\n {generate.isPending ? 'Generating…' : 'Generate disclosure'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -402,6 +402,54 @@ export interface TheCreateComplianceCertInput {
402
402
  evidenceFileId?: string | null;
403
403
  notes?: string | null;
404
404
  }
405
+ export type TheEsgFramework = 'GRI' | 'SASB' | 'CSRD' | 'SEC_CLIMATE' | 'CDP';
406
+ export type TheEsgDisclosureStatus = 'DRAFT' | 'FINAL';
407
+ /**
408
+ * A generated, reporting-period snapshot of ESG datapoints aligned to a named
409
+ * disclosure framework, computed from this workspace's own emission and
410
+ * compliance records at generation time. `datapoints` arrives as a
411
+ * JSON-encoded string — see `TheEsgDatapoints` for the parsed shape.
412
+ */
413
+ export interface TheEsgDisclosure {
414
+ id: string;
415
+ workspaceId: string;
416
+ framework: TheEsgFramework;
417
+ status: TheEsgDisclosureStatus;
418
+ periodStart: string;
419
+ periodEnd: string;
420
+ /** JSON-encoded computed datapoints (`TheEsgDatapoints`). */
421
+ datapoints: string;
422
+ generatedAt: string;
423
+ notes?: string | null;
424
+ createdAt: string;
425
+ updatedAt: string;
426
+ }
427
+ /** Parsed shape of `TheEsgDisclosure.datapoints`. */
428
+ export interface TheEsgDatapoints {
429
+ emissionsByScope: Array<{
430
+ scope: string;
431
+ co2eTonnes: number;
432
+ recordCount: number;
433
+ }>;
434
+ totalCo2eTonnes: number;
435
+ verifiedEmissionRecords: number;
436
+ totalEmissionRecords: number;
437
+ complianceCertsByCategory: Array<{
438
+ category: string;
439
+ count: number;
440
+ }>;
441
+ complianceCertsByStatus: Array<{
442
+ status: string;
443
+ count: number;
444
+ }>;
445
+ generatedFrom: 'live_operational_records';
446
+ }
447
+ export interface TheGenerateEsgDisclosureInput {
448
+ framework: TheEsgFramework;
449
+ periodStart: string;
450
+ periodEnd: string;
451
+ notes?: string | null;
452
+ }
405
453
  export type TheSafetyIncidentCategory = 'NEAR_MISS' | 'INJURY' | 'SPILL' | 'RELEASE' | 'EQUIPMENT_FAILURE';
406
454
  export type TheSafetyIncidentSeverity = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
407
455
  export type TheSafetyIncidentStatus = 'REPORTED' | 'INVESTIGATING' | 'ROOT_CAUSE_IDENTIFIED' | 'CORRECTIVE_ACTION' | 'CLOSED';