@burdenoff/microfe-ecoimpacthub 2026.720.3 → 2026.720.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (496) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +1 -1
  2. package/dist/ecoimpacthub/EcoImpactHubRoot.js.map +1 -1
  3. package/dist/ecoimpacthub/EcoImpactHubRoutes.js.map +1 -1
  4. package/dist/ecoimpacthub/components/DashboardCustomizerDialog.d.ts +11 -0
  5. package/dist/ecoimpacthub/components/DashboardCustomizerDialog.d.ts.map +1 -0
  6. package/dist/ecoimpacthub/components/DashboardCustomizerDialog.js +182 -0
  7. package/dist/ecoimpacthub/components/DashboardCustomizerDialog.js.map +1 -0
  8. package/dist/ecoimpacthub/components/DataTable.js.map +1 -1
  9. package/dist/ecoimpacthub/components/EcoDiscussion.js.map +1 -1
  10. package/dist/ecoimpacthub/components/EcoTags.js.map +1 -1
  11. package/dist/ecoimpacthub/components/EmptyState.js.map +1 -1
  12. package/dist/ecoimpacthub/components/EvidenceUpload.js.map +1 -1
  13. package/dist/ecoimpacthub/components/FeatureFlagGate.js.map +1 -1
  14. package/dist/ecoimpacthub/components/FileLink.js.map +1 -1
  15. package/dist/ecoimpacthub/components/FilterTabs.js.map +1 -1
  16. package/dist/ecoimpacthub/components/MetricsCard.js.map +1 -1
  17. package/dist/ecoimpacthub/components/MiniBar.js.map +1 -1
  18. package/dist/ecoimpacthub/components/PageLayout.js.map +1 -1
  19. package/dist/ecoimpacthub/components/Pagination.js.map +1 -1
  20. package/dist/ecoimpacthub/components/StateViews.js.map +1 -1
  21. package/dist/ecoimpacthub/components/StatusBadge.js.map +1 -1
  22. package/dist/ecoimpacthub/components/Tabs.js.map +1 -1
  23. package/dist/ecoimpacthub/context/EcoImpactHubContext.js.map +1 -1
  24. package/dist/ecoimpacthub/hooks/index.d.ts +1 -0
  25. package/dist/ecoimpacthub/hooks/index.d.ts.map +1 -1
  26. package/dist/ecoimpacthub/hooks/index.js +1 -0
  27. package/dist/ecoimpacthub/hooks/useCursorPager.js.map +1 -1
  28. package/dist/ecoimpacthub/hooks/useDashboardLayout.d.ts +29 -0
  29. package/dist/ecoimpacthub/hooks/useDashboardLayout.d.ts.map +1 -0
  30. package/dist/ecoimpacthub/hooks/useDashboardLayout.js +95 -0
  31. package/dist/ecoimpacthub/hooks/useDashboardLayout.js.map +1 -0
  32. package/dist/ecoimpacthub/hooks/useEcoComments.js.map +1 -1
  33. package/dist/ecoimpacthub/hooks/useEcoFiles.js.map +1 -1
  34. package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.js.map +1 -1
  35. package/dist/ecoimpacthub/hooks/useEcoTags.js.map +1 -1
  36. package/dist/ecoimpacthub/pages/DashboardPage.d.ts +7 -0
  37. package/dist/ecoimpacthub/pages/DashboardPage.d.ts.map +1 -1
  38. package/dist/ecoimpacthub/pages/DashboardPage.js +505 -447
  39. package/dist/ecoimpacthub/pages/DashboardPage.js.map +1 -1
  40. package/dist/ecoimpacthub/pages/_shared/ConservationBadge.js.map +1 -1
  41. package/dist/ecoimpacthub/pages/_shared/EvidenceThumb.js.map +1 -1
  42. package/dist/ecoimpacthub/pages/_shared/MethodBadge.js.map +1 -1
  43. package/dist/ecoimpacthub/pages/_shared/TaxonChip.js.map +1 -1
  44. package/dist/ecoimpacthub/pages/badges.js.map +1 -1
  45. package/dist/ecoimpacthub/pages/carbon/CarbonPage.js.map +1 -1
  46. package/dist/ecoimpacthub/pages/carbonVisuals.js.map +1 -1
  47. package/dist/ecoimpacthub/pages/habitat/HabitatProjectDetailPage.js.map +1 -1
  48. package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.js.map +1 -1
  49. package/dist/ecoimpacthub/pages/habitat/LifecycleProgress.js.map +1 -1
  50. package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.js.map +1 -1
  51. package/dist/ecoimpacthub/pages/observations/ObservationsPage.js.map +1 -1
  52. package/dist/ecoimpacthub/pages/reports/ReportDetailPage.js.map +1 -1
  53. package/dist/ecoimpacthub/pages/reports/ReportsPage.js.map +1 -1
  54. package/dist/ecoimpacthub/pages/sites/SiteDetailPage.js.map +1 -1
  55. package/dist/ecoimpacthub/pages/sites/SitesPage.js.map +1 -1
  56. package/dist/ecoimpacthub/pages/sites/siteTypeVisuals.js.map +1 -1
  57. package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.js.map +1 -1
  58. package/dist/ecoimpacthub/pages/species/SpeciesPage.js.map +1 -1
  59. package/dist/ecoimpacthub/services/createSandboxAssistantTransport.d.ts.map +1 -1
  60. package/dist/ecoimpacthub/services/createSandboxAssistantTransport.js.map +1 -1
  61. package/dist/ecoimpacthub/types/index.d.ts.map +1 -1
  62. package/dist/ecoimpacthub/utils/cn.js.map +1 -1
  63. package/dist/ecoimpacthub/utils/formatters.js.map +1 -1
  64. package/dist/ecoimpacthub/utils/navigation.js.map +1 -1
  65. package/dist/node_modules/clsx/dist/clsx.js.map +1 -1
  66. package/dist/node_modules/d3-array/src/ascending.js.map +1 -1
  67. package/dist/node_modules/d3-array/src/bisect.js.map +1 -1
  68. package/dist/node_modules/d3-array/src/bisector.js.map +1 -1
  69. package/dist/node_modules/d3-array/src/descending.js.map +1 -1
  70. package/dist/node_modules/d3-array/src/max.js.map +1 -1
  71. package/dist/node_modules/d3-array/src/min.js.map +1 -1
  72. package/dist/node_modules/d3-array/src/number.js.map +1 -1
  73. package/dist/node_modules/d3-array/src/quantile.js.map +1 -1
  74. package/dist/node_modules/d3-array/src/quickselect.js.map +1 -1
  75. package/dist/node_modules/d3-array/src/range.js.map +1 -1
  76. package/dist/node_modules/d3-array/src/sort.js.map +1 -1
  77. package/dist/node_modules/d3-array/src/ticks.js.map +1 -1
  78. package/dist/node_modules/d3-color/src/color.js.map +1 -1
  79. package/dist/node_modules/d3-color/src/define.js.map +1 -1
  80. package/dist/node_modules/d3-format/src/defaultLocale.js.map +1 -1
  81. package/dist/node_modules/d3-format/src/exponent.js.map +1 -1
  82. package/dist/node_modules/d3-format/src/formatDecimal.js.map +1 -1
  83. package/dist/node_modules/d3-format/src/formatGroup.js.map +1 -1
  84. package/dist/node_modules/d3-format/src/formatNumerals.js.map +1 -1
  85. package/dist/node_modules/d3-format/src/formatPrefixAuto.js.map +1 -1
  86. package/dist/node_modules/d3-format/src/formatRounded.js.map +1 -1
  87. package/dist/node_modules/d3-format/src/formatSpecifier.js.map +1 -1
  88. package/dist/node_modules/d3-format/src/formatTrim.js.map +1 -1
  89. package/dist/node_modules/d3-format/src/formatTypes.js.map +1 -1
  90. package/dist/node_modules/d3-format/src/identity.js.map +1 -1
  91. package/dist/node_modules/d3-format/src/locale.js.map +1 -1
  92. package/dist/node_modules/d3-format/src/precisionFixed.js.map +1 -1
  93. package/dist/node_modules/d3-format/src/precisionPrefix.js.map +1 -1
  94. package/dist/node_modules/d3-format/src/precisionRound.js.map +1 -1
  95. package/dist/node_modules/d3-interpolate/src/array.js.map +1 -1
  96. package/dist/node_modules/d3-interpolate/src/basis.js.map +1 -1
  97. package/dist/node_modules/d3-interpolate/src/basisClosed.js.map +1 -1
  98. package/dist/node_modules/d3-interpolate/src/color.js.map +1 -1
  99. package/dist/node_modules/d3-interpolate/src/date.js.map +1 -1
  100. package/dist/node_modules/d3-interpolate/src/number.js.map +1 -1
  101. package/dist/node_modules/d3-interpolate/src/numberArray.js.map +1 -1
  102. package/dist/node_modules/d3-interpolate/src/object.js.map +1 -1
  103. package/dist/node_modules/d3-interpolate/src/piecewise.js.map +1 -1
  104. package/dist/node_modules/d3-interpolate/src/rgb.js.map +1 -1
  105. package/dist/node_modules/d3-interpolate/src/round.js.map +1 -1
  106. package/dist/node_modules/d3-interpolate/src/string.js.map +1 -1
  107. package/dist/node_modules/d3-interpolate/src/value.js.map +1 -1
  108. package/dist/node_modules/d3-path/src/path.js.map +1 -1
  109. package/dist/node_modules/d3-scale/src/band.js.map +1 -1
  110. package/dist/node_modules/d3-scale/src/constant.js.map +1 -1
  111. package/dist/node_modules/d3-scale/src/continuous.js.map +1 -1
  112. package/dist/node_modules/d3-scale/src/diverging.js.map +1 -1
  113. package/dist/node_modules/d3-scale/src/identity.js.map +1 -1
  114. package/dist/node_modules/d3-scale/src/init.js.map +1 -1
  115. package/dist/node_modules/d3-scale/src/linear.js.map +1 -1
  116. package/dist/node_modules/d3-scale/src/log.js.map +1 -1
  117. package/dist/node_modules/d3-scale/src/nice.js.map +1 -1
  118. package/dist/node_modules/d3-scale/src/number.js.map +1 -1
  119. package/dist/node_modules/d3-scale/src/ordinal.js.map +1 -1
  120. package/dist/node_modules/d3-scale/src/pow.js.map +1 -1
  121. package/dist/node_modules/d3-scale/src/quantile.js.map +1 -1
  122. package/dist/node_modules/d3-scale/src/quantize.js.map +1 -1
  123. package/dist/node_modules/d3-scale/src/radial.js.map +1 -1
  124. package/dist/node_modules/d3-scale/src/sequential.js.map +1 -1
  125. package/dist/node_modules/d3-scale/src/sequentialQuantile.js.map +1 -1
  126. package/dist/node_modules/d3-scale/src/symlog.js.map +1 -1
  127. package/dist/node_modules/d3-scale/src/threshold.js.map +1 -1
  128. package/dist/node_modules/d3-scale/src/tickFormat.js.map +1 -1
  129. package/dist/node_modules/d3-scale/src/time.js.map +1 -1
  130. package/dist/node_modules/d3-scale/src/utcTime.js.map +1 -1
  131. package/dist/node_modules/d3-shape/src/area.js.map +1 -1
  132. package/dist/node_modules/d3-shape/src/array.js.map +1 -1
  133. package/dist/node_modules/d3-shape/src/constant.js.map +1 -1
  134. package/dist/node_modules/d3-shape/src/curve/basis.js.map +1 -1
  135. package/dist/node_modules/d3-shape/src/curve/basisClosed.js.map +1 -1
  136. package/dist/node_modules/d3-shape/src/curve/basisOpen.js.map +1 -1
  137. package/dist/node_modules/d3-shape/src/curve/bump.js.map +1 -1
  138. package/dist/node_modules/d3-shape/src/curve/linear.js.map +1 -1
  139. package/dist/node_modules/d3-shape/src/curve/linearClosed.js.map +1 -1
  140. package/dist/node_modules/d3-shape/src/curve/monotone.js.map +1 -1
  141. package/dist/node_modules/d3-shape/src/curve/natural.js.map +1 -1
  142. package/dist/node_modules/d3-shape/src/curve/step.js.map +1 -1
  143. package/dist/node_modules/d3-shape/src/line.js.map +1 -1
  144. package/dist/node_modules/d3-shape/src/noop.js.map +1 -1
  145. package/dist/node_modules/d3-shape/src/offset/expand.js.map +1 -1
  146. package/dist/node_modules/d3-shape/src/offset/none.js.map +1 -1
  147. package/dist/node_modules/d3-shape/src/offset/silhouette.js.map +1 -1
  148. package/dist/node_modules/d3-shape/src/offset/wiggle.js.map +1 -1
  149. package/dist/node_modules/d3-shape/src/order/none.js.map +1 -1
  150. package/dist/node_modules/d3-shape/src/path.js.map +1 -1
  151. package/dist/node_modules/d3-shape/src/point.js.map +1 -1
  152. package/dist/node_modules/d3-shape/src/stack.js.map +1 -1
  153. package/dist/node_modules/d3-shape/src/symbol/circle.js.map +1 -1
  154. package/dist/node_modules/d3-shape/src/symbol/cross.js.map +1 -1
  155. package/dist/node_modules/d3-shape/src/symbol/diamond.js.map +1 -1
  156. package/dist/node_modules/d3-shape/src/symbol/square.js.map +1 -1
  157. package/dist/node_modules/d3-shape/src/symbol/star.js.map +1 -1
  158. package/dist/node_modules/d3-shape/src/symbol/triangle.js.map +1 -1
  159. package/dist/node_modules/d3-shape/src/symbol/wye.js.map +1 -1
  160. package/dist/node_modules/d3-shape/src/symbol.js.map +1 -1
  161. package/dist/node_modules/d3-time/src/day.js.map +1 -1
  162. package/dist/node_modules/d3-time/src/hour.js.map +1 -1
  163. package/dist/node_modules/d3-time/src/interval.js.map +1 -1
  164. package/dist/node_modules/d3-time/src/millisecond.js.map +1 -1
  165. package/dist/node_modules/d3-time/src/minute.js.map +1 -1
  166. package/dist/node_modules/d3-time/src/month.js.map +1 -1
  167. package/dist/node_modules/d3-time/src/second.js.map +1 -1
  168. package/dist/node_modules/d3-time/src/ticks.js.map +1 -1
  169. package/dist/node_modules/d3-time/src/week.js.map +1 -1
  170. package/dist/node_modules/d3-time/src/year.js.map +1 -1
  171. package/dist/node_modules/d3-time-format/src/defaultLocale.js.map +1 -1
  172. package/dist/node_modules/d3-time-format/src/locale.js.map +1 -1
  173. package/dist/node_modules/decimal.js-light/decimal.js.map +1 -1
  174. package/dist/node_modules/eventemitter3/index.js.map +1 -1
  175. package/dist/node_modules/fast-equals/dist/es/index.js.map +1 -1
  176. package/dist/node_modules/internmap/src/index.js.map +1 -1
  177. package/dist/node_modules/lodash/_DataView.js.map +1 -1
  178. package/dist/node_modules/lodash/_Hash.js.map +1 -1
  179. package/dist/node_modules/lodash/_ListCache.js.map +1 -1
  180. package/dist/node_modules/lodash/_Map.js.map +1 -1
  181. package/dist/node_modules/lodash/_MapCache.js.map +1 -1
  182. package/dist/node_modules/lodash/_Promise.js.map +1 -1
  183. package/dist/node_modules/lodash/_Set.js.map +1 -1
  184. package/dist/node_modules/lodash/_SetCache.js.map +1 -1
  185. package/dist/node_modules/lodash/_Stack.js +2 -1
  186. package/dist/node_modules/lodash/_Stack.js.map +1 -1
  187. package/dist/node_modules/lodash/_Symbol.js.map +1 -1
  188. package/dist/node_modules/lodash/_Uint8Array.js.map +1 -1
  189. package/dist/node_modules/lodash/_WeakMap.js.map +1 -1
  190. package/dist/node_modules/lodash/_apply.js.map +1 -1
  191. package/dist/node_modules/lodash/_arrayEvery.js.map +1 -1
  192. package/dist/node_modules/lodash/_arrayFilter.js.map +1 -1
  193. package/dist/node_modules/lodash/_arrayIncludes.js.map +1 -1
  194. package/dist/node_modules/lodash/_arrayIncludesWith.js.map +1 -1
  195. package/dist/node_modules/lodash/_arrayLikeKeys.js.map +1 -1
  196. package/dist/node_modules/lodash/_arrayMap.js.map +1 -1
  197. package/dist/node_modules/lodash/_arrayPush.js.map +1 -1
  198. package/dist/node_modules/lodash/_arraySome.js.map +1 -1
  199. package/dist/node_modules/lodash/_asciiToArray.js.map +1 -1
  200. package/dist/node_modules/lodash/_assocIndexOf.js.map +1 -1
  201. package/dist/node_modules/lodash/_baseAssignValue.js.map +1 -1
  202. package/dist/node_modules/lodash/_baseEach.js.map +1 -1
  203. package/dist/node_modules/lodash/_baseEvery.js.map +1 -1
  204. package/dist/node_modules/lodash/_baseExtremum.js.map +1 -1
  205. package/dist/node_modules/lodash/_baseFindIndex.js.map +1 -1
  206. package/dist/node_modules/lodash/_baseFlatten.js.map +1 -1
  207. package/dist/node_modules/lodash/_baseFor.js.map +1 -1
  208. package/dist/node_modules/lodash/_baseForOwn.js.map +1 -1
  209. package/dist/node_modules/lodash/_baseGet.js.map +1 -1
  210. package/dist/node_modules/lodash/_baseGetAllKeys.js.map +1 -1
  211. package/dist/node_modules/lodash/_baseGetTag.js.map +1 -1
  212. package/dist/node_modules/lodash/_baseGt.js.map +1 -1
  213. package/dist/node_modules/lodash/_baseHasIn.js.map +1 -1
  214. package/dist/node_modules/lodash/_baseIndexOf.js.map +1 -1
  215. package/dist/node_modules/lodash/_baseIsArguments.js.map +1 -1
  216. package/dist/node_modules/lodash/_baseIsEqual.js.map +1 -1
  217. package/dist/node_modules/lodash/_baseIsEqualDeep.js.map +1 -1
  218. package/dist/node_modules/lodash/_baseIsMatch.js.map +1 -1
  219. package/dist/node_modules/lodash/_baseIsNaN.js.map +1 -1
  220. package/dist/node_modules/lodash/_baseIsNative.js.map +1 -1
  221. package/dist/node_modules/lodash/_baseIsTypedArray.js.map +1 -1
  222. package/dist/node_modules/lodash/_baseIteratee.js.map +1 -1
  223. package/dist/node_modules/lodash/_baseKeys.js.map +1 -1
  224. package/dist/node_modules/lodash/_baseLt.js.map +1 -1
  225. package/dist/node_modules/lodash/_baseMap.js.map +1 -1
  226. package/dist/node_modules/lodash/_baseMatches.js.map +1 -1
  227. package/dist/node_modules/lodash/_baseMatchesProperty.js.map +1 -1
  228. package/dist/node_modules/lodash/_baseOrderBy.js.map +1 -1
  229. package/dist/node_modules/lodash/_baseProperty.js.map +1 -1
  230. package/dist/node_modules/lodash/_basePropertyDeep.js.map +1 -1
  231. package/dist/node_modules/lodash/_baseRange.js.map +1 -1
  232. package/dist/node_modules/lodash/_baseRest.js.map +1 -1
  233. package/dist/node_modules/lodash/_baseSetToString.js.map +1 -1
  234. package/dist/node_modules/lodash/_baseSlice.js.map +1 -1
  235. package/dist/node_modules/lodash/_baseSome.js.map +1 -1
  236. package/dist/node_modules/lodash/_baseSortBy.js.map +1 -1
  237. package/dist/node_modules/lodash/_baseTimes.js.map +1 -1
  238. package/dist/node_modules/lodash/_baseToString.js.map +1 -1
  239. package/dist/node_modules/lodash/_baseTrim.js.map +1 -1
  240. package/dist/node_modules/lodash/_baseUnary.js.map +1 -1
  241. package/dist/node_modules/lodash/_baseUniq.js.map +1 -1
  242. package/dist/node_modules/lodash/_cacheHas.js.map +1 -1
  243. package/dist/node_modules/lodash/_castPath.js.map +1 -1
  244. package/dist/node_modules/lodash/_castSlice.js.map +1 -1
  245. package/dist/node_modules/lodash/_compareAscending.js.map +1 -1
  246. package/dist/node_modules/lodash/_compareMultiple.js.map +1 -1
  247. package/dist/node_modules/lodash/_coreJsData.js.map +1 -1
  248. package/dist/node_modules/lodash/_createBaseEach.js.map +1 -1
  249. package/dist/node_modules/lodash/_createBaseFor.js.map +1 -1
  250. package/dist/node_modules/lodash/_createCaseFirst.js.map +1 -1
  251. package/dist/node_modules/lodash/_createFind.js.map +1 -1
  252. package/dist/node_modules/lodash/_createRange.js.map +1 -1
  253. package/dist/node_modules/lodash/_createSet.js.map +1 -1
  254. package/dist/node_modules/lodash/_defineProperty.js.map +1 -1
  255. package/dist/node_modules/lodash/_equalArrays.js.map +1 -1
  256. package/dist/node_modules/lodash/_equalByTag.js.map +1 -1
  257. package/dist/node_modules/lodash/_equalObjects.js.map +1 -1
  258. package/dist/node_modules/lodash/_freeGlobal.js.map +1 -1
  259. package/dist/node_modules/lodash/_getAllKeys.js.map +1 -1
  260. package/dist/node_modules/lodash/_getMapData.js.map +1 -1
  261. package/dist/node_modules/lodash/_getMatchData.js.map +1 -1
  262. package/dist/node_modules/lodash/_getNative.js.map +1 -1
  263. package/dist/node_modules/lodash/_getPrototype.js.map +1 -1
  264. package/dist/node_modules/lodash/_getRawTag.js.map +1 -1
  265. package/dist/node_modules/lodash/_getSymbols.js.map +1 -1
  266. package/dist/node_modules/lodash/_getTag.js.map +1 -1
  267. package/dist/node_modules/lodash/_getValue.js.map +1 -1
  268. package/dist/node_modules/lodash/_hasPath.js.map +1 -1
  269. package/dist/node_modules/lodash/_hasUnicode.js.map +1 -1
  270. package/dist/node_modules/lodash/_hashClear.js.map +1 -1
  271. package/dist/node_modules/lodash/_hashDelete.js.map +1 -1
  272. package/dist/node_modules/lodash/_hashGet.js.map +1 -1
  273. package/dist/node_modules/lodash/_hashHas.js.map +1 -1
  274. package/dist/node_modules/lodash/_hashSet.js.map +1 -1
  275. package/dist/node_modules/lodash/_isFlattenable.js.map +1 -1
  276. package/dist/node_modules/lodash/_isIndex.js.map +1 -1
  277. package/dist/node_modules/lodash/_isIterateeCall.js.map +1 -1
  278. package/dist/node_modules/lodash/_isKey.js.map +1 -1
  279. package/dist/node_modules/lodash/_isKeyable.js.map +1 -1
  280. package/dist/node_modules/lodash/_isMasked.js.map +1 -1
  281. package/dist/node_modules/lodash/_isPrototype.js.map +1 -1
  282. package/dist/node_modules/lodash/_isStrictComparable.js.map +1 -1
  283. package/dist/node_modules/lodash/_listCacheClear.js.map +1 -1
  284. package/dist/node_modules/lodash/_listCacheDelete.js.map +1 -1
  285. package/dist/node_modules/lodash/_listCacheGet.js.map +1 -1
  286. package/dist/node_modules/lodash/_listCacheHas.js.map +1 -1
  287. package/dist/node_modules/lodash/_listCacheSet.js.map +1 -1
  288. package/dist/node_modules/lodash/_mapCacheClear.js.map +1 -1
  289. package/dist/node_modules/lodash/_mapCacheDelete.js.map +1 -1
  290. package/dist/node_modules/lodash/_mapCacheGet.js.map +1 -1
  291. package/dist/node_modules/lodash/_mapCacheHas.js.map +1 -1
  292. package/dist/node_modules/lodash/_mapCacheSet.js.map +1 -1
  293. package/dist/node_modules/lodash/_mapToArray.js.map +1 -1
  294. package/dist/node_modules/lodash/_matchesStrictComparable.js.map +1 -1
  295. package/dist/node_modules/lodash/_memoizeCapped.js.map +1 -1
  296. package/dist/node_modules/lodash/_nativeCreate.js.map +1 -1
  297. package/dist/node_modules/lodash/_nativeKeys.js.map +1 -1
  298. package/dist/node_modules/lodash/_nodeUtil.js.map +1 -1
  299. package/dist/node_modules/lodash/_objectToString.js.map +1 -1
  300. package/dist/node_modules/lodash/_overArg.js.map +1 -1
  301. package/dist/node_modules/lodash/_overRest.js.map +1 -1
  302. package/dist/node_modules/lodash/_root.js.map +1 -1
  303. package/dist/node_modules/lodash/_setCacheAdd.js.map +1 -1
  304. package/dist/node_modules/lodash/_setCacheHas.js.map +1 -1
  305. package/dist/node_modules/lodash/_setToArray.js.map +1 -1
  306. package/dist/node_modules/lodash/_setToString.js.map +1 -1
  307. package/dist/node_modules/lodash/_shortOut.js.map +1 -1
  308. package/dist/node_modules/lodash/_stackClear.js.map +1 -1
  309. package/dist/node_modules/lodash/_stackDelete.js.map +1 -1
  310. package/dist/node_modules/lodash/_stackGet.js.map +1 -1
  311. package/dist/node_modules/lodash/_stackHas.js.map +1 -1
  312. package/dist/node_modules/lodash/_stackSet.js.map +1 -1
  313. package/dist/node_modules/lodash/_strictIndexOf.js.map +1 -1
  314. package/dist/node_modules/lodash/_stringToArray.js.map +1 -1
  315. package/dist/node_modules/lodash/_stringToPath.js.map +1 -1
  316. package/dist/node_modules/lodash/_toKey.js.map +1 -1
  317. package/dist/node_modules/lodash/_toSource.js.map +1 -1
  318. package/dist/node_modules/lodash/_trimmedEndIndex.js.map +1 -1
  319. package/dist/node_modules/lodash/_unicodeToArray.js.map +1 -1
  320. package/dist/node_modules/lodash/constant.js.map +1 -1
  321. package/dist/node_modules/lodash/debounce.js.map +1 -1
  322. package/dist/node_modules/lodash/eq.js.map +1 -1
  323. package/dist/node_modules/lodash/every.js.map +1 -1
  324. package/dist/node_modules/lodash/find.js.map +1 -1
  325. package/dist/node_modules/lodash/findIndex.js.map +1 -1
  326. package/dist/node_modules/lodash/flatMap.js.map +1 -1
  327. package/dist/node_modules/lodash/get.js.map +1 -1
  328. package/dist/node_modules/lodash/hasIn.js.map +1 -1
  329. package/dist/node_modules/lodash/identity.js.map +1 -1
  330. package/dist/node_modules/lodash/isArguments.js.map +1 -1
  331. package/dist/node_modules/lodash/isArray.js.map +1 -1
  332. package/dist/node_modules/lodash/isArrayLike.js.map +1 -1
  333. package/dist/node_modules/lodash/isBoolean.js.map +1 -1
  334. package/dist/node_modules/lodash/isBuffer.js.map +1 -1
  335. package/dist/node_modules/lodash/isEqual.js.map +1 -1
  336. package/dist/node_modules/lodash/isFunction.js.map +1 -1
  337. package/dist/node_modules/lodash/isLength.js.map +1 -1
  338. package/dist/node_modules/lodash/isNaN.js.map +1 -1
  339. package/dist/node_modules/lodash/isNil.js.map +1 -1
  340. package/dist/node_modules/lodash/isNumber.js.map +1 -1
  341. package/dist/node_modules/lodash/isObject.js.map +1 -1
  342. package/dist/node_modules/lodash/isObjectLike.js.map +1 -1
  343. package/dist/node_modules/lodash/isPlainObject.js.map +1 -1
  344. package/dist/node_modules/lodash/isString.js.map +1 -1
  345. package/dist/node_modules/lodash/isSymbol.js.map +1 -1
  346. package/dist/node_modules/lodash/isTypedArray.js.map +1 -1
  347. package/dist/node_modules/lodash/keys.js.map +1 -1
  348. package/dist/node_modules/lodash/last.js.map +1 -1
  349. package/dist/node_modules/lodash/map.js.map +1 -1
  350. package/dist/node_modules/lodash/mapValues.js.map +1 -1
  351. package/dist/node_modules/lodash/max.js.map +1 -1
  352. package/dist/node_modules/lodash/memoize.js.map +1 -1
  353. package/dist/node_modules/lodash/min.js.map +1 -1
  354. package/dist/node_modules/lodash/noop.js.map +1 -1
  355. package/dist/node_modules/lodash/now.js.map +1 -1
  356. package/dist/node_modules/lodash/property.js.map +1 -1
  357. package/dist/node_modules/lodash/range.js.map +1 -1
  358. package/dist/node_modules/lodash/some.js.map +1 -1
  359. package/dist/node_modules/lodash/sortBy.js.map +1 -1
  360. package/dist/node_modules/lodash/stubArray.js.map +1 -1
  361. package/dist/node_modules/lodash/stubFalse.js.map +1 -1
  362. package/dist/node_modules/lodash/throttle.js.map +1 -1
  363. package/dist/node_modules/lodash/toFinite.js.map +1 -1
  364. package/dist/node_modules/lodash/toInteger.js.map +1 -1
  365. package/dist/node_modules/lodash/toNumber.js.map +1 -1
  366. package/dist/node_modules/lodash/toString.js.map +1 -1
  367. package/dist/node_modules/lodash/uniqBy.js.map +1 -1
  368. package/dist/node_modules/lodash/upperFirst.js.map +1 -1
  369. package/dist/node_modules/object-assign/index.js.map +1 -1
  370. package/dist/node_modules/prop-types/checkPropTypes.js.map +1 -1
  371. package/dist/node_modules/prop-types/factoryWithThrowingShims.js.map +1 -1
  372. package/dist/node_modules/prop-types/factoryWithTypeCheckers.js.map +1 -1
  373. package/dist/node_modules/prop-types/index.js.map +1 -1
  374. package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js.map +1 -1
  375. package/dist/node_modules/prop-types/lib/has.js.map +1 -1
  376. package/dist/node_modules/prop-types/node_modules/react-is/cjs/react-is.development.js.map +1 -1
  377. package/dist/node_modules/prop-types/node_modules/react-is/cjs/react-is.production.min.js.map +1 -1
  378. package/dist/node_modules/prop-types/node_modules/react-is/index.js.map +1 -1
  379. package/dist/node_modules/react-is/cjs/react-is.development.js.map +1 -1
  380. package/dist/node_modules/react-is/cjs/react-is.production.min.js.map +1 -1
  381. package/dist/node_modules/react-is/index.js.map +1 -1
  382. package/dist/node_modules/react-smooth/es6/Animate.js +2 -2
  383. package/dist/node_modules/react-smooth/es6/Animate.js.map +1 -1
  384. package/dist/node_modules/react-smooth/es6/AnimateManager.js.map +1 -1
  385. package/dist/node_modules/react-smooth/es6/configUpdate.js.map +1 -1
  386. package/dist/node_modules/react-smooth/es6/easing.js.map +1 -1
  387. package/dist/node_modules/react-smooth/es6/setRafTimeout.js.map +1 -1
  388. package/dist/node_modules/react-smooth/es6/util.js.map +1 -1
  389. package/dist/node_modules/recharts/es6/cartesian/Bar.js +9 -9
  390. package/dist/node_modules/recharts/es6/cartesian/Bar.js.map +1 -1
  391. package/dist/node_modules/recharts/es6/cartesian/Brush.js +12 -12
  392. package/dist/node_modules/recharts/es6/cartesian/Brush.js.map +1 -1
  393. package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js +7 -7
  394. package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js.map +1 -1
  395. package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js +13 -13
  396. package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js.map +1 -1
  397. package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js +4 -4
  398. package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js.map +1 -1
  399. package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js +3 -3
  400. package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js.map +1 -1
  401. package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js +3 -3
  402. package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js.map +1 -1
  403. package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js +4 -4
  404. package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js.map +1 -1
  405. package/dist/node_modules/recharts/es6/cartesian/XAxis.js +3 -3
  406. package/dist/node_modules/recharts/es6/cartesian/XAxis.js.map +1 -1
  407. package/dist/node_modules/recharts/es6/cartesian/YAxis.js +3 -3
  408. package/dist/node_modules/recharts/es6/cartesian/YAxis.js.map +1 -1
  409. package/dist/node_modules/recharts/es6/cartesian/getEquidistantTicks.js.map +1 -1
  410. package/dist/node_modules/recharts/es6/cartesian/getTicks.js.map +1 -1
  411. package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js +1 -1
  412. package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js.map +1 -1
  413. package/dist/node_modules/recharts/es6/chart/BarChart.js.map +1 -1
  414. package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js +22 -22
  415. package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js.map +1 -1
  416. package/dist/node_modules/recharts/es6/component/Cell.js.map +1 -1
  417. package/dist/node_modules/recharts/es6/component/Cursor.js +1 -1
  418. package/dist/node_modules/recharts/es6/component/Cursor.js.map +1 -1
  419. package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js +11 -11
  420. package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js.map +1 -1
  421. package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js +6 -6
  422. package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js.map +1 -1
  423. package/dist/node_modules/recharts/es6/component/Label.js +14 -14
  424. package/dist/node_modules/recharts/es6/component/Label.js.map +1 -1
  425. package/dist/node_modules/recharts/es6/component/LabelList.js +6 -6
  426. package/dist/node_modules/recharts/es6/component/LabelList.js.map +1 -1
  427. package/dist/node_modules/recharts/es6/component/Legend.js +5 -5
  428. package/dist/node_modules/recharts/es6/component/Legend.js.map +1 -1
  429. package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js +3 -3
  430. package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js.map +1 -1
  431. package/dist/node_modules/recharts/es6/component/Text.js +2 -2
  432. package/dist/node_modules/recharts/es6/component/Text.js.map +1 -1
  433. package/dist/node_modules/recharts/es6/component/Tooltip.js +3 -3
  434. package/dist/node_modules/recharts/es6/component/Tooltip.js.map +1 -1
  435. package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js +2 -2
  436. package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js.map +1 -1
  437. package/dist/node_modules/recharts/es6/container/Layer.js +2 -2
  438. package/dist/node_modules/recharts/es6/container/Layer.js.map +1 -1
  439. package/dist/node_modules/recharts/es6/container/Surface.js +2 -2
  440. package/dist/node_modules/recharts/es6/container/Surface.js.map +1 -1
  441. package/dist/node_modules/recharts/es6/context/chartLayoutContext.js +2 -2
  442. package/dist/node_modules/recharts/es6/context/chartLayoutContext.js.map +1 -1
  443. package/dist/node_modules/recharts/es6/shape/Cross.js +1 -1
  444. package/dist/node_modules/recharts/es6/shape/Cross.js.map +1 -1
  445. package/dist/node_modules/recharts/es6/shape/Curve.js +1 -1
  446. package/dist/node_modules/recharts/es6/shape/Curve.js.map +1 -1
  447. package/dist/node_modules/recharts/es6/shape/Dot.js +1 -1
  448. package/dist/node_modules/recharts/es6/shape/Dot.js.map +1 -1
  449. package/dist/node_modules/recharts/es6/shape/Rectangle.js +4 -4
  450. package/dist/node_modules/recharts/es6/shape/Rectangle.js.map +1 -1
  451. package/dist/node_modules/recharts/es6/shape/Sector.js +1 -1
  452. package/dist/node_modules/recharts/es6/shape/Sector.js.map +1 -1
  453. package/dist/node_modules/recharts/es6/shape/Symbols.js +1 -1
  454. package/dist/node_modules/recharts/es6/shape/Symbols.js.map +1 -1
  455. package/dist/node_modules/recharts/es6/shape/Trapezoid.js +4 -4
  456. package/dist/node_modules/recharts/es6/shape/Trapezoid.js.map +1 -1
  457. package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js +9 -9
  458. package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js.map +1 -1
  459. package/dist/node_modules/recharts/es6/util/BarUtils.js +1 -1
  460. package/dist/node_modules/recharts/es6/util/BarUtils.js.map +1 -1
  461. package/dist/node_modules/recharts/es6/util/CartesianUtils.js +1 -1
  462. package/dist/node_modules/recharts/es6/util/CartesianUtils.js.map +1 -1
  463. package/dist/node_modules/recharts/es6/util/ChartUtils.js.map +1 -1
  464. package/dist/node_modules/recharts/es6/util/CssPrefixUtils.js.map +1 -1
  465. package/dist/node_modules/recharts/es6/util/DOMUtils.js.map +1 -1
  466. package/dist/node_modules/recharts/es6/util/DataUtils.js.map +1 -1
  467. package/dist/node_modules/recharts/es6/util/DetectReferenceElementsDomain.js.map +1 -1
  468. package/dist/node_modules/recharts/es6/util/Events.js.map +1 -1
  469. package/dist/node_modules/recharts/es6/util/Global.js.map +1 -1
  470. package/dist/node_modules/recharts/es6/util/IfOverflowMatches.js.map +1 -1
  471. package/dist/node_modules/recharts/es6/util/LogUtils.js.map +1 -1
  472. package/dist/node_modules/recharts/es6/util/PolarUtils.js.map +1 -1
  473. package/dist/node_modules/recharts/es6/util/ReactUtils.js +1 -1
  474. package/dist/node_modules/recharts/es6/util/ReactUtils.js.map +1 -1
  475. package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js +1 -1
  476. package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js.map +1 -1
  477. package/dist/node_modules/recharts/es6/util/ShallowEqual.js.map +1 -1
  478. package/dist/node_modules/recharts/es6/util/TickUtils.js.map +1 -1
  479. package/dist/node_modules/recharts/es6/util/calculateViewBox.js.map +1 -1
  480. package/dist/node_modules/recharts/es6/util/cursor/getCursorPoints.js.map +1 -1
  481. package/dist/node_modules/recharts/es6/util/cursor/getCursorRectangle.js.map +1 -1
  482. package/dist/node_modules/recharts/es6/util/cursor/getRadialCursorPoints.js.map +1 -1
  483. package/dist/node_modules/recharts/es6/util/getEveryNthWithCondition.js.map +1 -1
  484. package/dist/node_modules/recharts/es6/util/getLegendProps.js.map +1 -1
  485. package/dist/node_modules/recharts/es6/util/isDomainSpecifiedByUser.js.map +1 -1
  486. package/dist/node_modules/recharts/es6/util/payload/getUniqPayload.js.map +1 -1
  487. package/dist/node_modules/recharts/es6/util/tooltip/translate.js.map +1 -1
  488. package/dist/node_modules/recharts/es6/util/types.js +1 -1
  489. package/dist/node_modules/recharts/es6/util/types.js.map +1 -1
  490. package/dist/node_modules/recharts-scale/es6/getNiceTickValues.js.map +1 -1
  491. package/dist/node_modules/recharts-scale/es6/util/arithmetic.js.map +1 -1
  492. package/dist/node_modules/recharts-scale/es6/util/utils.js.map +1 -1
  493. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1 -1
  494. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -1
  495. package/dist/node_modules/tiny-invariant/dist/esm/tiny-invariant.js.map +1 -1
  496. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"MiniBar.js","names":[],"sources":["../../../src/ecoimpacthub/components/MiniBar.tsx"],"sourcesContent":["/**\n * MiniBar — a thin inline progress bar (target progress, completion, breach %).\n * @module ecoimpacthub/components\n */\n\nimport { cn } from '../utils/cn';\n\ninterface MiniBarProps {\n /** 0–100. */\n value: number;\n className?: string;\n /** Bar fill token class (defaults to accent). */\n barClassName?: string;\n /** Height in px. */\n height?: number;\n}\n\nexport function MiniBar({\n value,\n className,\n barClassName = 'bg-accent',\n height = 6,\n}: MiniBarProps) {\n const clamped = Math.max(0, Math.min(100, value));\n return (\n <div\n className={cn('w-full overflow-hidden rounded-full bg-bg-sunken', className)}\n style={{ height }}\n role=\"progressbar\"\n aria-valuenow={Math.round(clamped)}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div\n className={cn('h-full rounded-full transition-[width] duration-700 ease-out', barClassName)}\n style={{ width: `${clamped}%` }}\n />\n </div>\n );\n}\n"],"mappings":";;;AAiBA,SAAgB,EAAQ,EACtB,UACA,cACA,kBAAe,aACf,YAAS,KACM;CACf,IAAM,IAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,EAAM,CAAC;AACjD,QACE,kBAAC,OAAD;EACE,WAAW,EAAG,oDAAoD,EAAU;EAC5E,OAAO,EAAE,WAAQ;EACjB,MAAK;EACL,iBAAe,KAAK,MAAM,EAAQ;EAClC,iBAAe;EACf,iBAAe;YAEf,kBAAC,OAAD;GACE,WAAW,EAAG,gEAAgE,EAAa;GAC3F,OAAO,EAAE,OAAO,GAAG,EAAQ,IAAI;GAC/B,CAAA;EACE,CAAA"}
1
+ {"version":3,"file":"MiniBar.js","names":[],"sources":["../../../src/ecoimpacthub/components/MiniBar.tsx"],"sourcesContent":["/**\n * MiniBar — a thin inline progress bar (target progress, completion, breach %).\n * @module ecoimpacthub/components\n */\n\nimport { cn } from '../utils/cn';\n\ninterface MiniBarProps {\n /** 0–100. */\n value: number;\n className?: string;\n /** Bar fill token class (defaults to accent). */\n barClassName?: string;\n /** Height in px. */\n height?: number;\n}\n\nexport function MiniBar({\n value,\n className,\n barClassName = 'bg-accent',\n height = 6,\n}: MiniBarProps) {\n const clamped = Math.max(0, Math.min(100, value));\n return (\n <div\n className={cn('w-full overflow-hidden rounded-full bg-bg-sunken', className)}\n style={{ height }}\n role=\"progressbar\"\n aria-valuenow={Math.round(clamped)}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div\n className={cn('h-full rounded-full transition-[width] duration-700 ease-out', barClassName)}\n style={{ width: `${clamped}%` }}\n />\n </div>\n );\n}\n"],"mappings":";;;AAiBA,SAAgB,EAAQ,EACtB,UACA,cACA,kBAAe,aACf,YAAS,KACM;CACf,IAAM,IAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,CAAK,CAAC;CAChD,OACE,kBAAC,OAAD;EACE,WAAW,EAAG,oDAAoD,CAAS;EAC3E,OAAO,EAAE,UAAO;EAChB,MAAK;EACL,iBAAe,KAAK,MAAM,CAAO;EACjC,iBAAe;EACf,iBAAe;YAEf,kBAAC,OAAD;GACE,WAAW,EAAG,gEAAgE,CAAY;GAC1F,OAAO,EAAE,OAAO,GAAG,EAAQ,GAAG;EAC/B,CAAA;CACE,CAAA;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"PageLayout.js","names":[],"sources":["../../../src/ecoimpacthub/components/PageLayout.tsx"],"sourcesContent":["/**\n * Page Layout Component\n * @module ecoimpacthub/components\n *\n * Boff UI 2.0 page wrapper. Supports a living-glass {@link AuroraBackground}\n * hero backdrop and a gradient hero title for the MFE's primary page.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { AuroraBackground, GradientText } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\ninterface PageLayoutProps {\n title: ReactNode;\n description?: string;\n actions?: ReactNode;\n children: ReactNode;\n className?: string;\n /** Render the title as a gradient hero heading (reserve for the ONE primary page). */\n titleGradient?: boolean;\n /** Drop a subtle living-glass aurora behind the header (primary page only). */\n aurora?: boolean;\n}\n\nexport const PageLayout: FC<PageLayoutProps> = ({\n title,\n description,\n actions,\n children,\n className,\n titleGradient = false,\n aurora = false,\n}) => {\n return (\n <div className={cn('flex flex-col h-full', className)}>\n <div\n className={cn(\n 'relative flex flex-col gap-3 px-6 py-4 border-b border-border-seam sm:flex-row sm:items-center sm:justify-between sm:gap-4',\n aurora ? 'overflow-hidden bg-gloss-card' : 'bg-bg-surface'\n )}\n >\n {aurora && <AuroraBackground intensity=\"subtle\" />}\n <div className=\"min-w-0\">\n {titleGradient && typeof title === 'string' ? (\n <GradientText as=\"h1\" className=\"text-2xl font-semibold tracking-tight\">\n {title}\n </GradientText>\n ) : (\n <h1 className=\"text-2xl font-semibold text-text-primary\">{title}</h1>\n )}\n {description && <p className=\"mt-1 text-sm text-text-secondary\">{description}</p>}\n </div>\n {actions && (\n <div className=\"flex flex-wrap items-center gap-3 shrink-0 max-sm:w-full\">{actions}</div>\n )}\n </div>\n\n <div className=\"flex-1 overflow-auto p-6\">{children}</div>\n </div>\n );\n};\n"],"mappings":";;;;AAwBA,IAAa,KAAmC,EAC9C,UACA,gBACA,YACA,aACA,cACA,mBAAgB,IAChB,YAAS,SAGP,kBAAC,OAAD;CAAK,WAAW,EAAG,wBAAwB,EAAU;WAArD,CACE,kBAAC,OAAD;EACE,WAAW,EACT,8HACA,IAAS,kCAAkC,gBAC5C;YAJH;GAMG,KAAU,kBAAC,GAAD,EAAkB,WAAU,UAAW,CAAA;GAClD,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,KAAiB,OAAO,KAAU,WACjC,kBAAC,GAAD;KAAc,IAAG;KAAK,WAAU;eAC7B;KACY,CAAA,GAEf,kBAAC,MAAD;KAAI,WAAU;eAA4C;KAAW,CAAA,EAEtE,KAAe,kBAAC,KAAD;KAAG,WAAU;eAAoC;KAAgB,CAAA,CAC7E;;GACL,KACC,kBAAC,OAAD;IAAK,WAAU;cAA4D;IAAc,CAAA;GAEvF;KAEN,kBAAC,OAAD;EAAK,WAAU;EAA4B;EAAe,CAAA,CACtD"}
1
+ {"version":3,"file":"PageLayout.js","names":[],"sources":["../../../src/ecoimpacthub/components/PageLayout.tsx"],"sourcesContent":["/**\n * Page Layout Component\n * @module ecoimpacthub/components\n *\n * Boff UI 2.0 page wrapper. Supports a living-glass {@link AuroraBackground}\n * hero backdrop and a gradient hero title for the MFE's primary page.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { AuroraBackground, GradientText } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\ninterface PageLayoutProps {\n title: ReactNode;\n description?: string;\n actions?: ReactNode;\n children: ReactNode;\n className?: string;\n /** Render the title as a gradient hero heading (reserve for the ONE primary page). */\n titleGradient?: boolean;\n /** Drop a subtle living-glass aurora behind the header (primary page only). */\n aurora?: boolean;\n}\n\nexport const PageLayout: FC<PageLayoutProps> = ({\n title,\n description,\n actions,\n children,\n className,\n titleGradient = false,\n aurora = false,\n}) => {\n return (\n <div className={cn('flex flex-col h-full', className)}>\n <div\n className={cn(\n 'relative flex flex-col gap-3 px-6 py-4 border-b border-border-seam sm:flex-row sm:items-center sm:justify-between sm:gap-4',\n aurora ? 'overflow-hidden bg-gloss-card' : 'bg-bg-surface'\n )}\n >\n {aurora && <AuroraBackground intensity=\"subtle\" />}\n <div className=\"min-w-0\">\n {titleGradient && typeof title === 'string' ? (\n <GradientText as=\"h1\" className=\"text-2xl font-semibold tracking-tight\">\n {title}\n </GradientText>\n ) : (\n <h1 className=\"text-2xl font-semibold text-text-primary\">{title}</h1>\n )}\n {description && <p className=\"mt-1 text-sm text-text-secondary\">{description}</p>}\n </div>\n {actions && (\n <div className=\"flex flex-wrap items-center gap-3 shrink-0 max-sm:w-full\">{actions}</div>\n )}\n </div>\n\n <div className=\"flex-1 overflow-auto p-6\">{children}</div>\n </div>\n );\n};\n"],"mappings":";;;;AAwBA,IAAa,KAAmC,EAC9C,UACA,gBACA,YACA,aACA,cACA,mBAAgB,IAChB,YAAS,SAGP,kBAAC,OAAD;CAAK,WAAW,EAAG,wBAAwB,CAAS;WAApD,CACE,kBAAC,OAAD;EACE,WAAW,EACT,8HACA,IAAS,kCAAkC,eAC7C;YAJF;GAMG,KAAU,kBAAC,GAAD,EAAkB,WAAU,SAAU,CAAA;GACjD,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,KAAiB,OAAO,KAAU,WACjC,kBAAC,GAAD;KAAc,IAAG;KAAK,WAAU;eAC7B;IACW,CAAA,IAEd,kBAAC,MAAD;KAAI,WAAU;eAA4C;IAAU,CAAA,GAErE,KAAe,kBAAC,KAAD;KAAG,WAAU;eAAoC;IAAe,CAAA,CAC7E;;GACJ,KACC,kBAAC,OAAD;IAAK,WAAU;cAA4D;GAAa,CAAA;EAEvF;KAEL,kBAAC,OAAD;EAAK,WAAU;EAA4B;CAAc,CAAA,CACtD"}
@@ -1 +1 @@
1
- {"version":3,"file":"Pagination.js","names":[],"sources":["../../../src/ecoimpacthub/components/Pagination.tsx"],"sourcesContent":["/**\n * Pagination — cursor-aware Prev/Next control for Eco* connection lists.\n * @module ecoimpacthub/components\n *\n * The svc list connections return `pageInfo { cursor, hasMore }` and paginate by\n * cursor (offset is a no-op). Pages track a 0-indexed `page` for display and a\n * cursor stack for navigation; this control exposes Prev/Next, disabling Prev on\n * page 0 and Next when the server reports no more rows.\n */\n\nimport { ChevronLeft, ChevronRight } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\ninterface PaginationProps {\n page: number;\n pageSize: number;\n /** Number of rows on the current page. */\n itemCount: number;\n /** Server flag: are there more rows after this page? */\n hasMore: boolean;\n onPageChange: (page: number) => void;\n className?: string;\n}\n\nexport function Pagination({\n page,\n pageSize,\n itemCount,\n hasMore,\n onPageChange,\n className,\n}: PaginationProps) {\n // Nothing to paginate: single page that also has no more rows.\n if (page === 0 && !hasMore) return null;\n\n const from = itemCount === 0 ? 0 : page * pageSize + 1;\n const to = page * pageSize + itemCount;\n\n return (\n <div\n className={cn('mt-4 flex flex-col items-center justify-between gap-3 sm:flex-row', className)}\n >\n <p className=\"text-sm text-text-secondary tabular-nums\" aria-live=\"polite\">\n Showing {from}–{to}\n </p>\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => onPageChange(page - 1)}\n disabled={page === 0}\n aria-label=\"Previous page\"\n >\n <ChevronLeft className=\"mr-1 h-4 w-4\" /> Previous\n </Button>\n <span className=\"min-w-[4.5rem] text-center text-sm text-text-secondary tabular-nums\">\n Page {page + 1}\n </span>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => onPageChange(page + 1)}\n disabled={!hasMore}\n aria-label=\"Next page\"\n >\n Next <ChevronRight className=\"ml-1 h-4 w-4\" />\n </Button>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAyBA,SAAgB,EAAW,EACzB,SACA,aACA,cACA,YACA,iBACA,gBACkB;AAElB,KAAI,MAAS,KAAK,CAAC,EAAS,QAAO;CAEnC,IAAM,IAAO,MAAc,IAAI,IAAI,IAAO,IAAW,GAC/C,IAAK,IAAO,IAAW;AAE7B,QACE,kBAAC,OAAD;EACE,WAAW,EAAG,qEAAqE,EAAU;YAD/F,CAGE,kBAAC,KAAD;GAAG,WAAU;GAA2C,aAAU;aAAlE;IAA2E;IAChE;IAAK;IAAE;IACd;MACJ,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,SAAQ;KACR,MAAK;KACL,eAAe,EAAa,IAAO,EAAE;KACrC,UAAU,MAAS;KACnB,cAAW;eALb,CAOE,kBAAC,GAAD,EAAa,WAAU,gBAAiB,CAAA,EAAA,YACjC;;IACT,kBAAC,QAAD;KAAM,WAAU;eAAhB,CAAsF,SAC9E,IAAO,EACR;;IACP,kBAAC,GAAD;KACE,SAAQ;KACR,MAAK;KACL,eAAe,EAAa,IAAO,EAAE;KACrC,UAAU,CAAC;KACX,cAAW;eALb,CAMC,SACM,kBAAC,GAAD,EAAc,WAAU,gBAAiB,CAAA,CACvC;;IACL;KACF"}
1
+ {"version":3,"file":"Pagination.js","names":[],"sources":["../../../src/ecoimpacthub/components/Pagination.tsx"],"sourcesContent":["/**\n * Pagination — cursor-aware Prev/Next control for Eco* connection lists.\n * @module ecoimpacthub/components\n *\n * The svc list connections return `pageInfo { cursor, hasMore }` and paginate by\n * cursor (offset is a no-op). Pages track a 0-indexed `page` for display and a\n * cursor stack for navigation; this control exposes Prev/Next, disabling Prev on\n * page 0 and Next when the server reports no more rows.\n */\n\nimport { ChevronLeft, ChevronRight } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\ninterface PaginationProps {\n page: number;\n pageSize: number;\n /** Number of rows on the current page. */\n itemCount: number;\n /** Server flag: are there more rows after this page? */\n hasMore: boolean;\n onPageChange: (page: number) => void;\n className?: string;\n}\n\nexport function Pagination({\n page,\n pageSize,\n itemCount,\n hasMore,\n onPageChange,\n className,\n}: PaginationProps) {\n // Nothing to paginate: single page that also has no more rows.\n if (page === 0 && !hasMore) return null;\n\n const from = itemCount === 0 ? 0 : page * pageSize + 1;\n const to = page * pageSize + itemCount;\n\n return (\n <div\n className={cn('mt-4 flex flex-col items-center justify-between gap-3 sm:flex-row', className)}\n >\n <p className=\"text-sm text-text-secondary tabular-nums\" aria-live=\"polite\">\n Showing {from}–{to}\n </p>\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => onPageChange(page - 1)}\n disabled={page === 0}\n aria-label=\"Previous page\"\n >\n <ChevronLeft className=\"mr-1 h-4 w-4\" /> Previous\n </Button>\n <span className=\"min-w-[4.5rem] text-center text-sm text-text-secondary tabular-nums\">\n Page {page + 1}\n </span>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => onPageChange(page + 1)}\n disabled={!hasMore}\n aria-label=\"Next page\"\n >\n Next <ChevronRight className=\"ml-1 h-4 w-4\" />\n </Button>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAyBA,SAAgB,EAAW,EACzB,SACA,aACA,cACA,YACA,iBACA,gBACkB;CAElB,IAAI,MAAS,KAAK,CAAC,GAAS,OAAO;CAEnC,IAAM,IAAO,MAAc,IAAI,IAAI,IAAO,IAAW,GAC/C,IAAK,IAAO,IAAW;CAE7B,OACE,kBAAC,OAAD;EACE,WAAW,EAAG,qEAAqE,CAAS;YAD9F,CAGE,kBAAC,KAAD;GAAG,WAAU;GAA2C,aAAU;aAAlE;IAA2E;IAChE;IAAK;IAAE;GACf;MACH,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,SAAQ;KACR,MAAK;KACL,eAAe,EAAa,IAAO,CAAC;KACpC,UAAU,MAAS;KACnB,cAAW;eALb,CAOE,kBAAC,GAAD,EAAa,WAAU,eAAgB,CAAA,GAAC,WAClC;;IACR,kBAAC,QAAD;KAAM,WAAU;eAAhB,CAAsF,SAC9E,IAAO,CACT;;IACN,kBAAC,GAAD;KACE,SAAQ;KACR,MAAK;KACL,eAAe,EAAa,IAAO,CAAC;KACpC,UAAU,CAAC;KACX,cAAW;eALb,CAMC,SACM,kBAAC,GAAD,EAAc,WAAU,eAAgB,CAAA,CACvC;;GACL;IACF;;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"StateViews.js","names":[],"sources":["../../../src/ecoimpacthub/components/StateViews.tsx"],"sourcesContent":["/**\n * Shared loading / error / section state views\n * @module ecoimpacthub/components\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { AlertCircle } from 'lucide-react';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\ninterface LoadingViewProps {\n label?: string;\n className?: string;\n}\n\nexport const LoadingView: FC<LoadingViewProps> = ({ label = 'Loading…', className }) => (\n <div className={cn('flex min-h-[40vh] flex-col items-center justify-center gap-3', className)}>\n <Spinner size=\"lg\" />\n <p className=\"text-sm text-text-secondary\">{label}</p>\n </div>\n);\n\ninterface ErrorViewProps {\n title?: string;\n message?: string;\n onRetry?: () => void;\n className?: string;\n}\n\nexport const ErrorView: FC<ErrorViewProps> = ({\n title = 'Something went wrong',\n message,\n onRetry,\n className,\n}) => (\n <div\n className={cn(\n 'flex min-h-[40vh] flex-col items-center justify-center gap-4 text-center',\n className\n )}\n >\n <AlertCircle className=\"h-10 w-10 text-status-error-text\" />\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">{title}</h2>\n {message && <p className=\"mt-1 max-w-md text-sm text-text-secondary\">{message}</p>}\n </div>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n Retry\n </button>\n )}\n </div>\n);\n\ninterface SectionProps {\n title: string;\n description?: string;\n action?: ReactNode;\n children: ReactNode;\n className?: string;\n}\n\nexport const Section: FC<SectionProps> = ({ title, description, action, children, className }) => (\n <section className={cn('mt-8 first:mt-0', className)}>\n <div className=\"mb-3 flex items-end justify-between gap-3\">\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">{title}</h2>\n {description && <p className=\"mt-0.5 text-sm text-text-secondary\">{description}</p>}\n </div>\n {action && <div className=\"shrink-0\">{action}</div>}\n </div>\n {children}\n </section>\n);\n"],"mappings":";;;;;AAeA,IAAa,KAAqC,EAAE,WAAQ,YAAY,mBACtE,kBAAC,OAAD;CAAK,WAAW,EAAG,gEAAgE,EAAU;WAA7F,CACE,kBAAC,GAAD,EAAS,MAAK,MAAO,CAAA,EACrB,kBAAC,KAAD;EAAG,WAAU;YAA+B;EAAU,CAAA,CAClD;IAUK,KAAiC,EAC5C,WAAQ,wBACR,YACA,YACA,mBAEA,kBAAC,OAAD;CACE,WAAW,EACT,4EACA,EACD;WAJH;EAME,kBAAC,GAAD,EAAa,WAAU,oCAAqC,CAAA;EAC5D,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;GAAI,WAAU;aAA2C;GAAW,CAAA,EACnE,KAAW,kBAAC,KAAD;GAAG,WAAU;aAA6C;GAAY,CAAA,CAC9E,EAAA,CAAA;EACL,KACC,kBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;aACX;GAEQ,CAAA;EAEP;IAWK,KAA6B,EAAE,UAAO,gBAAa,WAAQ,aAAU,mBAChF,kBAAC,WAAD;CAAS,WAAW,EAAG,mBAAmB,EAAU;WAApD,CACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;GAAI,WAAU;aAA6C;GAAW,CAAA,EACrE,KAAe,kBAAC,KAAD;GAAG,WAAU;aAAsC;GAAgB,CAAA,CAC/E,EAAA,CAAA,EACL,KAAU,kBAAC,OAAD;GAAK,WAAU;aAAY;GAAa,CAAA,CAC/C;KACL,EACO"}
1
+ {"version":3,"file":"StateViews.js","names":[],"sources":["../../../src/ecoimpacthub/components/StateViews.tsx"],"sourcesContent":["/**\n * Shared loading / error / section state views\n * @module ecoimpacthub/components\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { AlertCircle } from 'lucide-react';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\ninterface LoadingViewProps {\n label?: string;\n className?: string;\n}\n\nexport const LoadingView: FC<LoadingViewProps> = ({ label = 'Loading…', className }) => (\n <div className={cn('flex min-h-[40vh] flex-col items-center justify-center gap-3', className)}>\n <Spinner size=\"lg\" />\n <p className=\"text-sm text-text-secondary\">{label}</p>\n </div>\n);\n\ninterface ErrorViewProps {\n title?: string;\n message?: string;\n onRetry?: () => void;\n className?: string;\n}\n\nexport const ErrorView: FC<ErrorViewProps> = ({\n title = 'Something went wrong',\n message,\n onRetry,\n className,\n}) => (\n <div\n className={cn(\n 'flex min-h-[40vh] flex-col items-center justify-center gap-4 text-center',\n className\n )}\n >\n <AlertCircle className=\"h-10 w-10 text-status-error-text\" />\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">{title}</h2>\n {message && <p className=\"mt-1 max-w-md text-sm text-text-secondary\">{message}</p>}\n </div>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n Retry\n </button>\n )}\n </div>\n);\n\ninterface SectionProps {\n title: string;\n description?: string;\n action?: ReactNode;\n children: ReactNode;\n className?: string;\n}\n\nexport const Section: FC<SectionProps> = ({ title, description, action, children, className }) => (\n <section className={cn('mt-8 first:mt-0', className)}>\n <div className=\"mb-3 flex items-end justify-between gap-3\">\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">{title}</h2>\n {description && <p className=\"mt-0.5 text-sm text-text-secondary\">{description}</p>}\n </div>\n {action && <div className=\"shrink-0\">{action}</div>}\n </div>\n {children}\n </section>\n);\n"],"mappings":";;;;;AAeA,IAAa,KAAqC,EAAE,WAAQ,YAAY,mBACtE,kBAAC,OAAD;CAAK,WAAW,EAAG,gEAAgE,CAAS;WAA5F,CACE,kBAAC,GAAD,EAAS,MAAK,KAAM,CAAA,GACpB,kBAAC,KAAD;EAAG,WAAU;YAA+B;CAAS,CAAA,CAClD;IAUM,KAAiC,EAC5C,WAAQ,wBACR,YACA,YACA,mBAEA,kBAAC,OAAD;CACE,WAAW,EACT,4EACA,CACF;WAJF;EAME,kBAAC,GAAD,EAAa,WAAU,mCAAoC,CAAA;EAC3D,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;GAAI,WAAU;aAA2C;EAAU,CAAA,GAClE,KAAW,kBAAC,KAAD;GAAG,WAAU;aAA6C;EAAW,CAAA,CAC9E,EAAA,CAAA;EACJ,KACC,kBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;aACX;EAEO,CAAA;CAEP;IAWM,KAA6B,EAAE,UAAO,gBAAa,WAAQ,aAAU,mBAChF,kBAAC,WAAD;CAAS,WAAW,EAAG,mBAAmB,CAAS;WAAnD,CACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;GAAI,WAAU;aAA6C;EAAU,CAAA,GACpE,KAAe,kBAAC,KAAD;GAAG,WAAU;aAAsC;EAAe,CAAA,CAC/E,EAAA,CAAA,GACJ,KAAU,kBAAC,OAAD;GAAK,WAAU;aAAY;EAAY,CAAA,CAC/C;KACJ,CACM"}
@@ -1 +1 @@
1
- {"version":3,"file":"StatusBadge.js","names":[],"sources":["../../../src/ecoimpacthub/components/StatusBadge.tsx"],"sourcesContent":["/**\n * Status Badge Component\n * @module ecoimpacthub/components\n *\n * A colored badge for EcoImpactHub domain statuses (site status, sensor status,\n * threshold severity, conservation status, habitat-project lifecycle, carbon\n * entry status, reduction-target status, report status/framework, emission\n * scope) with semantic color mapping. Accepts the raw server enum value.\n */\n\nimport type { FC } from 'react';\nimport { cn } from '../utils/cn';\nimport { formatEnumLabel } from '../utils/formatters';\n\ninterface StatusBadgeProps {\n status: string;\n className?: string;\n}\n\ntype BadgeVariant = 'success' | 'warning' | 'destructive' | 'secondary' | 'info' | 'outline';\n\nconst variantStyles: Record<BadgeVariant, string> = {\n success: 'bg-status-success-bg-subtle text-status-success-text',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text',\n destructive: 'bg-status-error-bg-subtle text-status-error-text',\n secondary: 'bg-bg-sunken text-text-secondary',\n info: 'bg-[var(--color-accent-soft)] text-text-primary',\n outline: 'border border-border-seam text-text-primary',\n};\n\n// Statuses that represent a \"live\" / in-progress condition get a subtle,\n// opacity-only glow pulse (reduced-motion safe via motion-safe:).\nconst liveStatuses = new Set(['IN_PROGRESS', 'ONLINE', 'ACTIVE']);\n\nconst statusVariantMap: Record<string, BadgeVariant> = {\n // Site status\n ACTIVE: 'success',\n MONITORING_PAUSED: 'warning',\n ARCHIVED: 'outline',\n\n // Sensor status\n ONLINE: 'success',\n OFFLINE: 'destructive',\n DEGRADED: 'warning',\n MAINTENANCE: 'info',\n RETIRED: 'outline',\n\n // Threshold severity / generic severity\n INFO: 'secondary',\n WARNING: 'warning',\n CRITICAL: 'destructive',\n\n // Threshold direction\n ABOVE: 'warning',\n BELOW: 'info',\n OUTSIDE_RANGE: 'warning',\n\n // Measurement / breach\n BREACH: 'destructive',\n OK: 'success',\n\n // Conservation status (IUCN-style)\n LEAST_CONCERN: 'success',\n NEAR_THREATENED: 'info',\n VULNERABLE: 'warning',\n ENDANGERED: 'destructive',\n CRITICALLY_ENDANGERED: 'destructive',\n EXTINCT_IN_WILD: 'outline',\n DATA_DEFICIENT: 'secondary',\n NOT_EVALUATED: 'secondary',\n\n // Habitat-project lifecycle\n PLANNED: 'secondary',\n MONITORING: 'info',\n COMPLETED: 'success',\n ON_HOLD: 'warning',\n CANCELLED: 'destructive',\n\n // Carbon-entry status\n DRAFT: 'secondary',\n RECORDED: 'info',\n VERIFIED: 'success',\n ADJUSTED: 'warning',\n\n // Report status\n IN_REVIEW: 'warning',\n PUBLISHED: 'success',\n\n // Reduction-target status\n PROPOSED: 'secondary',\n ACHIEVED: 'success',\n MISSED: 'destructive',\n\n // Emission scope\n SCOPE_1: 'destructive',\n SCOPE_2: 'warning',\n SCOPE_3: 'info',\n\n // Report frameworks (neutral badges)\n GHG_PROTOCOL: 'outline',\n GRI: 'outline',\n TCFD: 'outline',\n CDP: 'outline',\n SASB: 'outline',\n CSRD: 'outline',\n ISSB: 'outline',\n EU_TAXONOMY: 'outline',\n CUSTOM: 'secondary',\n};\n\nexport const StatusBadge: FC<StatusBadgeProps> = ({ status, className }) => {\n const key = status.toUpperCase();\n const variant = statusVariantMap[key] ?? 'secondary';\n const isLive = liveStatuses.has(key);\n\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium',\n variantStyles[variant],\n className\n )}\n >\n {isLive && (\n <span\n aria-hidden=\"true\"\n className=\"size-1.5 rounded-full bg-current motion-safe:animate-vc-glow-pulse\"\n />\n )}\n {formatEnumLabel(status)}\n </span>\n );\n};\n"],"mappings":";;;;AAqBA,IAAM,IAA8C;CAClD,SAAS;CACT,SAAS;CACT,aAAa;CACb,WAAW;CACX,MAAM;CACN,SAAS;CACV,EAIK,IAAe,IAAI,IAAI;CAAC;CAAe;CAAU;CAAS,CAAC,EAE3D,IAAiD;CAErD,QAAQ;CACR,mBAAmB;CACnB,UAAU;CAGV,QAAQ;CACR,SAAS;CACT,UAAU;CACV,aAAa;CACb,SAAS;CAGT,MAAM;CACN,SAAS;CACT,UAAU;CAGV,OAAO;CACP,OAAO;CACP,eAAe;CAGf,QAAQ;CACR,IAAI;CAGJ,eAAe;CACf,iBAAiB;CACjB,YAAY;CACZ,YAAY;CACZ,uBAAuB;CACvB,iBAAiB;CACjB,gBAAgB;CAChB,eAAe;CAGf,SAAS;CACT,YAAY;CACZ,WAAW;CACX,SAAS;CACT,WAAW;CAGX,OAAO;CACP,UAAU;CACV,UAAU;CACV,UAAU;CAGV,WAAW;CACX,WAAW;CAGX,UAAU;CACV,UAAU;CACV,QAAQ;CAGR,SAAS;CACT,SAAS;CACT,SAAS;CAGT,cAAc;CACd,KAAK;CACL,MAAM;CACN,KAAK;CACL,MAAM;CACN,MAAM;CACN,MAAM;CACN,aAAa;CACb,QAAQ;CACT,EAEY,KAAqC,EAAE,WAAQ,mBAAgB;CAC1E,IAAM,IAAM,EAAO,aAAa,EAC1B,IAAU,EAAiB,MAAQ,aACnC,IAAS,EAAa,IAAI,EAAI;AAEpC,QACE,kBAAC,QAAD;EACE,WAAW,EACT,mFACA,EAAc,IACd,EACD;YALH,CAOG,KACC,kBAAC,QAAD;GACE,eAAY;GACZ,WAAU;GACV,CAAA,EAEH,EAAgB,EAAO,CACnB"}
1
+ {"version":3,"file":"StatusBadge.js","names":[],"sources":["../../../src/ecoimpacthub/components/StatusBadge.tsx"],"sourcesContent":["/**\n * Status Badge Component\n * @module ecoimpacthub/components\n *\n * A colored badge for EcoImpactHub domain statuses (site status, sensor status,\n * threshold severity, conservation status, habitat-project lifecycle, carbon\n * entry status, reduction-target status, report status/framework, emission\n * scope) with semantic color mapping. Accepts the raw server enum value.\n */\n\nimport type { FC } from 'react';\nimport { cn } from '../utils/cn';\nimport { formatEnumLabel } from '../utils/formatters';\n\ninterface StatusBadgeProps {\n status: string;\n className?: string;\n}\n\ntype BadgeVariant = 'success' | 'warning' | 'destructive' | 'secondary' | 'info' | 'outline';\n\nconst variantStyles: Record<BadgeVariant, string> = {\n success: 'bg-status-success-bg-subtle text-status-success-text',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text',\n destructive: 'bg-status-error-bg-subtle text-status-error-text',\n secondary: 'bg-bg-sunken text-text-secondary',\n info: 'bg-[var(--color-accent-soft)] text-text-primary',\n outline: 'border border-border-seam text-text-primary',\n};\n\n// Statuses that represent a \"live\" / in-progress condition get a subtle,\n// opacity-only glow pulse (reduced-motion safe via motion-safe:).\nconst liveStatuses = new Set(['IN_PROGRESS', 'ONLINE', 'ACTIVE']);\n\nconst statusVariantMap: Record<string, BadgeVariant> = {\n // Site status\n ACTIVE: 'success',\n MONITORING_PAUSED: 'warning',\n ARCHIVED: 'outline',\n\n // Sensor status\n ONLINE: 'success',\n OFFLINE: 'destructive',\n DEGRADED: 'warning',\n MAINTENANCE: 'info',\n RETIRED: 'outline',\n\n // Threshold severity / generic severity\n INFO: 'secondary',\n WARNING: 'warning',\n CRITICAL: 'destructive',\n\n // Threshold direction\n ABOVE: 'warning',\n BELOW: 'info',\n OUTSIDE_RANGE: 'warning',\n\n // Measurement / breach\n BREACH: 'destructive',\n OK: 'success',\n\n // Conservation status (IUCN-style)\n LEAST_CONCERN: 'success',\n NEAR_THREATENED: 'info',\n VULNERABLE: 'warning',\n ENDANGERED: 'destructive',\n CRITICALLY_ENDANGERED: 'destructive',\n EXTINCT_IN_WILD: 'outline',\n DATA_DEFICIENT: 'secondary',\n NOT_EVALUATED: 'secondary',\n\n // Habitat-project lifecycle\n PLANNED: 'secondary',\n MONITORING: 'info',\n COMPLETED: 'success',\n ON_HOLD: 'warning',\n CANCELLED: 'destructive',\n\n // Carbon-entry status\n DRAFT: 'secondary',\n RECORDED: 'info',\n VERIFIED: 'success',\n ADJUSTED: 'warning',\n\n // Report status\n IN_REVIEW: 'warning',\n PUBLISHED: 'success',\n\n // Reduction-target status\n PROPOSED: 'secondary',\n ACHIEVED: 'success',\n MISSED: 'destructive',\n\n // Emission scope\n SCOPE_1: 'destructive',\n SCOPE_2: 'warning',\n SCOPE_3: 'info',\n\n // Report frameworks (neutral badges)\n GHG_PROTOCOL: 'outline',\n GRI: 'outline',\n TCFD: 'outline',\n CDP: 'outline',\n SASB: 'outline',\n CSRD: 'outline',\n ISSB: 'outline',\n EU_TAXONOMY: 'outline',\n CUSTOM: 'secondary',\n};\n\nexport const StatusBadge: FC<StatusBadgeProps> = ({ status, className }) => {\n const key = status.toUpperCase();\n const variant = statusVariantMap[key] ?? 'secondary';\n const isLive = liveStatuses.has(key);\n\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium',\n variantStyles[variant],\n className\n )}\n >\n {isLive && (\n <span\n aria-hidden=\"true\"\n className=\"size-1.5 rounded-full bg-current motion-safe:animate-vc-glow-pulse\"\n />\n )}\n {formatEnumLabel(status)}\n </span>\n );\n};\n"],"mappings":";;;;AAqBA,IAAM,IAA8C;CAClD,SAAS;CACT,SAAS;CACT,aAAa;CACb,WAAW;CACX,MAAM;CACN,SAAS;AACX,GAIM,IAAe,IAAI,IAAI;CAAC;CAAe;CAAU;AAAQ,CAAC,GAE1D,IAAiD;CAErD,QAAQ;CACR,mBAAmB;CACnB,UAAU;CAGV,QAAQ;CACR,SAAS;CACT,UAAU;CACV,aAAa;CACb,SAAS;CAGT,MAAM;CACN,SAAS;CACT,UAAU;CAGV,OAAO;CACP,OAAO;CACP,eAAe;CAGf,QAAQ;CACR,IAAI;CAGJ,eAAe;CACf,iBAAiB;CACjB,YAAY;CACZ,YAAY;CACZ,uBAAuB;CACvB,iBAAiB;CACjB,gBAAgB;CAChB,eAAe;CAGf,SAAS;CACT,YAAY;CACZ,WAAW;CACX,SAAS;CACT,WAAW;CAGX,OAAO;CACP,UAAU;CACV,UAAU;CACV,UAAU;CAGV,WAAW;CACX,WAAW;CAGX,UAAU;CACV,UAAU;CACV,QAAQ;CAGR,SAAS;CACT,SAAS;CACT,SAAS;CAGT,cAAc;CACd,KAAK;CACL,MAAM;CACN,KAAK;CACL,MAAM;CACN,MAAM;CACN,MAAM;CACN,aAAa;CACb,QAAQ;AACV,GAEa,KAAqC,EAAE,WAAQ,mBAAgB;CAC1E,IAAM,IAAM,EAAO,YAAY,GACzB,IAAU,EAAiB,MAAQ,aACnC,IAAS,EAAa,IAAI,CAAG;CAEnC,OACE,kBAAC,QAAD;EACE,WAAW,EACT,mFACA,EAAc,IACd,CACF;YALF,CAOG,KACC,kBAAC,QAAD;GACE,eAAY;GACZ,WAAU;EACX,CAAA,GAEF,EAAgB,CAAM,CACnB;;AAEV"}
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.js","names":[],"sources":["../../../src/ecoimpacthub/components/Tabs.tsx"],"sourcesContent":["/**\n * Tabs — a top-level segmented navigation control for multi-section pages\n * (Monitoring: Sensors/Measurements/Thresholds; Carbon: Ledger/Factors/Targets).\n * @module ecoimpacthub/components\n *\n * Visually heavier than {@link FilterTabs} (underline-style page tabs vs a pill\n * filter). Purely presentational — the parent owns the active-tab state.\n */\n\nimport type { ReactNode } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface TabItem<V extends string> {\n value: V;\n label: string;\n icon?: ReactNode;\n count?: number;\n}\n\ninterface TabsProps<V extends string> {\n items: TabItem<V>[];\n value: V;\n onChange: (value: V) => void;\n className?: string;\n}\n\nexport function Tabs<V extends string>({ items, value, onChange, className }: TabsProps<V>) {\n return (\n <div\n role=\"tablist\"\n className={cn('flex flex-wrap items-center gap-1 border-b border-border-seam', className)}\n >\n {items.map((item) => {\n const active = item.value === value;\n return (\n <button\n key={item.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n onClick={() => onChange(item.value)}\n className={cn(\n 'relative -mb-px inline-flex items-center gap-2 border-b-2 px-4 py-2.5 text-sm font-medium transition-colors',\n active\n ? 'border-accent text-text-primary'\n : 'border-transparent text-text-secondary hover:text-text-primary'\n )}\n >\n {item.icon}\n {item.label}\n {typeof item.count === 'number' && (\n <span\n className={cn(\n 'rounded-full px-1.5 py-0.5 text-xs tabular-nums',\n active\n ? 'bg-[var(--color-accent-soft)] text-text-primary'\n : 'bg-bg-sunken text-text-secondary'\n )}\n >\n {item.count}\n </span>\n )}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;AA0BA,SAAgB,EAAuB,EAAE,UAAO,UAAO,aAAU,gBAA2B;AAC1F,QACE,kBAAC,OAAD;EACE,MAAK;EACL,WAAW,EAAG,iEAAiE,EAAU;YAExF,EAAM,KAAK,MAAS;GACnB,IAAM,IAAS,EAAK,UAAU;AAC9B,UACE,kBAAC,UAAD;IAEE,MAAK;IACL,MAAK;IACL,iBAAe;IACf,eAAe,EAAS,EAAK,MAAM;IACnC,WAAW,EACT,+GACA,IACI,oCACA,iEACL;cAXH;KAaG,EAAK;KACL,EAAK;KACL,OAAO,EAAK,SAAU,YACrB,kBAAC,QAAD;MACE,WAAW,EACT,mDACA,IACI,oDACA,mCACL;gBAEA,EAAK;MACD,CAAA;KAEF;MA1BF,EAAK,MA0BH;IAEX;EACE,CAAA"}
1
+ {"version":3,"file":"Tabs.js","names":[],"sources":["../../../src/ecoimpacthub/components/Tabs.tsx"],"sourcesContent":["/**\n * Tabs — a top-level segmented navigation control for multi-section pages\n * (Monitoring: Sensors/Measurements/Thresholds; Carbon: Ledger/Factors/Targets).\n * @module ecoimpacthub/components\n *\n * Visually heavier than {@link FilterTabs} (underline-style page tabs vs a pill\n * filter). Purely presentational — the parent owns the active-tab state.\n */\n\nimport type { ReactNode } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface TabItem<V extends string> {\n value: V;\n label: string;\n icon?: ReactNode;\n count?: number;\n}\n\ninterface TabsProps<V extends string> {\n items: TabItem<V>[];\n value: V;\n onChange: (value: V) => void;\n className?: string;\n}\n\nexport function Tabs<V extends string>({ items, value, onChange, className }: TabsProps<V>) {\n return (\n <div\n role=\"tablist\"\n className={cn('flex flex-wrap items-center gap-1 border-b border-border-seam', className)}\n >\n {items.map((item) => {\n const active = item.value === value;\n return (\n <button\n key={item.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n onClick={() => onChange(item.value)}\n className={cn(\n 'relative -mb-px inline-flex items-center gap-2 border-b-2 px-4 py-2.5 text-sm font-medium transition-colors',\n active\n ? 'border-accent text-text-primary'\n : 'border-transparent text-text-secondary hover:text-text-primary'\n )}\n >\n {item.icon}\n {item.label}\n {typeof item.count === 'number' && (\n <span\n className={cn(\n 'rounded-full px-1.5 py-0.5 text-xs tabular-nums',\n active\n ? 'bg-[var(--color-accent-soft)] text-text-primary'\n : 'bg-bg-sunken text-text-secondary'\n )}\n >\n {item.count}\n </span>\n )}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;AA0BA,SAAgB,EAAuB,EAAE,UAAO,UAAO,aAAU,gBAA2B;CAC1F,OACE,kBAAC,OAAD;EACE,MAAK;EACL,WAAW,EAAG,iEAAiE,CAAS;YAEvF,EAAM,KAAK,MAAS;GACnB,IAAM,IAAS,EAAK,UAAU;GAC9B,OACE,kBAAC,UAAD;IAEE,MAAK;IACL,MAAK;IACL,iBAAe;IACf,eAAe,EAAS,EAAK,KAAK;IAClC,WAAW,EACT,+GACA,IACI,oCACA,gEACN;cAXF;KAaG,EAAK;KACL,EAAK;KACL,OAAO,EAAK,SAAU,YACrB,kBAAC,QAAD;MACE,WAAW,EACT,mDACA,IACI,oDACA,kCACN;gBAEC,EAAK;KACF,CAAA;IAEF;MA1BD,EAAK,KA0BJ;EAEZ,CAAC;CACE,CAAA;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"EcoImpactHubContext.js","names":[],"sources":["../../../src/ecoimpacthub/context/EcoImpactHubContext.tsx"],"sourcesContent":["/**\n * EcoImpactHub Context Provider\n * @module ecoimpacthub/context\n *\n * Splits standalone mode (wraps its own MemoryRouter + useNavigate) from\n * integrated mode (the host shell supplies `navigate`). Exposes gateway/auth\n * context + relative navigation helpers to every page.\n */\n\nimport type { FC, PropsWithChildren } from 'react';\nimport { createContext, useContext, useMemo, useCallback } from 'react';\nimport { MemoryRouter, useNavigate as useRouterNavigate } from 'react-router-dom';\nimport type { EcoImpactHubRootProps } from '../types';\nimport { joinPath } from '../utils/navigation';\n\ninterface EcoImpactHubContextValue extends Omit<\n EcoImpactHubRootProps,\n 'registerNavItems' | 'registerFooterItems' | 'navigate'\n> {\n isStandalone: boolean;\n /** Shell's navigate function (only available in integrated mode). */\n navigate?: (path: string) => void;\n /** Navigate to a path relative to basePath. */\n navigateTo: (relativePath: string) => void;\n /** Get the full path for a relative path. */\n getPath: (relativePath: string) => string;\n}\n\nconst EcoImpactHubContext = createContext<EcoImpactHubContextValue | null>(null);\n\nexport function useEcoImpactHub(): EcoImpactHubContextValue {\n const context = useContext(EcoImpactHubContext);\n if (!context) {\n throw new Error('useEcoImpactHub must be used within an EcoImpactHubProvider');\n }\n return context;\n}\n\ntype ProviderProps = Omit<EcoImpactHubRootProps, 'registerNavItems' | 'registerFooterItems'> & {\n isStandalone: boolean;\n};\n\nconst StandaloneProviderInner: FC<PropsWithChildren<ProviderProps>> = ({\n children,\n basePath,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n}) => {\n const routerNavigate = useRouterNavigate();\n const effectiveBasePath = basePath || '/';\n\n const getPath = useCallback(\n (relativePath: string) => joinPath(effectiveBasePath, relativePath),\n [effectiveBasePath]\n );\n\n const navigateTo = useCallback(\n (relativePath: string) => {\n routerNavigate(joinPath(effectiveBasePath, relativePath));\n },\n [effectiveBasePath, routerNavigate]\n );\n\n const contextValue = useMemo<EcoImpactHubContextValue>(\n () => ({\n basePath: effectiveBasePath,\n navigate: undefined,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n isStandalone: true,\n navigateTo,\n getPath,\n }),\n [\n effectiveBasePath,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n navigateTo,\n getPath,\n ]\n );\n\n return (\n <EcoImpactHubContext.Provider value={contextValue}>{children}</EcoImpactHubContext.Provider>\n );\n};\n\nconst IntegratedProviderInner: FC<\n PropsWithChildren<ProviderProps & { navigate: (path: string) => void }>\n> = ({\n children,\n basePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n}) => {\n const effectiveBasePath = basePath || '/';\n\n const getPath = useCallback(\n (relativePath: string) => joinPath(effectiveBasePath, relativePath),\n [effectiveBasePath]\n );\n\n const navigateTo = useCallback(\n (relativePath: string) => {\n navigate(joinPath(effectiveBasePath, relativePath));\n },\n [effectiveBasePath, navigate]\n );\n\n const contextValue = useMemo<EcoImpactHubContextValue>(\n () => ({\n basePath: effectiveBasePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n isStandalone: false,\n navigateTo,\n getPath,\n }),\n [\n effectiveBasePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n navigateTo,\n getPath,\n ]\n );\n\n return (\n <EcoImpactHubContext.Provider value={contextValue}>{children}</EcoImpactHubContext.Provider>\n );\n};\n\nexport const EcoImpactHubProvider: FC<PropsWithChildren<EcoImpactHubRootProps>> = (props) => {\n const { children, navigate } = props;\n const isStandalone = !navigate;\n\n if (isStandalone) {\n return (\n <MemoryRouter>\n <StandaloneProviderInner {...props} isStandalone={true}>\n {children}\n </StandaloneProviderInner>\n </MemoryRouter>\n );\n }\n\n return (\n <IntegratedProviderInner {...props} navigate={navigate} isStandalone={false}>\n {children}\n </IntegratedProviderInner>\n );\n};\n"],"mappings":";;;;;AA4BA,IAAM,IAAsB,EAA+C,KAAK;AAEhF,SAAgB,IAA4C;CAC1D,IAAM,IAAU,EAAW,EAAoB;AAC/C,KAAI,CAAC,EACH,OAAU,MAAM,8DAA8D;AAEhF,QAAO;;AAOT,IAAM,KAAiE,EACrE,aACA,aACA,gBACA,aACA,gBACA,kBACA,mBACI;CACJ,IAAM,IAAiB,GAAmB,EACpC,IAAoB,KAAY,KAEhC,IAAU,GACb,MAAyB,EAAS,GAAmB,EAAa,EACnE,CAAC,EAAkB,CACpB,EAEK,IAAa,GAChB,MAAyB;AACxB,IAAe,EAAS,GAAmB,EAAa,CAAC;IAE3D,CAAC,GAAmB,EAAe,CACpC,EAEK,IAAe,SACZ;EACL,UAAU;EACV,UAAU,KAAA;EACV;EACA;EACA;EACA;EACA;EACA,cAAc;EACd;EACA;EACD,GACD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF;AAED,QACE,kBAAC,EAAoB,UAArB;EAA8B,OAAO;EAAe;EAAwC,CAAA;GAI1F,KAED,EACH,aACA,aACA,aACA,gBACA,aACA,gBACA,kBACA,mBACI;CACJ,IAAM,IAAoB,KAAY,KAEhC,IAAU,GACb,MAAyB,EAAS,GAAmB,EAAa,EACnE,CAAC,EAAkB,CACpB,EAEK,IAAa,GAChB,MAAyB;AACxB,IAAS,EAAS,GAAmB,EAAa,CAAC;IAErD,CAAC,GAAmB,EAAS,CAC9B,EAEK,IAAe,SACZ;EACL,UAAU;EACV;EACA;EACA;EACA;EACA;EACA;EACA,cAAc;EACd;EACA;EACD,GACD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF;AAED,QACE,kBAAC,EAAoB,UAArB;EAA8B,OAAO;EAAe;EAAwC,CAAA;GAInF,KAAsE,MAAU;CAC3F,IAAM,EAAE,aAAU,gBAAa;AAa/B,QAZsB,IAapB,kBAAC,GAAD;EAAyB,GAAI;EAAiB;EAAU,cAAc;EACnE;EACuB,CAAA,GAXxB,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EAAyB,GAAI;EAAO,cAAc;EAC/C;EACuB,CAAA,EACb,CAAA"}
1
+ {"version":3,"file":"EcoImpactHubContext.js","names":[],"sources":["../../../src/ecoimpacthub/context/EcoImpactHubContext.tsx"],"sourcesContent":["/**\n * EcoImpactHub Context Provider\n * @module ecoimpacthub/context\n *\n * Splits standalone mode (wraps its own MemoryRouter + useNavigate) from\n * integrated mode (the host shell supplies `navigate`). Exposes gateway/auth\n * context + relative navigation helpers to every page.\n */\n\nimport type { FC, PropsWithChildren } from 'react';\nimport { createContext, useContext, useMemo, useCallback } from 'react';\nimport { MemoryRouter, useNavigate as useRouterNavigate } from 'react-router-dom';\nimport type { EcoImpactHubRootProps } from '../types';\nimport { joinPath } from '../utils/navigation';\n\ninterface EcoImpactHubContextValue extends Omit<\n EcoImpactHubRootProps,\n 'registerNavItems' | 'registerFooterItems' | 'navigate'\n> {\n isStandalone: boolean;\n /** Shell's navigate function (only available in integrated mode). */\n navigate?: (path: string) => void;\n /** Navigate to a path relative to basePath. */\n navigateTo: (relativePath: string) => void;\n /** Get the full path for a relative path. */\n getPath: (relativePath: string) => string;\n}\n\nconst EcoImpactHubContext = createContext<EcoImpactHubContextValue | null>(null);\n\nexport function useEcoImpactHub(): EcoImpactHubContextValue {\n const context = useContext(EcoImpactHubContext);\n if (!context) {\n throw new Error('useEcoImpactHub must be used within an EcoImpactHubProvider');\n }\n return context;\n}\n\ntype ProviderProps = Omit<EcoImpactHubRootProps, 'registerNavItems' | 'registerFooterItems'> & {\n isStandalone: boolean;\n};\n\nconst StandaloneProviderInner: FC<PropsWithChildren<ProviderProps>> = ({\n children,\n basePath,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n}) => {\n const routerNavigate = useRouterNavigate();\n const effectiveBasePath = basePath || '/';\n\n const getPath = useCallback(\n (relativePath: string) => joinPath(effectiveBasePath, relativePath),\n [effectiveBasePath]\n );\n\n const navigateTo = useCallback(\n (relativePath: string) => {\n routerNavigate(joinPath(effectiveBasePath, relativePath));\n },\n [effectiveBasePath, routerNavigate]\n );\n\n const contextValue = useMemo<EcoImpactHubContextValue>(\n () => ({\n basePath: effectiveBasePath,\n navigate: undefined,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n isStandalone: true,\n navigateTo,\n getPath,\n }),\n [\n effectiveBasePath,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n navigateTo,\n getPath,\n ]\n );\n\n return (\n <EcoImpactHubContext.Provider value={contextValue}>{children}</EcoImpactHubContext.Provider>\n );\n};\n\nconst IntegratedProviderInner: FC<\n PropsWithChildren<ProviderProps & { navigate: (path: string) => void }>\n> = ({\n children,\n basePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n}) => {\n const effectiveBasePath = basePath || '/';\n\n const getPath = useCallback(\n (relativePath: string) => joinPath(effectiveBasePath, relativePath),\n [effectiveBasePath]\n );\n\n const navigateTo = useCallback(\n (relativePath: string) => {\n navigate(joinPath(effectiveBasePath, relativePath));\n },\n [effectiveBasePath, navigate]\n );\n\n const contextValue = useMemo<EcoImpactHubContextValue>(\n () => ({\n basePath: effectiveBasePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n isStandalone: false,\n navigateTo,\n getPath,\n }),\n [\n effectiveBasePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n navigateTo,\n getPath,\n ]\n );\n\n return (\n <EcoImpactHubContext.Provider value={contextValue}>{children}</EcoImpactHubContext.Provider>\n );\n};\n\nexport const EcoImpactHubProvider: FC<PropsWithChildren<EcoImpactHubRootProps>> = (props) => {\n const { children, navigate } = props;\n const isStandalone = !navigate;\n\n if (isStandalone) {\n return (\n <MemoryRouter>\n <StandaloneProviderInner {...props} isStandalone={true}>\n {children}\n </StandaloneProviderInner>\n </MemoryRouter>\n );\n }\n\n return (\n <IntegratedProviderInner {...props} navigate={navigate} isStandalone={false}>\n {children}\n </IntegratedProviderInner>\n );\n};\n"],"mappings":";;;;;AA4BA,IAAM,IAAsB,EAA+C,IAAI;AAE/E,SAAgB,IAA4C;CAC1D,IAAM,IAAU,EAAW,CAAmB;CAC9C,IAAI,CAAC,GACH,MAAU,MAAM,6DAA6D;CAE/E,OAAO;AACT;AAMA,IAAM,KAAiE,EACrE,aACA,aACA,gBACA,aACA,gBACA,kBACA,mBACI;CACJ,IAAM,IAAiB,EAAkB,GACnC,IAAoB,KAAY,KAEhC,IAAU,GACb,MAAyB,EAAS,GAAmB,CAAY,GAClE,CAAC,CAAiB,CACpB,GAEM,IAAa,GAChB,MAAyB;EACxB,EAAe,EAAS,GAAmB,CAAY,CAAC;CAC1D,GACA,CAAC,GAAmB,CAAc,CACpC,GAEM,IAAe,SACZ;EACL,UAAU;EACV,UAAU,KAAA;EACV;EACA;EACA;EACA;EACA;EACA,cAAc;EACd;EACA;CACF,IACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF;CAEA,OACE,kBAAC,EAAoB,UAArB;EAA8B,OAAO;EAAe;CAAuC,CAAA;AAE/F,GAEM,KAED,EACH,aACA,aACA,aACA,gBACA,aACA,gBACA,kBACA,mBACI;CACJ,IAAM,IAAoB,KAAY,KAEhC,IAAU,GACb,MAAyB,EAAS,GAAmB,CAAY,GAClE,CAAC,CAAiB,CACpB,GAEM,IAAa,GAChB,MAAyB;EACxB,EAAS,EAAS,GAAmB,CAAY,CAAC;CACpD,GACA,CAAC,GAAmB,CAAQ,CAC9B,GAEM,IAAe,SACZ;EACL,UAAU;EACV;EACA;EACA;EACA;EACA;EACA;EACA,cAAc;EACd;EACA;CACF,IACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF;CAEA,OACE,kBAAC,EAAoB,UAArB;EAA8B,OAAO;EAAe;CAAuC,CAAA;AAE/F,GAEa,KAAsE,MAAU;CAC3F,IAAM,EAAE,aAAU,gBAAa;CAa/B,OAZsB,IAapB,kBAAC,GAAD;EAAyB,GAAI;EAAiB;EAAU,cAAc;EACnE;CACsB,CAAA,IAXvB,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EAAyB,GAAI;EAAO,cAAc;EAC/C;CACsB,CAAA,EACb,CAAA;AASpB"}
@@ -7,4 +7,5 @@ export * from './useCursorPager';
7
7
  export * from './useEcoFiles';
8
8
  export * from './useEcoComments';
9
9
  export * from './useEcoTags';
10
+ export * from './useDashboardLayout';
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ecoimpacthub/hooks/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ecoimpacthub/hooks/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC"}
@@ -1,3 +1,4 @@
1
+ import "./useDashboardLayout.js";
1
2
  import "./useEcoImpactHubApi.js";
2
3
  import "./useCursorPager.js";
3
4
  import "./useEcoFiles.js";
@@ -1 +1 @@
1
- {"version":3,"file":"useCursorPager.js","names":[],"sources":["../../../src/ecoimpacthub/hooks/useCursorPager.ts"],"sourcesContent":["/**\n * useCursorPager — forward/back cursor pagination for Eco* list connections.\n * @module ecoimpacthub/hooks\n *\n * The svc paginates by cursor only (`PaginationInput.offset` is a no-op — the\n * resolver never sets Prisma `skip` from it). So a page must send\n * `pagination.cursor = the previous page's pageInfo.cursor` to advance. This\n * hook keeps a stack of the cursors that opened each visited page so Prev/Next\n * are exact, and exposes a 0-indexed `page` for display.\n */\n\nimport { useCallback, useState } from 'react';\n\nexport interface CursorPager {\n /** 0-indexed page number for display. */\n page: number;\n /**\n * Cursor that opens the current page — `undefined` on the first page so it is\n * OMITTED from the GraphQL variables (the svc rejects an explicit `cursor: null`;\n * a first page must send no cursor at all, per cursor-pagination convention).\n */\n cursor: string | undefined;\n /** Advance to the next page using the current page's end cursor. No-op if null. */\n next: (endCursor: string | null | undefined) => void;\n /** Go back one page. No-op on the first page. */\n prev: () => void;\n /** Reset to the first page (call when filters change). */\n reset: () => void;\n /**\n * Adapter for `<Pagination onPageChange>` — compares the requested page to the\n * current one and calls next()/prev() accordingly.\n */\n onPageChange: (targetPage: number, endCursor: string | null | undefined) => void;\n}\n\nexport function useCursorPager(): CursorPager {\n const [stack, setStack] = useState<(string | null)[]>([null]);\n const page = stack.length - 1;\n const cursor = stack[page] ?? undefined;\n\n const next = useCallback((endCursor: string | null | undefined) => {\n if (endCursor) setStack((s) => [...s, endCursor]);\n }, []);\n\n const prev = useCallback(() => {\n setStack((s) => (s.length > 1 ? s.slice(0, -1) : s));\n }, []);\n\n const reset = useCallback(() => {\n setStack([null]);\n }, []);\n\n const onPageChange = useCallback((targetPage: number, endCursor: string | null | undefined) => {\n setStack((s) => {\n const current = s.length - 1;\n if (targetPage > current) {\n return endCursor ? [...s, endCursor] : s;\n }\n return s.length > 1 ? s.slice(0, -1) : s;\n });\n }, []);\n\n return { page, cursor, next, prev, reset, onPageChange };\n}\n"],"mappings":";;AAmCA,SAAgB,IAA8B;CAC5C,IAAM,CAAC,GAAO,KAAY,EAA4B,CAAC,KAAK,CAAC,EACvD,IAAO,EAAM,SAAS;AAyB5B,QAAO;EAAE;EAAM,QAxBA,EAAM,MAAS,KAAA;EAwBP,MAtBV,GAAa,MAAyC;AACjE,GAAI,KAAW,GAAU,MAAM,CAAC,GAAG,GAAG,EAAU,CAAC;KAChD,EAAE,CAAC;EAoBuB,MAlBhB,QAAkB;AAC7B,MAAU,MAAO,EAAE,SAAS,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,EAAG;KACnD,EAAE,CAAC;EAgB6B,OAdrB,QAAkB;AAC9B,KAAS,CAAC,KAAK,CAAC;KACf,EAAE,CAAC;EAYoC,cAVrB,GAAa,GAAoB,MAAyC;AAC7F,MAAU,MAEJ,IADY,EAAE,SAAS,IAElB,IAAY,CAAC,GAAG,GAAG,EAAU,GAAG,IAElC,EAAE,SAAS,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,EACvC;KACD,EAAE,CAAC;EAEkD"}
1
+ {"version":3,"file":"useCursorPager.js","names":[],"sources":["../../../src/ecoimpacthub/hooks/useCursorPager.ts"],"sourcesContent":["/**\n * useCursorPager — forward/back cursor pagination for Eco* list connections.\n * @module ecoimpacthub/hooks\n *\n * The svc paginates by cursor only (`PaginationInput.offset` is a no-op — the\n * resolver never sets Prisma `skip` from it). So a page must send\n * `pagination.cursor = the previous page's pageInfo.cursor` to advance. This\n * hook keeps a stack of the cursors that opened each visited page so Prev/Next\n * are exact, and exposes a 0-indexed `page` for display.\n */\n\nimport { useCallback, useState } from 'react';\n\nexport interface CursorPager {\n /** 0-indexed page number for display. */\n page: number;\n /**\n * Cursor that opens the current page — `undefined` on the first page so it is\n * OMITTED from the GraphQL variables (the svc rejects an explicit `cursor: null`;\n * a first page must send no cursor at all, per cursor-pagination convention).\n */\n cursor: string | undefined;\n /** Advance to the next page using the current page's end cursor. No-op if null. */\n next: (endCursor: string | null | undefined) => void;\n /** Go back one page. No-op on the first page. */\n prev: () => void;\n /** Reset to the first page (call when filters change). */\n reset: () => void;\n /**\n * Adapter for `<Pagination onPageChange>` — compares the requested page to the\n * current one and calls next()/prev() accordingly.\n */\n onPageChange: (targetPage: number, endCursor: string | null | undefined) => void;\n}\n\nexport function useCursorPager(): CursorPager {\n const [stack, setStack] = useState<(string | null)[]>([null]);\n const page = stack.length - 1;\n const cursor = stack[page] ?? undefined;\n\n const next = useCallback((endCursor: string | null | undefined) => {\n if (endCursor) setStack((s) => [...s, endCursor]);\n }, []);\n\n const prev = useCallback(() => {\n setStack((s) => (s.length > 1 ? s.slice(0, -1) : s));\n }, []);\n\n const reset = useCallback(() => {\n setStack([null]);\n }, []);\n\n const onPageChange = useCallback((targetPage: number, endCursor: string | null | undefined) => {\n setStack((s) => {\n const current = s.length - 1;\n if (targetPage > current) {\n return endCursor ? [...s, endCursor] : s;\n }\n return s.length > 1 ? s.slice(0, -1) : s;\n });\n }, []);\n\n return { page, cursor, next, prev, reset, onPageChange };\n}\n"],"mappings":";;AAmCA,SAAgB,IAA8B;CAC5C,IAAM,CAAC,GAAO,KAAY,EAA4B,CAAC,IAAI,CAAC,GACtD,IAAO,EAAM,SAAS;CAyB5B,OAAO;EAAE;EAAM,QAxBA,EAAM,MAAS,KAAA;EAwBP,MAtBV,GAAa,MAAyC;GACjE,AAAI,KAAW,GAAU,MAAM,CAAC,GAAG,GAAG,CAAS,CAAC;EAClD,GAAG,CAAC,CAoBmB;EAAM,MAlBhB,QAAkB;GAC7B,GAAU,MAAO,EAAE,SAAS,IAAI,EAAE,MAAM,GAAG,EAAE,IAAI,CAAE;EACrD,GAAG,CAAC,CAgByB;EAAM,OAdrB,QAAkB;GAC9B,EAAS,CAAC,IAAI,CAAC;EACjB,GAAG,CAAC,CAY+B;EAAO,cAVrB,GAAa,GAAoB,MAAyC;GAC7F,GAAU,MAEJ,IADY,EAAE,SAAS,IAElB,IAAY,CAAC,GAAG,GAAG,CAAS,IAAI,IAElC,EAAE,SAAS,IAAI,EAAE,MAAM,GAAG,EAAE,IAAI,CACxC;EACH,GAAG,CAAC,CAEsC;CAAa;AACzD"}
@@ -0,0 +1,29 @@
1
+ /** Every built-in dashboard widget a user can show/hide/reorder. */
2
+ export type DashboardWidgetId = 'kpis' | 'carbonByScope' | 'recentBreaches' | 'recentObservations' | 'conservationStatus';
3
+ export declare const DASHBOARD_WIDGET_DEFS: ReadonlyArray<{
4
+ id: DashboardWidgetId;
5
+ label: string;
6
+ description: string;
7
+ }>;
8
+ /** A user-authored freeform note widget — the one net-new widget type. */
9
+ export interface DashboardNote {
10
+ id: string;
11
+ title: string;
12
+ body: string;
13
+ }
14
+ export interface DashboardLayout {
15
+ /** Built-in widget ids, in display order. Hidden widgets are simply absent. */
16
+ widgetOrder: DashboardWidgetId[];
17
+ notes: DashboardNote[];
18
+ }
19
+ export interface UseDashboardLayoutResult {
20
+ layout: DashboardLayout;
21
+ isWidgetVisible: (id: DashboardWidgetId) => boolean;
22
+ toggleWidget: (id: DashboardWidgetId) => void;
23
+ moveWidget: (id: DashboardWidgetId, direction: 'up' | 'down') => void;
24
+ addNote: (title: string, body: string) => void;
25
+ removeNote: (id: string) => void;
26
+ resetToDefault: () => void;
27
+ }
28
+ export declare function useDashboardLayout(workspaceId: string | undefined, userId: string | undefined): UseDashboardLayoutResult;
29
+ //# sourceMappingURL=useDashboardLayout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDashboardLayout.d.ts","sourceRoot":"","sources":["../../../src/ecoimpacthub/hooks/useDashboardLayout.ts"],"names":[],"mappings":"AAmBA,oEAAoE;AACpE,MAAM,MAAM,iBAAiB,GAC3B,MAAM,GAAG,eAAe,GAAG,gBAAgB,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAE5F,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC;IAChD,EAAE,EAAE,iBAAiB,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB,CA0BA,CAAC;AAEF,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAWD,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,eAAe,CAAC;IACxB,eAAe,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,OAAO,CAAC;IACpD,YAAY,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC9C,UAAU,EAAE,CAAC,EAAE,EAAE,iBAAiB,EAAE,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;IACtE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,wBAAwB,CAiF1B"}
@@ -0,0 +1,95 @@
1
+ import { useCallback as e, useMemo as t } from "react";
2
+ import { useLocalStorage as n } from "@burdenoff/fe-libs/shared/hooks";
3
+ //#region src/ecoimpacthub/hooks/useDashboardLayout.ts
4
+ var r = [
5
+ {
6
+ id: "kpis",
7
+ label: "KPI summary",
8
+ description: "Sites, species, projects, footprint, sensors, breaches."
9
+ },
10
+ {
11
+ id: "carbonByScope",
12
+ label: "Carbon footprint by scope",
13
+ description: "Scope 1 / 2 / 3 emissions chart."
14
+ },
15
+ {
16
+ id: "recentBreaches",
17
+ label: "Recent breaches",
18
+ description: "Latest threshold-breach measurements."
19
+ },
20
+ {
21
+ id: "recentObservations",
22
+ label: "Recent field observations",
23
+ description: "Latest species sightings."
24
+ },
25
+ {
26
+ id: "conservationStatus",
27
+ label: "Conservation status",
28
+ description: "Tracked species by IUCN-style status."
29
+ }
30
+ ], i = {
31
+ widgetOrder: r.map((e) => e.id),
32
+ notes: []
33
+ };
34
+ function a(e, t) {
35
+ return `eih.dashboard.layout.v1.${e ?? "no-workspace"}.${t ?? "no-user"}`;
36
+ }
37
+ function o(r, o) {
38
+ let [s, c, l] = n(a(r, o), i), u = e((e) => s.widgetOrder.includes(e), [s.widgetOrder]), d = e((e) => {
39
+ c((t) => {
40
+ let n = t.widgetOrder.includes(e);
41
+ return {
42
+ ...t,
43
+ widgetOrder: n ? t.widgetOrder.filter((t) => t !== e) : [...t.widgetOrder, e]
44
+ };
45
+ });
46
+ }, [c]), f = e((e, t) => {
47
+ c((n) => {
48
+ let r = n.widgetOrder.indexOf(e);
49
+ if (r === -1) return n;
50
+ let i = t === "up" ? r - 1 : r + 1;
51
+ if (i < 0 || i >= n.widgetOrder.length) return n;
52
+ let a = [...n.widgetOrder], [o] = a.splice(r, 1);
53
+ return a.splice(i, 0, o), {
54
+ ...n,
55
+ widgetOrder: a
56
+ };
57
+ });
58
+ }, [c]), p = e((e, t) => {
59
+ let n = e.trim(), r = t.trim();
60
+ !n && !r || c((e) => ({
61
+ ...e,
62
+ notes: [...e.notes, {
63
+ id: `note-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
64
+ title: n,
65
+ body: r
66
+ }]
67
+ }));
68
+ }, [c]), m = e((e) => {
69
+ c((t) => ({
70
+ ...t,
71
+ notes: t.notes.filter((t) => t.id !== e)
72
+ }));
73
+ }, [c]);
74
+ return t(() => ({
75
+ layout: s,
76
+ isWidgetVisible: u,
77
+ toggleWidget: d,
78
+ moveWidget: f,
79
+ addNote: p,
80
+ removeNote: m,
81
+ resetToDefault: l
82
+ }), [
83
+ s,
84
+ u,
85
+ d,
86
+ f,
87
+ p,
88
+ m,
89
+ l
90
+ ]);
91
+ }
92
+ //#endregion
93
+ export { r as DASHBOARD_WIDGET_DEFS, o as useDashboardLayout };
94
+
95
+ //# sourceMappingURL=useDashboardLayout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDashboardLayout.js","names":[],"sources":["../../../src/ecoimpacthub/hooks/useDashboardLayout.ts"],"sourcesContent":["/**\n * Dashboard layout customization (BOFF-3943).\n * @module ecoimpacthub/hooks\n *\n * Before this hook the dashboard was a fixed six-widget read-only layout with\n * no \"Create dashboard\" CTA, no widget palette, and no add/remove/reorder\n * state — the mock (01-dashboard.jpg) shows a customizable dashboard the\n * product never built.\n *\n * Persistence: no platform-wide dashboard-preference store exists yet (only\n * per-product Prisma models would), so this is a per-user, per-workspace\n * client preference stored via `useLocalStorage` — the same mechanism\n * `@burdenoff/fe-libs/shared` already ships for this class of UI state.\n * Uncustomized users see the exact same six widgets, in the same order, as\n * before this change (the stored layout is additive, not a migration).\n */\nimport { useCallback, useMemo } from 'react';\nimport { useLocalStorage } from '@burdenoff/fe-libs/shared/hooks';\n\n/** Every built-in dashboard widget a user can show/hide/reorder. */\nexport type DashboardWidgetId =\n 'kpis' | 'carbonByScope' | 'recentBreaches' | 'recentObservations' | 'conservationStatus';\n\nexport const DASHBOARD_WIDGET_DEFS: ReadonlyArray<{\n id: DashboardWidgetId;\n label: string;\n description: string;\n}> = [\n {\n id: 'kpis',\n label: 'KPI summary',\n description: 'Sites, species, projects, footprint, sensors, breaches.',\n },\n {\n id: 'carbonByScope',\n label: 'Carbon footprint by scope',\n description: 'Scope 1 / 2 / 3 emissions chart.',\n },\n {\n id: 'recentBreaches',\n label: 'Recent breaches',\n description: 'Latest threshold-breach measurements.',\n },\n {\n id: 'recentObservations',\n label: 'Recent field observations',\n description: 'Latest species sightings.',\n },\n {\n id: 'conservationStatus',\n label: 'Conservation status',\n description: 'Tracked species by IUCN-style status.',\n },\n];\n\n/** A user-authored freeform note widget — the one net-new widget type. */\nexport interface DashboardNote {\n id: string;\n title: string;\n body: string;\n}\n\nexport interface DashboardLayout {\n /** Built-in widget ids, in display order. Hidden widgets are simply absent. */\n widgetOrder: DashboardWidgetId[];\n notes: DashboardNote[];\n}\n\nconst DEFAULT_LAYOUT: DashboardLayout = {\n widgetOrder: DASHBOARD_WIDGET_DEFS.map((w) => w.id),\n notes: [],\n};\n\nfunction layoutStorageKey(workspaceId: string | undefined, userId: string | undefined): string {\n return `eih.dashboard.layout.v1.${workspaceId ?? 'no-workspace'}.${userId ?? 'no-user'}`;\n}\n\nexport interface UseDashboardLayoutResult {\n layout: DashboardLayout;\n isWidgetVisible: (id: DashboardWidgetId) => boolean;\n toggleWidget: (id: DashboardWidgetId) => void;\n moveWidget: (id: DashboardWidgetId, direction: 'up' | 'down') => void;\n addNote: (title: string, body: string) => void;\n removeNote: (id: string) => void;\n resetToDefault: () => void;\n}\n\nexport function useDashboardLayout(\n workspaceId: string | undefined,\n userId: string | undefined\n): UseDashboardLayoutResult {\n const [layout, setLayout, resetToDefault] = useLocalStorage<DashboardLayout>(\n layoutStorageKey(workspaceId, userId),\n DEFAULT_LAYOUT\n );\n\n const isWidgetVisible = useCallback(\n (id: DashboardWidgetId) => layout.widgetOrder.includes(id),\n [layout.widgetOrder]\n );\n\n const toggleWidget = useCallback(\n (id: DashboardWidgetId) => {\n setLayout((prev) => {\n const isVisible = prev.widgetOrder.includes(id);\n return {\n ...prev,\n widgetOrder: isVisible\n ? prev.widgetOrder.filter((w) => w !== id)\n : [...prev.widgetOrder, id],\n };\n });\n },\n [setLayout]\n );\n\n const moveWidget = useCallback(\n (id: DashboardWidgetId, direction: 'up' | 'down') => {\n setLayout((prev) => {\n const index = prev.widgetOrder.indexOf(id);\n if (index === -1) return prev;\n const targetIndex = direction === 'up' ? index - 1 : index + 1;\n if (targetIndex < 0 || targetIndex >= prev.widgetOrder.length) return prev;\n const next = [...prev.widgetOrder];\n const [moved] = next.splice(index, 1);\n next.splice(targetIndex, 0, moved);\n return { ...prev, widgetOrder: next };\n });\n },\n [setLayout]\n );\n\n const addNote = useCallback(\n (title: string, body: string) => {\n const trimmedTitle = title.trim();\n const trimmedBody = body.trim();\n if (!trimmedTitle && !trimmedBody) return;\n setLayout((prev) => ({\n ...prev,\n notes: [\n ...prev.notes,\n {\n id: `note-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n title: trimmedTitle,\n body: trimmedBody,\n },\n ],\n }));\n },\n [setLayout]\n );\n\n const removeNote = useCallback(\n (id: string) => {\n setLayout((prev) => ({ ...prev, notes: prev.notes.filter((n) => n.id !== id) }));\n },\n [setLayout]\n );\n\n return useMemo(\n () => ({\n layout,\n isWidgetVisible,\n toggleWidget,\n moveWidget,\n addNote,\n removeNote,\n resetToDefault,\n }),\n [layout, isWidgetVisible, toggleWidget, moveWidget, addNote, removeNote, resetToDefault]\n );\n}\n"],"mappings":";;;AAuBA,IAAa,IAIR;CACH;EACE,IAAI;EACJ,OAAO;EACP,aAAa;CACf;CACA;EACE,IAAI;EACJ,OAAO;EACP,aAAa;CACf;CACA;EACE,IAAI;EACJ,OAAO;EACP,aAAa;CACf;CACA;EACE,IAAI;EACJ,OAAO;EACP,aAAa;CACf;CACA;EACE,IAAI;EACJ,OAAO;EACP,aAAa;CACf;AACF,GAeM,IAAkC;CACtC,aAAa,EAAsB,KAAK,MAAM,EAAE,EAAE;CAClD,OAAO,CAAC;AACV;AAEA,SAAS,EAAiB,GAAiC,GAAoC;CAC7F,OAAO,2BAA2B,KAAe,eAAe,GAAG,KAAU;AAC/E;AAYA,SAAgB,EACd,GACA,GAC0B;CAC1B,IAAM,CAAC,GAAQ,GAAW,KAAkB,EAC1C,EAAiB,GAAa,CAAM,GACpC,CACF,GAEM,IAAkB,GACrB,MAA0B,EAAO,YAAY,SAAS,CAAE,GACzD,CAAC,EAAO,WAAW,CACrB,GAEM,IAAe,GAClB,MAA0B;EACzB,GAAW,MAAS;GAClB,IAAM,IAAY,EAAK,YAAY,SAAS,CAAE;GAC9C,OAAO;IACL,GAAG;IACH,aAAa,IACT,EAAK,YAAY,QAAQ,MAAM,MAAM,CAAE,IACvC,CAAC,GAAG,EAAK,aAAa,CAAE;GAC9B;EACF,CAAC;CACH,GACA,CAAC,CAAS,CACZ,GAEM,IAAa,GAChB,GAAuB,MAA6B;EACnD,GAAW,MAAS;GAClB,IAAM,IAAQ,EAAK,YAAY,QAAQ,CAAE;GACzC,IAAI,MAAU,IAAI,OAAO;GACzB,IAAM,IAAc,MAAc,OAAO,IAAQ,IAAI,IAAQ;GAC7D,IAAI,IAAc,KAAK,KAAe,EAAK,YAAY,QAAQ,OAAO;GACtE,IAAM,IAAO,CAAC,GAAG,EAAK,WAAW,GAC3B,CAAC,KAAS,EAAK,OAAO,GAAO,CAAC;GAEpC,OADA,EAAK,OAAO,GAAa,GAAG,CAAK,GAC1B;IAAE,GAAG;IAAM,aAAa;GAAK;EACtC,CAAC;CACH,GACA,CAAC,CAAS,CACZ,GAEM,IAAU,GACb,GAAe,MAAiB;EAC/B,IAAM,IAAe,EAAM,KAAK,GAC1B,IAAc,EAAK,KAAK;EAC1B,CAAC,KAAgB,CAAC,KACtB,GAAW,OAAU;GACnB,GAAG;GACH,OAAO,CACL,GAAG,EAAK,OACR;IACE,IAAI,QAAQ,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC;IAC/D,OAAO;IACP,MAAM;GACR,CACF;EACF,EAAE;CACJ,GACA,CAAC,CAAS,CACZ,GAEM,IAAa,GAChB,MAAe;EACd,GAAW,OAAU;GAAE,GAAG;GAAM,OAAO,EAAK,MAAM,QAAQ,MAAM,EAAE,OAAO,CAAE;EAAE,EAAE;CACjF,GACA,CAAC,CAAS,CACZ;CAEA,OAAO,SACE;EACL;EACA;EACA;EACA;EACA;EACA;EACA;CACF,IACA;EAAC;EAAQ;EAAiB;EAAc;EAAY;EAAS;EAAY;CAAc,CACzF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"useEcoComments.js","names":[],"sources":["../../../src/ecoimpacthub/hooks/useEcoComments.ts"],"sourcesContent":["/**\n * EcoImpactHub — wspace-conversations-svc EntityComment REUSE hooks (Integration B).\n * @module ecoimpacthub/hooks/useEcoComments\n *\n * Adds a discussion surface to eco entities WITHOUT any eco-svc change by\n * reusing the generic EntityComment API composed into the WORKSPACE supergraph.\n * Comments attach to any entity by `(entityType, entityId)`:\n * - `getEntityComments(input): EntityCommentConnection!`\n * - `createEntityComment(input): EntityComment!`\n *\n * Transport reuses `wspaceFetch` from `useEcoFiles` (workspace gateway +\n * workspace token). Lives in a separate file; `useEcoImpactHubApi.ts` is\n * untouched.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\n\nimport { useEcoImpactHub } from '../context';\nimport { wspaceFetch } from './useEcoFiles';\n\nexport interface EcoComment {\n id: string;\n authorId: string;\n authorType: string;\n content: {\n text: string | null;\n markdown: string | null;\n };\n createdAt: string;\n edited: boolean;\n parentCommentId: string | null;\n replyCount: number;\n}\n\nconst commentsKey = (entityType: string, entityId: string) =>\n ['ecoimpacthub', 'comments', entityType, entityId] as const;\n\n/** Top-level (root) comments for an eco entity, oldest first. */\nexport const useEcoComments = (entityType: string, entityId: string | undefined) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: commentsKey(entityType, entityId ?? ''),\n enabled: Boolean(entityId),\n queryFn: async () => {\n const data = await wspaceFetch<{\n getEntityComments: { items: EcoComment[]; total: number };\n }>(\n `query EcoGetEntityComments($input: GetCommentsInput!) {\n getEntityComments(input: $input) {\n total\n items {\n id\n authorId\n authorType\n content { text markdown }\n createdAt\n edited\n parentCommentId\n replyCount\n }\n }\n }`,\n {\n input: {\n entityType,\n entityId,\n take: 100,\n parentCommentId: null,\n },\n },\n apiGatewayUrl\n );\n // Render root comments oldest-first (server order is not guaranteed).\n const roots = data.getEntityComments.items.filter((c) => !c.parentCommentId);\n roots.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());\n return { items: roots, total: data.getEntityComments.total };\n },\n });\n};\n\nexport const useEcoCreateComment = (entityType: string, entityId: string) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (text: string) => {\n const data = await wspaceFetch<{ createEntityComment: { id: string } }>(\n `mutation EcoCreateEntityComment($input: CreateEntityCommentInput!) {\n createEntityComment(input: $input) { id }\n }`,\n {\n input: {\n entityType,\n entityId,\n content: { text },\n },\n },\n apiGatewayUrl\n );\n return data.createEntityComment;\n },\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: commentsKey(entityType, entityId) });\n },\n });\n};\n"],"mappings":";;;;;AAkCA,IAAM,KAAe,GAAoB,MACvC;CAAC;CAAgB;CAAY;CAAY;CAAS,EAGvC,KAAkB,GAAoB,MAAiC;CAClF,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU,EAAY,GAAY,KAAY,GAAG;EACjD,SAAS,EAAQ;EACjB,SAAS,YAAY;GACnB,IAAM,IAAO,MAAM,EAGjB,6YAeA,EACE,OAAO;IACL;IACA;IACA,MAAM;IACN,iBAAiB;IAClB,EACF,EACD,EACD,EAEK,IAAQ,EAAK,kBAAkB,MAAM,QAAQ,MAAM,CAAC,EAAE,gBAAgB;AAE5E,UADA,EAAM,MAAM,GAAG,MAAM,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,GAAG,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,EAChF;IAAE,OAAO;IAAO,OAAO,EAAK,kBAAkB;IAAO;;EAE/D,CAAC;GAGS,KAAuB,GAAoB,MAAqB;CAC3E,IAAM,EAAE,qBAAkB,GAAiB,EACrC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACJ,MAAM,EACjB,wIAGA,EACE,OAAO;GACL;GACA;GACA,SAAS,EAAE,SAAM;GAClB,EACF,EACD,EACD,EACW;EAEd,iBAAiB;AACf,KAAG,kBAAkB,EAAE,UAAU,EAAY,GAAY,EAAS,EAAE,CAAC;;EAExE,CAAC"}
1
+ {"version":3,"file":"useEcoComments.js","names":[],"sources":["../../../src/ecoimpacthub/hooks/useEcoComments.ts"],"sourcesContent":["/**\n * EcoImpactHub — wspace-conversations-svc EntityComment REUSE hooks (Integration B).\n * @module ecoimpacthub/hooks/useEcoComments\n *\n * Adds a discussion surface to eco entities WITHOUT any eco-svc change by\n * reusing the generic EntityComment API composed into the WORKSPACE supergraph.\n * Comments attach to any entity by `(entityType, entityId)`:\n * - `getEntityComments(input): EntityCommentConnection!`\n * - `createEntityComment(input): EntityComment!`\n *\n * Transport reuses `wspaceFetch` from `useEcoFiles` (workspace gateway +\n * workspace token). Lives in a separate file; `useEcoImpactHubApi.ts` is\n * untouched.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\n\nimport { useEcoImpactHub } from '../context';\nimport { wspaceFetch } from './useEcoFiles';\n\nexport interface EcoComment {\n id: string;\n authorId: string;\n authorType: string;\n content: {\n text: string | null;\n markdown: string | null;\n };\n createdAt: string;\n edited: boolean;\n parentCommentId: string | null;\n replyCount: number;\n}\n\nconst commentsKey = (entityType: string, entityId: string) =>\n ['ecoimpacthub', 'comments', entityType, entityId] as const;\n\n/** Top-level (root) comments for an eco entity, oldest first. */\nexport const useEcoComments = (entityType: string, entityId: string | undefined) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: commentsKey(entityType, entityId ?? ''),\n enabled: Boolean(entityId),\n queryFn: async () => {\n const data = await wspaceFetch<{\n getEntityComments: { items: EcoComment[]; total: number };\n }>(\n `query EcoGetEntityComments($input: GetCommentsInput!) {\n getEntityComments(input: $input) {\n total\n items {\n id\n authorId\n authorType\n content { text markdown }\n createdAt\n edited\n parentCommentId\n replyCount\n }\n }\n }`,\n {\n input: {\n entityType,\n entityId,\n take: 100,\n parentCommentId: null,\n },\n },\n apiGatewayUrl\n );\n // Render root comments oldest-first (server order is not guaranteed).\n const roots = data.getEntityComments.items.filter((c) => !c.parentCommentId);\n roots.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());\n return { items: roots, total: data.getEntityComments.total };\n },\n });\n};\n\nexport const useEcoCreateComment = (entityType: string, entityId: string) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (text: string) => {\n const data = await wspaceFetch<{ createEntityComment: { id: string } }>(\n `mutation EcoCreateEntityComment($input: CreateEntityCommentInput!) {\n createEntityComment(input: $input) { id }\n }`,\n {\n input: {\n entityType,\n entityId,\n content: { text },\n },\n },\n apiGatewayUrl\n );\n return data.createEntityComment;\n },\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: commentsKey(entityType, entityId) });\n },\n });\n};\n"],"mappings":";;;;;AAkCA,IAAM,KAAe,GAAoB,MACvC;CAAC;CAAgB;CAAY;CAAY;AAAQ,GAGtC,KAAkB,GAAoB,MAAiC;CAClF,IAAM,EAAE,qBAAkB,EAAgB;CAC1C,OAAO,EAAS;EACd,UAAU,EAAY,GAAY,KAAY,EAAE;EAChD,SAAS,EAAQ;EACjB,SAAS,YAAY;GACnB,IAAM,IAAO,MAAM,EAGjB,6YAeA,EACE,OAAO;IACL;IACA;IACA,MAAM;IACN,iBAAiB;GACnB,EACF,GACA,CACF,GAEM,IAAQ,EAAK,kBAAkB,MAAM,QAAQ,MAAM,CAAC,EAAE,eAAe;GAE3E,OADA,EAAM,MAAM,GAAG,MAAM,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,GAC/E;IAAE,OAAO;IAAO,OAAO,EAAK,kBAAkB;GAAM;EAC7D;CACF,CAAC;AACH,GAEa,KAAuB,GAAoB,MAAqB;CAC3E,IAAM,EAAE,qBAAkB,EAAgB,GACpC,IAAK,EAAe;CAC1B,OAAO,EAAY;EACjB,YAAY,OAAO,OAcV,MAbY,EACjB,wIAGA,EACE,OAAO;GACL;GACA;GACA,SAAS,EAAE,QAAK;EAClB,EACF,GACA,CACF,GACY;EAEd,iBAAiB;GACf,EAAG,kBAAkB,EAAE,UAAU,EAAY,GAAY,CAAQ,EAAE,CAAC;EACtE;CACF,CAAC;AACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"useEcoFiles.js","names":[],"sources":["../../../src/ecoimpacthub/hooks/useEcoFiles.ts"],"sourcesContent":["/**\n * EcoImpactHub — wspace-files-svc REUSE hooks (Integration A).\n * @module ecoimpacthub/hooks/useEcoFiles\n *\n * Reuses the platform file store (`wspace-files-svc`) WITHOUT any eco-svc\n * change: the eco schema already exposes `EcoObservation.evidenceFileId` /\n * `EcoReport.fileId`; this module lets the UI actually produce a `fileId` via\n * the canonical 3-step upload flow composed into the WORKSPACE supergraph:\n * 1. `initiateUpload(input)` → `{ uploadUrl, session { id } }`\n * 2. HTTP `PUT` the bytes to the returned signed `uploadUrl`\n * 3. `completeUpload(input: { sessionId })` → `{ fileId }`\n * plus `getFile(id)` to resolve an existing evidence/report file's name + URL.\n *\n * Transport mirrors `useEcoImpactHubApi` exactly — `graphqlFetch({ gateway:\n * 'workspace', workspaceToken: true })` — so no ApolloProvider is required.\n * These hooks live in a SEPARATE file by design; `useEcoImpactHubApi.ts` is\n * left untouched.\n */\n\nimport { useCallback, useState } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useEcoImpactHub } from '../context';\n\n// ============================================================================\n// Shared workspace-gateway transport (reused by the comments + tags hooks too)\n// ============================================================================\n\ntype GraphqlReadCacheGlobals = {\n __graphqlFetchResponseCache?: { clear: () => void };\n __graphqlFetchPendingResponses?: { clear: () => void };\n __boffGraphQLResponseCache?: { clear: () => void };\n};\n\n/**\n * fe-libs `graphqlFetch` coalesces `query` responses in a short-lived in-memory\n * cache. After a write we drop those caches so the invalidation refetch that\n * follows reads fresh data (same remedy `useEcoImpactHubApi` applies).\n */\nconst clearGraphqlReadCaches = (): void => {\n const g = globalThis as GraphqlReadCacheGlobals;\n g.__graphqlFetchResponseCache?.clear();\n g.__graphqlFetchPendingResponses?.clear();\n g.__boffGraphQLResponseCache?.clear();\n};\n\n/** Execute a workspace-gateway GraphQL operation with the workspace token. */\nexport const wspaceFetch = 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 if (/^\\s*mutation\\b/.test(query)) {\n clearGraphqlReadCaches();\n }\n return response.data;\n};\n\n// ============================================================================\n// File upload (initiate → PUT → complete)\n// ============================================================================\n\nexport interface UploadedEcoFile {\n fileId: string;\n fileName: string;\n}\n\n/** `PUT` the blob to the signed URL, reporting byte-progress via `onProgress`. */\nfunction putWithProgress(\n url: string,\n file: File,\n contentType: string,\n onProgress: (percent: number) => void\n): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.open('PUT', url);\n xhr.setRequestHeader('Content-Type', contentType);\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable) {\n onProgress(Math.round((event.loaded / event.total) * 100));\n }\n };\n xhr.onload = () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new Error(`File storage rejected the upload (HTTP ${xhr.status}).`));\n }\n };\n xhr.onerror = () => reject(new Error('Network error while uploading the file.'));\n xhr.onabort = () => reject(new Error('The upload was cancelled.'));\n xhr.send(file);\n });\n}\n\nexport interface UseEcoFileUploadResult {\n upload: (file: File) => Promise<UploadedEcoFile>;\n isUploading: boolean;\n /** 0–100 byte-progress of the signed-URL PUT. */\n progress: number;\n error: string | null;\n reset: () => void;\n}\n\n/**\n * Imperative upload hook: `await upload(file)` runs the platform 3-step flow and\n * resolves to `{ fileId, fileName }`. `fileId` is what the eco mutations accept\n * (`ecoRecordObservation.evidenceFileId`, `ecoPublishReport.fileId`).\n */\nexport const useEcoFileUpload = (): UseEcoFileUploadResult => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const [isUploading, setIsUploading] = useState(false);\n const [progress, setProgress] = useState(0);\n const [error, setError] = useState<string | null>(null);\n\n const reset = useCallback(() => {\n setIsUploading(false);\n setProgress(0);\n setError(null);\n }, []);\n\n const upload = useCallback(\n async (file: File): Promise<UploadedEcoFile> => {\n setIsUploading(true);\n setProgress(0);\n setError(null);\n try {\n const dotIndex = file.name.lastIndexOf('.');\n const extension = dotIndex > -1 ? file.name.slice(dotIndex + 1) : '';\n const mimeType = file.type || 'application/octet-stream';\n\n // 1. initiate\n const initiated = await wspaceFetch<{\n initiateUpload: { uploadUrl: string | null; session: { id: string } };\n }>(\n `mutation EcoInitiateUpload($input: InitiateUploadInput!) {\n initiateUpload(input: $input) {\n uploadUrl\n session { id }\n }\n }`,\n {\n input: {\n fileName: file.name,\n extension,\n mimeType,\n fileSize: String(file.size),\n visibility: 'WORKSPACE',\n },\n },\n apiGatewayUrl\n );\n\n const { uploadUrl } = initiated.initiateUpload;\n const sessionId = initiated.initiateUpload.session.id;\n if (!uploadUrl) {\n throw new Error('The file service did not return an upload URL.');\n }\n\n // 2. PUT the bytes\n await putWithProgress(uploadUrl, file, mimeType, setProgress);\n\n // 3. complete\n const completed = await wspaceFetch<{\n completeUpload: { fileId: string; file: { id: string; name: string } | null };\n }>(\n `mutation EcoCompleteUpload($input: CompleteUploadInput!) {\n completeUpload(input: $input) {\n fileId\n file { id name }\n }\n }`,\n { input: { sessionId } },\n apiGatewayUrl\n );\n\n setProgress(100);\n return {\n fileId: completed.completeUpload.fileId,\n fileName: completed.completeUpload.file?.name ?? file.name,\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : 'The file could not be uploaded.';\n setError(message);\n throw err instanceof Error ? err : new Error(message);\n } finally {\n setIsUploading(false);\n }\n },\n [apiGatewayUrl]\n );\n\n return { upload, isUploading, progress, error, reset };\n};\n\n// ============================================================================\n// Resolve an existing file (name + download URL) for rendering evidence links\n// ============================================================================\n\nexport interface EcoFileMeta {\n id: string;\n name: string;\n downloadUrl: string | null;\n mimeType: string;\n size: string;\n}\n\nexport const useEcoFile = (id: string | null | undefined) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: ['ecoimpacthub', 'file', id ?? ''],\n enabled: Boolean(id),\n queryFn: async () => {\n const data = await wspaceFetch<{ getFile: EcoFileMeta | null }>(\n `query EcoGetFile($id: ID!) {\n getFile(id: $id) {\n id\n name\n downloadUrl\n mimeType\n size\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return data.getFile;\n },\n });\n};\n"],"mappings":";;;;;;AAwCA,IAAM,UAAqC;CACzC,IAAM,IAAI;AAGV,CAFA,EAAE,6BAA6B,OAAO,EACtC,EAAE,gCAAgC,OAAO,EACzC,EAAE,4BAA4B,OAAO;GAI1B,IAAc,OACzB,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;AAK1D,QAHI,iBAAiB,KAAK,EAAM,IAC9B,GAAwB,EAEnB,EAAS;;AAalB,SAAS,EACP,GACA,GACA,GACA,GACe;AACf,QAAO,IAAI,SAAe,GAAS,MAAW;EAC5C,IAAM,IAAM,IAAI,gBAAgB;AAiBhC,EAhBA,EAAI,KAAK,OAAO,EAAI,EACpB,EAAI,iBAAiB,gBAAgB,EAAY,EACjD,EAAI,OAAO,cAAc,MAAU;AACjC,GAAI,EAAM,oBACR,EAAW,KAAK,MAAO,EAAM,SAAS,EAAM,QAAS,IAAI,CAAC;KAG9D,EAAI,eAAe;AACjB,GAAI,EAAI,UAAU,OAAO,EAAI,SAAS,MACpC,GAAS,GAET,EAAO,gBAAI,MAAM,0CAA0C,EAAI,OAAO,IAAI,CAAC;KAG/E,EAAI,gBAAgB,EAAO,gBAAI,MAAM,0CAA0C,CAAC,EAChF,EAAI,gBAAgB,EAAO,gBAAI,MAAM,4BAA4B,CAAC,EAClE,EAAI,KAAK,EAAK;GACd;;AAiBJ,IAAa,UAAiD;CAC5D,IAAM,EAAE,qBAAkB,GAAiB,EACrC,CAAC,GAAa,KAAkB,EAAS,GAAM,EAC/C,CAAC,GAAU,KAAe,EAAS,EAAE,EACrC,CAAC,GAAO,KAAY,EAAwB,KAAK,EAEjD,IAAQ,QAAkB;AAG9B,EAFA,EAAe,GAAM,EACrB,EAAY,EAAE,EACd,EAAS,KAAK;IACb,EAAE,CAAC;AAyEN,QAAO;EAAE,QAvEM,EACb,OAAO,MAAyC;AAG9C,GAFA,EAAe,GAAK,EACpB,EAAY,EAAE,EACd,EAAS,KAAK;AACd,OAAI;IACF,IAAM,IAAW,EAAK,KAAK,YAAY,IAAI,EACrC,IAAY,IAAW,KAAK,EAAK,KAAK,MAAM,IAAW,EAAE,GAAG,IAC5D,IAAW,EAAK,QAAQ,4BAGxB,IAAY,MAAM,EAGtB,8LAMA,EACE,OAAO;KACL,UAAU,EAAK;KACf;KACA;KACA,UAAU,OAAO,EAAK,KAAK;KAC3B,YAAY;KACb,EACF,EACD,EACD,EAEK,EAAE,iBAAc,EAAU,gBAC1B,IAAY,EAAU,eAAe,QAAQ;AACnD,QAAI,CAAC,EACH,OAAU,MAAM,iDAAiD;AAInE,UAAM,EAAgB,GAAW,GAAM,GAAU,EAAY;IAG7D,IAAM,IAAY,MAAM,EAGtB,6LAMA,EAAE,OAAO,EAAE,cAAW,EAAE,EACxB,EACD;AAGD,WADA,EAAY,IAAI,EACT;KACL,QAAQ,EAAU,eAAe;KACjC,UAAU,EAAU,eAAe,MAAM,QAAQ,EAAK;KACvD;YACM,GAAK;IACZ,IAAM,IAAU,aAAe,QAAQ,EAAI,UAAU;AAErD,UADA,EAAS,EAAQ,EACX,aAAe,QAAQ,IAAU,MAAM,EAAQ;aAC7C;AACR,MAAe,GAAM;;KAGzB,CAAC,EAAc,CAChB;EAEgB;EAAa;EAAU;EAAO;EAAO;GAe3C,KAAc,MAAkC;CAC3D,IAAM,EAAE,qBAAkB,GAAiB;AAC3C,QAAO,EAAS;EACd,UAAU;GAAC;GAAgB;GAAQ,KAAM;GAAG;EAC5C,SAAS,EAAQ;EACjB,SAAS,aACM,MAAM,EACjB,yLASA,EAAE,OAAI,EACN,EACD,EACW;EAEf,CAAC"}
1
+ {"version":3,"file":"useEcoFiles.js","names":[],"sources":["../../../src/ecoimpacthub/hooks/useEcoFiles.ts"],"sourcesContent":["/**\n * EcoImpactHub — wspace-files-svc REUSE hooks (Integration A).\n * @module ecoimpacthub/hooks/useEcoFiles\n *\n * Reuses the platform file store (`wspace-files-svc`) WITHOUT any eco-svc\n * change: the eco schema already exposes `EcoObservation.evidenceFileId` /\n * `EcoReport.fileId`; this module lets the UI actually produce a `fileId` via\n * the canonical 3-step upload flow composed into the WORKSPACE supergraph:\n * 1. `initiateUpload(input)` → `{ uploadUrl, session { id } }`\n * 2. HTTP `PUT` the bytes to the returned signed `uploadUrl`\n * 3. `completeUpload(input: { sessionId })` → `{ fileId }`\n * plus `getFile(id)` to resolve an existing evidence/report file's name + URL.\n *\n * Transport mirrors `useEcoImpactHubApi` exactly — `graphqlFetch({ gateway:\n * 'workspace', workspaceToken: true })` — so no ApolloProvider is required.\n * These hooks live in a SEPARATE file by design; `useEcoImpactHubApi.ts` is\n * left untouched.\n */\n\nimport { useCallback, useState } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useEcoImpactHub } from '../context';\n\n// ============================================================================\n// Shared workspace-gateway transport (reused by the comments + tags hooks too)\n// ============================================================================\n\ntype GraphqlReadCacheGlobals = {\n __graphqlFetchResponseCache?: { clear: () => void };\n __graphqlFetchPendingResponses?: { clear: () => void };\n __boffGraphQLResponseCache?: { clear: () => void };\n};\n\n/**\n * fe-libs `graphqlFetch` coalesces `query` responses in a short-lived in-memory\n * cache. After a write we drop those caches so the invalidation refetch that\n * follows reads fresh data (same remedy `useEcoImpactHubApi` applies).\n */\nconst clearGraphqlReadCaches = (): void => {\n const g = globalThis as GraphqlReadCacheGlobals;\n g.__graphqlFetchResponseCache?.clear();\n g.__graphqlFetchPendingResponses?.clear();\n g.__boffGraphQLResponseCache?.clear();\n};\n\n/** Execute a workspace-gateway GraphQL operation with the workspace token. */\nexport const wspaceFetch = 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 if (/^\\s*mutation\\b/.test(query)) {\n clearGraphqlReadCaches();\n }\n return response.data;\n};\n\n// ============================================================================\n// File upload (initiate → PUT → complete)\n// ============================================================================\n\nexport interface UploadedEcoFile {\n fileId: string;\n fileName: string;\n}\n\n/** `PUT` the blob to the signed URL, reporting byte-progress via `onProgress`. */\nfunction putWithProgress(\n url: string,\n file: File,\n contentType: string,\n onProgress: (percent: number) => void\n): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.open('PUT', url);\n xhr.setRequestHeader('Content-Type', contentType);\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable) {\n onProgress(Math.round((event.loaded / event.total) * 100));\n }\n };\n xhr.onload = () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new Error(`File storage rejected the upload (HTTP ${xhr.status}).`));\n }\n };\n xhr.onerror = () => reject(new Error('Network error while uploading the file.'));\n xhr.onabort = () => reject(new Error('The upload was cancelled.'));\n xhr.send(file);\n });\n}\n\nexport interface UseEcoFileUploadResult {\n upload: (file: File) => Promise<UploadedEcoFile>;\n isUploading: boolean;\n /** 0–100 byte-progress of the signed-URL PUT. */\n progress: number;\n error: string | null;\n reset: () => void;\n}\n\n/**\n * Imperative upload hook: `await upload(file)` runs the platform 3-step flow and\n * resolves to `{ fileId, fileName }`. `fileId` is what the eco mutations accept\n * (`ecoRecordObservation.evidenceFileId`, `ecoPublishReport.fileId`).\n */\nexport const useEcoFileUpload = (): UseEcoFileUploadResult => {\n const { apiGatewayUrl } = useEcoImpactHub();\n const [isUploading, setIsUploading] = useState(false);\n const [progress, setProgress] = useState(0);\n const [error, setError] = useState<string | null>(null);\n\n const reset = useCallback(() => {\n setIsUploading(false);\n setProgress(0);\n setError(null);\n }, []);\n\n const upload = useCallback(\n async (file: File): Promise<UploadedEcoFile> => {\n setIsUploading(true);\n setProgress(0);\n setError(null);\n try {\n const dotIndex = file.name.lastIndexOf('.');\n const extension = dotIndex > -1 ? file.name.slice(dotIndex + 1) : '';\n const mimeType = file.type || 'application/octet-stream';\n\n // 1. initiate\n const initiated = await wspaceFetch<{\n initiateUpload: { uploadUrl: string | null; session: { id: string } };\n }>(\n `mutation EcoInitiateUpload($input: InitiateUploadInput!) {\n initiateUpload(input: $input) {\n uploadUrl\n session { id }\n }\n }`,\n {\n input: {\n fileName: file.name,\n extension,\n mimeType,\n fileSize: String(file.size),\n visibility: 'WORKSPACE',\n },\n },\n apiGatewayUrl\n );\n\n const { uploadUrl } = initiated.initiateUpload;\n const sessionId = initiated.initiateUpload.session.id;\n if (!uploadUrl) {\n throw new Error('The file service did not return an upload URL.');\n }\n\n // 2. PUT the bytes\n await putWithProgress(uploadUrl, file, mimeType, setProgress);\n\n // 3. complete\n const completed = await wspaceFetch<{\n completeUpload: { fileId: string; file: { id: string; name: string } | null };\n }>(\n `mutation EcoCompleteUpload($input: CompleteUploadInput!) {\n completeUpload(input: $input) {\n fileId\n file { id name }\n }\n }`,\n { input: { sessionId } },\n apiGatewayUrl\n );\n\n setProgress(100);\n return {\n fileId: completed.completeUpload.fileId,\n fileName: completed.completeUpload.file?.name ?? file.name,\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : 'The file could not be uploaded.';\n setError(message);\n throw err instanceof Error ? err : new Error(message);\n } finally {\n setIsUploading(false);\n }\n },\n [apiGatewayUrl]\n );\n\n return { upload, isUploading, progress, error, reset };\n};\n\n// ============================================================================\n// Resolve an existing file (name + download URL) for rendering evidence links\n// ============================================================================\n\nexport interface EcoFileMeta {\n id: string;\n name: string;\n downloadUrl: string | null;\n mimeType: string;\n size: string;\n}\n\nexport const useEcoFile = (id: string | null | undefined) => {\n const { apiGatewayUrl } = useEcoImpactHub();\n return useQuery({\n queryKey: ['ecoimpacthub', 'file', id ?? ''],\n enabled: Boolean(id),\n queryFn: async () => {\n const data = await wspaceFetch<{ getFile: EcoFileMeta | null }>(\n `query EcoGetFile($id: ID!) {\n getFile(id: $id) {\n id\n name\n downloadUrl\n mimeType\n size\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return data.getFile;\n },\n });\n};\n"],"mappings":";;;;;;AAwCA,IAAM,UAAqC;CACzC,IAAM,IAAI;CAGV,AAFA,EAAE,6BAA6B,MAAM,GACrC,EAAE,gCAAgC,MAAM,GACxC,EAAE,4BAA4B,MAAM;AACtC,GAGa,IAAc,OACzB,GACA,GACA,MACmB;CACnB,IAAM,IAAW,MAAM,EAAoB;EACzC,SAAS;EACT;EACA;EACA;EACA,gBAAgB;CAClB,CAAC;CAED,IAAI,EAAS,QAAQ,QACnB,MAAU,MAAM,EAAS,OAAO,IAAI,WAAW,wBAAwB;CAEzE,IAAI,CAAC,EAAS,MACZ,MAAU,MAAM,uCAAuC;CAKzD,OAHI,iBAAiB,KAAK,CAAK,KAC7B,EAAuB,GAElB,EAAS;AAClB;AAYA,SAAS,EACP,GACA,GACA,GACA,GACe;CACf,OAAO,IAAI,SAAe,GAAS,MAAW;EAC5C,IAAM,IAAM,IAAI,eAAe;EAiB/B,AAhBA,EAAI,KAAK,OAAO,CAAG,GACnB,EAAI,iBAAiB,gBAAgB,CAAW,GAChD,EAAI,OAAO,cAAc,MAAU;GACjC,AAAI,EAAM,oBACR,EAAW,KAAK,MAAO,EAAM,SAAS,EAAM,QAAS,GAAG,CAAC;EAE7D,GACA,EAAI,eAAe;GACjB,AAAI,EAAI,UAAU,OAAO,EAAI,SAAS,MACpC,EAAQ,IAER,EAAO,gBAAI,MAAM,0CAA0C,EAAI,OAAO,GAAG,CAAC;EAE9E,GACA,EAAI,gBAAgB,EAAO,gBAAI,MAAM,yCAAyC,CAAC,GAC/E,EAAI,gBAAgB,EAAO,gBAAI,MAAM,2BAA2B,CAAC,GACjE,EAAI,KAAK,CAAI;CACf,CAAC;AACH;AAgBA,IAAa,UAAiD;CAC5D,IAAM,EAAE,qBAAkB,EAAgB,GACpC,CAAC,GAAa,KAAkB,EAAS,EAAK,GAC9C,CAAC,GAAU,KAAe,EAAS,CAAC,GACpC,CAAC,GAAO,KAAY,EAAwB,IAAI,GAEhD,IAAQ,QAAkB;EAG9B,AAFA,EAAe,EAAK,GACpB,EAAY,CAAC,GACb,EAAS,IAAI;CACf,GAAG,CAAC,CAAC;CAyEL,OAAO;EAAE,QAvEM,EACb,OAAO,MAAyC;GAG9C,AAFA,EAAe,EAAI,GACnB,EAAY,CAAC,GACb,EAAS,IAAI;GACb,IAAI;IACF,IAAM,IAAW,EAAK,KAAK,YAAY,GAAG,GACpC,IAAY,IAAW,KAAK,EAAK,KAAK,MAAM,IAAW,CAAC,IAAI,IAC5D,IAAW,EAAK,QAAQ,4BAGxB,IAAY,MAAM,EAGtB,8LAMA,EACE,OAAO;KACL,UAAU,EAAK;KACf;KACA;KACA,UAAU,OAAO,EAAK,IAAI;KAC1B,YAAY;IACd,EACF,GACA,CACF,GAEM,EAAE,iBAAc,EAAU,gBAC1B,IAAY,EAAU,eAAe,QAAQ;IACnD,IAAI,CAAC,GACH,MAAU,MAAM,gDAAgD;IAIlE,MAAM,EAAgB,GAAW,GAAM,GAAU,CAAW;IAG5D,IAAM,IAAY,MAAM,EAGtB,6LAMA,EAAE,OAAO,EAAE,aAAU,EAAE,GACvB,CACF;IAGA,OADA,EAAY,GAAG,GACR;KACL,QAAQ,EAAU,eAAe;KACjC,UAAU,EAAU,eAAe,MAAM,QAAQ,EAAK;IACxD;GACF,SAAS,GAAK;IACZ,IAAM,IAAU,aAAe,QAAQ,EAAI,UAAU;IAErD,MADA,EAAS,CAAO,GACV,aAAe,QAAQ,IAAU,MAAM,CAAO;GACtD,UAAU;IACR,EAAe,EAAK;GACtB;EACF,GACA,CAAC,CAAa,CAGP;EAAQ;EAAa;EAAU;EAAO;CAAM;AACvD,GAca,KAAc,MAAkC;CAC3D,IAAM,EAAE,qBAAkB,EAAgB;CAC1C,OAAO,EAAS;EACd,UAAU;GAAC;GAAgB;GAAQ,KAAM;EAAE;EAC3C,SAAS,EAAQ;EACjB,SAAS,aAcA,MAbY,EACjB,yLASA,EAAE,MAAG,GACL,CACF,GACY;CAEhB,CAAC;AACH"}