@burdenoff/microfe-ecoimpacthub 2026.704.1 → 2026.704.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/ecoimpacthub/components/EcoDiscussion.js +109 -0
  2. package/dist/ecoimpacthub/components/EcoDiscussion.js.map +1 -0
  3. package/dist/ecoimpacthub/components/EcoTags.js +149 -0
  4. package/dist/ecoimpacthub/components/EcoTags.js.map +1 -0
  5. package/dist/ecoimpacthub/components/EvidenceUpload.js +93 -0
  6. package/dist/ecoimpacthub/components/EvidenceUpload.js.map +1 -0
  7. package/dist/ecoimpacthub/components/FileLink.js +36 -0
  8. package/dist/ecoimpacthub/components/FileLink.js.map +1 -0
  9. package/dist/ecoimpacthub/components/PageLayout.js +2 -2
  10. package/dist/ecoimpacthub/components/PageLayout.js.map +1 -1
  11. package/dist/ecoimpacthub/hooks/index.js +3 -0
  12. package/dist/ecoimpacthub/hooks/useCursorPager.js +1 -1
  13. package/dist/ecoimpacthub/hooks/useCursorPager.js.map +1 -1
  14. package/dist/ecoimpacthub/hooks/useEcoComments.js +45 -0
  15. package/dist/ecoimpacthub/hooks/useEcoComments.js.map +1 -0
  16. package/dist/ecoimpacthub/hooks/useEcoFiles.js +81 -0
  17. package/dist/ecoimpacthub/hooks/useEcoFiles.js.map +1 -0
  18. package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.js +169 -166
  19. package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.js.map +1 -1
  20. package/dist/ecoimpacthub/hooks/useEcoTags.js +89 -0
  21. package/dist/ecoimpacthub/hooks/useEcoTags.js.map +1 -0
  22. package/dist/ecoimpacthub/pages/observations/ObservationsPage.js +124 -101
  23. package/dist/ecoimpacthub/pages/observations/ObservationsPage.js.map +1 -1
  24. package/dist/ecoimpacthub/pages/reports/ReportDetailPage.js +153 -126
  25. package/dist/ecoimpacthub/pages/reports/ReportDetailPage.js.map +1 -1
  26. package/dist/ecoimpacthub/pages/sites/SiteDetailPage.js +241 -230
  27. package/dist/ecoimpacthub/pages/sites/SiteDetailPage.js.map +1 -1
  28. package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.js +260 -225
  29. package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.js.map +1 -1
  30. package/package.json +1 -1
@@ -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\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 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":"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"}
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":"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"}
@@ -0,0 +1,89 @@
1
+ import { useEcoImpactHub as e } from "../context/EcoImpactHubContext.js";
2
+ import "../context/index.js";
3
+ import { wspaceFetch as t } from "./useEcoFiles.js";
4
+ import { useMutation as n, useQuery as r, useQueryClient as i } from "@tanstack/react-query";
5
+ //#region src/ecoimpacthub/hooks/useEcoTags.ts
6
+ var a = "ecoimpacthub", o = (e, t) => [
7
+ "ecoimpacthub",
8
+ "entity-tags",
9
+ e,
10
+ t
11
+ ], s = "id label color key", c = (e) => e.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48) || "tag", l = (n, i) => {
12
+ let { apiGatewayUrl: a } = e();
13
+ return r({
14
+ queryKey: o(n, i ?? ""),
15
+ enabled: !!i,
16
+ queryFn: async () => (await t(`query EcoGetEntityTags($entityType: String!, $entityId: ID!) {
17
+ getEntityTags(entityType: $entityType, entityId: $entityId) {
18
+ id
19
+ tag { ${s} }
20
+ }
21
+ }`, {
22
+ entityType: n,
23
+ entityId: i
24
+ }, a)).getEntityTags
25
+ });
26
+ }, u = (n) => {
27
+ let { apiGatewayUrl: i } = e(), a = n.trim();
28
+ return r({
29
+ queryKey: [
30
+ "ecoimpacthub",
31
+ "tag-search",
32
+ a
33
+ ],
34
+ enabled: a.length > 0,
35
+ queryFn: async () => (await t(`query EcoSearchTags($query: String!, $limit: Int) {
36
+ searchTags(query: $query, limit: $limit) { ${s} }
37
+ }`, {
38
+ query: a,
39
+ limit: 8
40
+ }, i)).searchTags
41
+ });
42
+ }, d = (r, a) => {
43
+ let { apiGatewayUrl: s } = e(), c = i();
44
+ return n({
45
+ mutationFn: async (e) => (await t("mutation EcoAssignTag($input: AssignTagInput!) {\n assignTag(input: $input) { id }\n }", { input: {
46
+ entityType: r,
47
+ entityId: a,
48
+ tagId: e
49
+ } }, s)).assignTag,
50
+ onSuccess: () => c.invalidateQueries({ queryKey: o(r, a) })
51
+ });
52
+ }, f = (r, a) => {
53
+ let { apiGatewayUrl: s } = e(), c = i();
54
+ return n({
55
+ mutationFn: async (e) => (await t("mutation EcoRemoveTagAssignment($id: ID!) {\n removeTagAssignment(id: $id)\n }", { id: e }, s)).removeTagAssignment,
56
+ onSuccess: () => c.invalidateQueries({ queryKey: o(r, a) })
57
+ });
58
+ }, p = async (e) => {
59
+ let n = await t("query EcoGetVocabulary($key: String!) {\n getVocabularyByKey(key: $key) { id }\n }", { key: a }, e);
60
+ return n.getVocabularyByKey?.id ? n.getVocabularyByKey.id : (await t("mutation EcoCreateVocabulary($input: CreateVocabularyInput!) {\n createVocabulary(input: $input) { id }\n }", { input: {
61
+ key: a,
62
+ name: "EcoImpactHub",
63
+ description: "Tags for EcoImpactHub sites, species and other records.",
64
+ allowCustomTags: !0
65
+ } }, e)).createVocabulary.id;
66
+ }, m = (r, a) => {
67
+ let { apiGatewayUrl: s } = e(), l = i();
68
+ return n({
69
+ mutationFn: async (e) => {
70
+ let n = e.trim();
71
+ if (!n) throw Error("A tag label is required.");
72
+ let i = await t("mutation EcoCreateTag($input: CreateTagInput!) {\n createTag(input: $input) { id }\n }", { input: {
73
+ vocabularyId: await p(s),
74
+ key: `${c(n)}-${Math.random().toString(36).slice(2, 6)}`,
75
+ label: n
76
+ } }, s);
77
+ return await t("mutation EcoAssignCreatedTag($input: AssignTagInput!) {\n assignTag(input: $input) { id }\n }", { input: {
78
+ entityType: r,
79
+ entityId: a,
80
+ tagId: i.createTag.id
81
+ } }, s), i.createTag;
82
+ },
83
+ onSuccess: () => l.invalidateQueries({ queryKey: o(r, a) })
84
+ });
85
+ };
86
+ //#endregion
87
+ export { d as useEcoAssignTag, m as useEcoCreateAndAssignTag, l as useEcoEntityTags, f as useEcoRemoveTagAssignment, u as useEcoTagSearch };
88
+
89
+ //# sourceMappingURL=useEcoTags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEcoTags.js","names":[],"sources":["../../../src/ecoimpacthub/hooks/useEcoTags.ts"],"sourcesContent":["/**\n * EcoImpactHub — wspace-tags-svc UniversalTag REUSE hooks (Integration C).\n * @module ecoimpacthub/hooks/useEcoTags\n *\n * The eco svc does NOT expose a tags field, so we drive the platform tag\n * assignment store directly (approach (b) in the reuse audit) — no eco-svc\n * change. All operations are composed into the WORKSPACE supergraph:\n * - `getEntityTags(entityType, entityId)` → current assignments (display)\n * - `searchTags(query)` → pick an existing tag\n * - `createTag(input)` → create a new tag (needs a vocabulary)\n * - `assignTag(input)` → link tag ↔ entity\n * - `removeTagAssignment(id)` → unlink\n *\n * `createTag` requires a `vocabularyId`; we resolve a stable, workspace-scoped\n * \"ecoimpacthub\" vocabulary (`getVocabularyByKey`, creating it on first use).\n *\n * Transport reuses `wspaceFetch` from `useEcoFiles`. Lives in a separate file;\n * `useEcoImpactHubApi.ts` is untouched.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\n\nimport { useEcoImpactHub } from '../context';\nimport { wspaceFetch } from './useEcoFiles';\n\nexport interface EcoTag {\n id: string;\n label: string;\n color: string | null;\n key: string;\n}\n\nexport interface EcoTagAssignment {\n id: string;\n tag: EcoTag;\n}\n\nconst ECO_VOCABULARY_KEY = 'ecoimpacthub';\n\nconst entityTagsKey = (entityType: string, entityId: string) =>\n ['ecoimpacthub', 'entity-tags', entityType, entityId] as const;\n\nconst TAG_FIELDS = 'id label color key';\n\nconst slugify = (value: string): string =>\n value\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 48) || 'tag';\n\n/** Current tag assignments for an eco entity. */\nexport const useEcoEntityTags = (entityType: string, entityId: string | undefined) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: entityTagsKey(entityType, entityId ?? ''),\n enabled: Boolean(entityId),\n queryFn: async () => {\n const data = await wspaceFetch<{ getEntityTags: EcoTagAssignment[] }>(\n `query EcoGetEntityTags($entityType: String!, $entityId: ID!) {\n getEntityTags(entityType: $entityType, entityId: $entityId) {\n id\n tag { ${TAG_FIELDS} }\n }\n }`,\n { entityType, entityId },\n apiGatewayUrl\n );\n return data.getEntityTags;\n },\n });\n};\n\n/** Search existing tags (enabled only for a non-empty query). */\nexport const useEcoTagSearch = (query: string) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const trimmed = query.trim();\n return useQuery({\n queryKey: ['ecoimpacthub', 'tag-search', trimmed],\n enabled: trimmed.length > 0,\n queryFn: async () => {\n const data = await wspaceFetch<{ searchTags: EcoTag[] }>(\n `query EcoSearchTags($query: String!, $limit: Int) {\n searchTags(query: $query, limit: $limit) { ${TAG_FIELDS} }\n }`,\n { query: trimmed, limit: 8 },\n apiGatewayUrl\n );\n return data.searchTags;\n },\n });\n};\n\n/** Assign an existing tag to the entity. */\nexport const useEcoAssignTag = (entityType: string, entityId: string) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (tagId: string) => {\n const data = await wspaceFetch<{ assignTag: { id: string } }>(\n `mutation EcoAssignTag($input: AssignTagInput!) {\n assignTag(input: $input) { id }\n }`,\n { input: { entityType, entityId, tagId } },\n apiGatewayUrl\n );\n return data.assignTag;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: entityTagsKey(entityType, entityId) }),\n });\n};\n\n/** Remove a tag assignment by its assignment id. */\nexport const useEcoRemoveTagAssignment = (entityType: string, entityId: string) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (assignmentId: string) => {\n const data = await wspaceFetch<{ removeTagAssignment: boolean }>(\n `mutation EcoRemoveTagAssignment($id: ID!) {\n removeTagAssignment(id: $id)\n }`,\n { id: assignmentId },\n apiGatewayUrl\n );\n return data.removeTagAssignment;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: entityTagsKey(entityType, entityId) }),\n });\n};\n\n/** Resolve (creating on first use) the workspace-scoped \"ecoimpacthub\" vocabulary. */\nconst resolveEcoVocabularyId = async (baseUrl?: string): Promise<string> => {\n const existing = await wspaceFetch<{ getVocabularyByKey: { id: string } | null }>(\n `query EcoGetVocabulary($key: String!) {\n getVocabularyByKey(key: $key) { id }\n }`,\n { key: ECO_VOCABULARY_KEY },\n baseUrl\n );\n if (existing.getVocabularyByKey?.id) {\n return existing.getVocabularyByKey.id;\n }\n const created = await wspaceFetch<{ createVocabulary: { id: string } }>(\n `mutation EcoCreateVocabulary($input: CreateVocabularyInput!) {\n createVocabulary(input: $input) { id }\n }`,\n {\n input: {\n key: ECO_VOCABULARY_KEY,\n name: 'EcoImpactHub',\n description: 'Tags for EcoImpactHub sites, species and other records.',\n allowCustomTags: true,\n },\n },\n baseUrl\n );\n return created.createVocabulary.id;\n};\n\n/** Create a new tag from a free-text label and assign it to the entity. */\nexport const useEcoCreateAndAssignTag = (entityType: string, entityId: string) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (label: string) => {\n const trimmed = label.trim();\n if (!trimmed) {\n throw new Error('A tag label is required.');\n }\n const vocabularyId = await resolveEcoVocabularyId(apiGatewayUrl);\n // A unique key avoids collisions with existing tags in the vocabulary;\n // the (non-unique) label is what users see.\n const key = `${slugify(trimmed)}-${Math.random().toString(36).slice(2, 6)}`;\n const created = await wspaceFetch<{ createTag: { id: string } }>(\n `mutation EcoCreateTag($input: CreateTagInput!) {\n createTag(input: $input) { id }\n }`,\n { input: { vocabularyId, key, label: trimmed } },\n apiGatewayUrl\n );\n await wspaceFetch<{ assignTag: { id: string } }>(\n `mutation EcoAssignCreatedTag($input: AssignTagInput!) {\n assignTag(input: $input) { id }\n }`,\n { input: { entityType, entityId, tagId: created.createTag.id } },\n apiGatewayUrl\n );\n return created.createTag;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: entityTagsKey(entityType, entityId) }),\n });\n};\n"],"mappings":";;;;;AAqCA,IAAM,IAAqB,gBAErB,KAAiB,GAAoB,MACzC;CAAC;CAAgB;CAAe;CAAY;CAAS,EAEjD,IAAa,sBAEb,KAAW,MACf,EACG,aAAa,CACb,MAAM,CACN,QAAQ,eAAe,IAAI,CAC3B,QAAQ,YAAY,GAAG,CACvB,MAAM,GAAG,GAAG,IAAI,OAGR,KAAoB,GAAoB,MAAiC;CACpF,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,EAAc,GAAY,KAAY,GAAG;EACnD,SAAS,EAAQ;EACjB,SAAS,aACM,MAAM,EACjB;;;oBAGY,EAAW;;YAGvB;GAAE;GAAY;GAAU,EACxB,EACD,EACW;EAEf,CAAC;GAIS,KAAmB,MAAkB;CAChD,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAU,EAAM,MAAM;AAC5B,QAAO,EAAS;EACd,UAAU;GAAC;GAAgB;GAAc;GAAQ;EACjD,SAAS,EAAQ,SAAS;EAC1B,SAAS,aACM,MAAM,EACjB;uDAC+C,EAAW;YAE1D;GAAE,OAAO;GAAS,OAAO;GAAG,EAC5B,EACD,EACW;EAEf,CAAC;GAIS,KAAmB,GAAoB,MAAqB;CACvE,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACJ,MAAM,EACjB,0GAGA,EAAE,OAAO;GAAE;GAAY;GAAU;GAAO,EAAE,EAC1C,EACD,EACW;EAEd,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAc,GAAY,EAAS,EAAE,CAAC;EACzF,CAAC;GAIS,KAA6B,GAAoB,MAAqB;CACjF,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACJ,MAAM,EACjB,kGAGA,EAAE,IAAI,GAAc,EACpB,EACD,EACW;EAEd,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAc,GAAY,EAAS,EAAE,CAAC;EACzF,CAAC;GAIE,IAAyB,OAAO,MAAsC;CAC1E,IAAM,IAAW,MAAM,EACrB,8FAGA,EAAE,KAAK,GAAoB,EAC3B,EACD;AAkBD,QAjBI,EAAS,oBAAoB,KACxB,EAAS,mBAAmB,MAErB,MAAM,EACpB,uHAGA,EACE,OAAO;EACL,KAAK;EACL,MAAM;EACN,aAAa;EACb,iBAAiB;EAClB,EACF,EACD,EACD,EACc,iBAAiB;GAIrB,KAA4B,GAAoB,MAAqB;CAChF,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,MAAkB;GACnC,IAAM,IAAU,EAAM,MAAM;AAC5B,OAAI,CAAC,EACH,OAAU,MAAM,2BAA2B;GAM7C,IAAM,IAAU,MAAM,EACpB,0GAGA,EAAE,OAAO;IAAE,cARQ,MAAM,EAAuB,EAAc;IAQrC,KALf,GAAG,EAAQ,EAAQ,CAAC,GAAG,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE;IAKzC,OAAO;IAAS,EAAE,EAChD,EACD;AAQD,UAPA,MAAM,EACJ,iHAGA,EAAE,OAAO;IAAE;IAAY;IAAU,OAAO,EAAQ,UAAU;IAAI,EAAE,EAChE,EACD,EACM,EAAQ;;EAEjB,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAc,GAAY,EAAS,EAAE,CAAC;EACzF,CAAC"}