@burdenoff/microfe-ecoimpacthub 2026.720.1 → 2026.720.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.d.ts +5 -5
- package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.d.ts.map +1 -1
- package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.js +20 -5
- package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.js.map +1 -1
- package/dist/ecoimpacthub/pages/DashboardPage.js +1 -1
- package/dist/ecoimpacthub/pages/DashboardPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.js +4 -4
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.d.ts +1 -1
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.js +1 -1
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.js +5 -5
- package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -18,7 +18,7 @@ export interface SensorFilters {
|
|
|
18
18
|
kind?: EcoSensorKind;
|
|
19
19
|
status?: EcoSensorStatus;
|
|
20
20
|
}
|
|
21
|
-
export declare const useEcoSensors: (filters?: SensorFilters) => import('@tanstack/react-query').UseQueryResult<EcoSensor
|
|
21
|
+
export declare const useEcoSensors: (filters?: SensorFilters) => import('@tanstack/react-query').UseQueryResult<EcoConnection<EcoSensor>, Error>;
|
|
22
22
|
export declare const useEcoCreateSensor: () => import('@tanstack/react-query').UseMutationResult<EcoSensor, Error, EcoCreateSensorInput, unknown>;
|
|
23
23
|
export declare const useEcoSetSensorStatus: () => import('@tanstack/react-query').UseMutationResult<EcoSensor, Error, {
|
|
24
24
|
id: string;
|
|
@@ -33,7 +33,7 @@ export interface MeasurementFilters {
|
|
|
33
33
|
}
|
|
34
34
|
export declare const useEcoMeasurements: (filters?: MeasurementFilters) => import('@tanstack/react-query').UseQueryResult<EcoConnection<EcoMeasurement>, Error>;
|
|
35
35
|
export declare const useEcoRecordMeasurement: () => import('@tanstack/react-query').UseMutationResult<EcoMeasurement, Error, EcoRecordMeasurementInput, unknown>;
|
|
36
|
-
export declare const useEcoThresholds: (siteId?: string) => import('@tanstack/react-query').UseQueryResult<EcoAlertThreshold
|
|
36
|
+
export declare const useEcoThresholds: (siteId?: string) => import('@tanstack/react-query').UseQueryResult<EcoConnection<EcoAlertThreshold>, Error>;
|
|
37
37
|
export declare const useEcoCreateThreshold: () => import('@tanstack/react-query').UseMutationResult<EcoAlertThreshold, Error, EcoCreateThresholdInput, unknown>;
|
|
38
38
|
export declare const useEcoSetThresholdActive: () => import('@tanstack/react-query').UseMutationResult<EcoAlertThreshold, Error, {
|
|
39
39
|
id: string;
|
|
@@ -60,7 +60,7 @@ export interface ObservationFilters {
|
|
|
60
60
|
}
|
|
61
61
|
export declare const useEcoObservations: (filters?: ObservationFilters) => import('@tanstack/react-query').UseQueryResult<EcoConnection<EcoObservation>, Error>;
|
|
62
62
|
export declare const useEcoRecordObservation: () => import('@tanstack/react-query').UseMutationResult<EcoObservation, Error, EcoRecordObservationInput, unknown>;
|
|
63
|
-
export declare const useEcoHabitatProjects: (status?: EcoHabitatProjectStatus) => import('@tanstack/react-query').UseQueryResult<EcoHabitatProject
|
|
63
|
+
export declare const useEcoHabitatProjects: (status?: EcoHabitatProjectStatus) => import('@tanstack/react-query').UseQueryResult<EcoConnection<EcoHabitatProject>, Error>;
|
|
64
64
|
export declare const useEcoHabitatProject: (id: string | undefined) => import('@tanstack/react-query').UseQueryResult<EcoHabitatProject | null, Error>;
|
|
65
65
|
export declare const useEcoCreateHabitatProject: () => import('@tanstack/react-query').UseMutationResult<EcoHabitatProject, Error, EcoCreateHabitatProjectInput, unknown>;
|
|
66
66
|
export declare const useEcoTransitionHabitatProject: () => import('@tanstack/react-query').UseMutationResult<EcoHabitatProject, Error, {
|
|
@@ -68,7 +68,7 @@ export declare const useEcoTransitionHabitatProject: () => import('@tanstack/rea
|
|
|
68
68
|
status: EcoHabitatProjectStatus;
|
|
69
69
|
}, unknown>;
|
|
70
70
|
export declare const useEcoLogRestorationActivity: () => import('@tanstack/react-query').UseMutationResult<EcoRestorationActivity, Error, EcoLogRestorationActivityInput, unknown>;
|
|
71
|
-
export declare const useEcoEmissionFactors: (scope?: EcoEmissionScope, activeOnly?: boolean) => import('@tanstack/react-query').UseQueryResult<EcoEmissionFactor
|
|
71
|
+
export declare const useEcoEmissionFactors: (scope?: EcoEmissionScope, activeOnly?: boolean) => import('@tanstack/react-query').UseQueryResult<EcoConnection<EcoEmissionFactor>, Error>;
|
|
72
72
|
export declare const useEcoCreateEmissionFactor: () => import('@tanstack/react-query').UseMutationResult<EcoEmissionFactor, Error, EcoCreateEmissionFactorInput, unknown>;
|
|
73
73
|
export interface CarbonEntryFilters {
|
|
74
74
|
scope?: EcoEmissionScope;
|
|
@@ -87,7 +87,7 @@ export interface EcoCarbonTotals {
|
|
|
87
87
|
export declare const useEcoCarbonTotals: (siteId?: string) => import('@tanstack/react-query').UseQueryResult<EcoCarbonTotals, Error>;
|
|
88
88
|
export declare const useEcoRecordCarbonEntry: () => import('@tanstack/react-query').UseMutationResult<EcoCarbonEntry, Error, EcoRecordCarbonEntryInput, unknown>;
|
|
89
89
|
export declare const useEcoVerifyCarbonEntry: () => import('@tanstack/react-query').UseMutationResult<EcoCarbonEntry, Error, string, unknown>;
|
|
90
|
-
export declare const useEcoReductionTargets: (status?: EcoReductionTargetStatus) => import('@tanstack/react-query').UseQueryResult<EcoReductionTarget
|
|
90
|
+
export declare const useEcoReductionTargets: (status?: EcoReductionTargetStatus) => import('@tanstack/react-query').UseQueryResult<EcoConnection<EcoReductionTarget>, Error>;
|
|
91
91
|
export declare const useEcoCreateReductionTarget: () => import('@tanstack/react-query').UseMutationResult<EcoReductionTarget, Error, EcoCreateReductionTargetInput, unknown>;
|
|
92
92
|
export declare const useEcoSetReductionTargetStatus: () => import('@tanstack/react-query').UseMutationResult<EcoReductionTarget, Error, {
|
|
93
93
|
id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEcoImpactHubApi.d.ts","sourceRoot":"","sources":["../../../src/ecoimpacthub/hooks/useEcoImpactHubApi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EACV,aAAa,EACb,OAAO,EACP,aAAa,EACb,WAAW,EACX,SAAS,EACT,aAAa,EACb,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,qBAAqB,EACrB,cAAc,EACd,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,wBAAwB,EACxB,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,EACzB,4BAA4B,EAC5B,8BAA8B,EAC9B,4BAA4B,EAC5B,yBAAyB,EACzB,6BAA6B,EAC7B,oBAAoB,EACpB,yBAAyB,EACzB,eAAe,EAChB,MAAM,UAAU,CAAC;AAqJlB,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B;AAED,eAAO,MAAM,WAAW,GAAI,UAAS,WAAgB,kFAsBpD,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,IAAI,MAAM,GAAG,SAAS,0EAoBhD,CAAC;AAEF,eAAO,MAAM,gBAAgB,sGAgB5B,CAAC;AAEF,eAAO,MAAM,gBAAgB;QAIM,MAAM;WAAS,kBAAkB;WAenE,CAAC;AAEF,eAAO,MAAM,iBAAiB,0FAc7B,CAAC;AAMF,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,eAAO,MAAM,aAAa,GAAI,UAAS,aAAkB,
|
|
1
|
+
{"version":3,"file":"useEcoImpactHubApi.d.ts","sourceRoot":"","sources":["../../../src/ecoimpacthub/hooks/useEcoImpactHubApi.ts"],"names":[],"mappings":"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"}
|
|
@@ -100,7 +100,10 @@ var a = () => {
|
|
|
100
100
|
return n({
|
|
101
101
|
queryKey: [...s.sensors, t],
|
|
102
102
|
queryFn: async () => (await o(`query EcoListSensors($siteId: ID, $kind: EcoSensorKind, $status: EcoSensorStatus) {
|
|
103
|
-
ecoListSensors(siteId: $siteId, kind: $kind, status: $status) {
|
|
103
|
+
ecoListSensors(siteId: $siteId, kind: $kind, status: $status) {
|
|
104
|
+
items { ${u} }
|
|
105
|
+
pageInfo { cursor hasMore }
|
|
106
|
+
}
|
|
104
107
|
}`, {
|
|
105
108
|
siteId: t.siteId,
|
|
106
109
|
kind: t.kind,
|
|
@@ -157,7 +160,10 @@ var a = () => {
|
|
|
157
160
|
return n({
|
|
158
161
|
queryKey: [...s.thresholds, t ?? "all"],
|
|
159
162
|
queryFn: async () => (await o(`query EcoListThresholds($siteId: ID) {
|
|
160
|
-
ecoListThresholds(siteId: $siteId) {
|
|
163
|
+
ecoListThresholds(siteId: $siteId) {
|
|
164
|
+
items { ${f} }
|
|
165
|
+
pageInfo { cursor hasMore }
|
|
166
|
+
}
|
|
161
167
|
}`, { siteId: t }, r)).ecoListThresholds
|
|
162
168
|
});
|
|
163
169
|
}, M = () => {
|
|
@@ -260,7 +266,10 @@ var a = () => {
|
|
|
260
266
|
return n({
|
|
261
267
|
queryKey: [...s.habitatProjects, t ?? "all"],
|
|
262
268
|
queryFn: async () => (await o(`query EcoListHabitatProjects($status: EcoHabitatProjectStatus) {
|
|
263
|
-
ecoListHabitatProjects(status: $status) {
|
|
269
|
+
ecoListHabitatProjects(status: $status) {
|
|
270
|
+
items { ${h} }
|
|
271
|
+
pageInfo { cursor hasMore }
|
|
272
|
+
}
|
|
264
273
|
}`, { status: t }, r)).ecoListHabitatProjects
|
|
265
274
|
});
|
|
266
275
|
}, V = (t) => {
|
|
@@ -310,7 +319,10 @@ var a = () => {
|
|
|
310
319
|
r ?? !1
|
|
311
320
|
],
|
|
312
321
|
queryFn: async () => (await o(`query EcoListEmissionFactors($scope: EcoEmissionScope, $activeOnly: Boolean) {
|
|
313
|
-
ecoListEmissionFactors(scope: $scope, activeOnly: $activeOnly) {
|
|
322
|
+
ecoListEmissionFactors(scope: $scope, activeOnly: $activeOnly) {
|
|
323
|
+
items { ${_} }
|
|
324
|
+
pageInfo { cursor hasMore }
|
|
325
|
+
}
|
|
314
326
|
}`, {
|
|
315
327
|
scope: t,
|
|
316
328
|
activeOnly: r
|
|
@@ -369,7 +381,10 @@ var a = () => {
|
|
|
369
381
|
return n({
|
|
370
382
|
queryKey: [...s.reductionTargets, t ?? "all"],
|
|
371
383
|
queryFn: async () => (await o(`query EcoListReductionTargets($status: EcoReductionTargetStatus) {
|
|
372
|
-
ecoListReductionTargets(status: $status) {
|
|
384
|
+
ecoListReductionTargets(status: $status) {
|
|
385
|
+
items { ${y} }
|
|
386
|
+
pageInfo { cursor hasMore }
|
|
387
|
+
}
|
|
373
388
|
}`, { status: t }, r)).ecoListReductionTargets
|
|
374
389
|
});
|
|
375
390
|
}, Q = () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEcoImpactHubApi.js","names":[],"sources":["../../../src/ecoimpacthub/hooks/useEcoImpactHubApi.ts"],"sourcesContent":["/**\n * EcoImpactHub API hooks\n * @module ecoimpacthub/hooks\n *\n * React-Query hooks wired DIRECTLY to the real `wspace-ecoimpacthub-svc`\n * federated GraphQL contract (the `eco*` operations). Every query/mutation\n * below uses an inline gql string whose fields match the svc\n * `.hive-schema.graphql` exactly. No mock data.\n *\n * Transport: `graphqlFetch({ gateway: 'workspace', workspaceToken: true })` —\n * the host shell supplies the gateway base URL + a workspace-scoped token.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useEcoImpactHub } from '../context';\nimport type {\n EcoConnection,\n EcoSite,\n EcoSiteStatus,\n EcoSiteType,\n EcoSensor,\n EcoSensorKind,\n EcoSensorStatus,\n EcoMeasurement,\n EcoAlertThreshold,\n EcoSpecies,\n EcoTaxonGroup,\n EcoConservationStatus,\n EcoObservation,\n EcoHabitatProject,\n EcoHabitatProjectStatus,\n EcoRestorationActivity,\n EcoEmissionFactor,\n EcoEmissionScope,\n EcoCarbonEntry,\n EcoCarbonEntryStatus,\n EcoReductionTarget,\n EcoReductionTargetStatus,\n EcoReport,\n EcoReportStatus,\n EcoReportLineItem,\n EcoCreateSiteInput,\n EcoUpdateSiteInput,\n EcoCreateSensorInput,\n EcoRecordMeasurementInput,\n EcoCreateThresholdInput,\n EcoCreateSpeciesInput,\n EcoUpdateSpeciesInput,\n EcoRecordObservationInput,\n EcoCreateHabitatProjectInput,\n EcoLogRestorationActivityInput,\n EcoCreateEmissionFactorInput,\n EcoRecordCarbonEntryInput,\n EcoCreateReductionTargetInput,\n EcoCreateReportInput,\n EcoAddReportLineItemInput,\n PaginationInput,\n} from '../types';\n\n// ============================================================================\n// Transport\n// ============================================================================\n\n/**\n * fe-libs `graphqlFetch` coalesces `query` responses in an in-memory cache keyed\n * by operationName+variables for ~15s (mutations are never cached). A read\n * issued right after a write (e.g. React-Query refetch triggered by our\n * `invalidateQueries`) would otherwise return the PRE-mutation response until the\n * TTL expires — making just-created/updated rows invisible until a full reload.\n * fe-libs' documented remedy is that write-performing callers clear those caches;\n * we do exactly that (the same maps `clearGraphqlFetchResponseCache` clears)\n * after every eco mutation so every follow-up read is fresh.\n */\ntype GraphqlReadCacheGlobals = {\n __graphqlFetchResponseCache?: { clear: () => void };\n __graphqlFetchPendingResponses?: { clear: () => void };\n __boffGraphQLResponseCache?: { clear: () => void };\n};\n\nconst clearGraphqlReadCaches = (): void => {\n const g = globalThis as GraphqlReadCacheGlobals;\n g.__graphqlFetchResponseCache?.clear();\n g.__graphqlFetchPendingResponses?.clear();\n g.__boffGraphQLResponseCache?.clear();\n};\n\nconst ecoQuery = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n });\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n // After a write, drop fe-libs' short-lived read caches so the invalidation\n // refetch that follows reads fresh data instead of the pre-mutation snapshot.\n if (/^\\s*mutation\\b/.test(query)) {\n clearGraphqlReadCaches();\n }\n return response.data;\n};\n\n// React-Query key roots (one namespace per domain entity).\nconst KEY = {\n sites: ['ecoimpacthub', 'sites'] as const,\n site: (id: string) => ['ecoimpacthub', 'site', id] as const,\n sensors: ['ecoimpacthub', 'sensors'] as const,\n measurements: ['ecoimpacthub', 'measurements'] as const,\n thresholds: ['ecoimpacthub', 'thresholds'] as const,\n species: ['ecoimpacthub', 'species'] as const,\n speciesOne: (id: string) => ['ecoimpacthub', 'species', id] as const,\n observations: ['ecoimpacthub', 'observations'] as const,\n habitatProjects: ['ecoimpacthub', 'habitat-projects'] as const,\n habitatProject: (id: string) => ['ecoimpacthub', 'habitat-project', id] as const,\n emissionFactors: ['ecoimpacthub', 'emission-factors'] as const,\n carbonEntries: ['ecoimpacthub', 'carbon-entries'] as const,\n carbonTotals: ['ecoimpacthub', 'carbon-totals'] as const,\n reductionTargets: ['ecoimpacthub', 'reduction-targets'] as const,\n reports: ['ecoimpacthub', 'reports'] as const,\n report: (id: string) => ['ecoimpacthub', 'report', id] as const,\n};\n\nconst DEFAULT_PAGE: PaginationInput = { limit: 50, offset: 0 };\n\n// ============================================================================\n// Reusable gql field selections (codegen-free strictness)\n// ============================================================================\n\nconst SITE_FIELDS = `\n id workspaceId name code type status description latitude longitude\n areaHectares country region createdAt updatedAt\n`;\n\nconst SENSOR_FIELDS = `\n id workspaceId siteId name kind status hardwareId unit lastReadingAt installedAt\n createdAt updatedAt\n`;\n\nconst MEASUREMENT_FIELDS = `\n id workspaceId siteId sensorId parameter value unit source recordedAt isBreach notes\n createdAt updatedAt\n`;\n\nconst THRESHOLD_FIELDS = `\n id workspaceId siteId parameter direction severity limitValue minValue maxValue unit\n isActive createdAt updatedAt\n`;\n\nconst SPECIES_FIELDS = `\n id workspaceId commonName scientificName taxonGroup conservationStatus isPriority\n description createdAt updatedAt\n`;\n\nconst OBSERVATION_FIELDS = `\n id workspaceId speciesId siteId method count observedAt latitude longitude observerId\n notes evidence { id } createdAt updatedAt\n`;\n\nconst HABITAT_FIELDS = `\n id workspaceId name status description siteId targetHectares budgetAmount currency\n managerId startDate endDate completedAt createdAt updatedAt\n`;\n\nconst ACTIVITY_FIELDS = `\n id workspaceId projectId type summary details quantity unit performedAt createdAt updatedAt\n`;\n\nconst FACTOR_FIELDS = `\n id workspaceId name scope activityUnit factorKgco2e source validYear isActive\n createdAt updatedAt\n`;\n\nconst CARBON_FIELDS = `\n id workspaceId siteId factorId scope status category activityValue activityUnit co2eKg\n periodStart notes createdAt updatedAt\n`;\n\nconst TARGET_FIELDS = `\n id workspaceId name status metric baselineYear baselineValue targetYear targetValue unit\n description createdAt updatedAt\n`;\n\nconst REPORT_FIELDS = `\n id workspaceId title framework status periodStart periodEnd summary publishedAt\n file { id } createdAt updatedAt\n`;\n\nconst LINE_ITEM_FIELDS = `\n id workspaceId reportId carbonEntryId label value unit category createdAt updatedAt\n`;\n\n// ============================================================================\n// Sites (Environmental Monitoring)\n// ============================================================================\n\nexport interface SiteFilters {\n status?: EcoSiteStatus;\n type?: EcoSiteType;\n pagination?: PaginationInput;\n}\n\nexport const useEcoSites = (filters: SiteFilters = {}) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.sites, filters],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListSites: EcoConnection<EcoSite> }>(\n `query EcoListSites($status: EcoSiteStatus, $type: EcoSiteType, $pagination: PaginationInput) {\n ecoListSites(status: $status, type: $type, pagination: $pagination) {\n items { ${SITE_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n status: filters.status,\n type: filters.type,\n pagination: filters.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.ecoListSites;\n },\n });\n};\n\nexport const useEcoSite = (id: string | undefined) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: KEY.site(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await ecoQuery<{ ecoSite: EcoSite | null }>(\n `query EcoSite($id: ID!) {\n ecoSite(id: $id) {\n ${SITE_FIELDS}\n sensors { ${SENSOR_FIELDS} }\n thresholds { ${THRESHOLD_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoSite;\n },\n });\n};\n\nexport const useEcoCreateSite = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateSiteInput) => {\n const result = await ecoQuery<{ ecoCreateSite: EcoSite }>(\n `mutation EcoCreateSite($input: EcoCreateSiteInput!) {\n ecoCreateSite(input: $input) { ${SITE_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateSite;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.sites }),\n });\n};\n\nexport const useEcoUpdateSite = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: EcoUpdateSiteInput }) => {\n const result = await ecoQuery<{ ecoUpdateSite: EcoSite }>(\n `mutation EcoUpdateSite($id: ID!, $input: EcoUpdateSiteInput!) {\n ecoUpdateSite(id: $id, input: $input) { ${SITE_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoUpdateSite;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.sites });\n qc.invalidateQueries({ queryKey: KEY.site(data.id) });\n },\n });\n};\n\nexport const useEcoArchiveSite = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await ecoQuery<{ ecoArchiveSite: boolean }>(\n `mutation EcoArchiveSite($id: ID!) { ecoArchiveSite(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoArchiveSite;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.sites }),\n });\n};\n\n// ============================================================================\n// Sensors / Measurements / Thresholds (Environmental Monitoring)\n// ============================================================================\n\nexport interface SensorFilters {\n siteId?: string;\n kind?: EcoSensorKind;\n status?: EcoSensorStatus;\n}\n\nexport const useEcoSensors = (filters: SensorFilters = {}) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.sensors, filters],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListSensors: EcoSensor[] }>(\n `query EcoListSensors($siteId: ID, $kind: EcoSensorKind, $status: EcoSensorStatus) {\n ecoListSensors(siteId: $siteId, kind: $kind, status: $status) { ${SENSOR_FIELDS} }\n }`,\n { siteId: filters.siteId, kind: filters.kind, status: filters.status },\n apiGatewayUrl\n );\n return result.ecoListSensors;\n },\n });\n};\n\nexport const useEcoCreateSensor = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateSensorInput) => {\n const result = await ecoQuery<{ ecoCreateSensor: EcoSensor }>(\n `mutation EcoCreateSensor($input: EcoCreateSensorInput!) {\n ecoCreateSensor(input: $input) { ${SENSOR_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateSensor;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.sensors });\n qc.invalidateQueries({ queryKey: KEY.site(data.siteId) });\n },\n });\n};\n\nexport const useEcoSetSensorStatus = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; status: EcoSensorStatus }) => {\n const result = await ecoQuery<{ ecoSetSensorStatus: EcoSensor }>(\n `mutation EcoSetSensorStatus($id: ID!, $status: EcoSensorStatus!) {\n ecoSetSensorStatus(id: $id, status: $status) { ${SENSOR_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoSetSensorStatus;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.sensors });\n qc.invalidateQueries({ queryKey: KEY.site(data.siteId) });\n },\n });\n};\n\nexport interface MeasurementFilters {\n siteId?: string;\n sensorId?: string;\n parameter?: string;\n breachesOnly?: boolean;\n pagination?: PaginationInput;\n}\n\nexport const useEcoMeasurements = (filters: MeasurementFilters = {}) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.measurements, filters],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListMeasurements: EcoConnection<EcoMeasurement> }>(\n `query EcoListMeasurements($siteId: ID, $sensorId: ID, $parameter: String, $breachesOnly: Boolean, $pagination: PaginationInput) {\n ecoListMeasurements(siteId: $siteId, sensorId: $sensorId, parameter: $parameter, breachesOnly: $breachesOnly, pagination: $pagination) {\n items { ${MEASUREMENT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n siteId: filters.siteId,\n sensorId: filters.sensorId,\n parameter: filters.parameter,\n breachesOnly: filters.breachesOnly,\n pagination: filters.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.ecoListMeasurements;\n },\n });\n};\n\nexport const useEcoRecordMeasurement = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoRecordMeasurementInput) => {\n const result = await ecoQuery<{ ecoRecordMeasurement: EcoMeasurement }>(\n `mutation EcoRecordMeasurement($input: EcoRecordMeasurementInput!) {\n ecoRecordMeasurement(input: $input) { ${MEASUREMENT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoRecordMeasurement;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.measurements }),\n });\n};\n\nexport const useEcoThresholds = (siteId?: string) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.thresholds, siteId ?? 'all'],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListThresholds: EcoAlertThreshold[] }>(\n `query EcoListThresholds($siteId: ID) {\n ecoListThresholds(siteId: $siteId) { ${THRESHOLD_FIELDS} }\n }`,\n { siteId },\n apiGatewayUrl\n );\n return result.ecoListThresholds;\n },\n });\n};\n\nexport const useEcoCreateThreshold = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateThresholdInput) => {\n const result = await ecoQuery<{ ecoCreateThreshold: EcoAlertThreshold }>(\n `mutation EcoCreateThreshold($input: EcoCreateThresholdInput!) {\n ecoCreateThreshold(input: $input) { ${THRESHOLD_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateThreshold;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.thresholds });\n qc.invalidateQueries({ queryKey: KEY.site(data.siteId) });\n },\n });\n};\n\nexport const useEcoSetThresholdActive = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; isActive: boolean }) => {\n const result = await ecoQuery<{ ecoSetThresholdActive: EcoAlertThreshold }>(\n `mutation EcoSetThresholdActive($id: ID!, $isActive: Boolean!) {\n ecoSetThresholdActive(id: $id, isActive: $isActive) { ${THRESHOLD_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoSetThresholdActive;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.thresholds }),\n });\n};\n\n// ============================================================================\n// Species / Observations / Habitat (Conservation)\n// ============================================================================\n\nexport interface SpeciesFilters {\n taxonGroup?: EcoTaxonGroup;\n conservationStatus?: EcoConservationStatus;\n priorityOnly?: boolean;\n pagination?: PaginationInput;\n}\n\nexport const useEcoSpecies = (filters: SpeciesFilters = {}) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.species, filters],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListSpecies: EcoConnection<EcoSpecies> }>(\n `query EcoListSpecies($taxonGroup: EcoTaxonGroup, $conservationStatus: EcoConservationStatus, $priorityOnly: Boolean, $pagination: PaginationInput) {\n ecoListSpecies(taxonGroup: $taxonGroup, conservationStatus: $conservationStatus, priorityOnly: $priorityOnly, pagination: $pagination) {\n items { ${SPECIES_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n taxonGroup: filters.taxonGroup,\n conservationStatus: filters.conservationStatus,\n priorityOnly: filters.priorityOnly,\n pagination: filters.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.ecoListSpecies;\n },\n });\n};\n\nexport const useEcoSpeciesDetail = (id: string | undefined) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: KEY.speciesOne(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await ecoQuery<{ ecoSpecies: EcoSpecies | null }>(\n `query EcoSpeciesDetail($id: ID!) {\n ecoSpecies(id: $id) {\n ${SPECIES_FIELDS}\n observations { ${OBSERVATION_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoSpecies;\n },\n });\n};\n\nexport const useEcoCreateSpecies = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateSpeciesInput) => {\n const result = await ecoQuery<{ ecoCreateSpecies: EcoSpecies }>(\n `mutation EcoCreateSpecies($input: EcoCreateSpeciesInput!) {\n ecoCreateSpecies(input: $input) { ${SPECIES_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateSpecies;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.species }),\n });\n};\n\nexport const useEcoUpdateSpecies = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: EcoUpdateSpeciesInput }) => {\n const result = await ecoQuery<{ ecoUpdateSpecies: EcoSpecies }>(\n `mutation EcoUpdateSpecies($id: ID!, $input: EcoUpdateSpeciesInput!) {\n ecoUpdateSpecies(id: $id, input: $input) { ${SPECIES_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoUpdateSpecies;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.species });\n qc.invalidateQueries({ queryKey: KEY.speciesOne(data.id) });\n },\n });\n};\n\nexport const useEcoArchiveSpecies = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await ecoQuery<{ ecoArchiveSpecies: boolean }>(\n `mutation EcoArchiveSpecies($id: ID!) { ecoArchiveSpecies(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoArchiveSpecies;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.species }),\n });\n};\n\nexport interface ObservationFilters {\n speciesId?: string;\n siteId?: string;\n pagination?: PaginationInput;\n}\n\nexport const useEcoObservations = (filters: ObservationFilters = {}) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.observations, filters],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListObservations: EcoConnection<EcoObservation> }>(\n `query EcoListObservations($speciesId: ID, $siteId: ID, $pagination: PaginationInput) {\n ecoListObservations(speciesId: $speciesId, siteId: $siteId, pagination: $pagination) {\n items { ${OBSERVATION_FIELDS} species { id commonName scientificName taxonGroup } }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n speciesId: filters.speciesId,\n siteId: filters.siteId,\n pagination: filters.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.ecoListObservations;\n },\n });\n};\n\nexport const useEcoRecordObservation = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoRecordObservationInput) => {\n const result = await ecoQuery<{ ecoRecordObservation: EcoObservation }>(\n `mutation EcoRecordObservation($input: EcoRecordObservationInput!) {\n ecoRecordObservation(input: $input) { ${OBSERVATION_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoRecordObservation;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.observations });\n qc.invalidateQueries({ queryKey: KEY.speciesOne(data.speciesId) });\n },\n });\n};\n\nexport const useEcoHabitatProjects = (status?: EcoHabitatProjectStatus) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.habitatProjects, status ?? 'all'],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListHabitatProjects: EcoHabitatProject[] }>(\n `query EcoListHabitatProjects($status: EcoHabitatProjectStatus) {\n ecoListHabitatProjects(status: $status) { ${HABITAT_FIELDS} }\n }`,\n { status },\n apiGatewayUrl\n );\n return result.ecoListHabitatProjects;\n },\n });\n};\n\nexport const useEcoHabitatProject = (id: string | undefined) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: KEY.habitatProject(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await ecoQuery<{ ecoHabitatProject: EcoHabitatProject | null }>(\n `query EcoHabitatProject($id: ID!) {\n ecoHabitatProject(id: $id) {\n ${HABITAT_FIELDS}\n activities { ${ACTIVITY_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoHabitatProject;\n },\n });\n};\n\nexport const useEcoCreateHabitatProject = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateHabitatProjectInput) => {\n const result = await ecoQuery<{ ecoCreateHabitatProject: EcoHabitatProject }>(\n `mutation EcoCreateHabitatProject($input: EcoCreateHabitatProjectInput!) {\n ecoCreateHabitatProject(input: $input) { ${HABITAT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateHabitatProject;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.habitatProjects }),\n });\n};\n\nexport const useEcoTransitionHabitatProject = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; status: EcoHabitatProjectStatus }) => {\n const result = await ecoQuery<{ ecoTransitionHabitatProject: EcoHabitatProject }>(\n `mutation EcoTransitionHabitatProject($id: ID!, $status: EcoHabitatProjectStatus!) {\n ecoTransitionHabitatProject(id: $id, status: $status) { ${HABITAT_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoTransitionHabitatProject;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.habitatProjects });\n qc.invalidateQueries({ queryKey: KEY.habitatProject(data.id) });\n },\n });\n};\n\nexport const useEcoLogRestorationActivity = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoLogRestorationActivityInput) => {\n const result = await ecoQuery<{ ecoLogRestorationActivity: EcoRestorationActivity }>(\n `mutation EcoLogRestorationActivity($input: EcoLogRestorationActivityInput!) {\n ecoLogRestorationActivity(input: $input) { ${ACTIVITY_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoLogRestorationActivity;\n },\n onSuccess: (data) => qc.invalidateQueries({ queryKey: KEY.habitatProject(data.projectId) }),\n });\n};\n\n// ============================================================================\n// Carbon ledger / Emission factors / Reduction targets (Sustainability)\n// ============================================================================\n\nexport const useEcoEmissionFactors = (scope?: EcoEmissionScope, activeOnly?: boolean) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.emissionFactors, scope ?? 'all', activeOnly ?? false],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListEmissionFactors: EcoEmissionFactor[] }>(\n `query EcoListEmissionFactors($scope: EcoEmissionScope, $activeOnly: Boolean) {\n ecoListEmissionFactors(scope: $scope, activeOnly: $activeOnly) { ${FACTOR_FIELDS} }\n }`,\n { scope, activeOnly },\n apiGatewayUrl\n );\n return result.ecoListEmissionFactors;\n },\n });\n};\n\nexport const useEcoCreateEmissionFactor = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateEmissionFactorInput) => {\n const result = await ecoQuery<{ ecoCreateEmissionFactor: EcoEmissionFactor }>(\n `mutation EcoCreateEmissionFactor($input: EcoCreateEmissionFactorInput!) {\n ecoCreateEmissionFactor(input: $input) { ${FACTOR_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateEmissionFactor;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.emissionFactors }),\n });\n};\n\nexport interface CarbonEntryFilters {\n scope?: EcoEmissionScope;\n siteId?: string;\n status?: EcoCarbonEntryStatus;\n pagination?: PaginationInput;\n}\n\nexport const useEcoCarbonEntries = (filters: CarbonEntryFilters = {}) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.carbonEntries, filters],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListCarbonEntries: EcoConnection<EcoCarbonEntry> }>(\n `query EcoListCarbonEntries($scope: EcoEmissionScope, $siteId: ID, $status: EcoCarbonEntryStatus, $pagination: PaginationInput) {\n ecoListCarbonEntries(scope: $scope, siteId: $siteId, status: $status, pagination: $pagination) {\n items { ${CARBON_FIELDS} factor { id name factorKgco2e activityUnit } }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n scope: filters.scope,\n siteId: filters.siteId,\n status: filters.status,\n pagination: filters.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.ecoListCarbonEntries;\n },\n });\n};\n\n/** Total CO2e by scope + grand total, in one aliased query. */\nexport interface EcoCarbonTotals {\n total: number;\n scope1: number;\n scope2: number;\n scope3: number;\n}\n\nexport const useEcoCarbonTotals = (siteId?: string) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.carbonTotals, siteId ?? 'all'],\n queryFn: async (): Promise<EcoCarbonTotals> => {\n const result = await ecoQuery<{\n total: number;\n scope1: number;\n scope2: number;\n scope3: number;\n }>(\n `query EcoCarbonTotals($siteId: ID) {\n total: ecoCarbonTotalKg(siteId: $siteId)\n scope1: ecoCarbonTotalKg(scope: SCOPE_1, siteId: $siteId)\n scope2: ecoCarbonTotalKg(scope: SCOPE_2, siteId: $siteId)\n scope3: ecoCarbonTotalKg(scope: SCOPE_3, siteId: $siteId)\n }`,\n { siteId },\n apiGatewayUrl\n );\n return result;\n },\n });\n};\n\nexport const useEcoRecordCarbonEntry = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoRecordCarbonEntryInput) => {\n const result = await ecoQuery<{ ecoRecordCarbonEntry: EcoCarbonEntry }>(\n `mutation EcoRecordCarbonEntry($input: EcoRecordCarbonEntryInput!) {\n ecoRecordCarbonEntry(input: $input) { ${CARBON_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoRecordCarbonEntry;\n },\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.carbonEntries });\n qc.invalidateQueries({ queryKey: KEY.carbonTotals });\n },\n });\n};\n\nexport const useEcoVerifyCarbonEntry = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await ecoQuery<{ ecoVerifyCarbonEntry: EcoCarbonEntry }>(\n `mutation EcoVerifyCarbonEntry($id: ID!) {\n ecoVerifyCarbonEntry(id: $id) { ${CARBON_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoVerifyCarbonEntry;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.carbonEntries }),\n });\n};\n\nexport const useEcoReductionTargets = (status?: EcoReductionTargetStatus) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.reductionTargets, status ?? 'all'],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListReductionTargets: EcoReductionTarget[] }>(\n `query EcoListReductionTargets($status: EcoReductionTargetStatus) {\n ecoListReductionTargets(status: $status) { ${TARGET_FIELDS} }\n }`,\n { status },\n apiGatewayUrl\n );\n return result.ecoListReductionTargets;\n },\n });\n};\n\nexport const useEcoCreateReductionTarget = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateReductionTargetInput) => {\n const result = await ecoQuery<{ ecoCreateReductionTarget: EcoReductionTarget }>(\n `mutation EcoCreateReductionTarget($input: EcoCreateReductionTargetInput!) {\n ecoCreateReductionTarget(input: $input) { ${TARGET_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateReductionTarget;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.reductionTargets }),\n });\n};\n\nexport const useEcoSetReductionTargetStatus = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; status: EcoReductionTargetStatus }) => {\n const result = await ecoQuery<{ ecoSetReductionTargetStatus: EcoReductionTarget }>(\n `mutation EcoSetReductionTargetStatus($id: ID!, $status: EcoReductionTargetStatus!) {\n ecoSetReductionTargetStatus(id: $id, status: $status) { ${TARGET_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoSetReductionTargetStatus;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.reductionTargets }),\n });\n};\n\n// ============================================================================\n// Reports (Sustainability & Reporting)\n// ============================================================================\n\nexport const useEcoReports = (status?: EcoReportStatus, pagination?: PaginationInput) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.reports, status ?? 'all', pagination ?? DEFAULT_PAGE],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListReports: EcoConnection<EcoReport> }>(\n `query EcoListReports($status: EcoReportStatus, $pagination: PaginationInput) {\n ecoListReports(status: $status, pagination: $pagination) {\n items { ${REPORT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { status, pagination: pagination ?? DEFAULT_PAGE },\n apiGatewayUrl\n );\n return result.ecoListReports;\n },\n });\n};\n\nexport const useEcoReport = (id: string | undefined) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: KEY.report(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await ecoQuery<{ ecoReport: EcoReport | null }>(\n `query EcoReport($id: ID!) {\n ecoReport(id: $id) {\n ${REPORT_FIELDS}\n lineItems { ${LINE_ITEM_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoReport;\n },\n });\n};\n\nexport const useEcoCreateReport = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateReportInput) => {\n const result = await ecoQuery<{ ecoCreateReport: EcoReport }>(\n `mutation EcoCreateReport($input: EcoCreateReportInput!) {\n ecoCreateReport(input: $input) { ${REPORT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateReport;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.reports }),\n });\n};\n\nexport const useEcoAddReportLineItem = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoAddReportLineItemInput) => {\n const result = await ecoQuery<{ ecoAddReportLineItem: EcoReportLineItem }>(\n `mutation EcoAddReportLineItem($input: EcoAddReportLineItemInput!) {\n ecoAddReportLineItem(input: $input) { ${LINE_ITEM_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoAddReportLineItem;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.reports });\n qc.invalidateQueries({ queryKey: KEY.report(data.reportId) });\n },\n });\n};\n\nexport const useEcoPublishReport = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; fileId?: string | null }) => {\n const result = await ecoQuery<{ ecoPublishReport: EcoReport }>(\n `mutation EcoPublishReport($id: ID!, $fileId: ID) {\n ecoPublishReport(id: $id, fileId: $fileId) { ${REPORT_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoPublishReport;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.reports });\n qc.invalidateQueries({ queryKey: KEY.report(data.id) });\n },\n });\n};\n"],"mappings":";;;;;AAiFA,IAAM,UAAqC;CACzC,IAAM,IAAI;AAGV,CAFA,EAAE,6BAA6B,OAAO,EACtC,EAAE,gCAAgC,OAAO,EACzC,EAAE,4BAA4B,OAAO;GAGjC,IAAW,OACf,GACA,GACA,MACmB;CACnB,IAAM,IAAW,MAAM,EAAoB;EACzC,SAAS;EACT;EACA;EACA;EACA,gBAAgB;EACjB,CAAC;AAEF,KAAI,EAAS,QAAQ,OACnB,OAAU,MAAM,EAAS,OAAO,IAAI,WAAW,yBAAyB;AAE1E,KAAI,CAAC,EAAS,KACZ,OAAU,MAAM,wCAAwC;AAO1D,QAHI,iBAAiB,KAAK,EAAM,IAC9B,GAAwB,EAEnB,EAAS;GAIZ,IAAM;CACV,OAAO,CAAC,gBAAgB,QAAQ;CAChC,OAAO,MAAe;EAAC;EAAgB;EAAQ;EAAG;CAClD,SAAS,CAAC,gBAAgB,UAAU;CACpC,cAAc,CAAC,gBAAgB,eAAe;CAC9C,YAAY,CAAC,gBAAgB,aAAa;CAC1C,SAAS,CAAC,gBAAgB,UAAU;CACpC,aAAa,MAAe;EAAC;EAAgB;EAAW;EAAG;CAC3D,cAAc,CAAC,gBAAgB,eAAe;CAC9C,iBAAiB,CAAC,gBAAgB,mBAAmB;CACrD,iBAAiB,MAAe;EAAC;EAAgB;EAAmB;EAAG;CACvE,iBAAiB,CAAC,gBAAgB,mBAAmB;CACrD,eAAe,CAAC,gBAAgB,iBAAiB;CACjD,cAAc,CAAC,gBAAgB,gBAAgB;CAC/C,kBAAkB,CAAC,gBAAgB,oBAAoB;CACvD,SAAS,CAAC,gBAAgB,UAAU;CACpC,SAAS,MAAe;EAAC;EAAgB;EAAU;EAAG;CACvD,EAEK,IAAgC;CAAE,OAAO;CAAI,QAAQ;CAAG,EAMxD,IAAc,gIAKd,IAAgB,iHAKhB,IAAqB,qHAKrB,IAAmB,8HAKnB,IAAiB,8HAKjB,IAAqB,4IAKrB,IAAiB,2JAKjB,IAAkB,qGAIlB,IAAgB,8GAKhB,IAAgB,yIAKhB,IAAgB,qIAKhB,IAAgB,4HAKhB,IAAmB,6FAcZ,KAAe,IAAuB,EAAE,KAAK;CACxD,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,CAAC,GAAG,EAAI,OAAO,EAAQ;EACjC,SAAS,aACQ,MAAM,EACnB;;sBAEc,EAAY;;;YAI1B;GACE,QAAQ,EAAQ;GAChB,MAAM,EAAQ;GACd,YAAY,EAAQ,cAAc;GACnC,EACD,EACD,EACa;EAEjB,CAAC;GAGS,KAAc,MAA2B;CACpD,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,EAAI,KAAK,KAAM,GAAG;EAC5B,SAAS,EAAQ;EACjB,SAAS,aACQ,MAAM,EACnB;;cAEM,EAAY;wBACF,EAAc;2BACX,EAAiB;;YAGpC,EAAE,OAAI,EACN,EACD,EACa;EAEjB,CAAC;GAGS,UAAyB;CACpC,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;2CACmC,EAAY;YAE/C,EAAE,UAAO,EACT,EACD,EACa;EAEhB,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,OAAO,CAAC;EAC/D,CAAC;GAwBS,UAA0B;CACrC,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB,iEACA,EAAE,OAAI,EACN,EACD,EACa;EAEhB,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,OAAO,CAAC;EAC/D,CAAC;GAaS,KAAiB,IAAyB,EAAE,KAAK;CAC5D,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,CAAC,GAAG,EAAI,SAAS,EAAQ;EACnC,SAAS,aACQ,MAAM,EACnB;4EACoE,EAAc;YAElF;GAAE,QAAQ,EAAQ;GAAQ,MAAM,EAAQ;GAAM,QAAQ,EAAQ;GAAQ,EACtE,EACD,EACa;EAEjB,CAAC;GAGS,UAA2B;CACtC,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;6CACqC,EAAc;YAEnD,EAAE,UAAO,EACT,EACD,EACa;EAEhB,YAAY,MAAS;AAEnB,GADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,SAAS,CAAC,EAC/C,EAAG,kBAAkB,EAAE,UAAU,EAAI,KAAK,EAAK,OAAO,EAAE,CAAC;;EAE5D,CAAC;GAGS,UAA8B;CACzC,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;2DACmD,EAAc;YAEjE,GACA,EACD,EACa;EAEhB,YAAY,MAAS;AAEnB,GADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,SAAS,CAAC,EAC/C,EAAG,kBAAkB,EAAE,UAAU,EAAI,KAAK,EAAK,OAAO,EAAE,CAAC;;EAE5D,CAAC;GAWS,KAAsB,IAA8B,EAAE,KAAK;CACtE,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,CAAC,GAAG,EAAI,cAAc,EAAQ;EACxC,SAAS,aACQ,MAAM,EACnB;;sBAEc,EAAmB;;;YAIjC;GACE,QAAQ,EAAQ;GAChB,UAAU,EAAQ;GAClB,WAAW,EAAQ;GACnB,cAAc,EAAQ;GACtB,YAAY,EAAQ,cAAc;GACnC,EACD,EACD,EACa;EAEjB,CAAC;GAGS,UAAgC;CAC3C,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;kDAC0C,EAAmB;YAE7D,EAAE,UAAO,EACT,EACD,EACa;EAEhB,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,cAAc,CAAC;EACtE,CAAC;GAGS,KAAoB,MAAoB;CACnD,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,CAAC,GAAG,EAAI,YAAY,KAAU,MAAM;EAC9C,SAAS,aACQ,MAAM,EACnB;iDACyC,EAAiB;YAE1D,EAAE,WAAQ,EACV,EACD,EACa;EAEjB,CAAC;GAGS,UAA8B;CACzC,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;gDACwC,EAAiB;YAEzD,EAAE,UAAO,EACT,EACD,EACa;EAEhB,YAAY,MAAS;AAEnB,GADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,YAAY,CAAC,EAClD,EAAG,kBAAkB,EAAE,UAAU,EAAI,KAAK,EAAK,OAAO,EAAE,CAAC;;EAE5D,CAAC;GAGS,UAAiC;CAC5C,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;kEAC0D,EAAiB;YAE3E,GACA,EACD,EACa;EAEhB,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,YAAY,CAAC;EACpE,CAAC;GAcS,KAAiB,IAA0B,EAAE,KAAK;CAC7D,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,CAAC,GAAG,EAAI,SAAS,EAAQ;EACnC,SAAS,aACQ,MAAM,EACnB;;sBAEc,EAAe;;;YAI7B;GACE,YAAY,EAAQ;GACpB,oBAAoB,EAAQ;GAC5B,cAAc,EAAQ;GACtB,YAAY,EAAQ,cAAc;GACnC,EACD,EACD,EACa;EAEjB,CAAC;GAGS,KAAuB,MAA2B;CAC7D,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,EAAI,WAAW,KAAM,GAAG;EAClC,SAAS,EAAQ;EACjB,SAAS,aACQ,MAAM,EACnB;;cAEM,EAAe;6BACA,EAAmB;;YAGxC,EAAE,OAAI,EACN,EACD,EACa;EAEjB,CAAC;GAGS,UAA4B;CACvC,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;8CACsC,EAAe;YAErD,EAAE,UAAO,EACT,EACD,EACa;EAEhB,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,SAAS,CAAC;EACjE,CAAC;GAGS,UAA4B;CACvC,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;uDAC+C,EAAe;YAE9D,GACA,EACD,EACa;EAEhB,YAAY,MAAS;AAEnB,GADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,SAAS,CAAC,EAC/C,EAAG,kBAAkB,EAAE,UAAU,EAAI,WAAW,EAAK,GAAG,EAAE,CAAC;;EAE9D,CAAC;GAGS,WAA6B;CACxC,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB,uEACA,EAAE,OAAI,EACN,EACD,EACa;EAEhB,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,SAAS,CAAC;EACjE,CAAC;GASS,KAAsB,IAA8B,EAAE,KAAK;CACtE,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,CAAC,GAAG,EAAI,cAAc,EAAQ;EACxC,SAAS,aACQ,MAAM,EACnB;;sBAEc,EAAmB;;;YAIjC;GACE,WAAW,EAAQ;GACnB,QAAQ,EAAQ;GAChB,YAAY,EAAQ,cAAc;GACnC,EACD,EACD,EACa;EAEjB,CAAC;GAGS,UAAgC;CAC3C,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;kDAC0C,EAAmB;YAE7D,EAAE,UAAO,EACT,EACD,EACa;EAEhB,YAAY,MAAS;AAEnB,GADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,cAAc,CAAC,EACpD,EAAG,kBAAkB,EAAE,UAAU,EAAI,WAAW,EAAK,UAAU,EAAE,CAAC;;EAErE,CAAC;GAGS,KAAyB,MAAqC;CACzE,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,CAAC,GAAG,EAAI,iBAAiB,KAAU,MAAM;EACnD,SAAS,aACQ,MAAM,EACnB;sDAC8C,EAAe;YAE7D,EAAE,WAAQ,EACV,EACD,EACa;EAEjB,CAAC;GAGS,KAAwB,MAA2B;CAC9D,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,EAAI,eAAe,KAAM,GAAG;EACtC,SAAS,EAAQ;EACjB,SAAS,aACQ,MAAM,EACnB;;cAEM,EAAe;2BACF,EAAgB;;YAGnC,EAAE,OAAI,EACN,EACD,EACa;EAEjB,CAAC;GAGS,UAAmC;CAC9C,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;qDAC6C,EAAe;YAE5D,EAAE,UAAO,EACT,EACD,EACa;EAEhB,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,iBAAiB,CAAC;EACzE,CAAC;GAGS,UAAuC;CAClD,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;oEAC4D,EAAe;YAE3E,GACA,EACD,EACa;EAEhB,YAAY,MAAS;AAEnB,GADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,iBAAiB,CAAC,EACvD,EAAG,kBAAkB,EAAE,UAAU,EAAI,eAAe,EAAK,GAAG,EAAE,CAAC;;EAElE,CAAC;GAGS,UAAqC;CAChD,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;uDAC+C,EAAgB;YAE/D,EAAE,UAAO,EACT,EACD,EACa;EAEhB,YAAY,MAAS,EAAG,kBAAkB,EAAE,UAAU,EAAI,eAAe,EAAK,UAAU,EAAE,CAAC;EAC5F,CAAC;GAOS,KAAyB,GAA0B,MAAyB;CACvF,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU;GAAC,GAAG,EAAI;GAAiB,KAAS;GAAO,KAAc;GAAM;EACvE,SAAS,aACQ,MAAM,EACnB;6EACqE,EAAc;YAEnF;GAAE;GAAO;GAAY,EACrB,EACD,EACa;EAEjB,CAAC;GAGS,UAAmC;CAC9C,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;qDAC6C,EAAc;YAE3D,EAAE,UAAO,EACT,EACD,EACa;EAEhB,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,iBAAiB,CAAC;EACzE,CAAC;GAUS,KAAuB,IAA8B,EAAE,KAAK;CACvE,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,CAAC,GAAG,EAAI,eAAe,EAAQ;EACzC,SAAS,aACQ,MAAM,EACnB;;sBAEc,EAAc;;;YAI5B;GACE,OAAO,EAAQ;GACf,QAAQ,EAAQ;GAChB,QAAQ,EAAQ;GAChB,YAAY,EAAQ,cAAc;GACnC,EACD,EACD,EACa;EAEjB,CAAC;GAWS,KAAsB,MAAoB;CACrD,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,CAAC,GAAG,EAAI,cAAc,KAAU,MAAM;EAChD,SAAS,YACQ,MAAM,EAMnB,sTAMA,EAAE,WAAQ,EACV,EACD;EAGJ,CAAC;GAGS,UAAgC;CAC3C,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;kDAC0C,EAAc;YAExD,EAAE,UAAO,EACT,EACD,EACa;EAEhB,iBAAiB;AAEf,GADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,eAAe,CAAC,EACrD,EAAG,kBAAkB,EAAE,UAAU,EAAI,cAAc,CAAC;;EAEvD,CAAC;GAGS,UAAgC;CAC3C,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;4CACoC,EAAc;YAElD,EAAE,OAAI,EACN,EACD,EACa;EAEhB,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,eAAe,CAAC;EACvE,CAAC;GAGS,KAA0B,MAAsC;CAC3E,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,CAAC,GAAG,EAAI,kBAAkB,KAAU,MAAM;EACpD,SAAS,aACQ,MAAM,EACnB;uDAC+C,EAAc;YAE7D,EAAE,WAAQ,EACV,EACD,EACa;EAEjB,CAAC;GAGS,UAAoC;CAC/C,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;sDAC8C,EAAc;YAE5D,EAAE,UAAO,EACT,EACD,EACa;EAEhB,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,kBAAkB,CAAC;EAC1E,CAAC;GAGS,UAAuC;CAClD,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;oEAC4D,EAAc;YAE1E,GACA,EACD,EACa;EAEhB,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,kBAAkB,CAAC;EAC1E,CAAC;GAOS,MAAiB,GAA0B,MAAiC;CACvF,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU;GAAC,GAAG,EAAI;GAAS,KAAU;GAAO,KAAc;GAAa;EACvE,SAAS,aACQ,MAAM,EACnB;;sBAEc,EAAc;;;YAI5B;GAAE;GAAQ,YAAY,KAAc;GAAc,EAClD,EACD,EACa;EAEjB,CAAC;GAGS,MAAgB,MAA2B;CACtD,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,EAAI,OAAO,KAAM,GAAG;EAC9B,SAAS,EAAQ;EACjB,SAAS,aACQ,MAAM,EACnB;;cAEM,EAAc;0BACF,EAAiB;;YAGnC,EAAE,OAAI,EACN,EACD,EACa;EAEjB,CAAC;GAGS,WAA2B;CACtC,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;6CACqC,EAAc;YAEnD,EAAE,UAAO,EACT,EACD,EACa;EAEhB,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,SAAS,CAAC;EACjE,CAAC;GAGS,WAAgC;CAC3C,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;kDAC0C,EAAiB;YAE3D,EAAE,UAAO,EACT,EACD,EACa;EAEhB,YAAY,MAAS;AAEnB,GADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,SAAS,CAAC,EAC/C,EAAG,kBAAkB,EAAE,UAAU,EAAI,OAAO,EAAK,SAAS,EAAE,CAAC;;EAEhE,CAAC;GAGS,WAA4B;CACvC,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;yDACiD,EAAc;YAE/D,GACA,EACD,EACa;EAEhB,YAAY,MAAS;AAEnB,GADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,SAAS,CAAC,EAC/C,EAAG,kBAAkB,EAAE,UAAU,EAAI,OAAO,EAAK,GAAG,EAAE,CAAC;;EAE1D,CAAC"}
|
|
1
|
+
{"version":3,"file":"useEcoImpactHubApi.js","names":[],"sources":["../../../src/ecoimpacthub/hooks/useEcoImpactHubApi.ts"],"sourcesContent":["/**\n * EcoImpactHub API hooks\n * @module ecoimpacthub/hooks\n *\n * React-Query hooks wired DIRECTLY to the real `wspace-ecoimpacthub-svc`\n * federated GraphQL contract (the `eco*` operations). Every query/mutation\n * below uses an inline gql string whose fields match the svc\n * `.hive-schema.graphql` exactly. No mock data.\n *\n * Transport: `graphqlFetch({ gateway: 'workspace', workspaceToken: true })` —\n * the host shell supplies the gateway base URL + a workspace-scoped token.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useEcoImpactHub } from '../context';\nimport type {\n EcoConnection,\n EcoSite,\n EcoSiteStatus,\n EcoSiteType,\n EcoSensor,\n EcoSensorKind,\n EcoSensorStatus,\n EcoMeasurement,\n EcoAlertThreshold,\n EcoSpecies,\n EcoTaxonGroup,\n EcoConservationStatus,\n EcoObservation,\n EcoHabitatProject,\n EcoHabitatProjectStatus,\n EcoRestorationActivity,\n EcoEmissionFactor,\n EcoEmissionScope,\n EcoCarbonEntry,\n EcoCarbonEntryStatus,\n EcoReductionTarget,\n EcoReductionTargetStatus,\n EcoReport,\n EcoReportStatus,\n EcoReportLineItem,\n EcoCreateSiteInput,\n EcoUpdateSiteInput,\n EcoCreateSensorInput,\n EcoRecordMeasurementInput,\n EcoCreateThresholdInput,\n EcoCreateSpeciesInput,\n EcoUpdateSpeciesInput,\n EcoRecordObservationInput,\n EcoCreateHabitatProjectInput,\n EcoLogRestorationActivityInput,\n EcoCreateEmissionFactorInput,\n EcoRecordCarbonEntryInput,\n EcoCreateReductionTargetInput,\n EcoCreateReportInput,\n EcoAddReportLineItemInput,\n PaginationInput,\n} from '../types';\n\n// ============================================================================\n// Transport\n// ============================================================================\n\n/**\n * fe-libs `graphqlFetch` coalesces `query` responses in an in-memory cache keyed\n * by operationName+variables for ~15s (mutations are never cached). A read\n * issued right after a write (e.g. React-Query refetch triggered by our\n * `invalidateQueries`) would otherwise return the PRE-mutation response until the\n * TTL expires — making just-created/updated rows invisible until a full reload.\n * fe-libs' documented remedy is that write-performing callers clear those caches;\n * we do exactly that (the same maps `clearGraphqlFetchResponseCache` clears)\n * after every eco mutation so every follow-up read is fresh.\n */\ntype GraphqlReadCacheGlobals = {\n __graphqlFetchResponseCache?: { clear: () => void };\n __graphqlFetchPendingResponses?: { clear: () => void };\n __boffGraphQLResponseCache?: { clear: () => void };\n};\n\nconst clearGraphqlReadCaches = (): void => {\n const g = globalThis as GraphqlReadCacheGlobals;\n g.__graphqlFetchResponseCache?.clear();\n g.__graphqlFetchPendingResponses?.clear();\n g.__boffGraphQLResponseCache?.clear();\n};\n\nconst ecoQuery = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n });\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n // After a write, drop fe-libs' short-lived read caches so the invalidation\n // refetch that follows reads fresh data instead of the pre-mutation snapshot.\n if (/^\\s*mutation\\b/.test(query)) {\n clearGraphqlReadCaches();\n }\n return response.data;\n};\n\n// React-Query key roots (one namespace per domain entity).\nconst KEY = {\n sites: ['ecoimpacthub', 'sites'] as const,\n site: (id: string) => ['ecoimpacthub', 'site', id] as const,\n sensors: ['ecoimpacthub', 'sensors'] as const,\n measurements: ['ecoimpacthub', 'measurements'] as const,\n thresholds: ['ecoimpacthub', 'thresholds'] as const,\n species: ['ecoimpacthub', 'species'] as const,\n speciesOne: (id: string) => ['ecoimpacthub', 'species', id] as const,\n observations: ['ecoimpacthub', 'observations'] as const,\n habitatProjects: ['ecoimpacthub', 'habitat-projects'] as const,\n habitatProject: (id: string) => ['ecoimpacthub', 'habitat-project', id] as const,\n emissionFactors: ['ecoimpacthub', 'emission-factors'] as const,\n carbonEntries: ['ecoimpacthub', 'carbon-entries'] as const,\n carbonTotals: ['ecoimpacthub', 'carbon-totals'] as const,\n reductionTargets: ['ecoimpacthub', 'reduction-targets'] as const,\n reports: ['ecoimpacthub', 'reports'] as const,\n report: (id: string) => ['ecoimpacthub', 'report', id] as const,\n};\n\nconst DEFAULT_PAGE: PaginationInput = { limit: 50, offset: 0 };\n\n// ============================================================================\n// Reusable gql field selections (codegen-free strictness)\n// ============================================================================\n\nconst SITE_FIELDS = `\n id workspaceId name code type status description latitude longitude\n areaHectares country region createdAt updatedAt\n`;\n\nconst SENSOR_FIELDS = `\n id workspaceId siteId name kind status hardwareId unit lastReadingAt installedAt\n createdAt updatedAt\n`;\n\nconst MEASUREMENT_FIELDS = `\n id workspaceId siteId sensorId parameter value unit source recordedAt isBreach notes\n createdAt updatedAt\n`;\n\nconst THRESHOLD_FIELDS = `\n id workspaceId siteId parameter direction severity limitValue minValue maxValue unit\n isActive createdAt updatedAt\n`;\n\nconst SPECIES_FIELDS = `\n id workspaceId commonName scientificName taxonGroup conservationStatus isPriority\n description createdAt updatedAt\n`;\n\nconst OBSERVATION_FIELDS = `\n id workspaceId speciesId siteId method count observedAt latitude longitude observerId\n notes evidence { id } createdAt updatedAt\n`;\n\nconst HABITAT_FIELDS = `\n id workspaceId name status description siteId targetHectares budgetAmount currency\n managerId startDate endDate completedAt createdAt updatedAt\n`;\n\nconst ACTIVITY_FIELDS = `\n id workspaceId projectId type summary details quantity unit performedAt createdAt updatedAt\n`;\n\nconst FACTOR_FIELDS = `\n id workspaceId name scope activityUnit factorKgco2e source validYear isActive\n createdAt updatedAt\n`;\n\nconst CARBON_FIELDS = `\n id workspaceId siteId factorId scope status category activityValue activityUnit co2eKg\n periodStart notes createdAt updatedAt\n`;\n\nconst TARGET_FIELDS = `\n id workspaceId name status metric baselineYear baselineValue targetYear targetValue unit\n description createdAt updatedAt\n`;\n\nconst REPORT_FIELDS = `\n id workspaceId title framework status periodStart periodEnd summary publishedAt\n file { id } createdAt updatedAt\n`;\n\nconst LINE_ITEM_FIELDS = `\n id workspaceId reportId carbonEntryId label value unit category createdAt updatedAt\n`;\n\n// ============================================================================\n// Sites (Environmental Monitoring)\n// ============================================================================\n\nexport interface SiteFilters {\n status?: EcoSiteStatus;\n type?: EcoSiteType;\n pagination?: PaginationInput;\n}\n\nexport const useEcoSites = (filters: SiteFilters = {}) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.sites, filters],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListSites: EcoConnection<EcoSite> }>(\n `query EcoListSites($status: EcoSiteStatus, $type: EcoSiteType, $pagination: PaginationInput) {\n ecoListSites(status: $status, type: $type, pagination: $pagination) {\n items { ${SITE_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n status: filters.status,\n type: filters.type,\n pagination: filters.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.ecoListSites;\n },\n });\n};\n\nexport const useEcoSite = (id: string | undefined) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: KEY.site(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await ecoQuery<{ ecoSite: EcoSite | null }>(\n `query EcoSite($id: ID!) {\n ecoSite(id: $id) {\n ${SITE_FIELDS}\n sensors { ${SENSOR_FIELDS} }\n thresholds { ${THRESHOLD_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoSite;\n },\n });\n};\n\nexport const useEcoCreateSite = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateSiteInput) => {\n const result = await ecoQuery<{ ecoCreateSite: EcoSite }>(\n `mutation EcoCreateSite($input: EcoCreateSiteInput!) {\n ecoCreateSite(input: $input) { ${SITE_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateSite;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.sites }),\n });\n};\n\nexport const useEcoUpdateSite = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: EcoUpdateSiteInput }) => {\n const result = await ecoQuery<{ ecoUpdateSite: EcoSite }>(\n `mutation EcoUpdateSite($id: ID!, $input: EcoUpdateSiteInput!) {\n ecoUpdateSite(id: $id, input: $input) { ${SITE_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoUpdateSite;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.sites });\n qc.invalidateQueries({ queryKey: KEY.site(data.id) });\n },\n });\n};\n\nexport const useEcoArchiveSite = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await ecoQuery<{ ecoArchiveSite: boolean }>(\n `mutation EcoArchiveSite($id: ID!) { ecoArchiveSite(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoArchiveSite;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.sites }),\n });\n};\n\n// ============================================================================\n// Sensors / Measurements / Thresholds (Environmental Monitoring)\n// ============================================================================\n\nexport interface SensorFilters {\n siteId?: string;\n kind?: EcoSensorKind;\n status?: EcoSensorStatus;\n}\n\nexport const useEcoSensors = (filters: SensorFilters = {}) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.sensors, filters],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListSensors: EcoConnection<EcoSensor> }>(\n `query EcoListSensors($siteId: ID, $kind: EcoSensorKind, $status: EcoSensorStatus) {\n ecoListSensors(siteId: $siteId, kind: $kind, status: $status) {\n items { ${SENSOR_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { siteId: filters.siteId, kind: filters.kind, status: filters.status },\n apiGatewayUrl\n );\n return result.ecoListSensors;\n },\n });\n};\n\nexport const useEcoCreateSensor = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateSensorInput) => {\n const result = await ecoQuery<{ ecoCreateSensor: EcoSensor }>(\n `mutation EcoCreateSensor($input: EcoCreateSensorInput!) {\n ecoCreateSensor(input: $input) { ${SENSOR_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateSensor;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.sensors });\n qc.invalidateQueries({ queryKey: KEY.site(data.siteId) });\n },\n });\n};\n\nexport const useEcoSetSensorStatus = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; status: EcoSensorStatus }) => {\n const result = await ecoQuery<{ ecoSetSensorStatus: EcoSensor }>(\n `mutation EcoSetSensorStatus($id: ID!, $status: EcoSensorStatus!) {\n ecoSetSensorStatus(id: $id, status: $status) { ${SENSOR_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoSetSensorStatus;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.sensors });\n qc.invalidateQueries({ queryKey: KEY.site(data.siteId) });\n },\n });\n};\n\nexport interface MeasurementFilters {\n siteId?: string;\n sensorId?: string;\n parameter?: string;\n breachesOnly?: boolean;\n pagination?: PaginationInput;\n}\n\nexport const useEcoMeasurements = (filters: MeasurementFilters = {}) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.measurements, filters],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListMeasurements: EcoConnection<EcoMeasurement> }>(\n `query EcoListMeasurements($siteId: ID, $sensorId: ID, $parameter: String, $breachesOnly: Boolean, $pagination: PaginationInput) {\n ecoListMeasurements(siteId: $siteId, sensorId: $sensorId, parameter: $parameter, breachesOnly: $breachesOnly, pagination: $pagination) {\n items { ${MEASUREMENT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n siteId: filters.siteId,\n sensorId: filters.sensorId,\n parameter: filters.parameter,\n breachesOnly: filters.breachesOnly,\n pagination: filters.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.ecoListMeasurements;\n },\n });\n};\n\nexport const useEcoRecordMeasurement = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoRecordMeasurementInput) => {\n const result = await ecoQuery<{ ecoRecordMeasurement: EcoMeasurement }>(\n `mutation EcoRecordMeasurement($input: EcoRecordMeasurementInput!) {\n ecoRecordMeasurement(input: $input) { ${MEASUREMENT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoRecordMeasurement;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.measurements }),\n });\n};\n\nexport const useEcoThresholds = (siteId?: string) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.thresholds, siteId ?? 'all'],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListThresholds: EcoConnection<EcoAlertThreshold> }>(\n `query EcoListThresholds($siteId: ID) {\n ecoListThresholds(siteId: $siteId) {\n items { ${THRESHOLD_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { siteId },\n apiGatewayUrl\n );\n return result.ecoListThresholds;\n },\n });\n};\n\nexport const useEcoCreateThreshold = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateThresholdInput) => {\n const result = await ecoQuery<{ ecoCreateThreshold: EcoAlertThreshold }>(\n `mutation EcoCreateThreshold($input: EcoCreateThresholdInput!) {\n ecoCreateThreshold(input: $input) { ${THRESHOLD_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateThreshold;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.thresholds });\n qc.invalidateQueries({ queryKey: KEY.site(data.siteId) });\n },\n });\n};\n\nexport const useEcoSetThresholdActive = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; isActive: boolean }) => {\n const result = await ecoQuery<{ ecoSetThresholdActive: EcoAlertThreshold }>(\n `mutation EcoSetThresholdActive($id: ID!, $isActive: Boolean!) {\n ecoSetThresholdActive(id: $id, isActive: $isActive) { ${THRESHOLD_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoSetThresholdActive;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.thresholds }),\n });\n};\n\n// ============================================================================\n// Species / Observations / Habitat (Conservation)\n// ============================================================================\n\nexport interface SpeciesFilters {\n taxonGroup?: EcoTaxonGroup;\n conservationStatus?: EcoConservationStatus;\n priorityOnly?: boolean;\n pagination?: PaginationInput;\n}\n\nexport const useEcoSpecies = (filters: SpeciesFilters = {}) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.species, filters],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListSpecies: EcoConnection<EcoSpecies> }>(\n `query EcoListSpecies($taxonGroup: EcoTaxonGroup, $conservationStatus: EcoConservationStatus, $priorityOnly: Boolean, $pagination: PaginationInput) {\n ecoListSpecies(taxonGroup: $taxonGroup, conservationStatus: $conservationStatus, priorityOnly: $priorityOnly, pagination: $pagination) {\n items { ${SPECIES_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n taxonGroup: filters.taxonGroup,\n conservationStatus: filters.conservationStatus,\n priorityOnly: filters.priorityOnly,\n pagination: filters.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.ecoListSpecies;\n },\n });\n};\n\nexport const useEcoSpeciesDetail = (id: string | undefined) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: KEY.speciesOne(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await ecoQuery<{ ecoSpecies: EcoSpecies | null }>(\n `query EcoSpeciesDetail($id: ID!) {\n ecoSpecies(id: $id) {\n ${SPECIES_FIELDS}\n observations { ${OBSERVATION_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoSpecies;\n },\n });\n};\n\nexport const useEcoCreateSpecies = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateSpeciesInput) => {\n const result = await ecoQuery<{ ecoCreateSpecies: EcoSpecies }>(\n `mutation EcoCreateSpecies($input: EcoCreateSpeciesInput!) {\n ecoCreateSpecies(input: $input) { ${SPECIES_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateSpecies;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.species }),\n });\n};\n\nexport const useEcoUpdateSpecies = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: EcoUpdateSpeciesInput }) => {\n const result = await ecoQuery<{ ecoUpdateSpecies: EcoSpecies }>(\n `mutation EcoUpdateSpecies($id: ID!, $input: EcoUpdateSpeciesInput!) {\n ecoUpdateSpecies(id: $id, input: $input) { ${SPECIES_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoUpdateSpecies;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.species });\n qc.invalidateQueries({ queryKey: KEY.speciesOne(data.id) });\n },\n });\n};\n\nexport const useEcoArchiveSpecies = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await ecoQuery<{ ecoArchiveSpecies: boolean }>(\n `mutation EcoArchiveSpecies($id: ID!) { ecoArchiveSpecies(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoArchiveSpecies;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.species }),\n });\n};\n\nexport interface ObservationFilters {\n speciesId?: string;\n siteId?: string;\n pagination?: PaginationInput;\n}\n\nexport const useEcoObservations = (filters: ObservationFilters = {}) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.observations, filters],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListObservations: EcoConnection<EcoObservation> }>(\n `query EcoListObservations($speciesId: ID, $siteId: ID, $pagination: PaginationInput) {\n ecoListObservations(speciesId: $speciesId, siteId: $siteId, pagination: $pagination) {\n items { ${OBSERVATION_FIELDS} species { id commonName scientificName taxonGroup } }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n speciesId: filters.speciesId,\n siteId: filters.siteId,\n pagination: filters.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.ecoListObservations;\n },\n });\n};\n\nexport const useEcoRecordObservation = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoRecordObservationInput) => {\n const result = await ecoQuery<{ ecoRecordObservation: EcoObservation }>(\n `mutation EcoRecordObservation($input: EcoRecordObservationInput!) {\n ecoRecordObservation(input: $input) { ${OBSERVATION_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoRecordObservation;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.observations });\n qc.invalidateQueries({ queryKey: KEY.speciesOne(data.speciesId) });\n },\n });\n};\n\nexport const useEcoHabitatProjects = (status?: EcoHabitatProjectStatus) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.habitatProjects, status ?? 'all'],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListHabitatProjects: EcoConnection<EcoHabitatProject> }>(\n `query EcoListHabitatProjects($status: EcoHabitatProjectStatus) {\n ecoListHabitatProjects(status: $status) {\n items { ${HABITAT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { status },\n apiGatewayUrl\n );\n return result.ecoListHabitatProjects;\n },\n });\n};\n\nexport const useEcoHabitatProject = (id: string | undefined) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: KEY.habitatProject(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await ecoQuery<{ ecoHabitatProject: EcoHabitatProject | null }>(\n `query EcoHabitatProject($id: ID!) {\n ecoHabitatProject(id: $id) {\n ${HABITAT_FIELDS}\n activities { ${ACTIVITY_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoHabitatProject;\n },\n });\n};\n\nexport const useEcoCreateHabitatProject = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateHabitatProjectInput) => {\n const result = await ecoQuery<{ ecoCreateHabitatProject: EcoHabitatProject }>(\n `mutation EcoCreateHabitatProject($input: EcoCreateHabitatProjectInput!) {\n ecoCreateHabitatProject(input: $input) { ${HABITAT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateHabitatProject;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.habitatProjects }),\n });\n};\n\nexport const useEcoTransitionHabitatProject = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; status: EcoHabitatProjectStatus }) => {\n const result = await ecoQuery<{ ecoTransitionHabitatProject: EcoHabitatProject }>(\n `mutation EcoTransitionHabitatProject($id: ID!, $status: EcoHabitatProjectStatus!) {\n ecoTransitionHabitatProject(id: $id, status: $status) { ${HABITAT_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoTransitionHabitatProject;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.habitatProjects });\n qc.invalidateQueries({ queryKey: KEY.habitatProject(data.id) });\n },\n });\n};\n\nexport const useEcoLogRestorationActivity = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoLogRestorationActivityInput) => {\n const result = await ecoQuery<{ ecoLogRestorationActivity: EcoRestorationActivity }>(\n `mutation EcoLogRestorationActivity($input: EcoLogRestorationActivityInput!) {\n ecoLogRestorationActivity(input: $input) { ${ACTIVITY_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoLogRestorationActivity;\n },\n onSuccess: (data) => qc.invalidateQueries({ queryKey: KEY.habitatProject(data.projectId) }),\n });\n};\n\n// ============================================================================\n// Carbon ledger / Emission factors / Reduction targets (Sustainability)\n// ============================================================================\n\nexport const useEcoEmissionFactors = (scope?: EcoEmissionScope, activeOnly?: boolean) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.emissionFactors, scope ?? 'all', activeOnly ?? false],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListEmissionFactors: EcoConnection<EcoEmissionFactor> }>(\n `query EcoListEmissionFactors($scope: EcoEmissionScope, $activeOnly: Boolean) {\n ecoListEmissionFactors(scope: $scope, activeOnly: $activeOnly) {\n items { ${FACTOR_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { scope, activeOnly },\n apiGatewayUrl\n );\n return result.ecoListEmissionFactors;\n },\n });\n};\n\nexport const useEcoCreateEmissionFactor = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateEmissionFactorInput) => {\n const result = await ecoQuery<{ ecoCreateEmissionFactor: EcoEmissionFactor }>(\n `mutation EcoCreateEmissionFactor($input: EcoCreateEmissionFactorInput!) {\n ecoCreateEmissionFactor(input: $input) { ${FACTOR_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateEmissionFactor;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.emissionFactors }),\n });\n};\n\nexport interface CarbonEntryFilters {\n scope?: EcoEmissionScope;\n siteId?: string;\n status?: EcoCarbonEntryStatus;\n pagination?: PaginationInput;\n}\n\nexport const useEcoCarbonEntries = (filters: CarbonEntryFilters = {}) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.carbonEntries, filters],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListCarbonEntries: EcoConnection<EcoCarbonEntry> }>(\n `query EcoListCarbonEntries($scope: EcoEmissionScope, $siteId: ID, $status: EcoCarbonEntryStatus, $pagination: PaginationInput) {\n ecoListCarbonEntries(scope: $scope, siteId: $siteId, status: $status, pagination: $pagination) {\n items { ${CARBON_FIELDS} factor { id name factorKgco2e activityUnit } }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n scope: filters.scope,\n siteId: filters.siteId,\n status: filters.status,\n pagination: filters.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.ecoListCarbonEntries;\n },\n });\n};\n\n/** Total CO2e by scope + grand total, in one aliased query. */\nexport interface EcoCarbonTotals {\n total: number;\n scope1: number;\n scope2: number;\n scope3: number;\n}\n\nexport const useEcoCarbonTotals = (siteId?: string) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.carbonTotals, siteId ?? 'all'],\n queryFn: async (): Promise<EcoCarbonTotals> => {\n const result = await ecoQuery<{\n total: number;\n scope1: number;\n scope2: number;\n scope3: number;\n }>(\n `query EcoCarbonTotals($siteId: ID) {\n total: ecoCarbonTotalKg(siteId: $siteId)\n scope1: ecoCarbonTotalKg(scope: SCOPE_1, siteId: $siteId)\n scope2: ecoCarbonTotalKg(scope: SCOPE_2, siteId: $siteId)\n scope3: ecoCarbonTotalKg(scope: SCOPE_3, siteId: $siteId)\n }`,\n { siteId },\n apiGatewayUrl\n );\n return result;\n },\n });\n};\n\nexport const useEcoRecordCarbonEntry = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoRecordCarbonEntryInput) => {\n const result = await ecoQuery<{ ecoRecordCarbonEntry: EcoCarbonEntry }>(\n `mutation EcoRecordCarbonEntry($input: EcoRecordCarbonEntryInput!) {\n ecoRecordCarbonEntry(input: $input) { ${CARBON_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoRecordCarbonEntry;\n },\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.carbonEntries });\n qc.invalidateQueries({ queryKey: KEY.carbonTotals });\n },\n });\n};\n\nexport const useEcoVerifyCarbonEntry = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await ecoQuery<{ ecoVerifyCarbonEntry: EcoCarbonEntry }>(\n `mutation EcoVerifyCarbonEntry($id: ID!) {\n ecoVerifyCarbonEntry(id: $id) { ${CARBON_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoVerifyCarbonEntry;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.carbonEntries }),\n });\n};\n\nexport const useEcoReductionTargets = (status?: EcoReductionTargetStatus) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.reductionTargets, status ?? 'all'],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListReductionTargets: EcoConnection<EcoReductionTarget> }>(\n `query EcoListReductionTargets($status: EcoReductionTargetStatus) {\n ecoListReductionTargets(status: $status) {\n items { ${TARGET_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { status },\n apiGatewayUrl\n );\n return result.ecoListReductionTargets;\n },\n });\n};\n\nexport const useEcoCreateReductionTarget = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateReductionTargetInput) => {\n const result = await ecoQuery<{ ecoCreateReductionTarget: EcoReductionTarget }>(\n `mutation EcoCreateReductionTarget($input: EcoCreateReductionTargetInput!) {\n ecoCreateReductionTarget(input: $input) { ${TARGET_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateReductionTarget;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.reductionTargets }),\n });\n};\n\nexport const useEcoSetReductionTargetStatus = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; status: EcoReductionTargetStatus }) => {\n const result = await ecoQuery<{ ecoSetReductionTargetStatus: EcoReductionTarget }>(\n `mutation EcoSetReductionTargetStatus($id: ID!, $status: EcoReductionTargetStatus!) {\n ecoSetReductionTargetStatus(id: $id, status: $status) { ${TARGET_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoSetReductionTargetStatus;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.reductionTargets }),\n });\n};\n\n// ============================================================================\n// Reports (Sustainability & Reporting)\n// ============================================================================\n\nexport const useEcoReports = (status?: EcoReportStatus, pagination?: PaginationInput) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: [...KEY.reports, status ?? 'all', pagination ?? DEFAULT_PAGE],\n queryFn: async () => {\n const result = await ecoQuery<{ ecoListReports: EcoConnection<EcoReport> }>(\n `query EcoListReports($status: EcoReportStatus, $pagination: PaginationInput) {\n ecoListReports(status: $status, pagination: $pagination) {\n items { ${REPORT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { status, pagination: pagination ?? DEFAULT_PAGE },\n apiGatewayUrl\n );\n return result.ecoListReports;\n },\n });\n};\n\nexport const useEcoReport = (id: string | undefined) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: KEY.report(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await ecoQuery<{ ecoReport: EcoReport | null }>(\n `query EcoReport($id: ID!) {\n ecoReport(id: $id) {\n ${REPORT_FIELDS}\n lineItems { ${LINE_ITEM_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.ecoReport;\n },\n });\n};\n\nexport const useEcoCreateReport = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoCreateReportInput) => {\n const result = await ecoQuery<{ ecoCreateReport: EcoReport }>(\n `mutation EcoCreateReport($input: EcoCreateReportInput!) {\n ecoCreateReport(input: $input) { ${REPORT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoCreateReport;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.reports }),\n });\n};\n\nexport const useEcoAddReportLineItem = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: EcoAddReportLineItemInput) => {\n const result = await ecoQuery<{ ecoAddReportLineItem: EcoReportLineItem }>(\n `mutation EcoAddReportLineItem($input: EcoAddReportLineItemInput!) {\n ecoAddReportLineItem(input: $input) { ${LINE_ITEM_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.ecoAddReportLineItem;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.reports });\n qc.invalidateQueries({ queryKey: KEY.report(data.reportId) });\n },\n });\n};\n\nexport const useEcoPublishReport = () => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; fileId?: string | null }) => {\n const result = await ecoQuery<{ ecoPublishReport: EcoReport }>(\n `mutation EcoPublishReport($id: ID!, $fileId: ID) {\n ecoPublishReport(id: $id, fileId: $fileId) { ${REPORT_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.ecoPublishReport;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.reports });\n qc.invalidateQueries({ queryKey: KEY.report(data.id) });\n },\n });\n};\n"],"mappings":"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"}
|
|
@@ -54,7 +54,7 @@ function F() {
|
|
|
54
54
|
}), me = S({ pagination: {
|
|
55
55
|
limit: 6,
|
|
56
56
|
offset: 0
|
|
57
|
-
} }), he = C(), H = L.data?.items ?? [], U = R.data?.items ?? [], W = z.data ?? [], G = he.data ?? [], K = H.filter((e) => e.status === "ACTIVE").length, ge = U.filter((e) => e.isPriority).length, q = U.filter((e) => [
|
|
57
|
+
} }), he = C(), H = L.data?.items ?? [], U = R.data?.items ?? [], W = z.data?.items ?? [], G = he.data?.items ?? [], K = H.filter((e) => e.status === "ACTIVE").length, ge = U.filter((e) => e.isPriority).length, q = U.filter((e) => [
|
|
58
58
|
"VULNERABLE",
|
|
59
59
|
"ENDANGERED",
|
|
60
60
|
"CRITICALLY_ENDANGERED"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/ecoimpacthub/pages/DashboardPage.tsx"],"sourcesContent":["/**\n * Dashboard — EcoImpactHub environment, conservation & sustainability overview.\n * @module ecoimpacthub/pages\n *\n * KPIs are aggregated client-side from the real `eco*` list endpoints plus the\n * `ecoCarbonTotalKg` aggregate (by scope). Widgets show recent field\n * observations and open threshold breaches. No mock data.\n */\n\nimport { useMemo } from 'react';\nimport {\n MapPin,\n PawPrint,\n Trees,\n Factory,\n TriangleAlert,\n Binoculars,\n ShieldCheck,\n ArrowRight,\n Radio,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n BarChart,\n Bar,\n XAxis,\n YAxis,\n CartesianGrid,\n ResponsiveContainer,\n Tooltip,\n Cell,\n LabelList,\n} from 'recharts';\nimport { PageLayout } from '../components/PageLayout';\nimport { MetricsCard } from '../components/MetricsCard';\nimport { StatusBadge } from '../components/StatusBadge';\nimport { MiniBar } from '../components/MiniBar';\nimport { LoadingView, Section } from '../components/StateViews';\nimport { EmptyState } from '../components/EmptyState';\nimport { ScopeSplitBar, ScopeLegend, Meter, SCOPE_HUE } from './carbonVisuals';\nimport { useEcoImpactHub } from '../context';\nimport {\n useEcoSites,\n useEcoSpecies,\n useEcoHabitatProjects,\n useEcoCarbonTotals,\n useEcoMeasurements,\n useEcoObservations,\n useEcoSensors,\n} from '../hooks';\nimport {\n formatNumber,\n formatRelativeTime,\n formatCo2e,\n formatEnumLabel,\n formatPercent,\n} from '../utils/formatters';\nimport type { EcoConservationStatus, EcoEmissionScope } from '../types';\n\nconst ACTIVE_PROJECT_STATUSES = new Set(['PLANNED', 'IN_PROGRESS', 'MONITORING']);\n\n/** Conservation-status → meter tint (semantic, IUCN-severity ordered). */\nconst CONSERVATION_TONE: Record<EcoConservationStatus, string> = {\n LEAST_CONCERN: 'var(--color-status-success-text)',\n NEAR_THREATENED: 'var(--color-accent-teal)',\n VULNERABLE: 'var(--color-status-warning-text)',\n ENDANGERED: 'var(--color-status-error-text)',\n CRITICALLY_ENDANGERED: 'var(--color-status-error-text)',\n EXTINCT_IN_WILD: 'var(--color-text-tertiary)',\n DATA_DEFICIENT: 'var(--color-text-tertiary)',\n NOT_EVALUATED: 'var(--color-text-tertiary)',\n};\n\nexport function DashboardPage() {\n const { navigateTo, currentUser } = useEcoImpactHub();\n\n const sites = useEcoSites({ pagination: { limit: 100, offset: 0 } });\n const species = useEcoSpecies({ pagination: { limit: 100, offset: 0 } });\n const projects = useEcoHabitatProjects();\n const carbon = useEcoCarbonTotals();\n const breaches = useEcoMeasurements({ breachesOnly: true, pagination: { limit: 6, offset: 0 } });\n const observations = useEcoObservations({ pagination: { limit: 6, offset: 0 } });\n const sensors = useEcoSensors();\n\n const siteRows = sites.data?.items ?? [];\n const speciesRows = species.data?.items ?? [];\n const projectRows = projects.data ?? [];\n const sensorRows = sensors.data ?? [];\n\n const activeSites = siteRows.filter((s) => s.status === 'ACTIVE').length;\n const priorityCount = speciesRows.filter((s) => s.isPriority).length;\n const threatened = speciesRows.filter((s) =>\n ['VULNERABLE', 'ENDANGERED', 'CRITICALLY_ENDANGERED'].includes(s.conservationStatus)\n ).length;\n const activeProjects = projectRows.filter((p) => ACTIVE_PROJECT_STATUSES.has(p.status)).length;\n const onlineSensors = sensorRows.filter((s) => s.status === 'ONLINE').length;\n const offlineSensors = sensorRows.filter((s) =>\n ['OFFLINE', 'DEGRADED', 'MAINTENANCE'].includes(s.status)\n ).length;\n\n const carbonData = useMemo<{ scope: EcoEmissionScope; label: string; kg: number }[]>(() => {\n const c = carbon.data;\n if (!c) return [];\n return [\n { scope: 'SCOPE_1', label: 'Scope 1', kg: c.scope1 },\n { scope: 'SCOPE_2', label: 'Scope 2', kg: c.scope2 },\n { scope: 'SCOPE_3', label: 'Scope 3', kg: c.scope3 },\n ];\n }, [carbon.data]);\n\n const isInitialLoading =\n sites.isLoading && species.isLoading && projects.isLoading && carbon.isLoading;\n\n if (isInitialLoading) {\n return (\n <PageLayout title=\"EcoImpactHub\" titleGradient aurora>\n <LoadingView label=\"Loading your impact overview…\" />\n </PageLayout>\n );\n }\n\n const greetingName = currentUser?.firstName || currentUser?.name || 'there';\n const breachRows = breaches.data?.items ?? [];\n const observationRows = observations.data?.items ?? [];\n\n return (\n <PageLayout\n title=\"EcoImpactHub\"\n titleGradient\n aurora\n description={`Welcome back, ${greetingName} — your environment, conservation & sustainability control room.`}\n >\n {/* KPI grid */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6\">\n <MetricsCard\n icon={<MapPin className=\"h-5 w-5\" />}\n value={\n sites.data?.pageInfo?.hasMore ? `${siteRows.length}+` : formatNumber(siteRows.length)\n }\n label=\"Monitored sites\"\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={siteRows.length ? (activeSites / siteRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-action-primary-bg\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{activeSites}</span> active\n </p>\n </div>\n }\n />\n <MetricsCard\n icon={<PawPrint className=\"h-5 w-5\" />}\n value={\n species.data?.pageInfo?.hasMore\n ? `${speciesRows.length}+`\n : formatNumber(speciesRows.length)\n }\n label=\"Species tracked\"\n accent={threatened > 0 ? 'warning' : undefined}\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={speciesRows.length ? (threatened / speciesRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-status-warning-text\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{priorityCount}</span> priority ·{' '}\n <span className=\"tabular-nums text-text-secondary\">{threatened}</span> threatened\n </p>\n </div>\n }\n />\n <MetricsCard\n icon={<Trees className=\"h-5 w-5\" />}\n value={formatNumber(activeProjects)}\n label=\"Active habitat projects\"\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={projectRows.length ? (activeProjects / projectRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-action-primary-bg\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">\n {formatNumber(projectRows.length)}\n </span>{' '}\n total\n </p>\n </div>\n }\n />\n <MetricsCard\n icon={<Factory className=\"h-5 w-5\" />}\n value={carbon.data ? formatCo2e(carbon.data.total) : '—'}\n label=\"Total footprint\"\n featured\n footer={\n carbon.data && carbon.data.total > 0 ? (\n <div className=\"space-y-2\">\n <ScopeSplitBar\n scope1={carbon.data.scope1}\n scope2={carbon.data.scope2}\n scope3={carbon.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={<Radio className=\"h-5 w-5\" />}\n value={formatNumber(onlineSensors)}\n label=\"Sensors online\"\n accent={offlineSensors > 0 ? 'warning' : 'success'}\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={sensorRows.length ? (onlineSensors / sensorRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-status-success-text\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{offlineSensors}</span> need\n attention\n </p>\n </div>\n }\n />\n <MetricsCard\n icon={<TriangleAlert className=\"h-5 w-5\" />}\n value={\n breaches.data?.pageInfo?.hasMore\n ? `${breachRows.length}+`\n : formatNumber(breachRows.length)\n }\n label=\"Open breaches\"\n accent={breachRows.length > 0 ? 'error' : 'success'}\n footer={\n <p\n className={\n breachRows.length > 0\n ? 'text-xs font-medium text-status-error-text'\n : 'text-xs text-text-tertiary'\n }\n >\n {breachRows.length > 0 ? 'Needs attention' : 'All parameters in range'}\n </p>\n }\n />\n </div>\n\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Carbon by scope */}\n <GlassCard treatment=\"glass\" className=\"p-6 lg:col-span-2\">\n <div className=\"mb-4 flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">\n Carbon footprint by scope\n </h2>\n <p className=\"mt-0.5 text-sm text-text-secondary\">\n GHG Protocol Scope 1 / 2 / 3 emissions (CO₂e).\n </p>\n </div>\n <div className=\"flex items-center gap-4\">\n {carbon.data && carbon.data.total > 0 && (\n <div className=\"text-right\">\n <p className=\"text-lg font-semibold tabular-nums text-text-primary\">\n {formatCo2e(carbon.data.total)}\n </p>\n <p className=\"text-xs text-text-tertiary\">total</p>\n </div>\n )}\n <button\n type=\"button\"\n onClick={() => navigateTo('carbon')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n Ledger <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n {carbonData.every((d) => d.kg === 0) ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Factory className=\"h-10 w-10\" />}\n title=\"No carbon entries yet\"\n description=\"Record activity in the carbon ledger to see your Scope 1–3 footprint here.\"\n />\n ) : (\n <>\n <div className=\"h-56\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={carbonData} margin={{ top: 20, right: 8, left: 8, bottom: 0 }}>\n <defs>\n {carbonData.map((d) => (\n <linearGradient\n key={d.scope}\n id={`ecoScopeGrad-${d.scope}`}\n x1=\"0\"\n y1=\"0\"\n x2=\"0\"\n y2=\"1\"\n >\n <stop\n offset=\"0%\"\n style={{ stopColor: SCOPE_HUE[d.scope], stopOpacity: 1 }}\n />\n <stop\n offset=\"100%\"\n style={{ stopColor: SCOPE_HUE[d.scope], stopOpacity: 0.55 }}\n />\n </linearGradient>\n ))}\n </defs>\n <CartesianGrid\n vertical={false}\n stroke=\"var(--color-border-seam)\"\n strokeOpacity={0.6}\n strokeDasharray=\"3 4\"\n />\n <XAxis\n dataKey=\"label\"\n tick={{ fill: 'var(--color-text-secondary)', fontSize: 12 }}\n axisLine={{ stroke: 'var(--color-border-seam)' }}\n tickLine={false}\n dy={4}\n />\n <YAxis\n tick={{ fill: 'var(--color-text-tertiary)', fontSize: 11 }}\n axisLine={false}\n tickLine={false}\n width={48}\n tickFormatter={(v: number) =>\n v >= 1000 ? `${Math.round(v / 1000)}t` : `${v}`\n }\n />\n <Tooltip\n cursor={{ fill: 'var(--color-bg-sunken)', opacity: 0.4 }}\n contentStyle={{\n background: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border-seam)',\n borderRadius: 12,\n color: 'var(--color-text-primary)',\n }}\n formatter={(value: number) => [formatCo2e(value), 'Emissions']}\n />\n <Bar dataKey=\"kg\" radius={[8, 8, 2, 2]} maxBarSize={72}>\n {carbonData.map((d) => (\n <Cell key={d.scope} fill={`url(#ecoScopeGrad-${d.scope})`} />\n ))}\n <LabelList\n dataKey=\"kg\"\n position=\"top\"\n formatter={(v: number) => (v > 0 ? formatCo2e(v) : '')}\n style={{\n fill: 'var(--color-text-secondary)',\n fontSize: 11,\n fontWeight: 600,\n }}\n />\n </Bar>\n </BarChart>\n </ResponsiveContainer>\n </div>\n <ScopeLegend data={carbonData} className=\"mt-4 border-t border-border-seam pt-4\" />\n </>\n )}\n </GlassCard>\n\n {/* Recent breaches */}\n <GlassCard treatment=\"glass\" className=\"p-6\">\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"text-base font-semibold text-text-primary\">Recent breaches</h2>\n {breachRows.length > 0 && (\n <span className=\"rounded-full bg-status-error-bg-subtle px-2 py-0.5 text-xs font-medium tabular-nums text-status-error-text\">\n {breaches.data?.pageInfo?.hasMore ? `${breachRows.length}+` : breachRows.length}\n </span>\n )}\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo('monitoring')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n Monitoring <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n {breachRows.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center rounded-xl border border-dashed border-border-seam py-10 text-center\">\n <span className=\"flex size-12 items-center justify-center rounded-full bg-status-success-bg-subtle\">\n <ShieldCheck className=\"h-6 w-6 text-status-success-text\" />\n </span>\n <p className=\"mt-3 text-sm font-medium text-text-primary\">All parameters in range</p>\n <p className=\"mt-1 text-xs text-text-tertiary\">No open threshold breaches.</p>\n </div>\n ) : (\n <ul className=\"space-y-2.5\">\n {breachRows.map((m) => (\n <li\n key={m.id}\n className=\"flex items-start justify-between gap-3 rounded-xl bg-bg-sunken/50 p-3\"\n >\n <div className=\"flex min-w-0 items-start gap-2.5\">\n <span\n aria-hidden=\"true\"\n className=\"mt-1.5 size-2 shrink-0 rounded-full bg-status-error-text motion-safe:animate-vc-glow-pulse\"\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {m.parameter}\n </p>\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums\">\n {formatNumber(m.value)} {m.unit}\n </span>{' '}\n · {formatRelativeTime(m.recordedAt)}\n </p>\n </div>\n </div>\n <StatusBadge status=\"BREACH\" />\n </li>\n ))}\n </ul>\n )}\n </GlassCard>\n </div>\n\n {/* Recent observations */}\n <Section\n title=\"Recent field observations\"\n description=\"Latest wildlife & biodiversity sightings recorded across your sites.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('observations')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n All observations <ArrowRight className=\"h-4 w-4\" />\n </button>\n }\n >\n {observationRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Binoculars className=\"h-10 w-10\" />}\n title=\"No observations yet\"\n description=\"Record your first field observation to build your biodiversity dataset.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {observationRows.map((o) => (\n <GlassCard\n key={o.id}\n treatment=\"plain\"\n className=\"p-4 transition-shadow hover:shadow-float\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex min-w-0 items-start gap-2.5\">\n <span className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n <Binoculars className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold text-text-primary\">\n {o.species?.commonName ?? 'Unknown species'}\n </p>\n {o.species?.scientificName && (\n <p className=\"truncate text-xs italic text-text-tertiary\">\n {o.species.scientificName}\n </p>\n )}\n </div>\n </div>\n <span className=\"shrink-0 rounded-full bg-[var(--color-accent-soft)] px-2 py-0.5 text-xs font-medium tabular-nums text-text-primary\">\n ×{formatNumber(o.count)}\n </span>\n </div>\n <div className=\"mt-3 flex items-center justify-between border-t border-border-seam/70 pt-2.5\">\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\">\n {formatEnumLabel(o.method)}\n </span>\n <span className=\"text-xs text-text-tertiary\">\n {formatRelativeTime(o.observedAt)}\n </span>\n </div>\n </GlassCard>\n ))}\n </div>\n )}\n </Section>\n\n {/* Conservation status snapshot */}\n {speciesRows.length > 0 && (\n <Section\n title=\"Conservation status\"\n description=\"Distribution of tracked species by IUCN-style status.\"\n >\n <GlassCard treatment=\"plain\" className=\"p-6\">\n <div className=\"space-y-3.5\">\n {(() => {\n const counts = new Map<string, number>();\n for (const s of speciesRows) {\n counts.set(s.conservationStatus, (counts.get(s.conservationStatus) ?? 0) + 1);\n }\n const total = speciesRows.length;\n return [...counts.entries()]\n .sort((a, b) => b[1] - a[1])\n .map(([status, count]) => {\n const pct = (count / total) * 100;\n const tone =\n CONSERVATION_TONE[status as EcoConservationStatus] ??\n 'var(--color-text-tertiary)';\n return (\n <div key={status} className=\"flex items-center gap-3 sm:gap-4\">\n <div className=\"w-36 shrink-0 sm:w-48\">\n <StatusBadge status={status} />\n </div>\n <Meter value={pct} color={tone} className=\"flex-1\" />\n <span className=\"w-9 shrink-0 text-right text-sm font-medium tabular-nums text-text-primary\">\n {count}\n </span>\n <span className=\"hidden w-12 shrink-0 text-right text-xs tabular-nums text-text-tertiary sm:inline\">\n {formatPercent(pct)}\n </span>\n </div>\n );\n });\n })()}\n </div>\n </GlassCard>\n </Section>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/ecoimpacthub/pages/DashboardPage.tsx"],"sourcesContent":["/**\n * Dashboard — EcoImpactHub environment, conservation & sustainability overview.\n * @module ecoimpacthub/pages\n *\n * KPIs are aggregated client-side from the real `eco*` list endpoints plus the\n * `ecoCarbonTotalKg` aggregate (by scope). Widgets show recent field\n * observations and open threshold breaches. No mock data.\n */\n\nimport { useMemo } from 'react';\nimport {\n MapPin,\n PawPrint,\n Trees,\n Factory,\n TriangleAlert,\n Binoculars,\n ShieldCheck,\n ArrowRight,\n Radio,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n BarChart,\n Bar,\n XAxis,\n YAxis,\n CartesianGrid,\n ResponsiveContainer,\n Tooltip,\n Cell,\n LabelList,\n} from 'recharts';\nimport { PageLayout } from '../components/PageLayout';\nimport { MetricsCard } from '../components/MetricsCard';\nimport { StatusBadge } from '../components/StatusBadge';\nimport { MiniBar } from '../components/MiniBar';\nimport { LoadingView, Section } from '../components/StateViews';\nimport { EmptyState } from '../components/EmptyState';\nimport { ScopeSplitBar, ScopeLegend, Meter, SCOPE_HUE } from './carbonVisuals';\nimport { useEcoImpactHub } from '../context';\nimport {\n useEcoSites,\n useEcoSpecies,\n useEcoHabitatProjects,\n useEcoCarbonTotals,\n useEcoMeasurements,\n useEcoObservations,\n useEcoSensors,\n} from '../hooks';\nimport {\n formatNumber,\n formatRelativeTime,\n formatCo2e,\n formatEnumLabel,\n formatPercent,\n} from '../utils/formatters';\nimport type { EcoConservationStatus, EcoEmissionScope } from '../types';\n\nconst ACTIVE_PROJECT_STATUSES = new Set(['PLANNED', 'IN_PROGRESS', 'MONITORING']);\n\n/** Conservation-status → meter tint (semantic, IUCN-severity ordered). */\nconst CONSERVATION_TONE: Record<EcoConservationStatus, string> = {\n LEAST_CONCERN: 'var(--color-status-success-text)',\n NEAR_THREATENED: 'var(--color-accent-teal)',\n VULNERABLE: 'var(--color-status-warning-text)',\n ENDANGERED: 'var(--color-status-error-text)',\n CRITICALLY_ENDANGERED: 'var(--color-status-error-text)',\n EXTINCT_IN_WILD: 'var(--color-text-tertiary)',\n DATA_DEFICIENT: 'var(--color-text-tertiary)',\n NOT_EVALUATED: 'var(--color-text-tertiary)',\n};\n\nexport function DashboardPage() {\n const { navigateTo, currentUser } = useEcoImpactHub();\n\n const sites = useEcoSites({ pagination: { limit: 100, offset: 0 } });\n const species = useEcoSpecies({ pagination: { limit: 100, offset: 0 } });\n const projects = useEcoHabitatProjects();\n const carbon = useEcoCarbonTotals();\n const breaches = useEcoMeasurements({ breachesOnly: true, pagination: { limit: 6, offset: 0 } });\n const observations = useEcoObservations({ pagination: { limit: 6, offset: 0 } });\n const sensors = useEcoSensors();\n\n const siteRows = sites.data?.items ?? [];\n const speciesRows = species.data?.items ?? [];\n const projectRows = projects.data?.items ?? [];\n const sensorRows = sensors.data?.items ?? [];\n\n const activeSites = siteRows.filter((s) => s.status === 'ACTIVE').length;\n const priorityCount = speciesRows.filter((s) => s.isPriority).length;\n const threatened = speciesRows.filter((s) =>\n ['VULNERABLE', 'ENDANGERED', 'CRITICALLY_ENDANGERED'].includes(s.conservationStatus)\n ).length;\n const activeProjects = projectRows.filter((p) => ACTIVE_PROJECT_STATUSES.has(p.status)).length;\n const onlineSensors = sensorRows.filter((s) => s.status === 'ONLINE').length;\n const offlineSensors = sensorRows.filter((s) =>\n ['OFFLINE', 'DEGRADED', 'MAINTENANCE'].includes(s.status)\n ).length;\n\n const carbonData = useMemo<{ scope: EcoEmissionScope; label: string; kg: number }[]>(() => {\n const c = carbon.data;\n if (!c) return [];\n return [\n { scope: 'SCOPE_1', label: 'Scope 1', kg: c.scope1 },\n { scope: 'SCOPE_2', label: 'Scope 2', kg: c.scope2 },\n { scope: 'SCOPE_3', label: 'Scope 3', kg: c.scope3 },\n ];\n }, [carbon.data]);\n\n const isInitialLoading =\n sites.isLoading && species.isLoading && projects.isLoading && carbon.isLoading;\n\n if (isInitialLoading) {\n return (\n <PageLayout title=\"EcoImpactHub\" titleGradient aurora>\n <LoadingView label=\"Loading your impact overview…\" />\n </PageLayout>\n );\n }\n\n const greetingName = currentUser?.firstName || currentUser?.name || 'there';\n const breachRows = breaches.data?.items ?? [];\n const observationRows = observations.data?.items ?? [];\n\n return (\n <PageLayout\n title=\"EcoImpactHub\"\n titleGradient\n aurora\n description={`Welcome back, ${greetingName} — your environment, conservation & sustainability control room.`}\n >\n {/* KPI grid */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6\">\n <MetricsCard\n icon={<MapPin className=\"h-5 w-5\" />}\n value={\n sites.data?.pageInfo?.hasMore ? `${siteRows.length}+` : formatNumber(siteRows.length)\n }\n label=\"Monitored sites\"\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={siteRows.length ? (activeSites / siteRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-action-primary-bg\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{activeSites}</span> active\n </p>\n </div>\n }\n />\n <MetricsCard\n icon={<PawPrint className=\"h-5 w-5\" />}\n value={\n species.data?.pageInfo?.hasMore\n ? `${speciesRows.length}+`\n : formatNumber(speciesRows.length)\n }\n label=\"Species tracked\"\n accent={threatened > 0 ? 'warning' : undefined}\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={speciesRows.length ? (threatened / speciesRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-status-warning-text\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{priorityCount}</span> priority ·{' '}\n <span className=\"tabular-nums text-text-secondary\">{threatened}</span> threatened\n </p>\n </div>\n }\n />\n <MetricsCard\n icon={<Trees className=\"h-5 w-5\" />}\n value={formatNumber(activeProjects)}\n label=\"Active habitat projects\"\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={projectRows.length ? (activeProjects / projectRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-action-primary-bg\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">\n {formatNumber(projectRows.length)}\n </span>{' '}\n total\n </p>\n </div>\n }\n />\n <MetricsCard\n icon={<Factory className=\"h-5 w-5\" />}\n value={carbon.data ? formatCo2e(carbon.data.total) : '—'}\n label=\"Total footprint\"\n featured\n footer={\n carbon.data && carbon.data.total > 0 ? (\n <div className=\"space-y-2\">\n <ScopeSplitBar\n scope1={carbon.data.scope1}\n scope2={carbon.data.scope2}\n scope3={carbon.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={<Radio className=\"h-5 w-5\" />}\n value={formatNumber(onlineSensors)}\n label=\"Sensors online\"\n accent={offlineSensors > 0 ? 'warning' : 'success'}\n footer={\n <div className=\"space-y-2\">\n <MiniBar\n value={sensorRows.length ? (onlineSensors / sensorRows.length) * 100 : 0}\n height={4}\n barClassName=\"bg-status-success-text\"\n />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{offlineSensors}</span> need\n attention\n </p>\n </div>\n }\n />\n <MetricsCard\n icon={<TriangleAlert className=\"h-5 w-5\" />}\n value={\n breaches.data?.pageInfo?.hasMore\n ? `${breachRows.length}+`\n : formatNumber(breachRows.length)\n }\n label=\"Open breaches\"\n accent={breachRows.length > 0 ? 'error' : 'success'}\n footer={\n <p\n className={\n breachRows.length > 0\n ? 'text-xs font-medium text-status-error-text'\n : 'text-xs text-text-tertiary'\n }\n >\n {breachRows.length > 0 ? 'Needs attention' : 'All parameters in range'}\n </p>\n }\n />\n </div>\n\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Carbon by scope */}\n <GlassCard treatment=\"glass\" className=\"p-6 lg:col-span-2\">\n <div className=\"mb-4 flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">\n Carbon footprint by scope\n </h2>\n <p className=\"mt-0.5 text-sm text-text-secondary\">\n GHG Protocol Scope 1 / 2 / 3 emissions (CO₂e).\n </p>\n </div>\n <div className=\"flex items-center gap-4\">\n {carbon.data && carbon.data.total > 0 && (\n <div className=\"text-right\">\n <p className=\"text-lg font-semibold tabular-nums text-text-primary\">\n {formatCo2e(carbon.data.total)}\n </p>\n <p className=\"text-xs text-text-tertiary\">total</p>\n </div>\n )}\n <button\n type=\"button\"\n onClick={() => navigateTo('carbon')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n Ledger <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n {carbonData.every((d) => d.kg === 0) ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Factory className=\"h-10 w-10\" />}\n title=\"No carbon entries yet\"\n description=\"Record activity in the carbon ledger to see your Scope 1–3 footprint here.\"\n />\n ) : (\n <>\n <div className=\"h-56\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={carbonData} margin={{ top: 20, right: 8, left: 8, bottom: 0 }}>\n <defs>\n {carbonData.map((d) => (\n <linearGradient\n key={d.scope}\n id={`ecoScopeGrad-${d.scope}`}\n x1=\"0\"\n y1=\"0\"\n x2=\"0\"\n y2=\"1\"\n >\n <stop\n offset=\"0%\"\n style={{ stopColor: SCOPE_HUE[d.scope], stopOpacity: 1 }}\n />\n <stop\n offset=\"100%\"\n style={{ stopColor: SCOPE_HUE[d.scope], stopOpacity: 0.55 }}\n />\n </linearGradient>\n ))}\n </defs>\n <CartesianGrid\n vertical={false}\n stroke=\"var(--color-border-seam)\"\n strokeOpacity={0.6}\n strokeDasharray=\"3 4\"\n />\n <XAxis\n dataKey=\"label\"\n tick={{ fill: 'var(--color-text-secondary)', fontSize: 12 }}\n axisLine={{ stroke: 'var(--color-border-seam)' }}\n tickLine={false}\n dy={4}\n />\n <YAxis\n tick={{ fill: 'var(--color-text-tertiary)', fontSize: 11 }}\n axisLine={false}\n tickLine={false}\n width={48}\n tickFormatter={(v: number) =>\n v >= 1000 ? `${Math.round(v / 1000)}t` : `${v}`\n }\n />\n <Tooltip\n cursor={{ fill: 'var(--color-bg-sunken)', opacity: 0.4 }}\n contentStyle={{\n background: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border-seam)',\n borderRadius: 12,\n color: 'var(--color-text-primary)',\n }}\n formatter={(value: number) => [formatCo2e(value), 'Emissions']}\n />\n <Bar dataKey=\"kg\" radius={[8, 8, 2, 2]} maxBarSize={72}>\n {carbonData.map((d) => (\n <Cell key={d.scope} fill={`url(#ecoScopeGrad-${d.scope})`} />\n ))}\n <LabelList\n dataKey=\"kg\"\n position=\"top\"\n formatter={(v: number) => (v > 0 ? formatCo2e(v) : '')}\n style={{\n fill: 'var(--color-text-secondary)',\n fontSize: 11,\n fontWeight: 600,\n }}\n />\n </Bar>\n </BarChart>\n </ResponsiveContainer>\n </div>\n <ScopeLegend data={carbonData} className=\"mt-4 border-t border-border-seam pt-4\" />\n </>\n )}\n </GlassCard>\n\n {/* Recent breaches */}\n <GlassCard treatment=\"glass\" className=\"p-6\">\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"text-base font-semibold text-text-primary\">Recent breaches</h2>\n {breachRows.length > 0 && (\n <span className=\"rounded-full bg-status-error-bg-subtle px-2 py-0.5 text-xs font-medium tabular-nums text-status-error-text\">\n {breaches.data?.pageInfo?.hasMore ? `${breachRows.length}+` : breachRows.length}\n </span>\n )}\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo('monitoring')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n Monitoring <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n {breachRows.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center rounded-xl border border-dashed border-border-seam py-10 text-center\">\n <span className=\"flex size-12 items-center justify-center rounded-full bg-status-success-bg-subtle\">\n <ShieldCheck className=\"h-6 w-6 text-status-success-text\" />\n </span>\n <p className=\"mt-3 text-sm font-medium text-text-primary\">All parameters in range</p>\n <p className=\"mt-1 text-xs text-text-tertiary\">No open threshold breaches.</p>\n </div>\n ) : (\n <ul className=\"space-y-2.5\">\n {breachRows.map((m) => (\n <li\n key={m.id}\n className=\"flex items-start justify-between gap-3 rounded-xl bg-bg-sunken/50 p-3\"\n >\n <div className=\"flex min-w-0 items-start gap-2.5\">\n <span\n aria-hidden=\"true\"\n className=\"mt-1.5 size-2 shrink-0 rounded-full bg-status-error-text motion-safe:animate-vc-glow-pulse\"\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {m.parameter}\n </p>\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums\">\n {formatNumber(m.value)} {m.unit}\n </span>{' '}\n · {formatRelativeTime(m.recordedAt)}\n </p>\n </div>\n </div>\n <StatusBadge status=\"BREACH\" />\n </li>\n ))}\n </ul>\n )}\n </GlassCard>\n </div>\n\n {/* Recent observations */}\n <Section\n title=\"Recent field observations\"\n description=\"Latest wildlife & biodiversity sightings recorded across your sites.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('observations')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n All observations <ArrowRight className=\"h-4 w-4\" />\n </button>\n }\n >\n {observationRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Binoculars className=\"h-10 w-10\" />}\n title=\"No observations yet\"\n description=\"Record your first field observation to build your biodiversity dataset.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {observationRows.map((o) => (\n <GlassCard\n key={o.id}\n treatment=\"plain\"\n className=\"p-4 transition-shadow hover:shadow-float\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex min-w-0 items-start gap-2.5\">\n <span className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-accent\">\n <Binoculars className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold text-text-primary\">\n {o.species?.commonName ?? 'Unknown species'}\n </p>\n {o.species?.scientificName && (\n <p className=\"truncate text-xs italic text-text-tertiary\">\n {o.species.scientificName}\n </p>\n )}\n </div>\n </div>\n <span className=\"shrink-0 rounded-full bg-[var(--color-accent-soft)] px-2 py-0.5 text-xs font-medium tabular-nums text-text-primary\">\n ×{formatNumber(o.count)}\n </span>\n </div>\n <div className=\"mt-3 flex items-center justify-between border-t border-border-seam/70 pt-2.5\">\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\">\n {formatEnumLabel(o.method)}\n </span>\n <span className=\"text-xs text-text-tertiary\">\n {formatRelativeTime(o.observedAt)}\n </span>\n </div>\n </GlassCard>\n ))}\n </div>\n )}\n </Section>\n\n {/* Conservation status snapshot */}\n {speciesRows.length > 0 && (\n <Section\n title=\"Conservation status\"\n description=\"Distribution of tracked species by IUCN-style status.\"\n >\n <GlassCard treatment=\"plain\" className=\"p-6\">\n <div className=\"space-y-3.5\">\n {(() => {\n const counts = new Map<string, number>();\n for (const s of speciesRows) {\n counts.set(s.conservationStatus, (counts.get(s.conservationStatus) ?? 0) + 1);\n }\n const total = speciesRows.length;\n return [...counts.entries()]\n .sort((a, b) => b[1] - a[1])\n .map(([status, count]) => {\n const pct = (count / total) * 100;\n const tone =\n CONSERVATION_TONE[status as EcoConservationStatus] ??\n 'var(--color-text-tertiary)';\n return (\n <div key={status} className=\"flex items-center gap-3 sm:gap-4\">\n <div className=\"w-36 shrink-0 sm:w-48\">\n <StatusBadge status={status} />\n </div>\n <Meter value={pct} color={tone} className=\"flex-1\" />\n <span className=\"w-9 shrink-0 text-right text-sm font-medium tabular-nums text-text-primary\">\n {count}\n </span>\n <span className=\"hidden w-12 shrink-0 text-right text-xs tabular-nums text-text-tertiary sm:inline\">\n {formatPercent(pct)}\n </span>\n </div>\n );\n });\n })()}\n </div>\n </GlassCard>\n </Section>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -93,7 +93,7 @@ function N() {
|
|
|
93
93
|
limit: ke,
|
|
94
94
|
cursor: I.cursor
|
|
95
95
|
}
|
|
96
|
-
}), Ue = Z.data?.items ?? [], We = ce(), Q = ce(L === "ALL" ? void 0 : L), Ge = Q.data ?? [], $ = ue(R === "ALL" ? void 0 : R), Ke = $.data ?? [], qe = le(), Je = pe(), Ye = oe(), Xe = se(), Ze = de(), Qe = () => {
|
|
96
|
+
}), Ue = Z.data?.items ?? [], We = ce(), Q = ce(L === "ALL" ? void 0 : L), Ge = Q.data?.items ?? [], $ = ue(R === "ALL" ? void 0 : R), Ke = $.data?.items ?? [], qe = le(), Je = pe(), Ye = oe(), Xe = se(), Ze = de(), Qe = () => {
|
|
97
97
|
V({
|
|
98
98
|
...k,
|
|
99
99
|
periodStart: Ae()
|
|
@@ -394,13 +394,13 @@ function N() {
|
|
|
394
394
|
value: "factors",
|
|
395
395
|
label: "Emission factors",
|
|
396
396
|
icon: /* @__PURE__ */ m(ye, { className: "h-4 w-4" }),
|
|
397
|
-
count: Q.data?.length
|
|
397
|
+
count: Q.data?.items?.length
|
|
398
398
|
},
|
|
399
399
|
{
|
|
400
400
|
value: "targets",
|
|
401
401
|
label: "Reduction targets",
|
|
402
402
|
icon: /* @__PURE__ */ m(be, { className: "h-4 w-4" }),
|
|
403
|
-
count: $.data?.length
|
|
403
|
+
count: $.data?.items?.length
|
|
404
404
|
}
|
|
405
405
|
];
|
|
406
406
|
return /* @__PURE__ */ h(e, {
|
|
@@ -729,7 +729,7 @@ function N() {
|
|
|
729
729
|
children: [/* @__PURE__ */ m(E, {
|
|
730
730
|
id: "ceFactor",
|
|
731
731
|
children: /* @__PURE__ */ m(D, { placeholder: "Optional" })
|
|
732
|
-
}), /* @__PURE__ */ m(w, { children: (We.data ?? []).map((e) => /* @__PURE__ */ m(T, {
|
|
732
|
+
}), /* @__PURE__ */ m(w, { children: (We.data?.items ?? []).map((e) => /* @__PURE__ */ m(T, {
|
|
733
733
|
value: e.id,
|
|
734
734
|
children: e.name
|
|
735
735
|
}, e.id)) })]
|