@burdenoff/microfe-ecoimpacthub 2026.704.3 → 2026.704.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/ecoimpacthub/pages/DashboardPage.js +345 -189
  2. package/dist/ecoimpacthub/pages/DashboardPage.js.map +1 -1
  3. package/dist/ecoimpacthub/pages/_shared/ConservationBadge.js +58 -0
  4. package/dist/ecoimpacthub/pages/_shared/ConservationBadge.js.map +1 -0
  5. package/dist/ecoimpacthub/pages/_shared/EvidenceThumb.js +70 -0
  6. package/dist/ecoimpacthub/pages/_shared/EvidenceThumb.js.map +1 -0
  7. package/dist/ecoimpacthub/pages/_shared/MethodBadge.js +51 -0
  8. package/dist/ecoimpacthub/pages/_shared/MethodBadge.js.map +1 -0
  9. package/dist/ecoimpacthub/pages/_shared/TaxonChip.js +29 -0
  10. package/dist/ecoimpacthub/pages/_shared/TaxonChip.js.map +1 -0
  11. package/dist/ecoimpacthub/pages/badges.js +71 -0
  12. package/dist/ecoimpacthub/pages/badges.js.map +1 -0
  13. package/dist/ecoimpacthub/pages/carbon/CarbonPage.js +341 -300
  14. package/dist/ecoimpacthub/pages/carbon/CarbonPage.js.map +1 -1
  15. package/dist/ecoimpacthub/pages/carbonVisuals.js +89 -0
  16. package/dist/ecoimpacthub/pages/carbonVisuals.js.map +1 -0
  17. package/dist/ecoimpacthub/pages/habitat/HabitatProjectDetailPage.js +252 -218
  18. package/dist/ecoimpacthub/pages/habitat/HabitatProjectDetailPage.js.map +1 -1
  19. package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.js +15 -12
  20. package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.js.map +1 -1
  21. package/dist/ecoimpacthub/pages/habitat/LifecycleProgress.js +168 -0
  22. package/dist/ecoimpacthub/pages/habitat/LifecycleProgress.js.map +1 -0
  23. package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.js +30 -17
  24. package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.js.map +1 -1
  25. package/dist/ecoimpacthub/pages/observations/ObservationsPage.js +236 -219
  26. package/dist/ecoimpacthub/pages/observations/ObservationsPage.js.map +1 -1
  27. package/dist/ecoimpacthub/pages/reports/ReportDetailPage.js +248 -212
  28. package/dist/ecoimpacthub/pages/reports/ReportDetailPage.js.map +1 -1
  29. package/dist/ecoimpacthub/pages/reports/ReportsPage.js +119 -118
  30. package/dist/ecoimpacthub/pages/reports/ReportsPage.js.map +1 -1
  31. package/dist/ecoimpacthub/pages/sites/SiteDetailPage.js +498 -370
  32. package/dist/ecoimpacthub/pages/sites/SiteDetailPage.js.map +1 -1
  33. package/dist/ecoimpacthub/pages/sites/SitesPage.js +109 -99
  34. package/dist/ecoimpacthub/pages/sites/SitesPage.js.map +1 -1
  35. package/dist/ecoimpacthub/pages/sites/siteTypeVisuals.js +64 -0
  36. package/dist/ecoimpacthub/pages/sites/siteTypeVisuals.js.map +1 -0
  37. package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.js +275 -259
  38. package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.js.map +1 -1
  39. package/dist/ecoimpacthub/pages/species/SpeciesPage.js +235 -177
  40. package/dist/ecoimpacthub/pages/species/SpeciesPage.js.map +1 -1
  41. package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js +305 -0
  42. package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js.map +1 -0
  43. package/dist/node_modules/recharts/es6/context/chartLayoutContext.js +44 -33
  44. package/dist/node_modules/recharts/es6/context/chartLayoutContext.js.map +1 -1
  45. package/dist/node_modules/recharts/es6/util/ChartUtils.js +31 -23
  46. package/dist/node_modules/recharts/es6/util/ChartUtils.js.map +1 -1
  47. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CarbonPage.js","names":[],"sources":["../../../../src/ecoimpacthub/pages/carbon/CarbonPage.tsx"],"sourcesContent":["/**\n * Carbon & Sustainability — the GHG accounting hub.\n * @module ecoimpacthub/pages/carbon\n *\n * A KPI strip of Scope 1/2/3 + total footprint (from `ecoCarbonTotalKg`) over a\n * three-tab workspace:\n * - Ledger — `ecoListCarbonEntries` (+ `ecoRecordCarbonEntry` / `ecoVerifyCarbonEntry`)\n * - Emission factors — `ecoListEmissionFactors` (+ `ecoCreateEmissionFactor`)\n * - Reduction targets — `ecoListReductionTargets` (+ `ecoCreateReductionTarget`,\n * `ecoSetReductionTargetStatus`)\n *\n * CO₂e (`co2eKg`) is computed server-side from `activityValue × factor`. No mock data.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, Factory, Flame, Zap, Truck, Leaf, Target } 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 { MiniBar } from '../../components/MiniBar';\nimport { DataTable, type Column } from '../../components/DataTable';\nimport { Tabs, type TabItem } from '../../components/Tabs';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Pagination } from '../../components/Pagination';\nimport {\n useEcoSites,\n useEcoCarbonTotals,\n useEcoCarbonEntries,\n useEcoRecordCarbonEntry,\n useEcoVerifyCarbonEntry,\n useEcoEmissionFactors,\n useEcoCreateEmissionFactor,\n useEcoReductionTargets,\n useEcoCreateReductionTarget,\n useEcoSetReductionTargetStatus,\n useCursorPager,\n} from '../../hooks';\nimport { formatCo2e, formatNumber, formatDate, formatEnumLabel } from '../../utils/formatters';\nimport type {\n EcoCarbonEntry,\n EcoCarbonEntryStatus,\n EcoEmissionFactor,\n EcoEmissionScope,\n EcoReductionTarget,\n EcoReductionTargetStatus,\n} from '../../types';\n\ntype CarbonTab = 'ledger' | 'factors' | 'targets';\n\nconst SCOPES: EcoEmissionScope[] = ['SCOPE_1', 'SCOPE_2', 'SCOPE_3'];\nconst CARBON_STATUSES: EcoCarbonEntryStatus[] = ['DRAFT', 'RECORDED', 'VERIFIED', 'ADJUSTED'];\nconst TARGET_STATUSES: EcoReductionTargetStatus[] = [\n 'PROPOSED',\n 'ACTIVE',\n 'ACHIEVED',\n 'MISSED',\n 'RETIRED',\n];\n\nconst PAGE_SIZE = 25;\n\nconst today = (): string => new Date().toISOString().slice(0, 10);\n\ninterface EntryFormState {\n category: string;\n scope: EcoEmissionScope;\n activityValue: string;\n activityUnit: string;\n factorId: string;\n siteId: string;\n periodStart: string;\n notes: string;\n}\n\nconst EMPTY_ENTRY: EntryFormState = {\n category: '',\n scope: 'SCOPE_1',\n activityValue: '',\n activityUnit: '',\n factorId: '',\n siteId: '',\n periodStart: '',\n notes: '',\n};\n\ninterface FactorFormState {\n name: string;\n scope: EcoEmissionScope;\n activityUnit: string;\n factorKgco2e: string;\n source: string;\n validYear: string;\n}\n\nconst EMPTY_FACTOR: FactorFormState = {\n name: '',\n scope: 'SCOPE_1',\n activityUnit: '',\n factorKgco2e: '',\n source: '',\n validYear: '',\n};\n\ninterface TargetFormState {\n name: string;\n metric: string;\n baselineValue: string;\n baselineYear: string;\n targetValue: string;\n targetYear: string;\n unit: string;\n description: string;\n}\n\nconst EMPTY_TARGET: TargetFormState = {\n name: '',\n metric: '',\n baselineValue: '',\n baselineYear: '',\n targetValue: '',\n targetYear: '',\n unit: '',\n description: '',\n};\n\nconst clampPercent = (value: number): number => Math.max(0, Math.min(100, value));\n\nexport function CarbonPage() {\n const [activeTab, setActiveTab] = useState<CarbonTab>('ledger');\n\n // Ledger filters\n const [scope, setScope] = useState<EcoEmissionScope | 'ALL'>('ALL');\n const [entryStatus, setEntryStatus] = useState<EcoCarbonEntryStatus | 'ALL'>('ALL');\n const [ledgerSiteId, setLedgerSiteId] = useState<string>('ALL');\n const ledgerPager = useCursorPager();\n\n // Section filters\n const [factorScope, setFactorScope] = useState<EcoEmissionScope | 'ALL'>('ALL');\n const [targetStatus, setTargetStatus] = useState<EcoReductionTargetStatus | 'ALL'>('ALL');\n\n // Dialog + form state\n const [entryOpen, setEntryOpen] = useState(false);\n const [entryForm, setEntryForm] = useState<EntryFormState>(EMPTY_ENTRY);\n const [factorOpen, setFactorOpen] = useState(false);\n const [factorForm, setFactorForm] = useState<FactorFormState>(EMPTY_FACTOR);\n const [targetOpen, setTargetOpen] = useState(false);\n const [targetForm, setTargetForm] = useState<TargetFormState>(EMPTY_TARGET);\n const [formError, setFormError] = useState<string | null>(null);\n\n // Data\n const sites = useEcoSites({ pagination: { limit: 100, offset: 0 } });\n const siteMap = useMemo<Record<string, string>>(() => {\n const map: Record<string, string> = {};\n for (const s of sites.data?.items ?? []) map[s.id] = s.name;\n return map;\n }, [sites.data]);\n\n const totals = useEcoCarbonTotals();\n\n const entries = useEcoCarbonEntries({\n scope: scope === 'ALL' ? undefined : scope,\n siteId: ledgerSiteId === 'ALL' ? undefined : ledgerSiteId,\n status: entryStatus === 'ALL' ? undefined : entryStatus,\n pagination: { limit: PAGE_SIZE, cursor: ledgerPager.cursor },\n });\n const entryRows = entries.data?.items ?? [];\n\n // Unfiltered factor list — feeds the \"record entry\" factor picker.\n const allFactors = useEcoEmissionFactors();\n const factors = useEcoEmissionFactors(factorScope === 'ALL' ? undefined : factorScope);\n const factorRows = factors.data ?? [];\n\n const targets = useEcoReductionTargets(targetStatus === 'ALL' ? undefined : targetStatus);\n const targetRows = targets.data ?? [];\n\n // Mutations\n const recordEntry = useEcoRecordCarbonEntry();\n const verifyEntry = useEcoVerifyCarbonEntry();\n const createFactor = useEcoCreateEmissionFactor();\n const createTarget = useEcoCreateReductionTarget();\n const setTargetStatusMut = useEcoSetReductionTargetStatus();\n\n const openEntry = () => {\n setEntryForm({ ...EMPTY_ENTRY, periodStart: today() });\n setFormError(null);\n setEntryOpen(true);\n };\n const openFactor = () => {\n setFactorForm(EMPTY_FACTOR);\n setFormError(null);\n setFactorOpen(true);\n };\n const openTarget = () => {\n setTargetForm(EMPTY_TARGET);\n setFormError(null);\n setTargetOpen(true);\n };\n\n const handleRecordEntry = async () => {\n if (!entryForm.category.trim() || !entryForm.activityValue || !entryForm.activityUnit.trim()) {\n setFormError('Category, activity value and unit are required.');\n return;\n }\n setFormError(null);\n try {\n await recordEntry.mutateAsync({\n category: entryForm.category.trim(),\n scope: entryForm.scope,\n activityValue: Number(entryForm.activityValue),\n activityUnit: entryForm.activityUnit.trim(),\n factorId: entryForm.factorId || null,\n siteId: entryForm.siteId || null,\n periodStart: new Date(entryForm.periodStart || today()).toISOString(),\n notes: entryForm.notes.trim() || null,\n });\n setEntryOpen(false);\n setEntryForm(EMPTY_ENTRY);\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to record carbon entry.');\n }\n };\n\n const handleCreateFactor = async () => {\n if (!factorForm.name.trim() || !factorForm.activityUnit.trim() || !factorForm.factorKgco2e) {\n setFormError('Name, activity unit and factor value are required.');\n return;\n }\n setFormError(null);\n try {\n await createFactor.mutateAsync({\n name: factorForm.name.trim(),\n scope: factorForm.scope,\n activityUnit: factorForm.activityUnit.trim(),\n factorKgco2e: Number(factorForm.factorKgco2e),\n source: factorForm.source.trim() || null,\n validYear: factorForm.validYear ? Number(factorForm.validYear) : null,\n });\n setFactorOpen(false);\n setFactorForm(EMPTY_FACTOR);\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create emission factor.');\n }\n };\n\n const handleCreateTarget = async () => {\n if (\n !targetForm.name.trim() ||\n !targetForm.metric.trim() ||\n !targetForm.baselineValue ||\n !targetForm.baselineYear ||\n !targetForm.targetValue ||\n !targetForm.targetYear ||\n !targetForm.unit.trim()\n ) {\n setFormError('All fields except description are required.');\n return;\n }\n setFormError(null);\n try {\n await createTarget.mutateAsync({\n name: targetForm.name.trim(),\n metric: targetForm.metric.trim(),\n baselineValue: Number(targetForm.baselineValue),\n baselineYear: Number(targetForm.baselineYear),\n targetValue: Number(targetForm.targetValue),\n targetYear: Number(targetForm.targetYear),\n unit: targetForm.unit.trim(),\n description: targetForm.description.trim() || null,\n });\n setTargetOpen(false);\n setTargetForm(EMPTY_TARGET);\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create reduction target.');\n }\n };\n\n // ── Columns ───────────────────────────────────────────────────────────────\n const entryColumns: Column<EcoCarbonEntry>[] = [\n {\n key: 'category',\n header: 'Category',\n render: (e) => <span className=\"font-medium text-text-primary\">{e.category}</span>,\n },\n { key: 'scope', header: 'Scope', render: (e) => <StatusBadge status={e.scope} /> },\n {\n key: 'activity',\n header: 'Activity',\n align: 'right',\n hideOnMobile: true,\n sortValue: (e) => e.activityValue,\n render: (e) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatNumber(e.activityValue)} {e.activityUnit}\n </span>\n ),\n },\n {\n key: 'co2e',\n header: 'CO₂e',\n align: 'right',\n sortValue: (e) => e.co2eKg,\n render: (e) => (\n <span className=\"tabular-nums font-medium text-text-primary\">{formatCo2e(e.co2eKg)}</span>\n ),\n },\n { key: 'status', header: 'Status', render: (e) => <StatusBadge status={e.status} /> },\n {\n key: 'period',\n header: 'Period',\n align: 'right',\n hideOnMobile: true,\n render: (e) => <span className=\"text-text-tertiary\">{formatDate(e.periodStart)}</span>,\n },\n {\n key: 'factor',\n header: 'Factor',\n hideOnMobile: true,\n render: (e) => <span className=\"text-text-secondary\">{e.factor?.name ?? '—'}</span>,\n },\n {\n key: 'verify',\n header: '',\n align: 'right',\n render: (e) =>\n e.status !== 'VERIFIED' ? (\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => verifyEntry.mutate(e.id)}\n disabled={verifyEntry.isPending}\n >\n Verify\n </Button>\n ) : null,\n },\n ];\n\n const factorColumns: Column<EcoEmissionFactor>[] = [\n {\n key: 'name',\n header: 'Factor',\n render: (f) => <span className=\"font-medium text-text-primary\">{f.name}</span>,\n },\n { key: 'scope', header: 'Scope', render: (f) => <StatusBadge status={f.scope} /> },\n {\n key: 'value',\n header: 'Emission factor',\n align: 'right',\n hideOnMobile: true,\n sortValue: (f) => f.factorKgco2e,\n render: (f) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatNumber(f.factorKgco2e)} kg/{f.activityUnit}\n </span>\n ),\n },\n {\n key: 'source',\n header: 'Source',\n hideOnMobile: true,\n render: (f) => <span className=\"text-text-secondary\">{f.source ?? '—'}</span>,\n },\n {\n key: 'validYear',\n header: 'Valid year',\n align: 'right',\n hideOnMobile: true,\n render: (f) => <span className=\"tabular-nums text-text-tertiary\">{f.validYear ?? '—'}</span>,\n },\n {\n key: 'active',\n header: 'Active',\n align: 'right',\n render: (f) => (f.isActive ? <StatusBadge status=\"OK\" /> : <StatusBadge status=\"Inactive\" />),\n },\n ];\n\n const targetColumns: Column<EcoReductionTarget>[] = [\n {\n key: 'name',\n header: 'Target',\n render: (t) => <span className=\"font-medium text-text-primary\">{t.name}</span>,\n },\n {\n key: 'metric',\n header: 'Metric',\n hideOnMobile: true,\n render: (t) => <span className=\"text-text-secondary\">{t.metric}</span>,\n },\n {\n key: 'baseline',\n header: 'Baseline',\n hideOnMobile: true,\n render: (t) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatNumber(t.baselineValue)} {t.unit} @{t.baselineYear}\n </span>\n ),\n },\n {\n key: 'target',\n header: 'Target',\n hideOnMobile: true,\n render: (t) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatNumber(t.targetValue)} {t.unit} @{t.targetYear}\n </span>\n ),\n },\n {\n key: 'reduction',\n header: 'Planned reduction',\n render: (t) => {\n const pct =\n t.baselineValue > 0\n ? clampPercent(((t.baselineValue - t.targetValue) / t.baselineValue) * 100)\n : 0;\n return (\n <div className=\"flex min-w-[9rem] items-center gap-2\">\n <MiniBar value={pct} className=\"flex-1\" />\n <span className=\"w-11 shrink-0 text-right text-sm tabular-nums text-text-secondary\">\n {Math.round(pct)}%\n </span>\n </div>\n );\n },\n },\n { key: 'status', header: 'Status', render: (t) => <StatusBadge status={t.status} /> },\n {\n key: 'setStatus',\n header: '',\n align: 'right',\n render: (t) => (\n <Select\n value={t.status}\n onValueChange={(v) =>\n setTargetStatusMut.mutate({ id: t.id, status: v as EcoReductionTargetStatus })\n }\n >\n <SelectTrigger className=\"h-8 w-36\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TARGET_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ),\n },\n ];\n\n const tabs: TabItem<CarbonTab>[] = [\n { value: 'ledger', label: 'Ledger', icon: <Factory className=\"h-4 w-4\" /> },\n {\n value: 'factors',\n label: 'Emission factors',\n icon: <Leaf className=\"h-4 w-4\" />,\n count: factors.data?.length,\n },\n {\n value: 'targets',\n label: 'Reduction targets',\n icon: <Target className=\"h-4 w-4\" />,\n count: targets.data?.length,\n },\n ];\n\n const actionButton =\n activeTab === 'ledger' ? (\n <Button onClick={openEntry}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Record entry\n </Button>\n ) : activeTab === 'factors' ? (\n <Button onClick={openFactor}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New factor\n </Button>\n ) : (\n <Button onClick={openTarget}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New target\n </Button>\n );\n\n return (\n <PageLayout\n title=\"Carbon & Sustainability\"\n description=\"Carbon ledger, emission factors & science-based reduction targets — GHG Protocol Scope 1 / 2 / 3.\"\n actions={actionButton}\n >\n {/* KPI strip */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <MetricsCard\n icon={<Factory className=\"h-5 w-5\" />}\n value={totals.data ? formatCo2e(totals.data.total) : '—'}\n label=\"Total footprint\"\n featured\n />\n <MetricsCard\n icon={<Flame className=\"h-5 w-5\" />}\n value={totals.data ? formatCo2e(totals.data.scope1) : '—'}\n label=\"Scope 1 · Direct\"\n />\n <MetricsCard\n icon={<Zap className=\"h-5 w-5\" />}\n value={totals.data ? formatCo2e(totals.data.scope2) : '—'}\n label=\"Scope 2 · Purchased energy\"\n />\n <MetricsCard\n icon={<Truck className=\"h-5 w-5\" />}\n value={totals.data ? formatCo2e(totals.data.scope3) : '—'}\n label=\"Scope 3 · Value chain\"\n />\n </div>\n\n <div className=\"mt-6\">\n <Tabs items={tabs} value={activeTab} onChange={setActiveTab} />\n </div>\n\n {/* ── Ledger ─────────────────────────────────────────────────────────── */}\n {activeTab === 'ledger' && (\n <div className=\"mt-6\">\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <Select\n value={scope}\n onValueChange={(v) => {\n setScope(v as EcoEmissionScope | 'ALL');\n ledgerPager.reset();\n }}\n >\n <SelectTrigger className=\"w-40\">\n <SelectValue placeholder=\"All scopes\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All scopes</SelectItem>\n {SCOPES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select\n value={entryStatus}\n onValueChange={(v) => {\n setEntryStatus(v as EcoCarbonEntryStatus | 'ALL');\n ledgerPager.reset();\n }}\n >\n <SelectTrigger className=\"w-40\">\n <SelectValue placeholder=\"All statuses\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All statuses</SelectItem>\n {CARBON_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select\n value={ledgerSiteId}\n onValueChange={(v) => {\n setLedgerSiteId(v);\n ledgerPager.reset();\n }}\n >\n <SelectTrigger className=\"w-48\">\n <SelectValue placeholder=\"All sites\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All sites</SelectItem>\n {Object.entries(siteMap).map(([id, name]) => (\n <SelectItem key={id} value={id}>\n {name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {entries.isLoading ? (\n <LoadingView label=\"Loading carbon ledger…\" />\n ) : entries.isError ? (\n <ErrorView message=\"Couldn't load carbon entries.\" onRetry={() => entries.refetch()} />\n ) : entryRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Factory className=\"h-10 w-10\" />}\n title=\"No carbon entries\"\n description={\n scope === 'ALL' && entryStatus === 'ALL' && ledgerSiteId === 'ALL'\n ? 'Record activity to build your Scope 1–3 emissions ledger.'\n : 'No entries match these filters.'\n }\n action={\n <Button onClick={openEntry}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Record entry\n </Button>\n }\n />\n ) : (\n <>\n <DataTable columns={entryColumns} rows={entryRows} rowKey={(e) => e.id} />\n <Pagination\n page={ledgerPager.page}\n pageSize={PAGE_SIZE}\n itemCount={entryRows.length}\n hasMore={entries.data?.pageInfo?.hasMore ?? false}\n onPageChange={(target) =>\n ledgerPager.onPageChange(target, entries.data?.pageInfo?.cursor)\n }\n />\n </>\n )}\n </div>\n )}\n\n {/* ── Emission factors ───────────────────────────────────────────────── */}\n {activeTab === 'factors' && (\n <div className=\"mt-6\">\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <Select\n value={factorScope}\n onValueChange={(v) => setFactorScope(v as EcoEmissionScope | 'ALL')}\n >\n <SelectTrigger className=\"w-40\">\n <SelectValue placeholder=\"All scopes\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All scopes</SelectItem>\n {SCOPES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {factors.isLoading ? (\n <LoadingView label=\"Loading emission factors…\" />\n ) : factors.isError ? (\n <ErrorView\n message=\"Couldn't load emission factors.\"\n onRetry={() => factors.refetch()}\n />\n ) : factorRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Leaf className=\"h-10 w-10\" />}\n title=\"No emission factors\"\n description={\n factorScope === 'ALL'\n ? 'Add emission factors (kg CO₂e per activity unit) to convert activity into CO₂e.'\n : 'No emission factors match this scope.'\n }\n action={\n <Button onClick={openFactor}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New factor\n </Button>\n }\n />\n ) : (\n <DataTable columns={factorColumns} rows={factorRows} rowKey={(f) => f.id} />\n )}\n </div>\n )}\n\n {/* ── Reduction targets ──────────────────────────────────────────────── */}\n {activeTab === 'targets' && (\n <div className=\"mt-6\">\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <Select\n value={targetStatus}\n onValueChange={(v) => setTargetStatus(v as EcoReductionTargetStatus | 'ALL')}\n >\n <SelectTrigger className=\"w-44\">\n <SelectValue placeholder=\"All statuses\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All statuses</SelectItem>\n {TARGET_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {targets.isLoading ? (\n <LoadingView label=\"Loading reduction targets…\" />\n ) : targets.isError ? (\n <ErrorView\n message=\"Couldn't load reduction targets.\"\n onRetry={() => targets.refetch()}\n />\n ) : targetRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Target className=\"h-10 w-10\" />}\n title=\"No reduction targets\"\n description={\n targetStatus === 'ALL'\n ? 'Set science-based reduction targets to track progress against a baseline.'\n : 'No targets match this status.'\n }\n action={\n <Button onClick={openTarget}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New target\n </Button>\n }\n />\n ) : (\n <DataTable columns={targetColumns} rows={targetRows} rowKey={(t) => t.id} />\n )}\n </div>\n )}\n\n {/* Record carbon entry dialog */}\n <ResponsiveDialog\n open={entryOpen}\n onOpenChange={(open) => {\n setEntryOpen(open);\n if (!open) {\n setEntryForm(EMPTY_ENTRY);\n setFormError(null);\n }\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Record carbon entry</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Log an activity — CO₂e is computed server-side from activity value × emission factor.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"ceCategory\">Category *</Label>\n <Input\n id=\"ceCategory\"\n value={entryForm.category}\n onChange={(e) => setEntryForm({ ...entryForm, category: e.target.value })}\n placeholder=\"Diesel generators\"\n />\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"ceScope\">Scope</Label>\n <Select\n value={entryForm.scope}\n onValueChange={(v) =>\n setEntryForm({ ...entryForm, scope: v as EcoEmissionScope })\n }\n >\n <SelectTrigger id=\"ceScope\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SCOPES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"cePeriod\">Period start</Label>\n <Input\n id=\"cePeriod\"\n type=\"date\"\n value={entryForm.periodStart}\n onChange={(e) => setEntryForm({ ...entryForm, periodStart: e.target.value })}\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"ceValue\">Activity value *</Label>\n <Input\n id=\"ceValue\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={entryForm.activityValue}\n onChange={(e) => setEntryForm({ ...entryForm, activityValue: e.target.value })}\n placeholder=\"1200\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"ceUnit\">Activity unit *</Label>\n <Input\n id=\"ceUnit\"\n value={entryForm.activityUnit}\n onChange={(e) => setEntryForm({ ...entryForm, activityUnit: e.target.value })}\n placeholder=\"L, kWh, km\"\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=\"ceFactor\">Emission factor</Label>\n <Select\n value={entryForm.factorId}\n onValueChange={(v) => setEntryForm({ ...entryForm, factorId: v })}\n >\n <SelectTrigger id=\"ceFactor\">\n <SelectValue placeholder=\"Optional\" />\n </SelectTrigger>\n <SelectContent>\n {(allFactors.data ?? []).map((f) => (\n <SelectItem key={f.id} value={f.id}>\n {f.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"ceSite\">Site</Label>\n <Select\n value={entryForm.siteId}\n onValueChange={(v) => setEntryForm({ ...entryForm, siteId: v })}\n >\n <SelectTrigger id=\"ceSite\">\n <SelectValue placeholder=\"Optional\" />\n </SelectTrigger>\n <SelectContent>\n {Object.entries(siteMap).map(([id, name]) => (\n <SelectItem key={id} value={id}>\n {name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"ceNotes\">Notes</Label>\n <Textarea\n id=\"ceNotes\"\n rows={2}\n value={entryForm.notes}\n onChange={(e) => setEntryForm({ ...entryForm, notes: e.target.value })}\n placeholder=\"Optional context about this entry.\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setEntryOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleRecordEntry} disabled={recordEntry.isPending}>\n {recordEntry.isPending ? 'Recording…' : 'Record entry'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n {/* New emission factor dialog */}\n <ResponsiveDialog\n open={factorOpen}\n onOpenChange={(open) => {\n setFactorOpen(open);\n if (!open) {\n setFactorForm(EMPTY_FACTOR);\n setFormError(null);\n }\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New emission factor</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Define kg CO₂e per activity unit — used to convert ledger activity into CO₂e.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"efName\">Name *</Label>\n <Input\n id=\"efName\"\n value={factorForm.name}\n onChange={(e) => setFactorForm({ ...factorForm, name: e.target.value })}\n placeholder=\"Diesel (stationary combustion)\"\n />\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"efScope\">Scope</Label>\n <Select\n value={factorForm.scope}\n onValueChange={(v) =>\n setFactorForm({ ...factorForm, scope: v as EcoEmissionScope })\n }\n >\n <SelectTrigger id=\"efScope\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SCOPES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"efUnit\">Activity unit *</Label>\n <Input\n id=\"efUnit\"\n value={factorForm.activityUnit}\n onChange={(e) => setFactorForm({ ...factorForm, activityUnit: e.target.value })}\n placeholder=\"kWh, L, km\"\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=\"efFactor\">Factor (kg CO₂e / unit) *</Label>\n <Input\n id=\"efFactor\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={factorForm.factorKgco2e}\n onChange={(e) => setFactorForm({ ...factorForm, factorKgco2e: e.target.value })}\n placeholder=\"2.68\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"efYear\">Valid year</Label>\n <Input\n id=\"efYear\"\n type=\"number\"\n step=\"1\"\n value={factorForm.validYear}\n onChange={(e) => setFactorForm({ ...factorForm, validYear: e.target.value })}\n placeholder=\"2026\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"efSource\">Source</Label>\n <Input\n id=\"efSource\"\n value={factorForm.source}\n onChange={(e) => setFactorForm({ ...factorForm, source: e.target.value })}\n placeholder=\"DEFRA / IPCC / EPA\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setFactorOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleCreateFactor} disabled={createFactor.isPending}>\n {createFactor.isPending ? 'Creating…' : 'Create factor'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n {/* New reduction target dialog */}\n <ResponsiveDialog\n open={targetOpen}\n onOpenChange={(open) => {\n setTargetOpen(open);\n if (!open) {\n setTargetForm(EMPTY_TARGET);\n setFormError(null);\n }\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New reduction target</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Commit to a measurable reduction from a baseline to a target year.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"rtName\">Name *</Label>\n <Input\n id=\"rtName\"\n value={targetForm.name}\n onChange={(e) => setTargetForm({ ...targetForm, name: e.target.value })}\n placeholder=\"Net-zero operations\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"rtMetric\">Metric *</Label>\n <Input\n id=\"rtMetric\"\n value={targetForm.metric}\n onChange={(e) => setTargetForm({ ...targetForm, metric: e.target.value })}\n placeholder=\"tCO2e/yr\"\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=\"rtBaseVal\">Baseline value *</Label>\n <Input\n id=\"rtBaseVal\"\n type=\"number\"\n step=\"any\"\n value={targetForm.baselineValue}\n onChange={(e) => setTargetForm({ ...targetForm, baselineValue: e.target.value })}\n placeholder=\"1000\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"rtBaseYear\">Baseline year *</Label>\n <Input\n id=\"rtBaseYear\"\n type=\"number\"\n step=\"1\"\n value={targetForm.baselineYear}\n onChange={(e) => setTargetForm({ ...targetForm, baselineYear: e.target.value })}\n placeholder=\"2024\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"rtUnit\">Unit *</Label>\n <Input\n id=\"rtUnit\"\n value={targetForm.unit}\n onChange={(e) => setTargetForm({ ...targetForm, unit: e.target.value })}\n placeholder=\"tCO2e\"\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=\"rtTargetVal\">Target value *</Label>\n <Input\n id=\"rtTargetVal\"\n type=\"number\"\n step=\"any\"\n value={targetForm.targetValue}\n onChange={(e) => setTargetForm({ ...targetForm, targetValue: e.target.value })}\n placeholder=\"0\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"rtTargetYear\">Target year *</Label>\n <Input\n id=\"rtTargetYear\"\n type=\"number\"\n step=\"1\"\n value={targetForm.targetYear}\n onChange={(e) => setTargetForm({ ...targetForm, targetYear: e.target.value })}\n placeholder=\"2030\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"rtDesc\">Description</Label>\n <Textarea\n id=\"rtDesc\"\n rows={2}\n value={targetForm.description}\n onChange={(e) => setTargetForm({ ...targetForm, description: e.target.value })}\n placeholder=\"Optional context about this target.\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setTargetOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleCreateTarget} disabled={createTarget.isPending}>\n {createTarget.isPending ? 'Creating…' : 'Create target'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CarbonPage.js","names":[],"sources":["../../../../src/ecoimpacthub/pages/carbon/CarbonPage.tsx"],"sourcesContent":["/**\n * Carbon & Sustainability — the GHG accounting hub.\n * @module ecoimpacthub/pages/carbon\n *\n * A KPI strip of Scope 1/2/3 + total footprint (from `ecoCarbonTotalKg`) over a\n * three-tab workspace:\n * - Ledger — `ecoListCarbonEntries` (+ `ecoRecordCarbonEntry` / `ecoVerifyCarbonEntry`)\n * - Emission factors — `ecoListEmissionFactors` (+ `ecoCreateEmissionFactor`)\n * - Reduction targets — `ecoListReductionTargets` (+ `ecoCreateReductionTarget`,\n * `ecoSetReductionTargetStatus`)\n *\n * CO₂e (`co2eKg`) is computed server-side from `activityValue × factor`. No mock data.\n */\n\nimport { useMemo, useState, type ReactNode } from 'react';\nimport { Plus, Factory, Flame, Zap, Truck, Leaf, Target } 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 { Tabs, type TabItem } from '../../components/Tabs';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Pagination } from '../../components/Pagination';\nimport { ScopeSplitBar, Meter, SCOPE_HUE } from '../carbonVisuals';\nimport {\n useEcoSites,\n useEcoCarbonTotals,\n useEcoCarbonEntries,\n useEcoRecordCarbonEntry,\n useEcoVerifyCarbonEntry,\n useEcoEmissionFactors,\n useEcoCreateEmissionFactor,\n useEcoReductionTargets,\n useEcoCreateReductionTarget,\n useEcoSetReductionTargetStatus,\n useCursorPager,\n} from '../../hooks';\nimport {\n formatCo2e,\n formatNumber,\n formatDate,\n formatEnumLabel,\n formatPercent,\n} from '../../utils/formatters';\nimport type {\n EcoCarbonEntry,\n EcoCarbonEntryStatus,\n EcoEmissionFactor,\n EcoEmissionScope,\n EcoReductionTarget,\n EcoReductionTargetStatus,\n} from '../../types';\n\ntype CarbonTab = 'ledger' | 'factors' | 'targets';\n\nconst SCOPES: EcoEmissionScope[] = ['SCOPE_1', 'SCOPE_2', 'SCOPE_3'];\nconst CARBON_STATUSES: EcoCarbonEntryStatus[] = ['DRAFT', 'RECORDED', 'VERIFIED', 'ADJUSTED'];\nconst TARGET_STATUSES: EcoReductionTargetStatus[] = [\n 'PROPOSED',\n 'ACTIVE',\n 'ACHIEVED',\n 'MISSED',\n 'RETIRED',\n];\n\nconst PAGE_SIZE = 25;\n\nconst today = (): string => new Date().toISOString().slice(0, 10);\n\ninterface EntryFormState {\n category: string;\n scope: EcoEmissionScope;\n activityValue: string;\n activityUnit: string;\n factorId: string;\n siteId: string;\n periodStart: string;\n notes: string;\n}\n\nconst EMPTY_ENTRY: EntryFormState = {\n category: '',\n scope: 'SCOPE_1',\n activityValue: '',\n activityUnit: '',\n factorId: '',\n siteId: '',\n periodStart: '',\n notes: '',\n};\n\ninterface FactorFormState {\n name: string;\n scope: EcoEmissionScope;\n activityUnit: string;\n factorKgco2e: string;\n source: string;\n validYear: string;\n}\n\nconst EMPTY_FACTOR: FactorFormState = {\n name: '',\n scope: 'SCOPE_1',\n activityUnit: '',\n factorKgco2e: '',\n source: '',\n validYear: '',\n};\n\ninterface TargetFormState {\n name: string;\n metric: string;\n baselineValue: string;\n baselineYear: string;\n targetValue: string;\n targetYear: string;\n unit: string;\n description: string;\n}\n\nconst EMPTY_TARGET: TargetFormState = {\n name: '',\n metric: '',\n baselineValue: '',\n baselineYear: '',\n targetValue: '',\n targetYear: '',\n unit: '',\n description: '',\n};\n\nconst clampPercent = (value: number): number => Math.max(0, Math.min(100, value));\n\n/** Reduction-target progress meter tint by lifecycle status (semantic tokens). */\nconst TARGET_METER_COLOR: Record<EcoReductionTargetStatus, string> = {\n PROPOSED: 'var(--color-text-tertiary)',\n ACTIVE: 'var(--color-action-primary-bg)',\n ACHIEVED: 'var(--color-status-success-text)',\n MISSED: 'var(--color-status-error-text)',\n RETIRED: 'var(--color-text-tertiary)',\n};\n\n/** KPI-card footer: this scope's share of the total footprint, tinted by scope. */\nconst renderScopeShare = (\n value: number | undefined,\n total: number | undefined,\n scope: EcoEmissionScope\n): ReactNode => {\n if (value == null || total == null || total <= 0) return undefined;\n const pct = (value / total) * 100;\n return (\n <div className=\"space-y-2\">\n <Meter value={pct} color={SCOPE_HUE[scope]} height={4} />\n <p className=\"text-xs tabular-nums text-text-tertiary\">{formatPercent(pct)} of total</p>\n </div>\n );\n};\n\nexport function CarbonPage() {\n const [activeTab, setActiveTab] = useState<CarbonTab>('ledger');\n\n // Ledger filters\n const [scope, setScope] = useState<EcoEmissionScope | 'ALL'>('ALL');\n const [entryStatus, setEntryStatus] = useState<EcoCarbonEntryStatus | 'ALL'>('ALL');\n const [ledgerSiteId, setLedgerSiteId] = useState<string>('ALL');\n const ledgerPager = useCursorPager();\n\n // Section filters\n const [factorScope, setFactorScope] = useState<EcoEmissionScope | 'ALL'>('ALL');\n const [targetStatus, setTargetStatus] = useState<EcoReductionTargetStatus | 'ALL'>('ALL');\n\n // Dialog + form state\n const [entryOpen, setEntryOpen] = useState(false);\n const [entryForm, setEntryForm] = useState<EntryFormState>(EMPTY_ENTRY);\n const [factorOpen, setFactorOpen] = useState(false);\n const [factorForm, setFactorForm] = useState<FactorFormState>(EMPTY_FACTOR);\n const [targetOpen, setTargetOpen] = useState(false);\n const [targetForm, setTargetForm] = useState<TargetFormState>(EMPTY_TARGET);\n const [formError, setFormError] = useState<string | null>(null);\n\n // Data\n const sites = useEcoSites({ pagination: { limit: 100, offset: 0 } });\n const siteMap = useMemo<Record<string, string>>(() => {\n const map: Record<string, string> = {};\n for (const s of sites.data?.items ?? []) map[s.id] = s.name;\n return map;\n }, [sites.data]);\n\n const totals = useEcoCarbonTotals();\n\n const entries = useEcoCarbonEntries({\n scope: scope === 'ALL' ? undefined : scope,\n siteId: ledgerSiteId === 'ALL' ? undefined : ledgerSiteId,\n status: entryStatus === 'ALL' ? undefined : entryStatus,\n pagination: { limit: PAGE_SIZE, cursor: ledgerPager.cursor },\n });\n const entryRows = entries.data?.items ?? [];\n\n // Unfiltered factor list — feeds the \"record entry\" factor picker.\n const allFactors = useEcoEmissionFactors();\n const factors = useEcoEmissionFactors(factorScope === 'ALL' ? undefined : factorScope);\n const factorRows = factors.data ?? [];\n\n const targets = useEcoReductionTargets(targetStatus === 'ALL' ? undefined : targetStatus);\n const targetRows = targets.data ?? [];\n\n // Mutations\n const recordEntry = useEcoRecordCarbonEntry();\n const verifyEntry = useEcoVerifyCarbonEntry();\n const createFactor = useEcoCreateEmissionFactor();\n const createTarget = useEcoCreateReductionTarget();\n const setTargetStatusMut = useEcoSetReductionTargetStatus();\n\n const openEntry = () => {\n setEntryForm({ ...EMPTY_ENTRY, periodStart: today() });\n setFormError(null);\n setEntryOpen(true);\n };\n const openFactor = () => {\n setFactorForm(EMPTY_FACTOR);\n setFormError(null);\n setFactorOpen(true);\n };\n const openTarget = () => {\n setTargetForm(EMPTY_TARGET);\n setFormError(null);\n setTargetOpen(true);\n };\n\n const handleRecordEntry = async () => {\n if (!entryForm.category.trim() || !entryForm.activityValue || !entryForm.activityUnit.trim()) {\n setFormError('Category, activity value and unit are required.');\n return;\n }\n setFormError(null);\n try {\n await recordEntry.mutateAsync({\n category: entryForm.category.trim(),\n scope: entryForm.scope,\n activityValue: Number(entryForm.activityValue),\n activityUnit: entryForm.activityUnit.trim(),\n factorId: entryForm.factorId || null,\n siteId: entryForm.siteId || null,\n periodStart: new Date(entryForm.periodStart || today()).toISOString(),\n notes: entryForm.notes.trim() || null,\n });\n setEntryOpen(false);\n setEntryForm(EMPTY_ENTRY);\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to record carbon entry.');\n }\n };\n\n const handleCreateFactor = async () => {\n if (!factorForm.name.trim() || !factorForm.activityUnit.trim() || !factorForm.factorKgco2e) {\n setFormError('Name, activity unit and factor value are required.');\n return;\n }\n setFormError(null);\n try {\n await createFactor.mutateAsync({\n name: factorForm.name.trim(),\n scope: factorForm.scope,\n activityUnit: factorForm.activityUnit.trim(),\n factorKgco2e: Number(factorForm.factorKgco2e),\n source: factorForm.source.trim() || null,\n validYear: factorForm.validYear ? Number(factorForm.validYear) : null,\n });\n setFactorOpen(false);\n setFactorForm(EMPTY_FACTOR);\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create emission factor.');\n }\n };\n\n const handleCreateTarget = async () => {\n if (\n !targetForm.name.trim() ||\n !targetForm.metric.trim() ||\n !targetForm.baselineValue ||\n !targetForm.baselineYear ||\n !targetForm.targetValue ||\n !targetForm.targetYear ||\n !targetForm.unit.trim()\n ) {\n setFormError('All fields except description are required.');\n return;\n }\n if (Number(targetForm.targetYear) <= Number(targetForm.baselineYear)) {\n setFormError('Target year must be later than the baseline year.');\n return;\n }\n setFormError(null);\n try {\n await createTarget.mutateAsync({\n name: targetForm.name.trim(),\n metric: targetForm.metric.trim(),\n baselineValue: Number(targetForm.baselineValue),\n baselineYear: Number(targetForm.baselineYear),\n targetValue: Number(targetForm.targetValue),\n targetYear: Number(targetForm.targetYear),\n unit: targetForm.unit.trim(),\n description: targetForm.description.trim() || null,\n });\n setTargetOpen(false);\n setTargetForm(EMPTY_TARGET);\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create reduction target.');\n }\n };\n\n // ── Columns ───────────────────────────────────────────────────────────────\n const entryColumns: Column<EcoCarbonEntry>[] = [\n {\n key: 'category',\n header: 'Category',\n render: (e) => <span className=\"font-medium text-text-primary\">{e.category}</span>,\n },\n { key: 'scope', header: 'Scope', render: (e) => <StatusBadge status={e.scope} /> },\n {\n key: 'activity',\n header: 'Activity',\n align: 'right',\n hideOnMobile: true,\n sortValue: (e) => e.activityValue,\n render: (e) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatNumber(e.activityValue)} {e.activityUnit}\n </span>\n ),\n },\n {\n key: 'co2e',\n header: 'CO₂e',\n align: 'right',\n sortValue: (e) => e.co2eKg,\n render: (e) => (\n <span className=\"tabular-nums font-medium text-text-primary\">{formatCo2e(e.co2eKg)}</span>\n ),\n },\n { key: 'status', header: 'Status', render: (e) => <StatusBadge status={e.status} /> },\n {\n key: 'period',\n header: 'Period',\n align: 'right',\n hideOnMobile: true,\n render: (e) => <span className=\"text-text-tertiary\">{formatDate(e.periodStart)}</span>,\n },\n {\n key: 'factor',\n header: 'Factor',\n hideOnMobile: true,\n render: (e) => <span className=\"text-text-secondary\">{e.factor?.name ?? '—'}</span>,\n },\n {\n key: 'verify',\n header: '',\n align: 'right',\n render: (e) =>\n e.status !== 'VERIFIED' ? (\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => verifyEntry.mutate(e.id)}\n disabled={verifyEntry.isPending}\n >\n Verify\n </Button>\n ) : null,\n },\n ];\n\n const factorColumns: Column<EcoEmissionFactor>[] = [\n {\n key: 'name',\n header: 'Factor',\n render: (f) => <span className=\"font-medium text-text-primary\">{f.name}</span>,\n },\n { key: 'scope', header: 'Scope', render: (f) => <StatusBadge status={f.scope} /> },\n {\n key: 'value',\n header: 'Emission factor',\n align: 'right',\n hideOnMobile: true,\n sortValue: (f) => f.factorKgco2e,\n render: (f) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatNumber(f.factorKgco2e)} kg/{f.activityUnit}\n </span>\n ),\n },\n {\n key: 'source',\n header: 'Source',\n hideOnMobile: true,\n render: (f) => <span className=\"text-text-secondary\">{f.source ?? '—'}</span>,\n },\n {\n key: 'validYear',\n header: 'Valid year',\n align: 'right',\n hideOnMobile: true,\n render: (f) => <span className=\"tabular-nums text-text-tertiary\">{f.validYear ?? '—'}</span>,\n },\n {\n key: 'active',\n header: 'Active',\n align: 'right',\n render: (f) => (f.isActive ? <StatusBadge status=\"OK\" /> : <StatusBadge status=\"Inactive\" />),\n },\n ];\n\n const targetColumns: Column<EcoReductionTarget>[] = [\n {\n key: 'name',\n header: 'Target',\n render: (t) => <span className=\"font-medium text-text-primary\">{t.name}</span>,\n },\n {\n key: 'metric',\n header: 'Metric',\n hideOnMobile: true,\n render: (t) => <span className=\"text-text-secondary\">{t.metric}</span>,\n },\n {\n key: 'baseline',\n header: 'Baseline',\n hideOnMobile: true,\n render: (t) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatNumber(t.baselineValue)} {t.unit} @{t.baselineYear}\n </span>\n ),\n },\n {\n key: 'target',\n header: 'Target',\n hideOnMobile: true,\n render: (t) => (\n <span className=\"tabular-nums text-text-secondary\">\n {formatNumber(t.targetValue)} {t.unit} @{t.targetYear}\n </span>\n ),\n },\n {\n key: 'reduction',\n header: 'Planned reduction',\n render: (t) => {\n const pct =\n t.baselineValue > 0\n ? clampPercent(((t.baselineValue - t.targetValue) / t.baselineValue) * 100)\n : 0;\n return (\n <div className=\"flex min-w-[10rem] items-center gap-3\">\n <Meter\n value={pct}\n color={TARGET_METER_COLOR[t.status] ?? 'var(--color-action-primary-bg)'}\n height={8}\n className=\"flex-1\"\n />\n <span className=\"w-11 shrink-0 text-right text-sm font-semibold tabular-nums text-text-primary\">\n {Math.round(pct)}%\n </span>\n </div>\n );\n },\n },\n { key: 'status', header: 'Status', render: (t) => <StatusBadge status={t.status} /> },\n {\n key: 'setStatus',\n header: '',\n align: 'right',\n render: (t) => (\n <Select\n value={t.status}\n onValueChange={(v) =>\n setTargetStatusMut.mutate({ id: t.id, status: v as EcoReductionTargetStatus })\n }\n >\n <SelectTrigger className=\"h-8 w-36\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TARGET_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ),\n },\n ];\n\n const tabs: TabItem<CarbonTab>[] = [\n { value: 'ledger', label: 'Ledger', icon: <Factory className=\"h-4 w-4\" /> },\n {\n value: 'factors',\n label: 'Emission factors',\n icon: <Leaf className=\"h-4 w-4\" />,\n count: factors.data?.length,\n },\n {\n value: 'targets',\n label: 'Reduction targets',\n icon: <Target className=\"h-4 w-4\" />,\n count: targets.data?.length,\n },\n ];\n\n const actionButton =\n activeTab === 'ledger' ? (\n <Button onClick={openEntry}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Record entry\n </Button>\n ) : activeTab === 'factors' ? (\n <Button onClick={openFactor}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New factor\n </Button>\n ) : (\n <Button onClick={openTarget}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New target\n </Button>\n );\n\n return (\n <PageLayout\n title=\"Carbon & Sustainability\"\n description=\"Carbon ledger, emission factors & science-based reduction targets — GHG Protocol Scope 1 / 2 / 3.\"\n actions={actionButton}\n >\n {/* KPI strip */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <MetricsCard\n icon={<Factory className=\"h-5 w-5\" />}\n value={totals.data ? formatCo2e(totals.data.total) : '—'}\n label=\"Total footprint\"\n featured\n footer={\n totals.data && totals.data.total > 0 ? (\n <div className=\"space-y-2\">\n <ScopeSplitBar\n scope1={totals.data.scope1}\n scope2={totals.data.scope2}\n scope3={totals.data.scope3}\n height={6}\n />\n <p className=\"text-xs text-text-tertiary\">Scope 1 · 2 · 3 split</p>\n </div>\n ) : undefined\n }\n />\n <MetricsCard\n icon={<Flame className=\"h-5 w-5\" />}\n value={totals.data ? formatCo2e(totals.data.scope1) : '—'}\n label=\"Scope 1 · Direct\"\n footer={renderScopeShare(totals.data?.scope1, totals.data?.total, 'SCOPE_1')}\n />\n <MetricsCard\n icon={<Zap className=\"h-5 w-5\" />}\n value={totals.data ? formatCo2e(totals.data.scope2) : '—'}\n label=\"Scope 2 · Purchased energy\"\n footer={renderScopeShare(totals.data?.scope2, totals.data?.total, 'SCOPE_2')}\n />\n <MetricsCard\n icon={<Truck className=\"h-5 w-5\" />}\n value={totals.data ? formatCo2e(totals.data.scope3) : '—'}\n label=\"Scope 3 · Value chain\"\n footer={renderScopeShare(totals.data?.scope3, totals.data?.total, 'SCOPE_3')}\n />\n </div>\n\n <div className=\"mt-6\">\n <Tabs items={tabs} value={activeTab} onChange={setActiveTab} />\n </div>\n\n {/* ── Ledger ─────────────────────────────────────────────────────────── */}\n {activeTab === 'ledger' && (\n <div className=\"mt-6\">\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <Select\n value={scope}\n onValueChange={(v) => {\n setScope(v as EcoEmissionScope | 'ALL');\n ledgerPager.reset();\n }}\n >\n <SelectTrigger className=\"w-40\">\n <SelectValue placeholder=\"All scopes\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All scopes</SelectItem>\n {SCOPES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select\n value={entryStatus}\n onValueChange={(v) => {\n setEntryStatus(v as EcoCarbonEntryStatus | 'ALL');\n ledgerPager.reset();\n }}\n >\n <SelectTrigger className=\"w-40\">\n <SelectValue placeholder=\"All statuses\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All statuses</SelectItem>\n {CARBON_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select\n value={ledgerSiteId}\n onValueChange={(v) => {\n setLedgerSiteId(v);\n ledgerPager.reset();\n }}\n >\n <SelectTrigger className=\"w-48\">\n <SelectValue placeholder=\"All sites\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All sites</SelectItem>\n {Object.entries(siteMap).map(([id, name]) => (\n <SelectItem key={id} value={id}>\n {name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {entries.isLoading ? (\n <LoadingView label=\"Loading carbon ledger…\" />\n ) : entries.isError ? (\n <ErrorView message=\"Couldn't load carbon entries.\" onRetry={() => entries.refetch()} />\n ) : entryRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Factory className=\"h-10 w-10\" />}\n title=\"No carbon entries\"\n description={\n scope === 'ALL' && entryStatus === 'ALL' && ledgerSiteId === 'ALL'\n ? 'Record activity to build your Scope 1–3 emissions ledger.'\n : 'No entries match these filters.'\n }\n action={\n <Button onClick={openEntry}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Record entry\n </Button>\n }\n />\n ) : (\n <>\n <DataTable columns={entryColumns} rows={entryRows} rowKey={(e) => e.id} />\n <Pagination\n page={ledgerPager.page}\n pageSize={PAGE_SIZE}\n itemCount={entryRows.length}\n hasMore={entries.data?.pageInfo?.hasMore ?? false}\n onPageChange={(target) =>\n ledgerPager.onPageChange(target, entries.data?.pageInfo?.cursor)\n }\n />\n </>\n )}\n </div>\n )}\n\n {/* ── Emission factors ───────────────────────────────────────────────── */}\n {activeTab === 'factors' && (\n <div className=\"mt-6\">\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <Select\n value={factorScope}\n onValueChange={(v) => setFactorScope(v as EcoEmissionScope | 'ALL')}\n >\n <SelectTrigger className=\"w-40\">\n <SelectValue placeholder=\"All scopes\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All scopes</SelectItem>\n {SCOPES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {factors.isLoading ? (\n <LoadingView label=\"Loading emission factors…\" />\n ) : factors.isError ? (\n <ErrorView\n message=\"Couldn't load emission factors.\"\n onRetry={() => factors.refetch()}\n />\n ) : factorRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Leaf className=\"h-10 w-10\" />}\n title=\"No emission factors\"\n description={\n factorScope === 'ALL'\n ? 'Add emission factors (kg CO₂e per activity unit) to convert activity into CO₂e.'\n : 'No emission factors match this scope.'\n }\n action={\n <Button onClick={openFactor}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New factor\n </Button>\n }\n />\n ) : (\n <DataTable columns={factorColumns} rows={factorRows} rowKey={(f) => f.id} />\n )}\n </div>\n )}\n\n {/* ── Reduction targets ──────────────────────────────────────────────── */}\n {activeTab === 'targets' && (\n <div className=\"mt-6\">\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <Select\n value={targetStatus}\n onValueChange={(v) => setTargetStatus(v as EcoReductionTargetStatus | 'ALL')}\n >\n <SelectTrigger className=\"w-44\">\n <SelectValue placeholder=\"All statuses\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All statuses</SelectItem>\n {TARGET_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {targets.isLoading ? (\n <LoadingView label=\"Loading reduction targets…\" />\n ) : targets.isError ? (\n <ErrorView\n message=\"Couldn't load reduction targets.\"\n onRetry={() => targets.refetch()}\n />\n ) : targetRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Target className=\"h-10 w-10\" />}\n title=\"No reduction targets\"\n description={\n targetStatus === 'ALL'\n ? 'Set science-based reduction targets to track progress against a baseline.'\n : 'No targets match this status.'\n }\n action={\n <Button onClick={openTarget}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New target\n </Button>\n }\n />\n ) : (\n <DataTable columns={targetColumns} rows={targetRows} rowKey={(t) => t.id} />\n )}\n </div>\n )}\n\n {/* Record carbon entry dialog */}\n <ResponsiveDialog\n open={entryOpen}\n onOpenChange={(open) => {\n setEntryOpen(open);\n if (!open) {\n setEntryForm(EMPTY_ENTRY);\n setFormError(null);\n }\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Record carbon entry</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Log an activity — CO₂e is computed server-side from activity value × emission factor.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"ceCategory\">Category *</Label>\n <Input\n id=\"ceCategory\"\n value={entryForm.category}\n onChange={(e) => setEntryForm({ ...entryForm, category: e.target.value })}\n placeholder=\"Diesel generators\"\n />\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"ceScope\">Scope</Label>\n <Select\n value={entryForm.scope}\n onValueChange={(v) =>\n setEntryForm({ ...entryForm, scope: v as EcoEmissionScope })\n }\n >\n <SelectTrigger id=\"ceScope\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SCOPES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"cePeriod\">Period start</Label>\n <Input\n id=\"cePeriod\"\n type=\"date\"\n value={entryForm.periodStart}\n onChange={(e) => setEntryForm({ ...entryForm, periodStart: e.target.value })}\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"ceValue\">Activity value *</Label>\n <Input\n id=\"ceValue\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={entryForm.activityValue}\n onChange={(e) => setEntryForm({ ...entryForm, activityValue: e.target.value })}\n placeholder=\"1200\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"ceUnit\">Activity unit *</Label>\n <Input\n id=\"ceUnit\"\n value={entryForm.activityUnit}\n onChange={(e) => setEntryForm({ ...entryForm, activityUnit: e.target.value })}\n placeholder=\"L, kWh, km\"\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=\"ceFactor\">Emission factor</Label>\n <Select\n value={entryForm.factorId}\n onValueChange={(v) => setEntryForm({ ...entryForm, factorId: v })}\n >\n <SelectTrigger id=\"ceFactor\">\n <SelectValue placeholder=\"Optional\" />\n </SelectTrigger>\n <SelectContent>\n {(allFactors.data ?? []).map((f) => (\n <SelectItem key={f.id} value={f.id}>\n {f.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"ceSite\">Site</Label>\n <Select\n value={entryForm.siteId}\n onValueChange={(v) => setEntryForm({ ...entryForm, siteId: v })}\n >\n <SelectTrigger id=\"ceSite\">\n <SelectValue placeholder=\"Optional\" />\n </SelectTrigger>\n <SelectContent>\n {Object.entries(siteMap).map(([id, name]) => (\n <SelectItem key={id} value={id}>\n {name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"ceNotes\">Notes</Label>\n <Textarea\n id=\"ceNotes\"\n rows={2}\n value={entryForm.notes}\n onChange={(e) => setEntryForm({ ...entryForm, notes: e.target.value })}\n placeholder=\"Optional context about this entry.\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setEntryOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleRecordEntry} disabled={recordEntry.isPending}>\n {recordEntry.isPending ? 'Recording…' : 'Record entry'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n {/* New emission factor dialog */}\n <ResponsiveDialog\n open={factorOpen}\n onOpenChange={(open) => {\n setFactorOpen(open);\n if (!open) {\n setFactorForm(EMPTY_FACTOR);\n setFormError(null);\n }\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New emission factor</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Define kg CO₂e per activity unit — used to convert ledger activity into CO₂e.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"efName\">Name *</Label>\n <Input\n id=\"efName\"\n value={factorForm.name}\n onChange={(e) => setFactorForm({ ...factorForm, name: e.target.value })}\n placeholder=\"Diesel (stationary combustion)\"\n />\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"efScope\">Scope</Label>\n <Select\n value={factorForm.scope}\n onValueChange={(v) =>\n setFactorForm({ ...factorForm, scope: v as EcoEmissionScope })\n }\n >\n <SelectTrigger id=\"efScope\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SCOPES.map((s) => (\n <SelectItem key={s} value={s}>\n {formatEnumLabel(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"efUnit\">Activity unit *</Label>\n <Input\n id=\"efUnit\"\n value={factorForm.activityUnit}\n onChange={(e) => setFactorForm({ ...factorForm, activityUnit: e.target.value })}\n placeholder=\"kWh, L, km\"\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=\"efFactor\">Factor (kg CO₂e / unit) *</Label>\n <Input\n id=\"efFactor\"\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={factorForm.factorKgco2e}\n onChange={(e) => setFactorForm({ ...factorForm, factorKgco2e: e.target.value })}\n placeholder=\"2.68\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"efYear\">Valid year</Label>\n <Input\n id=\"efYear\"\n type=\"number\"\n step=\"1\"\n value={factorForm.validYear}\n onChange={(e) => setFactorForm({ ...factorForm, validYear: e.target.value })}\n placeholder=\"2026\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"efSource\">Source</Label>\n <Input\n id=\"efSource\"\n value={factorForm.source}\n onChange={(e) => setFactorForm({ ...factorForm, source: e.target.value })}\n placeholder=\"DEFRA / IPCC / EPA\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setFactorOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleCreateFactor} disabled={createFactor.isPending}>\n {createFactor.isPending ? 'Creating…' : 'Create factor'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n {/* New reduction target dialog */}\n <ResponsiveDialog\n open={targetOpen}\n onOpenChange={(open) => {\n setTargetOpen(open);\n if (!open) {\n setTargetForm(EMPTY_TARGET);\n setFormError(null);\n }\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New reduction target</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Commit to a measurable reduction from a baseline to a target year.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"rtName\">Name *</Label>\n <Input\n id=\"rtName\"\n value={targetForm.name}\n onChange={(e) => setTargetForm({ ...targetForm, name: e.target.value })}\n placeholder=\"Net-zero operations\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"rtMetric\">Metric *</Label>\n <Input\n id=\"rtMetric\"\n value={targetForm.metric}\n onChange={(e) => setTargetForm({ ...targetForm, metric: e.target.value })}\n placeholder=\"tCO2e/yr\"\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=\"rtBaseVal\">Baseline value *</Label>\n <Input\n id=\"rtBaseVal\"\n type=\"number\"\n step=\"any\"\n value={targetForm.baselineValue}\n onChange={(e) => setTargetForm({ ...targetForm, baselineValue: e.target.value })}\n placeholder=\"1000\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"rtBaseYear\">Baseline year *</Label>\n <Input\n id=\"rtBaseYear\"\n type=\"number\"\n step=\"1\"\n value={targetForm.baselineYear}\n onChange={(e) => setTargetForm({ ...targetForm, baselineYear: e.target.value })}\n placeholder=\"2024\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"rtUnit\">Unit *</Label>\n <Input\n id=\"rtUnit\"\n value={targetForm.unit}\n onChange={(e) => setTargetForm({ ...targetForm, unit: e.target.value })}\n placeholder=\"tCO2e\"\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=\"rtTargetVal\">Target value *</Label>\n <Input\n id=\"rtTargetVal\"\n type=\"number\"\n step=\"any\"\n value={targetForm.targetValue}\n onChange={(e) => setTargetForm({ ...targetForm, targetValue: e.target.value })}\n placeholder=\"0\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"rtTargetYear\">Target year *</Label>\n <Input\n id=\"rtTargetYear\"\n type=\"number\"\n step=\"1\"\n value={targetForm.targetYear}\n onChange={(e) => setTargetForm({ ...targetForm, targetYear: e.target.value })}\n placeholder=\"2030\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"rtDesc\">Description</Label>\n <Textarea\n id=\"rtDesc\"\n rows={2}\n value={targetForm.description}\n onChange={(e) => setTargetForm({ ...targetForm, description: e.target.value })}\n placeholder=\"Optional context about this target.\"\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setTargetOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleCreateTarget} disabled={createTarget.isPending}>\n {createTarget.isPending ? 'Creating…' : 'Create target'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ import { cn as e } from "../utils/cn.js";
2
+ import { formatCo2e as t } from "../utils/formatters.js";
3
+ import { jsx as n, jsxs as r } from "react/jsx-runtime";
4
+ //#region src/ecoimpacthub/pages/carbonVisuals.tsx
5
+ var i = {
6
+ SCOPE_1: "var(--color-accent-teal)",
7
+ SCOPE_2: "var(--color-chart-positive)",
8
+ SCOPE_3: "var(--color-status-success-text)"
9
+ }, a = {
10
+ SCOPE_1: "Scope 1",
11
+ SCOPE_2: "Scope 2",
12
+ SCOPE_3: "Scope 3"
13
+ }, o = [
14
+ "SCOPE_1",
15
+ "SCOPE_2",
16
+ "SCOPE_3"
17
+ ], s = ({ value: t, color: r, className: i, height: a = 6 }) => {
18
+ let o = Math.max(0, Math.min(100, t));
19
+ return /* @__PURE__ */ n("div", {
20
+ className: e("w-full overflow-hidden rounded-full bg-bg-sunken", i),
21
+ style: { height: a },
22
+ role: "progressbar",
23
+ "aria-valuenow": Math.round(o),
24
+ "aria-valuemin": 0,
25
+ "aria-valuemax": 100,
26
+ children: /* @__PURE__ */ n("div", {
27
+ className: "h-full rounded-full transition-[width] duration-700 ease-out",
28
+ style: {
29
+ width: `${o}%`,
30
+ backgroundColor: r
31
+ }
32
+ })
33
+ });
34
+ }, c = ({ scope1: r, scope2: a, scope3: o, className: s, height: c = 8 }) => {
35
+ let l = [
36
+ {
37
+ scope: "SCOPE_1",
38
+ value: Math.max(0, r)
39
+ },
40
+ {
41
+ scope: "SCOPE_2",
42
+ value: Math.max(0, a)
43
+ },
44
+ {
45
+ scope: "SCOPE_3",
46
+ value: Math.max(0, o)
47
+ }
48
+ ], u = l.reduce((e, t) => e + t.value, 0);
49
+ return /* @__PURE__ */ n("div", {
50
+ className: e("flex w-full overflow-hidden rounded-full bg-bg-sunken", s),
51
+ style: { height: c },
52
+ role: "img",
53
+ "aria-label": `Footprint split — Scope 1 ${t(r)}, Scope 2 ${t(a)}, Scope 3 ${t(o)}`,
54
+ children: u > 0 && l.map((e) => e.value > 0 ? /* @__PURE__ */ n("div", {
55
+ className: "h-full transition-[width] duration-700 ease-out first:rounded-l-full last:rounded-r-full",
56
+ style: {
57
+ width: `${e.value / u * 100}%`,
58
+ backgroundColor: i[e.scope]
59
+ }
60
+ }, e.scope) : null)
61
+ });
62
+ }, l = ({ data: s, className: c }) => /* @__PURE__ */ n("div", {
63
+ className: e("flex flex-wrap items-center gap-x-6 gap-y-2", c),
64
+ children: o.map((e) => {
65
+ let o = s.find((t) => t.scope === e);
66
+ return /* @__PURE__ */ r("div", {
67
+ className: "flex items-center gap-2",
68
+ children: [
69
+ /* @__PURE__ */ n("span", {
70
+ "aria-hidden": "true",
71
+ className: "size-2.5 shrink-0 rounded-full",
72
+ style: { backgroundColor: i[e] }
73
+ }),
74
+ /* @__PURE__ */ n("span", {
75
+ className: "text-xs font-medium text-text-secondary",
76
+ children: a[e]
77
+ }),
78
+ /* @__PURE__ */ n("span", {
79
+ className: "text-xs tabular-nums text-text-tertiary",
80
+ children: o ? t(o.kg) : "—"
81
+ })
82
+ ]
83
+ }, e);
84
+ })
85
+ });
86
+ //#endregion
87
+ export { s as Meter, i as SCOPE_HUE, l as ScopeLegend, c as ScopeSplitBar };
88
+
89
+ //# sourceMappingURL=carbonVisuals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"carbonVisuals.js","names":[],"sources":["../../../src/ecoimpacthub/pages/carbonVisuals.tsx"],"sourcesContent":["/**\n * Shared carbon-scope visual helpers for the EcoImpactHub Dashboard & Carbon\n * pages.\n * @module ecoimpacthub/pages\n *\n * A single, on-brand emerald → teal scale so scope *magnitudes* read as one\n * cohesive system across the footprint chart, the featured KPI split bar and the\n * per-scope share meters. Categorical scope *tags* keep StatusBadge's semantic\n * colours (red / amber / blue) — these hues encode quantity only. All tokens\n * resolve to a green/teal family across every Boff theme, so nothing is a raw\n * colour. No mock data — every value passed in comes from the real `eco*`\n * aggregates.\n */\n\nimport type { FC } from 'react';\nimport { cn } from '../utils/cn';\nimport { formatCo2e } from '../utils/formatters';\nimport type { EcoEmissionScope } from '../types';\n\n/**\n * Graduated teal → emerald scale. Every token here resolves to a green/teal in\n * ALL Boff themes (accent-teal is always teal; chart-positive + success-text are\n * always the \"positive\" green), so the footprint palette never drifts to the\n * brand-variable blue/purple that `chart-1` / `action-primary-bg` can take.\n */\nexport const SCOPE_HUE: Record<EcoEmissionScope, string> = {\n SCOPE_1: 'var(--color-accent-teal)',\n SCOPE_2: 'var(--color-chart-positive)',\n SCOPE_3: 'var(--color-status-success-text)',\n};\n\nexport const SCOPE_LABEL: Record<EcoEmissionScope, string> = {\n SCOPE_1: 'Scope 1',\n SCOPE_2: 'Scope 2',\n SCOPE_3: 'Scope 3',\n};\n\nexport const SCOPE_ORDER: EcoEmissionScope[] = ['SCOPE_1', 'SCOPE_2', 'SCOPE_3'];\n\n// ── Meter ────────────────────────────────────────────────────────────────────\n\ninterface MeterProps {\n /** 0–100. */\n value: number;\n /** Fill colour — a semantic token `var(--color-*)` string. */\n color: string;\n className?: string;\n /** Height in px. */\n height?: number;\n}\n\n/**\n * A thin rounded progress meter whose fill colour is an arbitrary semantic\n * token (unlike the class-based {@link MiniBar}). Used for per-scope share and\n * reduction-target progress so the fill can be tinted by scope / status.\n */\nexport const Meter: FC<MeterProps> = ({ value, color, className, height = 6 }) => {\n const clamped = Math.max(0, Math.min(100, value));\n return (\n <div\n className={cn('w-full overflow-hidden rounded-full bg-bg-sunken', className)}\n style={{ height }}\n role=\"progressbar\"\n aria-valuenow={Math.round(clamped)}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div\n className=\"h-full rounded-full transition-[width] duration-700 ease-out\"\n style={{ width: `${clamped}%`, backgroundColor: color }}\n />\n </div>\n );\n};\n\n// ── ScopeSplitBar ──────────────────────────────────────────────────────────────\n\ninterface ScopeSplitBarProps {\n scope1: number;\n scope2: number;\n scope3: number;\n className?: string;\n height?: number;\n}\n\n/** A single thin rounded meter that splits the total footprint into 3 scopes. */\nexport const ScopeSplitBar: FC<ScopeSplitBarProps> = ({\n scope1,\n scope2,\n scope3,\n className,\n height = 8,\n}) => {\n const segments: { scope: EcoEmissionScope; value: number }[] = [\n { scope: 'SCOPE_1', value: Math.max(0, scope1) },\n { scope: 'SCOPE_2', value: Math.max(0, scope2) },\n { scope: 'SCOPE_3', value: Math.max(0, scope3) },\n ];\n const total = segments.reduce((sum, s) => sum + s.value, 0);\n\n return (\n <div\n className={cn('flex w-full overflow-hidden rounded-full bg-bg-sunken', className)}\n style={{ height }}\n role=\"img\"\n aria-label={`Footprint split — Scope 1 ${formatCo2e(scope1)}, Scope 2 ${formatCo2e(\n scope2\n )}, Scope 3 ${formatCo2e(scope3)}`}\n >\n {total > 0 &&\n segments.map((seg) =>\n seg.value > 0 ? (\n <div\n key={seg.scope}\n className=\"h-full transition-[width] duration-700 ease-out first:rounded-l-full last:rounded-r-full\"\n style={{\n width: `${(seg.value / total) * 100}%`,\n backgroundColor: SCOPE_HUE[seg.scope],\n }}\n />\n ) : null\n )}\n </div>\n );\n};\n\n// ── ScopeLegend ────────────────────────────────────────────────────────────────\n\ninterface ScopeLegendProps {\n data: { scope: EcoEmissionScope; kg: number }[];\n className?: string;\n}\n\n/** Colour-swatch legend + per-scope value shown beneath the footprint chart. */\nexport const ScopeLegend: FC<ScopeLegendProps> = ({ data, className }) => (\n <div className={cn('flex flex-wrap items-center gap-x-6 gap-y-2', className)}>\n {SCOPE_ORDER.map((scope) => {\n const row = data.find((d) => d.scope === scope);\n return (\n <div key={scope} className=\"flex items-center gap-2\">\n <span\n aria-hidden=\"true\"\n className=\"size-2.5 shrink-0 rounded-full\"\n style={{ backgroundColor: SCOPE_HUE[scope] }}\n />\n <span className=\"text-xs font-medium text-text-secondary\">{SCOPE_LABEL[scope]}</span>\n <span className=\"text-xs tabular-nums text-text-tertiary\">\n {row ? formatCo2e(row.kg) : '—'}\n </span>\n </div>\n );\n })}\n </div>\n);\n"],"mappings":";;;;AAyBA,IAAa,IAA8C;CACzD,SAAS;CACT,SAAS;CACT,SAAS;CACV,EAEY,IAAgD;CAC3D,SAAS;CACT,SAAS;CACT,SAAS;CACV,EAEY,IAAkC;CAAC;CAAW;CAAW;CAAU,EAmBnE,KAAyB,EAAE,UAAO,UAAO,cAAW,YAAS,QAAQ;CAChF,IAAM,IAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,EAAM,CAAC;AACjD,QACE,kBAAC,OAAD;EACE,WAAW,EAAG,oDAAoD,EAAU;EAC5E,OAAO,EAAE,WAAQ;EACjB,MAAK;EACL,iBAAe,KAAK,MAAM,EAAQ;EAClC,iBAAe;EACf,iBAAe;YAEf,kBAAC,OAAD;GACE,WAAU;GACV,OAAO;IAAE,OAAO,GAAG,EAAQ;IAAI,iBAAiB;IAAO;GACvD,CAAA;EACE,CAAA;GAeG,KAAyC,EACpD,WACA,WACA,WACA,cACA,YAAS,QACL;CACJ,IAAM,IAAyD;EAC7D;GAAE,OAAO;GAAW,OAAO,KAAK,IAAI,GAAG,EAAO;GAAE;EAChD;GAAE,OAAO;GAAW,OAAO,KAAK,IAAI,GAAG,EAAO;GAAE;EAChD;GAAE,OAAO;GAAW,OAAO,KAAK,IAAI,GAAG,EAAO;GAAE;EACjD,EACK,IAAQ,EAAS,QAAQ,GAAK,MAAM,IAAM,EAAE,OAAO,EAAE;AAE3D,QACE,kBAAC,OAAD;EACE,WAAW,EAAG,yDAAyD,EAAU;EACjF,OAAO,EAAE,WAAQ;EACjB,MAAK;EACL,cAAY,6BAA6B,EAAW,EAAO,CAAC,YAAY,EACtE,EACD,CAAC,YAAY,EAAW,EAAO;YAE/B,IAAQ,KACP,EAAS,KAAK,MACZ,EAAI,QAAQ,IACV,kBAAC,OAAD;GAEE,WAAU;GACV,OAAO;IACL,OAAO,GAAI,EAAI,QAAQ,IAAS,IAAI;IACpC,iBAAiB,EAAU,EAAI;IAChC;GACD,EANK,EAAI,MAMT,GACA,KACL;EACC,CAAA;GAYG,KAAqC,EAAE,SAAM,mBACxD,kBAAC,OAAD;CAAK,WAAW,EAAG,+CAA+C,EAAU;WACzE,EAAY,KAAK,MAAU;EAC1B,IAAM,IAAM,EAAK,MAAM,MAAM,EAAE,UAAU,EAAM;AAC/C,SACE,kBAAC,OAAD;GAAiB,WAAU;aAA3B;IACE,kBAAC,QAAD;KACE,eAAY;KACZ,WAAU;KACV,OAAO,EAAE,iBAAiB,EAAU,IAAQ;KAC5C,CAAA;IACF,kBAAC,QAAD;KAAM,WAAU;eAA2C,EAAY;KAAc,CAAA;IACrF,kBAAC,QAAD;KAAM,WAAU;eACb,IAAM,EAAW,EAAI,GAAG,GAAG;KACvB,CAAA;IACH;KAVI,EAUJ;GAER;CACE,CAAA"}