@burdenoff/microfe-ecoimpacthub 2026.720.2 → 2026.720.4

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 (484) 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/DataTable.js.map +1 -1
  5. package/dist/ecoimpacthub/components/EcoDiscussion.js.map +1 -1
  6. package/dist/ecoimpacthub/components/EcoTags.js.map +1 -1
  7. package/dist/ecoimpacthub/components/EmptyState.js.map +1 -1
  8. package/dist/ecoimpacthub/components/EvidenceUpload.js.map +1 -1
  9. package/dist/ecoimpacthub/components/FeatureFlagGate.js.map +1 -1
  10. package/dist/ecoimpacthub/components/FileLink.js.map +1 -1
  11. package/dist/ecoimpacthub/components/FilterTabs.js.map +1 -1
  12. package/dist/ecoimpacthub/components/MetricsCard.js.map +1 -1
  13. package/dist/ecoimpacthub/components/MiniBar.js.map +1 -1
  14. package/dist/ecoimpacthub/components/PageLayout.js.map +1 -1
  15. package/dist/ecoimpacthub/components/Pagination.js.map +1 -1
  16. package/dist/ecoimpacthub/components/StateViews.js.map +1 -1
  17. package/dist/ecoimpacthub/components/StatusBadge.d.ts.map +1 -1
  18. package/dist/ecoimpacthub/components/StatusBadge.js +3 -0
  19. package/dist/ecoimpacthub/components/StatusBadge.js.map +1 -1
  20. package/dist/ecoimpacthub/components/Tabs.js.map +1 -1
  21. package/dist/ecoimpacthub/context/EcoImpactHubContext.js.map +1 -1
  22. package/dist/ecoimpacthub/hooks/useCursorPager.js.map +1 -1
  23. package/dist/ecoimpacthub/hooks/useEcoComments.js.map +1 -1
  24. package/dist/ecoimpacthub/hooks/useEcoFiles.js.map +1 -1
  25. package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.js.map +1 -1
  26. package/dist/ecoimpacthub/hooks/useEcoTags.js.map +1 -1
  27. package/dist/ecoimpacthub/pages/DashboardPage.js.map +1 -1
  28. package/dist/ecoimpacthub/pages/_shared/ConservationBadge.js.map +1 -1
  29. package/dist/ecoimpacthub/pages/_shared/EvidenceThumb.js.map +1 -1
  30. package/dist/ecoimpacthub/pages/_shared/MethodBadge.js.map +1 -1
  31. package/dist/ecoimpacthub/pages/_shared/TaxonChip.js.map +1 -1
  32. package/dist/ecoimpacthub/pages/badges.js.map +1 -1
  33. package/dist/ecoimpacthub/pages/carbon/CarbonPage.js.map +1 -1
  34. package/dist/ecoimpacthub/pages/carbonVisuals.js.map +1 -1
  35. package/dist/ecoimpacthub/pages/habitat/HabitatProjectDetailPage.js.map +1 -1
  36. package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.js.map +1 -1
  37. package/dist/ecoimpacthub/pages/habitat/LifecycleProgress.js.map +1 -1
  38. package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.js.map +1 -1
  39. package/dist/ecoimpacthub/pages/observations/ObservationsPage.js.map +1 -1
  40. package/dist/ecoimpacthub/pages/reports/ReportDetailPage.js.map +1 -1
  41. package/dist/ecoimpacthub/pages/reports/ReportsPage.js.map +1 -1
  42. package/dist/ecoimpacthub/pages/sites/SiteDetailPage.js.map +1 -1
  43. package/dist/ecoimpacthub/pages/sites/SitesPage.js.map +1 -1
  44. package/dist/ecoimpacthub/pages/sites/siteTypeVisuals.js.map +1 -1
  45. package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.js.map +1 -1
  46. package/dist/ecoimpacthub/pages/species/SpeciesPage.js.map +1 -1
  47. package/dist/ecoimpacthub/services/createSandboxAssistantTransport.d.ts.map +1 -1
  48. package/dist/ecoimpacthub/services/createSandboxAssistantTransport.js.map +1 -1
  49. package/dist/ecoimpacthub/types/index.d.ts.map +1 -1
  50. package/dist/ecoimpacthub/utils/cn.js.map +1 -1
  51. package/dist/ecoimpacthub/utils/formatters.js.map +1 -1
  52. package/dist/ecoimpacthub/utils/navigation.js.map +1 -1
  53. package/dist/node_modules/clsx/dist/clsx.js.map +1 -1
  54. package/dist/node_modules/d3-array/src/ascending.js.map +1 -1
  55. package/dist/node_modules/d3-array/src/bisect.js.map +1 -1
  56. package/dist/node_modules/d3-array/src/bisector.js.map +1 -1
  57. package/dist/node_modules/d3-array/src/descending.js.map +1 -1
  58. package/dist/node_modules/d3-array/src/max.js.map +1 -1
  59. package/dist/node_modules/d3-array/src/min.js.map +1 -1
  60. package/dist/node_modules/d3-array/src/number.js.map +1 -1
  61. package/dist/node_modules/d3-array/src/quantile.js.map +1 -1
  62. package/dist/node_modules/d3-array/src/quickselect.js.map +1 -1
  63. package/dist/node_modules/d3-array/src/range.js.map +1 -1
  64. package/dist/node_modules/d3-array/src/sort.js.map +1 -1
  65. package/dist/node_modules/d3-array/src/ticks.js.map +1 -1
  66. package/dist/node_modules/d3-color/src/color.js.map +1 -1
  67. package/dist/node_modules/d3-color/src/define.js.map +1 -1
  68. package/dist/node_modules/d3-format/src/defaultLocale.js.map +1 -1
  69. package/dist/node_modules/d3-format/src/exponent.js.map +1 -1
  70. package/dist/node_modules/d3-format/src/formatDecimal.js.map +1 -1
  71. package/dist/node_modules/d3-format/src/formatGroup.js.map +1 -1
  72. package/dist/node_modules/d3-format/src/formatNumerals.js.map +1 -1
  73. package/dist/node_modules/d3-format/src/formatPrefixAuto.js.map +1 -1
  74. package/dist/node_modules/d3-format/src/formatRounded.js.map +1 -1
  75. package/dist/node_modules/d3-format/src/formatSpecifier.js.map +1 -1
  76. package/dist/node_modules/d3-format/src/formatTrim.js.map +1 -1
  77. package/dist/node_modules/d3-format/src/formatTypes.js.map +1 -1
  78. package/dist/node_modules/d3-format/src/identity.js.map +1 -1
  79. package/dist/node_modules/d3-format/src/locale.js.map +1 -1
  80. package/dist/node_modules/d3-format/src/precisionFixed.js.map +1 -1
  81. package/dist/node_modules/d3-format/src/precisionPrefix.js.map +1 -1
  82. package/dist/node_modules/d3-format/src/precisionRound.js.map +1 -1
  83. package/dist/node_modules/d3-interpolate/src/array.js.map +1 -1
  84. package/dist/node_modules/d3-interpolate/src/basis.js.map +1 -1
  85. package/dist/node_modules/d3-interpolate/src/basisClosed.js.map +1 -1
  86. package/dist/node_modules/d3-interpolate/src/color.js.map +1 -1
  87. package/dist/node_modules/d3-interpolate/src/date.js.map +1 -1
  88. package/dist/node_modules/d3-interpolate/src/number.js.map +1 -1
  89. package/dist/node_modules/d3-interpolate/src/numberArray.js.map +1 -1
  90. package/dist/node_modules/d3-interpolate/src/object.js.map +1 -1
  91. package/dist/node_modules/d3-interpolate/src/piecewise.js.map +1 -1
  92. package/dist/node_modules/d3-interpolate/src/rgb.js.map +1 -1
  93. package/dist/node_modules/d3-interpolate/src/round.js.map +1 -1
  94. package/dist/node_modules/d3-interpolate/src/string.js.map +1 -1
  95. package/dist/node_modules/d3-interpolate/src/value.js.map +1 -1
  96. package/dist/node_modules/d3-path/src/path.js.map +1 -1
  97. package/dist/node_modules/d3-scale/src/band.js.map +1 -1
  98. package/dist/node_modules/d3-scale/src/constant.js.map +1 -1
  99. package/dist/node_modules/d3-scale/src/continuous.js.map +1 -1
  100. package/dist/node_modules/d3-scale/src/diverging.js.map +1 -1
  101. package/dist/node_modules/d3-scale/src/identity.js.map +1 -1
  102. package/dist/node_modules/d3-scale/src/init.js.map +1 -1
  103. package/dist/node_modules/d3-scale/src/linear.js.map +1 -1
  104. package/dist/node_modules/d3-scale/src/log.js.map +1 -1
  105. package/dist/node_modules/d3-scale/src/nice.js.map +1 -1
  106. package/dist/node_modules/d3-scale/src/number.js.map +1 -1
  107. package/dist/node_modules/d3-scale/src/ordinal.js.map +1 -1
  108. package/dist/node_modules/d3-scale/src/pow.js.map +1 -1
  109. package/dist/node_modules/d3-scale/src/quantile.js.map +1 -1
  110. package/dist/node_modules/d3-scale/src/quantize.js.map +1 -1
  111. package/dist/node_modules/d3-scale/src/radial.js.map +1 -1
  112. package/dist/node_modules/d3-scale/src/sequential.js.map +1 -1
  113. package/dist/node_modules/d3-scale/src/sequentialQuantile.js.map +1 -1
  114. package/dist/node_modules/d3-scale/src/symlog.js.map +1 -1
  115. package/dist/node_modules/d3-scale/src/threshold.js.map +1 -1
  116. package/dist/node_modules/d3-scale/src/tickFormat.js.map +1 -1
  117. package/dist/node_modules/d3-scale/src/time.js.map +1 -1
  118. package/dist/node_modules/d3-scale/src/utcTime.js.map +1 -1
  119. package/dist/node_modules/d3-shape/src/area.js.map +1 -1
  120. package/dist/node_modules/d3-shape/src/array.js.map +1 -1
  121. package/dist/node_modules/d3-shape/src/constant.js.map +1 -1
  122. package/dist/node_modules/d3-shape/src/curve/basis.js.map +1 -1
  123. package/dist/node_modules/d3-shape/src/curve/basisClosed.js.map +1 -1
  124. package/dist/node_modules/d3-shape/src/curve/basisOpen.js.map +1 -1
  125. package/dist/node_modules/d3-shape/src/curve/bump.js.map +1 -1
  126. package/dist/node_modules/d3-shape/src/curve/linear.js.map +1 -1
  127. package/dist/node_modules/d3-shape/src/curve/linearClosed.js.map +1 -1
  128. package/dist/node_modules/d3-shape/src/curve/monotone.js.map +1 -1
  129. package/dist/node_modules/d3-shape/src/curve/natural.js.map +1 -1
  130. package/dist/node_modules/d3-shape/src/curve/step.js.map +1 -1
  131. package/dist/node_modules/d3-shape/src/line.js.map +1 -1
  132. package/dist/node_modules/d3-shape/src/noop.js.map +1 -1
  133. package/dist/node_modules/d3-shape/src/offset/expand.js.map +1 -1
  134. package/dist/node_modules/d3-shape/src/offset/none.js.map +1 -1
  135. package/dist/node_modules/d3-shape/src/offset/silhouette.js.map +1 -1
  136. package/dist/node_modules/d3-shape/src/offset/wiggle.js.map +1 -1
  137. package/dist/node_modules/d3-shape/src/order/none.js.map +1 -1
  138. package/dist/node_modules/d3-shape/src/path.js.map +1 -1
  139. package/dist/node_modules/d3-shape/src/point.js.map +1 -1
  140. package/dist/node_modules/d3-shape/src/stack.js.map +1 -1
  141. package/dist/node_modules/d3-shape/src/symbol/circle.js.map +1 -1
  142. package/dist/node_modules/d3-shape/src/symbol/cross.js.map +1 -1
  143. package/dist/node_modules/d3-shape/src/symbol/diamond.js.map +1 -1
  144. package/dist/node_modules/d3-shape/src/symbol/square.js.map +1 -1
  145. package/dist/node_modules/d3-shape/src/symbol/star.js.map +1 -1
  146. package/dist/node_modules/d3-shape/src/symbol/triangle.js.map +1 -1
  147. package/dist/node_modules/d3-shape/src/symbol/wye.js.map +1 -1
  148. package/dist/node_modules/d3-shape/src/symbol.js.map +1 -1
  149. package/dist/node_modules/d3-time/src/day.js.map +1 -1
  150. package/dist/node_modules/d3-time/src/hour.js.map +1 -1
  151. package/dist/node_modules/d3-time/src/interval.js.map +1 -1
  152. package/dist/node_modules/d3-time/src/millisecond.js.map +1 -1
  153. package/dist/node_modules/d3-time/src/minute.js.map +1 -1
  154. package/dist/node_modules/d3-time/src/month.js.map +1 -1
  155. package/dist/node_modules/d3-time/src/second.js.map +1 -1
  156. package/dist/node_modules/d3-time/src/ticks.js.map +1 -1
  157. package/dist/node_modules/d3-time/src/week.js.map +1 -1
  158. package/dist/node_modules/d3-time/src/year.js.map +1 -1
  159. package/dist/node_modules/d3-time-format/src/defaultLocale.js.map +1 -1
  160. package/dist/node_modules/d3-time-format/src/locale.js.map +1 -1
  161. package/dist/node_modules/decimal.js-light/decimal.js.map +1 -1
  162. package/dist/node_modules/eventemitter3/index.js.map +1 -1
  163. package/dist/node_modules/fast-equals/dist/es/index.js.map +1 -1
  164. package/dist/node_modules/internmap/src/index.js.map +1 -1
  165. package/dist/node_modules/lodash/_DataView.js.map +1 -1
  166. package/dist/node_modules/lodash/_Hash.js.map +1 -1
  167. package/dist/node_modules/lodash/_ListCache.js.map +1 -1
  168. package/dist/node_modules/lodash/_Map.js.map +1 -1
  169. package/dist/node_modules/lodash/_MapCache.js.map +1 -1
  170. package/dist/node_modules/lodash/_Promise.js.map +1 -1
  171. package/dist/node_modules/lodash/_Set.js.map +1 -1
  172. package/dist/node_modules/lodash/_SetCache.js.map +1 -1
  173. package/dist/node_modules/lodash/_Stack.js +2 -1
  174. package/dist/node_modules/lodash/_Stack.js.map +1 -1
  175. package/dist/node_modules/lodash/_Symbol.js.map +1 -1
  176. package/dist/node_modules/lodash/_Uint8Array.js.map +1 -1
  177. package/dist/node_modules/lodash/_WeakMap.js.map +1 -1
  178. package/dist/node_modules/lodash/_apply.js.map +1 -1
  179. package/dist/node_modules/lodash/_arrayEvery.js.map +1 -1
  180. package/dist/node_modules/lodash/_arrayFilter.js.map +1 -1
  181. package/dist/node_modules/lodash/_arrayIncludes.js.map +1 -1
  182. package/dist/node_modules/lodash/_arrayIncludesWith.js.map +1 -1
  183. package/dist/node_modules/lodash/_arrayLikeKeys.js.map +1 -1
  184. package/dist/node_modules/lodash/_arrayMap.js.map +1 -1
  185. package/dist/node_modules/lodash/_arrayPush.js.map +1 -1
  186. package/dist/node_modules/lodash/_arraySome.js.map +1 -1
  187. package/dist/node_modules/lodash/_asciiToArray.js.map +1 -1
  188. package/dist/node_modules/lodash/_assocIndexOf.js.map +1 -1
  189. package/dist/node_modules/lodash/_baseAssignValue.js.map +1 -1
  190. package/dist/node_modules/lodash/_baseEach.js.map +1 -1
  191. package/dist/node_modules/lodash/_baseEvery.js.map +1 -1
  192. package/dist/node_modules/lodash/_baseExtremum.js.map +1 -1
  193. package/dist/node_modules/lodash/_baseFindIndex.js.map +1 -1
  194. package/dist/node_modules/lodash/_baseFlatten.js.map +1 -1
  195. package/dist/node_modules/lodash/_baseFor.js.map +1 -1
  196. package/dist/node_modules/lodash/_baseForOwn.js.map +1 -1
  197. package/dist/node_modules/lodash/_baseGet.js.map +1 -1
  198. package/dist/node_modules/lodash/_baseGetAllKeys.js.map +1 -1
  199. package/dist/node_modules/lodash/_baseGetTag.js.map +1 -1
  200. package/dist/node_modules/lodash/_baseGt.js.map +1 -1
  201. package/dist/node_modules/lodash/_baseHasIn.js.map +1 -1
  202. package/dist/node_modules/lodash/_baseIndexOf.js.map +1 -1
  203. package/dist/node_modules/lodash/_baseIsArguments.js.map +1 -1
  204. package/dist/node_modules/lodash/_baseIsEqual.js.map +1 -1
  205. package/dist/node_modules/lodash/_baseIsEqualDeep.js.map +1 -1
  206. package/dist/node_modules/lodash/_baseIsMatch.js.map +1 -1
  207. package/dist/node_modules/lodash/_baseIsNaN.js.map +1 -1
  208. package/dist/node_modules/lodash/_baseIsNative.js.map +1 -1
  209. package/dist/node_modules/lodash/_baseIsTypedArray.js.map +1 -1
  210. package/dist/node_modules/lodash/_baseIteratee.js.map +1 -1
  211. package/dist/node_modules/lodash/_baseKeys.js.map +1 -1
  212. package/dist/node_modules/lodash/_baseLt.js.map +1 -1
  213. package/dist/node_modules/lodash/_baseMap.js.map +1 -1
  214. package/dist/node_modules/lodash/_baseMatches.js.map +1 -1
  215. package/dist/node_modules/lodash/_baseMatchesProperty.js.map +1 -1
  216. package/dist/node_modules/lodash/_baseOrderBy.js.map +1 -1
  217. package/dist/node_modules/lodash/_baseProperty.js.map +1 -1
  218. package/dist/node_modules/lodash/_basePropertyDeep.js.map +1 -1
  219. package/dist/node_modules/lodash/_baseRange.js.map +1 -1
  220. package/dist/node_modules/lodash/_baseRest.js.map +1 -1
  221. package/dist/node_modules/lodash/_baseSetToString.js.map +1 -1
  222. package/dist/node_modules/lodash/_baseSlice.js.map +1 -1
  223. package/dist/node_modules/lodash/_baseSome.js.map +1 -1
  224. package/dist/node_modules/lodash/_baseSortBy.js.map +1 -1
  225. package/dist/node_modules/lodash/_baseTimes.js.map +1 -1
  226. package/dist/node_modules/lodash/_baseToString.js.map +1 -1
  227. package/dist/node_modules/lodash/_baseTrim.js.map +1 -1
  228. package/dist/node_modules/lodash/_baseUnary.js.map +1 -1
  229. package/dist/node_modules/lodash/_baseUniq.js.map +1 -1
  230. package/dist/node_modules/lodash/_cacheHas.js.map +1 -1
  231. package/dist/node_modules/lodash/_castPath.js.map +1 -1
  232. package/dist/node_modules/lodash/_castSlice.js.map +1 -1
  233. package/dist/node_modules/lodash/_compareAscending.js.map +1 -1
  234. package/dist/node_modules/lodash/_compareMultiple.js.map +1 -1
  235. package/dist/node_modules/lodash/_coreJsData.js.map +1 -1
  236. package/dist/node_modules/lodash/_createBaseEach.js.map +1 -1
  237. package/dist/node_modules/lodash/_createBaseFor.js.map +1 -1
  238. package/dist/node_modules/lodash/_createCaseFirst.js.map +1 -1
  239. package/dist/node_modules/lodash/_createFind.js.map +1 -1
  240. package/dist/node_modules/lodash/_createRange.js.map +1 -1
  241. package/dist/node_modules/lodash/_createSet.js.map +1 -1
  242. package/dist/node_modules/lodash/_defineProperty.js.map +1 -1
  243. package/dist/node_modules/lodash/_equalArrays.js.map +1 -1
  244. package/dist/node_modules/lodash/_equalByTag.js.map +1 -1
  245. package/dist/node_modules/lodash/_equalObjects.js.map +1 -1
  246. package/dist/node_modules/lodash/_freeGlobal.js.map +1 -1
  247. package/dist/node_modules/lodash/_getAllKeys.js.map +1 -1
  248. package/dist/node_modules/lodash/_getMapData.js.map +1 -1
  249. package/dist/node_modules/lodash/_getMatchData.js.map +1 -1
  250. package/dist/node_modules/lodash/_getNative.js.map +1 -1
  251. package/dist/node_modules/lodash/_getPrototype.js.map +1 -1
  252. package/dist/node_modules/lodash/_getRawTag.js.map +1 -1
  253. package/dist/node_modules/lodash/_getSymbols.js.map +1 -1
  254. package/dist/node_modules/lodash/_getTag.js.map +1 -1
  255. package/dist/node_modules/lodash/_getValue.js.map +1 -1
  256. package/dist/node_modules/lodash/_hasPath.js.map +1 -1
  257. package/dist/node_modules/lodash/_hasUnicode.js.map +1 -1
  258. package/dist/node_modules/lodash/_hashClear.js.map +1 -1
  259. package/dist/node_modules/lodash/_hashDelete.js.map +1 -1
  260. package/dist/node_modules/lodash/_hashGet.js.map +1 -1
  261. package/dist/node_modules/lodash/_hashHas.js.map +1 -1
  262. package/dist/node_modules/lodash/_hashSet.js.map +1 -1
  263. package/dist/node_modules/lodash/_isFlattenable.js.map +1 -1
  264. package/dist/node_modules/lodash/_isIndex.js.map +1 -1
  265. package/dist/node_modules/lodash/_isIterateeCall.js.map +1 -1
  266. package/dist/node_modules/lodash/_isKey.js.map +1 -1
  267. package/dist/node_modules/lodash/_isKeyable.js.map +1 -1
  268. package/dist/node_modules/lodash/_isMasked.js.map +1 -1
  269. package/dist/node_modules/lodash/_isPrototype.js.map +1 -1
  270. package/dist/node_modules/lodash/_isStrictComparable.js.map +1 -1
  271. package/dist/node_modules/lodash/_listCacheClear.js.map +1 -1
  272. package/dist/node_modules/lodash/_listCacheDelete.js.map +1 -1
  273. package/dist/node_modules/lodash/_listCacheGet.js.map +1 -1
  274. package/dist/node_modules/lodash/_listCacheHas.js.map +1 -1
  275. package/dist/node_modules/lodash/_listCacheSet.js.map +1 -1
  276. package/dist/node_modules/lodash/_mapCacheClear.js.map +1 -1
  277. package/dist/node_modules/lodash/_mapCacheDelete.js.map +1 -1
  278. package/dist/node_modules/lodash/_mapCacheGet.js.map +1 -1
  279. package/dist/node_modules/lodash/_mapCacheHas.js.map +1 -1
  280. package/dist/node_modules/lodash/_mapCacheSet.js.map +1 -1
  281. package/dist/node_modules/lodash/_mapToArray.js.map +1 -1
  282. package/dist/node_modules/lodash/_matchesStrictComparable.js.map +1 -1
  283. package/dist/node_modules/lodash/_memoizeCapped.js.map +1 -1
  284. package/dist/node_modules/lodash/_nativeCreate.js.map +1 -1
  285. package/dist/node_modules/lodash/_nativeKeys.js.map +1 -1
  286. package/dist/node_modules/lodash/_nodeUtil.js.map +1 -1
  287. package/dist/node_modules/lodash/_objectToString.js.map +1 -1
  288. package/dist/node_modules/lodash/_overArg.js.map +1 -1
  289. package/dist/node_modules/lodash/_overRest.js.map +1 -1
  290. package/dist/node_modules/lodash/_root.js.map +1 -1
  291. package/dist/node_modules/lodash/_setCacheAdd.js.map +1 -1
  292. package/dist/node_modules/lodash/_setCacheHas.js.map +1 -1
  293. package/dist/node_modules/lodash/_setToArray.js.map +1 -1
  294. package/dist/node_modules/lodash/_setToString.js.map +1 -1
  295. package/dist/node_modules/lodash/_shortOut.js.map +1 -1
  296. package/dist/node_modules/lodash/_stackClear.js.map +1 -1
  297. package/dist/node_modules/lodash/_stackDelete.js.map +1 -1
  298. package/dist/node_modules/lodash/_stackGet.js.map +1 -1
  299. package/dist/node_modules/lodash/_stackHas.js.map +1 -1
  300. package/dist/node_modules/lodash/_stackSet.js.map +1 -1
  301. package/dist/node_modules/lodash/_strictIndexOf.js.map +1 -1
  302. package/dist/node_modules/lodash/_stringToArray.js.map +1 -1
  303. package/dist/node_modules/lodash/_stringToPath.js.map +1 -1
  304. package/dist/node_modules/lodash/_toKey.js.map +1 -1
  305. package/dist/node_modules/lodash/_toSource.js.map +1 -1
  306. package/dist/node_modules/lodash/_trimmedEndIndex.js.map +1 -1
  307. package/dist/node_modules/lodash/_unicodeToArray.js.map +1 -1
  308. package/dist/node_modules/lodash/constant.js.map +1 -1
  309. package/dist/node_modules/lodash/debounce.js.map +1 -1
  310. package/dist/node_modules/lodash/eq.js.map +1 -1
  311. package/dist/node_modules/lodash/every.js.map +1 -1
  312. package/dist/node_modules/lodash/find.js.map +1 -1
  313. package/dist/node_modules/lodash/findIndex.js.map +1 -1
  314. package/dist/node_modules/lodash/flatMap.js.map +1 -1
  315. package/dist/node_modules/lodash/get.js.map +1 -1
  316. package/dist/node_modules/lodash/hasIn.js.map +1 -1
  317. package/dist/node_modules/lodash/identity.js.map +1 -1
  318. package/dist/node_modules/lodash/isArguments.js.map +1 -1
  319. package/dist/node_modules/lodash/isArray.js.map +1 -1
  320. package/dist/node_modules/lodash/isArrayLike.js.map +1 -1
  321. package/dist/node_modules/lodash/isBoolean.js.map +1 -1
  322. package/dist/node_modules/lodash/isBuffer.js.map +1 -1
  323. package/dist/node_modules/lodash/isEqual.js.map +1 -1
  324. package/dist/node_modules/lodash/isFunction.js.map +1 -1
  325. package/dist/node_modules/lodash/isLength.js.map +1 -1
  326. package/dist/node_modules/lodash/isNaN.js.map +1 -1
  327. package/dist/node_modules/lodash/isNil.js.map +1 -1
  328. package/dist/node_modules/lodash/isNumber.js.map +1 -1
  329. package/dist/node_modules/lodash/isObject.js.map +1 -1
  330. package/dist/node_modules/lodash/isObjectLike.js.map +1 -1
  331. package/dist/node_modules/lodash/isPlainObject.js.map +1 -1
  332. package/dist/node_modules/lodash/isString.js.map +1 -1
  333. package/dist/node_modules/lodash/isSymbol.js.map +1 -1
  334. package/dist/node_modules/lodash/isTypedArray.js.map +1 -1
  335. package/dist/node_modules/lodash/keys.js.map +1 -1
  336. package/dist/node_modules/lodash/last.js.map +1 -1
  337. package/dist/node_modules/lodash/map.js.map +1 -1
  338. package/dist/node_modules/lodash/mapValues.js.map +1 -1
  339. package/dist/node_modules/lodash/max.js.map +1 -1
  340. package/dist/node_modules/lodash/memoize.js.map +1 -1
  341. package/dist/node_modules/lodash/min.js.map +1 -1
  342. package/dist/node_modules/lodash/noop.js.map +1 -1
  343. package/dist/node_modules/lodash/now.js.map +1 -1
  344. package/dist/node_modules/lodash/property.js.map +1 -1
  345. package/dist/node_modules/lodash/range.js.map +1 -1
  346. package/dist/node_modules/lodash/some.js.map +1 -1
  347. package/dist/node_modules/lodash/sortBy.js.map +1 -1
  348. package/dist/node_modules/lodash/stubArray.js.map +1 -1
  349. package/dist/node_modules/lodash/stubFalse.js.map +1 -1
  350. package/dist/node_modules/lodash/throttle.js.map +1 -1
  351. package/dist/node_modules/lodash/toFinite.js.map +1 -1
  352. package/dist/node_modules/lodash/toInteger.js.map +1 -1
  353. package/dist/node_modules/lodash/toNumber.js.map +1 -1
  354. package/dist/node_modules/lodash/toString.js.map +1 -1
  355. package/dist/node_modules/lodash/uniqBy.js.map +1 -1
  356. package/dist/node_modules/lodash/upperFirst.js.map +1 -1
  357. package/dist/node_modules/object-assign/index.js.map +1 -1
  358. package/dist/node_modules/prop-types/checkPropTypes.js.map +1 -1
  359. package/dist/node_modules/prop-types/factoryWithThrowingShims.js.map +1 -1
  360. package/dist/node_modules/prop-types/factoryWithTypeCheckers.js.map +1 -1
  361. package/dist/node_modules/prop-types/index.js.map +1 -1
  362. package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js.map +1 -1
  363. package/dist/node_modules/prop-types/lib/has.js.map +1 -1
  364. package/dist/node_modules/prop-types/node_modules/react-is/cjs/react-is.development.js.map +1 -1
  365. package/dist/node_modules/prop-types/node_modules/react-is/cjs/react-is.production.min.js.map +1 -1
  366. package/dist/node_modules/prop-types/node_modules/react-is/index.js.map +1 -1
  367. package/dist/node_modules/react-is/cjs/react-is.development.js.map +1 -1
  368. package/dist/node_modules/react-is/cjs/react-is.production.min.js.map +1 -1
  369. package/dist/node_modules/react-is/index.js.map +1 -1
  370. package/dist/node_modules/react-smooth/es6/Animate.js +2 -2
  371. package/dist/node_modules/react-smooth/es6/Animate.js.map +1 -1
  372. package/dist/node_modules/react-smooth/es6/AnimateManager.js.map +1 -1
  373. package/dist/node_modules/react-smooth/es6/configUpdate.js.map +1 -1
  374. package/dist/node_modules/react-smooth/es6/easing.js.map +1 -1
  375. package/dist/node_modules/react-smooth/es6/setRafTimeout.js.map +1 -1
  376. package/dist/node_modules/react-smooth/es6/util.js.map +1 -1
  377. package/dist/node_modules/recharts/es6/cartesian/Bar.js +9 -9
  378. package/dist/node_modules/recharts/es6/cartesian/Bar.js.map +1 -1
  379. package/dist/node_modules/recharts/es6/cartesian/Brush.js +12 -12
  380. package/dist/node_modules/recharts/es6/cartesian/Brush.js.map +1 -1
  381. package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js +7 -7
  382. package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js.map +1 -1
  383. package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js +13 -13
  384. package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js.map +1 -1
  385. package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js +4 -4
  386. package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js.map +1 -1
  387. package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js +3 -3
  388. package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js.map +1 -1
  389. package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js +3 -3
  390. package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js.map +1 -1
  391. package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js +4 -4
  392. package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js.map +1 -1
  393. package/dist/node_modules/recharts/es6/cartesian/XAxis.js +3 -3
  394. package/dist/node_modules/recharts/es6/cartesian/XAxis.js.map +1 -1
  395. package/dist/node_modules/recharts/es6/cartesian/YAxis.js +3 -3
  396. package/dist/node_modules/recharts/es6/cartesian/YAxis.js.map +1 -1
  397. package/dist/node_modules/recharts/es6/cartesian/getEquidistantTicks.js.map +1 -1
  398. package/dist/node_modules/recharts/es6/cartesian/getTicks.js.map +1 -1
  399. package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js +1 -1
  400. package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js.map +1 -1
  401. package/dist/node_modules/recharts/es6/chart/BarChart.js.map +1 -1
  402. package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js +22 -22
  403. package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js.map +1 -1
  404. package/dist/node_modules/recharts/es6/component/Cell.js.map +1 -1
  405. package/dist/node_modules/recharts/es6/component/Cursor.js +1 -1
  406. package/dist/node_modules/recharts/es6/component/Cursor.js.map +1 -1
  407. package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js +11 -11
  408. package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js.map +1 -1
  409. package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js +6 -6
  410. package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js.map +1 -1
  411. package/dist/node_modules/recharts/es6/component/Label.js +14 -14
  412. package/dist/node_modules/recharts/es6/component/Label.js.map +1 -1
  413. package/dist/node_modules/recharts/es6/component/LabelList.js +6 -6
  414. package/dist/node_modules/recharts/es6/component/LabelList.js.map +1 -1
  415. package/dist/node_modules/recharts/es6/component/Legend.js +5 -5
  416. package/dist/node_modules/recharts/es6/component/Legend.js.map +1 -1
  417. package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js +3 -3
  418. package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js.map +1 -1
  419. package/dist/node_modules/recharts/es6/component/Text.js +2 -2
  420. package/dist/node_modules/recharts/es6/component/Text.js.map +1 -1
  421. package/dist/node_modules/recharts/es6/component/Tooltip.js +3 -3
  422. package/dist/node_modules/recharts/es6/component/Tooltip.js.map +1 -1
  423. package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js +2 -2
  424. package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js.map +1 -1
  425. package/dist/node_modules/recharts/es6/container/Layer.js +2 -2
  426. package/dist/node_modules/recharts/es6/container/Layer.js.map +1 -1
  427. package/dist/node_modules/recharts/es6/container/Surface.js +2 -2
  428. package/dist/node_modules/recharts/es6/container/Surface.js.map +1 -1
  429. package/dist/node_modules/recharts/es6/context/chartLayoutContext.js +2 -2
  430. package/dist/node_modules/recharts/es6/context/chartLayoutContext.js.map +1 -1
  431. package/dist/node_modules/recharts/es6/shape/Cross.js +1 -1
  432. package/dist/node_modules/recharts/es6/shape/Cross.js.map +1 -1
  433. package/dist/node_modules/recharts/es6/shape/Curve.js +1 -1
  434. package/dist/node_modules/recharts/es6/shape/Curve.js.map +1 -1
  435. package/dist/node_modules/recharts/es6/shape/Dot.js +1 -1
  436. package/dist/node_modules/recharts/es6/shape/Dot.js.map +1 -1
  437. package/dist/node_modules/recharts/es6/shape/Rectangle.js +4 -4
  438. package/dist/node_modules/recharts/es6/shape/Rectangle.js.map +1 -1
  439. package/dist/node_modules/recharts/es6/shape/Sector.js +1 -1
  440. package/dist/node_modules/recharts/es6/shape/Sector.js.map +1 -1
  441. package/dist/node_modules/recharts/es6/shape/Symbols.js +1 -1
  442. package/dist/node_modules/recharts/es6/shape/Symbols.js.map +1 -1
  443. package/dist/node_modules/recharts/es6/shape/Trapezoid.js +4 -4
  444. package/dist/node_modules/recharts/es6/shape/Trapezoid.js.map +1 -1
  445. package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js +9 -9
  446. package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js.map +1 -1
  447. package/dist/node_modules/recharts/es6/util/BarUtils.js +1 -1
  448. package/dist/node_modules/recharts/es6/util/BarUtils.js.map +1 -1
  449. package/dist/node_modules/recharts/es6/util/CartesianUtils.js +1 -1
  450. package/dist/node_modules/recharts/es6/util/CartesianUtils.js.map +1 -1
  451. package/dist/node_modules/recharts/es6/util/ChartUtils.js.map +1 -1
  452. package/dist/node_modules/recharts/es6/util/CssPrefixUtils.js.map +1 -1
  453. package/dist/node_modules/recharts/es6/util/DOMUtils.js.map +1 -1
  454. package/dist/node_modules/recharts/es6/util/DataUtils.js.map +1 -1
  455. package/dist/node_modules/recharts/es6/util/DetectReferenceElementsDomain.js.map +1 -1
  456. package/dist/node_modules/recharts/es6/util/Events.js.map +1 -1
  457. package/dist/node_modules/recharts/es6/util/Global.js.map +1 -1
  458. package/dist/node_modules/recharts/es6/util/IfOverflowMatches.js.map +1 -1
  459. package/dist/node_modules/recharts/es6/util/LogUtils.js.map +1 -1
  460. package/dist/node_modules/recharts/es6/util/PolarUtils.js.map +1 -1
  461. package/dist/node_modules/recharts/es6/util/ReactUtils.js +1 -1
  462. package/dist/node_modules/recharts/es6/util/ReactUtils.js.map +1 -1
  463. package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js +1 -1
  464. package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js.map +1 -1
  465. package/dist/node_modules/recharts/es6/util/ShallowEqual.js.map +1 -1
  466. package/dist/node_modules/recharts/es6/util/TickUtils.js.map +1 -1
  467. package/dist/node_modules/recharts/es6/util/calculateViewBox.js.map +1 -1
  468. package/dist/node_modules/recharts/es6/util/cursor/getCursorPoints.js.map +1 -1
  469. package/dist/node_modules/recharts/es6/util/cursor/getCursorRectangle.js.map +1 -1
  470. package/dist/node_modules/recharts/es6/util/cursor/getRadialCursorPoints.js.map +1 -1
  471. package/dist/node_modules/recharts/es6/util/getEveryNthWithCondition.js.map +1 -1
  472. package/dist/node_modules/recharts/es6/util/getLegendProps.js.map +1 -1
  473. package/dist/node_modules/recharts/es6/util/isDomainSpecifiedByUser.js.map +1 -1
  474. package/dist/node_modules/recharts/es6/util/payload/getUniqPayload.js.map +1 -1
  475. package/dist/node_modules/recharts/es6/util/tooltip/translate.js.map +1 -1
  476. package/dist/node_modules/recharts/es6/util/types.js +1 -1
  477. package/dist/node_modules/recharts/es6/util/types.js.map +1 -1
  478. package/dist/node_modules/recharts-scale/es6/getNiceTickValues.js.map +1 -1
  479. package/dist/node_modules/recharts-scale/es6/util/arithmetic.js.map +1 -1
  480. package/dist/node_modules/recharts-scale/es6/util/utils.js.map +1 -1
  481. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1 -1
  482. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -1
  483. package/dist/node_modules/tiny-invariant/dist/esm/tiny-invariant.js.map +1 -1
  484. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  //#region \0rolldown/runtime.js
2
- var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescriptor, r = Object.getOwnPropertyNames, i = Object.getPrototypeOf, a = Object.prototype.hasOwnProperty, o = (e, t) => () => (t || e((t = { exports: {} }).exports, t), t.exports), s = (e, n) => {
2
+ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescriptor, r = Object.getOwnPropertyNames, i = Object.getPrototypeOf, a = Object.prototype.hasOwnProperty, o = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), s = (e, n) => {
3
3
  let r = {};
4
4
  for (var i in e) t(r, i, {
5
5
  get: e[i],
@@ -1 +1 @@
1
- {"version":3,"file":"EcoImpactHubRoot.js","names":[],"sources":["../../src/ecoimpacthub/EcoImpactHubRoot.tsx"],"sourcesContent":["/**\n * EcoImpactHub Root Component\n * @module ecoimpacthub\n *\n * Host-contract entry point. Registers the product's sidebar nav (eight sections\n * that map 1:1 to the wspace-ecoimpacthub-svc `eco*` backend) and mounts the\n * routed pages inside the shared QueryClient + FeatureFlag providers.\n */\n\nimport type { FC } from 'react';\nimport { useCallback, useEffect } from 'react';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n LayoutDashboard,\n MapPin,\n Gauge,\n PawPrint,\n Binoculars,\n Trees,\n Factory,\n FileText,\n} from 'lucide-react';\nimport { EcoImpactHubProvider } from './context/EcoImpactHubContext';\nimport { EcoImpactHubRoutes } from './EcoImpactHubRoutes';\nimport { joinPath } from './utils/navigation';\nimport type { EcoImpactHubRootProps, NavItem } from './types';\n\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 5 * 60 * 1000,\n retry: 1,\n refetchOnWindowFocus: false,\n },\n },\n});\n\nexport const EcoImpactHubRoot: FC<EcoImpactHubRootProps> = (props) => {\n const { registerNavItems, registerFooterItems, basePath = '/' } = props;\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n // Register navigation items with the shell on mount. Ids/paths/orders match\n // the app-shell static NavRegistration block so the two are a single,\n // consistent source of truth.\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: 'ecoimpacthub-dashboard',\n label: t('ecoimpacthub.nav.dashboard', 'Dashboard'),\n path: joinPath(basePath, ''),\n icon: <LayoutDashboard size={20} />,\n order: 0,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-sites',\n label: t('ecoimpacthub.nav.sites', 'Sites'),\n path: joinPath(basePath, 'sites'),\n icon: <MapPin size={20} />,\n order: 1,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-monitoring',\n label: t('ecoimpacthub.nav.monitoring', 'Monitoring'),\n path: joinPath(basePath, 'monitoring'),\n icon: <Gauge size={20} />,\n order: 2,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-species',\n label: t('ecoimpacthub.nav.species', 'Species'),\n path: joinPath(basePath, 'species'),\n icon: <PawPrint size={20} />,\n order: 3,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-observations',\n label: t('ecoimpacthub.nav.observations', 'Observations'),\n path: joinPath(basePath, 'observations'),\n icon: <Binoculars size={20} />,\n order: 4,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-habitat',\n label: t('ecoimpacthub.nav.habitat', 'Habitat'),\n path: joinPath(basePath, 'habitat'),\n icon: <Trees size={20} />,\n order: 5,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-carbon',\n label: t('ecoimpacthub.nav.carbon', 'Carbon'),\n path: joinPath(basePath, 'carbon'),\n icon: <Factory size={20} />,\n order: 6,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-reports',\n label: t('ecoimpacthub.nav.reports', 'Reports'),\n path: joinPath(basePath, 'reports'),\n icon: <FileText size={20} />,\n order: 7,\n group: 'products',\n },\n ];\n\n return registerNavItems(navItems);\n }, [registerNavItems, basePath, t]);\n\n useEffect(() => {\n if (!registerFooterItems) return;\n return registerFooterItems([\n {\n id: 'ecoimpacthub-status',\n label: t('ecoimpacthub.footer.ready', 'EcoImpactHub Ready'),\n type: 'status',\n section: 'left',\n order: 10,\n },\n ]);\n }, [registerFooterItems, t]);\n\n return (\n <QueryClientProvider client={queryClient}>\n <FeatureFlagProvider workspaceId={null} gateway=\"global\" defaultEnabled={true}>\n <EcoImpactHubProvider {...props}>\n <EcoImpactHubRoutes />\n </EcoImpactHubProvider>\n </FeatureFlagProvider>\n </QueryClientProvider>\n );\n};\n"],"mappings":";;;;;;;;;;AA6BA,IAAM,IAAc,IAAI,EAAY,EAClC,gBAAgB,EACd,SAAS;CACP,WAAW,MAAS;CACpB,OAAO;CACP,sBAAsB;CACvB,EACF,EACF,CAAC,EAEW,KAA+C,MAAU;CACpE,IAAM,EAAE,qBAAkB,wBAAqB,cAAW,QAAQ,GAC5D,EAAE,GAAG,MAAc,GAAS,EAC5B,IAAI,GACP,GAAa,MAA6B;EACzC,IAAM,IAAQ,EAAU,EAAI;AAC5B,SAAO,MAAU,IAAM,IAAW;IAEpC,CAAC,EAAU,CACZ;AA2FD,QAtFA,QAAgB;AACT,QAqEL,QAAO,EAnEqB;GAC1B;IACE,IAAI;IACJ,OAAO,EAAE,8BAA8B,YAAY;IACnD,MAAM,EAAS,GAAU,GAAG;IAC5B,MAAM,kBAAC,GAAD,EAAiB,MAAM,IAAM,CAAA;IACnC,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,0BAA0B,QAAQ;IAC3C,MAAM,EAAS,GAAU,QAAQ;IACjC,MAAM,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;IAC1B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,+BAA+B,aAAa;IACrD,MAAM,EAAS,GAAU,aAAa;IACtC,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,4BAA4B,UAAU;IAC/C,MAAM,EAAS,GAAU,UAAU;IACnC,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;IAC5B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,iCAAiC,eAAe;IACzD,MAAM,EAAS,GAAU,eAAe;IACxC,MAAM,kBAAC,GAAD,EAAY,MAAM,IAAM,CAAA;IAC9B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,4BAA4B,UAAU;IAC/C,MAAM,EAAS,GAAU,UAAU;IACnC,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,2BAA2B,SAAS;IAC7C,MAAM,EAAS,GAAU,SAAS;IAClC,MAAM,kBAAC,GAAD,EAAS,MAAM,IAAM,CAAA;IAC3B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,4BAA4B,UAAU;IAC/C,MAAM,EAAS,GAAU,UAAU;IACnC,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;IAC5B,OAAO;IACP,OAAO;IACR;GACF,CAEgC;IAChC;EAAC;EAAkB;EAAU;EAAE,CAAC,EAEnC,QAAgB;AACT,QACL,QAAO,EAAoB,CACzB;GACE,IAAI;GACJ,OAAO,EAAE,6BAA6B,qBAAqB;GAC3D,MAAM;GACN,SAAS;GACT,OAAO;GACR,CACF,CAAC;IACD,CAAC,GAAqB,EAAE,CAAC,EAG1B,kBAAC,GAAD;EAAqB,QAAQ;YAC3B,kBAAC,GAAD;GAAqB,aAAa;GAAM,SAAQ;GAAS,gBAAgB;aACvE,kBAAC,GAAD;IAAsB,GAAI;cACxB,kBAAC,GAAD,EAAsB,CAAA;IACD,CAAA;GACH,CAAA;EACF,CAAA"}
1
+ {"version":3,"file":"EcoImpactHubRoot.js","names":[],"sources":["../../src/ecoimpacthub/EcoImpactHubRoot.tsx"],"sourcesContent":["/**\n * EcoImpactHub Root Component\n * @module ecoimpacthub\n *\n * Host-contract entry point. Registers the product's sidebar nav (eight sections\n * that map 1:1 to the wspace-ecoimpacthub-svc `eco*` backend) and mounts the\n * routed pages inside the shared QueryClient + FeatureFlag providers.\n */\n\nimport type { FC } from 'react';\nimport { useCallback, useEffect } from 'react';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n LayoutDashboard,\n MapPin,\n Gauge,\n PawPrint,\n Binoculars,\n Trees,\n Factory,\n FileText,\n} from 'lucide-react';\nimport { EcoImpactHubProvider } from './context/EcoImpactHubContext';\nimport { EcoImpactHubRoutes } from './EcoImpactHubRoutes';\nimport { joinPath } from './utils/navigation';\nimport type { EcoImpactHubRootProps, NavItem } from './types';\n\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 5 * 60 * 1000,\n retry: 1,\n refetchOnWindowFocus: false,\n },\n },\n});\n\nexport const EcoImpactHubRoot: FC<EcoImpactHubRootProps> = (props) => {\n const { registerNavItems, registerFooterItems, basePath = '/' } = props;\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n // Register navigation items with the shell on mount. Ids/paths/orders match\n // the app-shell static NavRegistration block so the two are a single,\n // consistent source of truth.\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: 'ecoimpacthub-dashboard',\n label: t('ecoimpacthub.nav.dashboard', 'Dashboard'),\n path: joinPath(basePath, ''),\n icon: <LayoutDashboard size={20} />,\n order: 0,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-sites',\n label: t('ecoimpacthub.nav.sites', 'Sites'),\n path: joinPath(basePath, 'sites'),\n icon: <MapPin size={20} />,\n order: 1,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-monitoring',\n label: t('ecoimpacthub.nav.monitoring', 'Monitoring'),\n path: joinPath(basePath, 'monitoring'),\n icon: <Gauge size={20} />,\n order: 2,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-species',\n label: t('ecoimpacthub.nav.species', 'Species'),\n path: joinPath(basePath, 'species'),\n icon: <PawPrint size={20} />,\n order: 3,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-observations',\n label: t('ecoimpacthub.nav.observations', 'Observations'),\n path: joinPath(basePath, 'observations'),\n icon: <Binoculars size={20} />,\n order: 4,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-habitat',\n label: t('ecoimpacthub.nav.habitat', 'Habitat'),\n path: joinPath(basePath, 'habitat'),\n icon: <Trees size={20} />,\n order: 5,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-carbon',\n label: t('ecoimpacthub.nav.carbon', 'Carbon'),\n path: joinPath(basePath, 'carbon'),\n icon: <Factory size={20} />,\n order: 6,\n group: 'products',\n },\n {\n id: 'ecoimpacthub-reports',\n label: t('ecoimpacthub.nav.reports', 'Reports'),\n path: joinPath(basePath, 'reports'),\n icon: <FileText size={20} />,\n order: 7,\n group: 'products',\n },\n ];\n\n return registerNavItems(navItems);\n }, [registerNavItems, basePath, t]);\n\n useEffect(() => {\n if (!registerFooterItems) return;\n return registerFooterItems([\n {\n id: 'ecoimpacthub-status',\n label: t('ecoimpacthub.footer.ready', 'EcoImpactHub Ready'),\n type: 'status',\n section: 'left',\n order: 10,\n },\n ]);\n }, [registerFooterItems, t]);\n\n return (\n <QueryClientProvider client={queryClient}>\n <FeatureFlagProvider workspaceId={null} gateway=\"global\" defaultEnabled={true}>\n <EcoImpactHubProvider {...props}>\n <EcoImpactHubRoutes />\n </EcoImpactHubProvider>\n </FeatureFlagProvider>\n </QueryClientProvider>\n );\n};\n"],"mappings":";;;;;;;;;;AA6BA,IAAM,IAAc,IAAI,EAAY,EAClC,gBAAgB,EACd,SAAS;CACP,WAAW,MAAS;CACpB,OAAO;CACP,sBAAsB;AACxB,EACF,EACF,CAAC,GAEY,KAA+C,MAAU;CACpE,IAAM,EAAE,qBAAkB,wBAAqB,cAAW,QAAQ,GAC5D,EAAE,GAAG,MAAc,EAAQ,GAC3B,IAAI,GACP,GAAa,MAA6B;EACzC,IAAM,IAAQ,EAAU,CAAG;EAC3B,OAAO,MAAU,IAAM,IAAW;CACpC,GACA,CAAC,CAAS,CACZ;CA2FA,OAtFA,QAAgB;EACT,OAqEL,OAAO,EAAiB;GAlEtB;IACE,IAAI;IACJ,OAAO,EAAE,8BAA8B,WAAW;IAClD,MAAM,EAAS,GAAU,EAAE;IAC3B,MAAM,kBAAC,GAAD,EAAiB,MAAM,GAAK,CAAA;IAClC,OAAO;IACP,OAAO;GACT;GACA;IACE,IAAI;IACJ,OAAO,EAAE,0BAA0B,OAAO;IAC1C,MAAM,EAAS,GAAU,OAAO;IAChC,MAAM,kBAAC,GAAD,EAAQ,MAAM,GAAK,CAAA;IACzB,OAAO;IACP,OAAO;GACT;GACA;IACE,IAAI;IACJ,OAAO,EAAE,+BAA+B,YAAY;IACpD,MAAM,EAAS,GAAU,YAAY;IACrC,MAAM,kBAAC,GAAD,EAAO,MAAM,GAAK,CAAA;IACxB,OAAO;IACP,OAAO;GACT;GACA;IACE,IAAI;IACJ,OAAO,EAAE,4BAA4B,SAAS;IAC9C,MAAM,EAAS,GAAU,SAAS;IAClC,MAAM,kBAAC,GAAD,EAAU,MAAM,GAAK,CAAA;IAC3B,OAAO;IACP,OAAO;GACT;GACA;IACE,IAAI;IACJ,OAAO,EAAE,iCAAiC,cAAc;IACxD,MAAM,EAAS,GAAU,cAAc;IACvC,MAAM,kBAAC,GAAD,EAAY,MAAM,GAAK,CAAA;IAC7B,OAAO;IACP,OAAO;GACT;GACA;IACE,IAAI;IACJ,OAAO,EAAE,4BAA4B,SAAS;IAC9C,MAAM,EAAS,GAAU,SAAS;IAClC,MAAM,kBAAC,GAAD,EAAO,MAAM,GAAK,CAAA;IACxB,OAAO;IACP,OAAO;GACT;GACA;IACE,IAAI;IACJ,OAAO,EAAE,2BAA2B,QAAQ;IAC5C,MAAM,EAAS,GAAU,QAAQ;IACjC,MAAM,kBAAC,GAAD,EAAS,MAAM,GAAK,CAAA;IAC1B,OAAO;IACP,OAAO;GACT;GACA;IACE,IAAI;IACJ,OAAO,EAAE,4BAA4B,SAAS;IAC9C,MAAM,EAAS,GAAU,SAAS;IAClC,MAAM,kBAAC,GAAD,EAAU,MAAM,GAAK,CAAA;IAC3B,OAAO;IACP,OAAO;GACT;EAGsB,CAAQ;CAClC,GAAG;EAAC;EAAkB;EAAU;CAAC,CAAC,GAElC,QAAgB;EACT,OACL,OAAO,EAAoB,CACzB;GACE,IAAI;GACJ,OAAO,EAAE,6BAA6B,oBAAoB;GAC1D,MAAM;GACN,SAAS;GACT,OAAO;EACT,CACF,CAAC;CACH,GAAG,CAAC,GAAqB,CAAC,CAAC,GAGzB,kBAAC,GAAD;EAAqB,QAAQ;YAC3B,kBAAC,GAAD;GAAqB,aAAa;GAAM,SAAQ;GAAS,gBAAgB;aACvE,kBAAC,GAAD;IAAsB,GAAI;cACxB,kBAAC,GAAD,CAAqB,CAAA;GACD,CAAA;EACH,CAAA;CACF,CAAA;AAEzB"}
@@ -1 +1 @@
1
- {"version":3,"file":"EcoImpactHubRoutes.js","names":[],"sources":["../../src/ecoimpacthub/EcoImpactHubRoutes.tsx"],"sourcesContent":["/**\n * EcoImpactHub Routes\n * @module ecoimpacthub\n *\n * Domain routes. The dashboard is eager-loaded (primary landing); all other\n * pages are lazy-loaded. Every route maps to a real `eco*` backend capability.\n */\n\nimport { type FC, lazy, Suspense, type ReactNode } from 'react';\nimport { Routes, Route, Navigate, useLocation } from 'react-router-dom';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { useEcoImpactHub } from './context/EcoImpactHubContext';\nimport { FeatureFlagGate } from './components/FeatureFlagGate';\n\n// Eager — primary landing\nimport { DashboardPage } from './pages/DashboardPage';\n\n// Sites (Environmental Monitoring)\nconst SitesPage = lazy(() =>\n import('./pages/sites/SitesPage').then((m) => ({ default: m.SitesPage }))\n);\nconst SiteDetailPage = lazy(() =>\n import('./pages/sites/SiteDetailPage').then((m) => ({ default: m.SiteDetailPage }))\n);\n\n// Monitoring (sensors / measurements / thresholds)\nconst MonitoringPage = lazy(() =>\n import('./pages/monitoring/MonitoringPage').then((m) => ({ default: m.MonitoringPage }))\n);\n\n// Species (Conservation)\nconst SpeciesPage = lazy(() =>\n import('./pages/species/SpeciesPage').then((m) => ({ default: m.SpeciesPage }))\n);\nconst SpeciesDetailPage = lazy(() =>\n import('./pages/species/SpeciesDetailPage').then((m) => ({ default: m.SpeciesDetailPage }))\n);\n\n// Observations (citizen science / field data)\nconst ObservationsPage = lazy(() =>\n import('./pages/observations/ObservationsPage').then((m) => ({ default: m.ObservationsPage }))\n);\n\n// Habitat projects & restoration\nconst HabitatProjectsPage = lazy(() =>\n import('./pages/habitat/HabitatProjectsPage').then((m) => ({ default: m.HabitatProjectsPage }))\n);\nconst HabitatProjectDetailPage = lazy(() =>\n import('./pages/habitat/HabitatProjectDetailPage').then((m) => ({\n default: m.HabitatProjectDetailPage,\n }))\n);\n\n// Carbon ledger / emission factors / reduction targets (Sustainability)\nconst CarbonPage = lazy(() =>\n import('./pages/carbon/CarbonPage').then((m) => ({ default: m.CarbonPage }))\n);\n\n// ESG Reports\nconst ReportsPage = lazy(() =>\n import('./pages/reports/ReportsPage').then((m) => ({ default: m.ReportsPage }))\n);\nconst ReportDetailPage = lazy(() =>\n import('./pages/reports/ReportDetailPage').then((m) => ({ default: m.ReportDetailPage }))\n);\n\nconst PageLoader: FC = () => (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <Spinner size=\"lg\" />\n </div>\n);\n\nfunction gated(flag: string, element: ReactNode): ReactNode {\n return <FeatureFlagGate flag={flag}>{element}</FeatureFlagGate>;\n}\n\nexport const EcoImpactHubRoutes: FC = () => {\n const { basePath, isStandalone } = useEcoImpactHub();\n const location = useLocation();\n\n const normalizedBasePath = basePath === '/' ? '' : (basePath ?? '').replace(/\\/$/, '');\n\n // Guard: only render if the current path matches basePath (integrated mode).\n if (normalizedBasePath && !isStandalone) {\n const pathMatches =\n location.pathname === normalizedBasePath ||\n location.pathname.startsWith(normalizedBasePath + '/');\n if (!pathMatches) {\n return null;\n }\n }\n\n return (\n <div className=\"flex min-h-full flex-col\">\n <Suspense fallback={<PageLoader />}>\n <Routes>\n <Route index element={gated('ecoimpacthub.page.dashboard', <DashboardPage />)} />\n\n <Route path=\"sites\" element={gated('ecoimpacthub.page.sites', <SitesPage />)} />\n <Route path=\"sites/:id\" element={gated('ecoimpacthub.page.sites', <SiteDetailPage />)} />\n\n <Route\n path=\"monitoring\"\n element={gated('ecoimpacthub.page.monitoring', <MonitoringPage />)}\n />\n\n <Route path=\"species\" element={gated('ecoimpacthub.page.species', <SpeciesPage />)} />\n <Route\n path=\"species/:id\"\n element={gated('ecoimpacthub.page.species', <SpeciesDetailPage />)}\n />\n\n <Route\n path=\"observations\"\n element={gated('ecoimpacthub.page.observations', <ObservationsPage />)}\n />\n\n <Route\n path=\"habitat\"\n element={gated('ecoimpacthub.page.habitat', <HabitatProjectsPage />)}\n />\n <Route\n path=\"habitat/:id\"\n element={gated('ecoimpacthub.page.habitat', <HabitatProjectDetailPage />)}\n />\n\n <Route path=\"carbon\" element={gated('ecoimpacthub.page.carbon', <CarbonPage />)} />\n\n <Route path=\"reports\" element={gated('ecoimpacthub.page.reports', <ReportsPage />)} />\n <Route\n path=\"reports/:id\"\n element={gated('ecoimpacthub.page.reports', <ReportDetailPage />)}\n />\n\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"EcoImpactHubRoutes.js","names":[],"sources":["../../src/ecoimpacthub/EcoImpactHubRoutes.tsx"],"sourcesContent":["/**\n * EcoImpactHub Routes\n * @module ecoimpacthub\n *\n * Domain routes. The dashboard is eager-loaded (primary landing); all other\n * pages are lazy-loaded. Every route maps to a real `eco*` backend capability.\n */\n\nimport { type FC, lazy, Suspense, type ReactNode } from 'react';\nimport { Routes, Route, Navigate, useLocation } from 'react-router-dom';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { useEcoImpactHub } from './context/EcoImpactHubContext';\nimport { FeatureFlagGate } from './components/FeatureFlagGate';\n\n// Eager — primary landing\nimport { DashboardPage } from './pages/DashboardPage';\n\n// Sites (Environmental Monitoring)\nconst SitesPage = lazy(() =>\n import('./pages/sites/SitesPage').then((m) => ({ default: m.SitesPage }))\n);\nconst SiteDetailPage = lazy(() =>\n import('./pages/sites/SiteDetailPage').then((m) => ({ default: m.SiteDetailPage }))\n);\n\n// Monitoring (sensors / measurements / thresholds)\nconst MonitoringPage = lazy(() =>\n import('./pages/monitoring/MonitoringPage').then((m) => ({ default: m.MonitoringPage }))\n);\n\n// Species (Conservation)\nconst SpeciesPage = lazy(() =>\n import('./pages/species/SpeciesPage').then((m) => ({ default: m.SpeciesPage }))\n);\nconst SpeciesDetailPage = lazy(() =>\n import('./pages/species/SpeciesDetailPage').then((m) => ({ default: m.SpeciesDetailPage }))\n);\n\n// Observations (citizen science / field data)\nconst ObservationsPage = lazy(() =>\n import('./pages/observations/ObservationsPage').then((m) => ({ default: m.ObservationsPage }))\n);\n\n// Habitat projects & restoration\nconst HabitatProjectsPage = lazy(() =>\n import('./pages/habitat/HabitatProjectsPage').then((m) => ({ default: m.HabitatProjectsPage }))\n);\nconst HabitatProjectDetailPage = lazy(() =>\n import('./pages/habitat/HabitatProjectDetailPage').then((m) => ({\n default: m.HabitatProjectDetailPage,\n }))\n);\n\n// Carbon ledger / emission factors / reduction targets (Sustainability)\nconst CarbonPage = lazy(() =>\n import('./pages/carbon/CarbonPage').then((m) => ({ default: m.CarbonPage }))\n);\n\n// ESG Reports\nconst ReportsPage = lazy(() =>\n import('./pages/reports/ReportsPage').then((m) => ({ default: m.ReportsPage }))\n);\nconst ReportDetailPage = lazy(() =>\n import('./pages/reports/ReportDetailPage').then((m) => ({ default: m.ReportDetailPage }))\n);\n\nconst PageLoader: FC = () => (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <Spinner size=\"lg\" />\n </div>\n);\n\nfunction gated(flag: string, element: ReactNode): ReactNode {\n return <FeatureFlagGate flag={flag}>{element}</FeatureFlagGate>;\n}\n\nexport const EcoImpactHubRoutes: FC = () => {\n const { basePath, isStandalone } = useEcoImpactHub();\n const location = useLocation();\n\n const normalizedBasePath = basePath === '/' ? '' : (basePath ?? '').replace(/\\/$/, '');\n\n // Guard: only render if the current path matches basePath (integrated mode).\n if (normalizedBasePath && !isStandalone) {\n const pathMatches =\n location.pathname === normalizedBasePath ||\n location.pathname.startsWith(normalizedBasePath + '/');\n if (!pathMatches) {\n return null;\n }\n }\n\n return (\n <div className=\"flex min-h-full flex-col\">\n <Suspense fallback={<PageLoader />}>\n <Routes>\n <Route index element={gated('ecoimpacthub.page.dashboard', <DashboardPage />)} />\n\n <Route path=\"sites\" element={gated('ecoimpacthub.page.sites', <SitesPage />)} />\n <Route path=\"sites/:id\" element={gated('ecoimpacthub.page.sites', <SiteDetailPage />)} />\n\n <Route\n path=\"monitoring\"\n element={gated('ecoimpacthub.page.monitoring', <MonitoringPage />)}\n />\n\n <Route path=\"species\" element={gated('ecoimpacthub.page.species', <SpeciesPage />)} />\n <Route\n path=\"species/:id\"\n element={gated('ecoimpacthub.page.species', <SpeciesDetailPage />)}\n />\n\n <Route\n path=\"observations\"\n element={gated('ecoimpacthub.page.observations', <ObservationsPage />)}\n />\n\n <Route\n path=\"habitat\"\n element={gated('ecoimpacthub.page.habitat', <HabitatProjectsPage />)}\n />\n <Route\n path=\"habitat/:id\"\n element={gated('ecoimpacthub.page.habitat', <HabitatProjectDetailPage />)}\n />\n\n <Route path=\"carbon\" element={gated('ecoimpacthub.page.carbon', <CarbonPage />)} />\n\n <Route path=\"reports\" element={gated('ecoimpacthub.page.reports', <ReportsPage />)} />\n <Route\n path=\"reports/:id\"\n element={gated('ecoimpacthub.page.reports', <ReportDetailPage />)}\n />\n\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n </div>\n );\n};\n"],"mappings":";;;;;;;;AAkBA,IAAM,IAAY,QAChB,OAAO,8BAA2B,MAAM,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,CAC1E,GACM,IAAiB,QACrB,OAAO,mCAAgC,MAAM,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CACpF,GAGM,IAAiB,QACrB,OAAO,wCAAqC,MAAM,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CACzF,GAGM,IAAc,QAClB,OAAO,kCAA+B,MAAM,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,CAChF,GACM,IAAoB,QACxB,OAAO,wCAAqC,MAAM,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAC5F,GAGM,IAAmB,QACvB,OAAO,4CAAyC,MAAM,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAC/F,GAGM,IAAsB,QAC1B,OAAO,0CAAuC,MAAM,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,CAChG,GACM,IAA2B,QAC/B,OAAO,+CAA4C,MAAM,OAAO,EAC9D,SAAS,EAAE,yBACb,EAAE,CACJ,GAGM,IAAa,QACjB,OAAO,gCAA6B,MAAM,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,CAC7E,GAGM,IAAc,QAClB,OAAO,kCAA+B,MAAM,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,CAChF,GACM,IAAmB,QACvB,OAAO,uCAAoC,MAAM,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAC1F,GAEM,UACJ,kBAAC,OAAD;CAAK,WAAU;WACb,kBAAC,GAAD,EAAS,MAAK,KAAM,CAAA;AACjB,CAAA;AAGP,SAAS,EAAM,GAAc,GAA+B;CAC1D,OAAO,kBAAC,GAAD;EAAuB;YAAO;CAAyB,CAAA;AAChE;AAEA,IAAa,UAA+B;CAC1C,IAAM,EAAE,aAAU,oBAAiB,EAAgB,GAC7C,IAAW,EAAY,GAEvB,IAAqB,MAAa,MAAM,MAAM,KAAY,IAAI,QAAQ,OAAO,EAAE;CAYrF,OATI,KAAsB,CAAC,KAIrB,EAFF,EAAS,aAAa,KACtB,EAAS,SAAS,WAAW,IAAqB,GAAG,KAE9C,OAKT,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAU,UAAU,kBAAC,GAAD,CAAa,CAAA;aAC/B,kBAAC,GAAD,EAAA,UAAA;IACE,kBAAC,GAAD;KAAO,OAAA;KAAM,SAAS,EAAM,+BAA+B,kBAAC,GAAD,CAAgB,CAAA,CAAC;IAAI,CAAA;IAEhF,kBAAC,GAAD;KAAO,MAAK;KAAQ,SAAS,EAAM,2BAA2B,kBAAC,GAAD,CAAY,CAAA,CAAC;IAAI,CAAA;IAC/E,kBAAC,GAAD;KAAO,MAAK;KAAY,SAAS,EAAM,2BAA2B,kBAAC,GAAD,CAAiB,CAAA,CAAC;IAAI,CAAA;IAExF,kBAAC,GAAD;KACE,MAAK;KACL,SAAS,EAAM,gCAAgC,kBAAC,GAAD,CAAiB,CAAA,CAAC;IAClE,CAAA;IAED,kBAAC,GAAD;KAAO,MAAK;KAAU,SAAS,EAAM,6BAA6B,kBAAC,GAAD,CAAc,CAAA,CAAC;IAAI,CAAA;IACrF,kBAAC,GAAD;KACE,MAAK;KACL,SAAS,EAAM,6BAA6B,kBAAC,GAAD,CAAoB,CAAA,CAAC;IAClE,CAAA;IAED,kBAAC,GAAD;KACE,MAAK;KACL,SAAS,EAAM,kCAAkC,kBAAC,GAAD,CAAmB,CAAA,CAAC;IACtE,CAAA;IAED,kBAAC,GAAD;KACE,MAAK;KACL,SAAS,EAAM,6BAA6B,kBAAC,GAAD,CAAsB,CAAA,CAAC;IACpE,CAAA;IACD,kBAAC,GAAD;KACE,MAAK;KACL,SAAS,EAAM,6BAA6B,kBAAC,GAAD,CAA2B,CAAA,CAAC;IACzE,CAAA;IAED,kBAAC,GAAD;KAAO,MAAK;KAAS,SAAS,EAAM,4BAA4B,kBAAC,GAAD,CAAa,CAAA,CAAC;IAAI,CAAA;IAElF,kBAAC,GAAD;KAAO,MAAK;KAAU,SAAS,EAAM,6BAA6B,kBAAC,GAAD,CAAc,CAAA,CAAC;IAAI,CAAA;IACrF,kBAAC,GAAD;KACE,MAAK;KACL,SAAS,EAAM,6BAA6B,kBAAC,GAAD,CAAmB,CAAA,CAAC;IACjE,CAAA;IAED,kBAAC,GAAD;KAAO,MAAK;KAAI,SAAS,kBAAC,GAAD;MAAU,IAAG;MAAG,SAAA;KAAS,CAAA;IAAI,CAAA;GAChD,EAAA,CAAA;EACA,CAAA;CACP,CAAA;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.js","names":[],"sources":["../../../src/ecoimpacthub/components/DataTable.tsx"],"sourcesContent":["/**\n * DataTable — a lightweight, semantic-token table for list pages.\n * @module ecoimpacthub/components\n *\n * Deliberately minimal (no external table lib). Renders a responsive,\n * horizontally-scrollable table wrapped in a GlassCard. Columns declare a\n * header, a render fn, optional alignment, and optionally a `sortValue` to make\n * the column click-sortable.\n */\n\nimport { useMemo, useState, type ReactNode } from 'react';\nimport { ChevronUp, ChevronDown, ChevronsUpDown } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\nexport interface Column<T> {\n key: string;\n header: ReactNode;\n render: (row: T) => ReactNode;\n align?: 'left' | 'right' | 'center';\n className?: string;\n /** Hide below the `md` breakpoint for a mobile-friendly layout. */\n hideOnMobile?: boolean;\n /** Provide to make this column click-sortable (returns a comparable value). */\n sortValue?: (row: T) => string | number;\n}\n\ninterface DataTableProps<T> {\n columns: Column<T>[];\n rows: T[];\n rowKey: (row: T) => string;\n onRowClick?: (row: T) => void;\n className?: string;\n /** Default sort: a column key + direction. */\n defaultSort?: { key: string; dir: 'asc' | 'desc' };\n}\n\nconst alignClass = {\n left: 'text-left',\n right: 'text-right',\n center: 'text-center',\n} as const;\n\nexport function DataTable<T>({\n columns,\n rows,\n rowKey,\n onRowClick,\n className,\n defaultSort,\n}: DataTableProps<T>) {\n const [sort, setSort] = useState<{ key: string; dir: 'asc' | 'desc' } | null>(\n defaultSort ?? null\n );\n\n const sortedRows = useMemo(() => {\n if (!sort) return rows;\n const col = columns.find((c) => c.key === sort.key);\n if (!col?.sortValue) return rows;\n const dir = sort.dir === 'asc' ? 1 : -1;\n return [...rows].sort((a, b) => {\n const va = col.sortValue!(a);\n const vb = col.sortValue!(b);\n if (va < vb) return -1 * dir;\n if (va > vb) return 1 * dir;\n return 0;\n });\n }, [rows, sort, columns]);\n\n const toggleSort = (key: string) => {\n setSort((prev) =>\n prev?.key === key ? { key, dir: prev.dir === 'asc' ? 'desc' : 'asc' } : { key, dir: 'asc' }\n );\n };\n\n return (\n <GlassCard treatment=\"plain\" className={cn('overflow-hidden', className)}>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam\">\n {columns.map((col) => {\n const sortable = Boolean(col.sortValue);\n const active = sort?.key === col.key;\n return (\n <th\n key={col.key}\n onClick={sortable ? () => toggleSort(col.key) : undefined}\n aria-sort={\n active ? (sort?.dir === 'asc' ? 'ascending' : 'descending') : undefined\n }\n className={cn(\n 'px-4 py-3 font-medium text-text-secondary whitespace-nowrap',\n alignClass[col.align ?? 'left'],\n col.hideOnMobile && 'hidden md:table-cell',\n sortable && 'cursor-pointer select-none hover:text-text-primary'\n )}\n >\n <span\n className={cn(\n 'inline-flex items-center gap-1',\n col.align === 'right' && 'flex-row-reverse'\n )}\n >\n {col.header}\n {sortable &&\n (active ? (\n sort?.dir === 'asc' ? (\n <ChevronUp className=\"h-3.5 w-3.5 text-accent\" />\n ) : (\n <ChevronDown className=\"h-3.5 w-3.5 text-accent\" />\n )\n ) : (\n <ChevronsUpDown className=\"h-3.5 w-3.5 opacity-40\" />\n ))}\n </span>\n </th>\n );\n })}\n </tr>\n </thead>\n <tbody>\n {sortedRows.map((row) => (\n <tr\n key={rowKey(row)}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n className={cn(\n 'group border-b border-border-seam/60 last:border-0',\n onRowClick && 'cursor-pointer transition-colors hover:bg-bg-sunken/60'\n )}\n >\n {columns.map((col) => (\n <td\n key={col.key}\n className={cn(\n 'px-4 py-3 text-text-primary align-middle',\n alignClass[col.align ?? 'left'],\n col.hideOnMobile && 'hidden md:table-cell',\n col.className\n )}\n >\n {col.render(row)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </GlassCard>\n );\n}\n"],"mappings":";;;;;;AAqCA,IAAM,IAAa;CACjB,MAAM;CACN,OAAO;CACP,QAAQ;CACT;AAED,SAAgB,EAAa,EAC3B,YACA,SACA,WACA,eACA,cACA,kBACoB;CACpB,IAAM,CAAC,GAAM,KAAW,EACtB,KAAe,KAChB,EAEK,IAAa,QAAc;AAC/B,MAAI,CAAC,EAAM,QAAO;EAClB,IAAM,IAAM,EAAQ,MAAM,MAAM,EAAE,QAAQ,EAAK,IAAI;AACnD,MAAI,CAAC,GAAK,UAAW,QAAO;EAC5B,IAAM,IAAM,EAAK,QAAQ,QAAQ,IAAI;AACrC,SAAO,CAAC,GAAG,EAAK,CAAC,MAAM,GAAG,MAAM;GAC9B,IAAM,IAAK,EAAI,UAAW,EAAE,EACtB,IAAK,EAAI,UAAW,EAAE;AAG5B,UAFI,IAAK,IAAW,KAAK,IACrB,IAAK,IAAW,IAAI,IACjB;IACP;IACD;EAAC;EAAM;EAAM;EAAQ,CAAC,EAEnB,KAAc,MAAgB;AAClC,KAAS,MACP,GAAM,QAAQ,IAAM;GAAE;GAAK,KAAK,EAAK,QAAQ,QAAQ,SAAS;GAAO,GAAG;GAAE;GAAK,KAAK;GAAO,CAC5F;;AAGH,QACE,kBAAC,GAAD;EAAW,WAAU;EAAQ,WAAW,EAAG,mBAAmB,EAAU;YACtE,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,SAAD;IAAO,WAAU;cAAjB,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAQ,KAAK,MAAQ;MACpB,IAAM,IAAW,EAAQ,EAAI,WACvB,IAAS,GAAM,QAAQ,EAAI;AACjC,aACE,kBAAC,MAAD;OAEE,SAAS,UAAiB,EAAW,EAAI,IAAI,GAAG,KAAA;OAChD,aACE,IAAU,GAAM,QAAQ,QAAQ,cAAc,eAAgB,KAAA;OAEhE,WAAW,EACT,+DACA,EAAW,EAAI,SAAS,SACxB,EAAI,gBAAgB,wBACpB,KAAY,qDACb;iBAED,kBAAC,QAAD;QACE,WAAW,EACT,kCACA,EAAI,UAAU,WAAW,mBAC1B;kBAJH,CAMG,EAAI,QACJ,MACE,IACC,GAAM,QAAQ,QACZ,kBAAC,GAAD,EAAW,WAAU,2BAA4B,CAAA,GAEjD,kBAAC,GAAD,EAAa,WAAU,2BAA4B,CAAA,GAGrD,kBAAC,GAAD,EAAgB,WAAU,0BAA2B,CAAA,EAEpD;;OACJ,EA9BE,EAAI,IA8BN;OAEP;KACC,CAAA,EACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAW,KAAK,MACf,kBAAC,MAAD;KAEE,SAAS,UAAmB,EAAW,EAAI,GAAG,KAAA;KAC9C,WAAW,EACT,sDACA,KAAc,yDACf;eAEA,EAAQ,KAAK,MACZ,kBAAC,MAAD;MAEE,WAAW,EACT,4CACA,EAAW,EAAI,SAAS,SACxB,EAAI,gBAAgB,wBACpB,EAAI,UACL;gBAEA,EAAI,OAAO,EAAI;MACb,EATE,EAAI,IASN,CACL;KACC,EApBE,EAAO,EAAI,CAoBb,CACL,EACI,CAAA,CACF;;GACJ,CAAA;EACI,CAAA"}
1
+ {"version":3,"file":"DataTable.js","names":[],"sources":["../../../src/ecoimpacthub/components/DataTable.tsx"],"sourcesContent":["/**\n * DataTable — a lightweight, semantic-token table for list pages.\n * @module ecoimpacthub/components\n *\n * Deliberately minimal (no external table lib). Renders a responsive,\n * horizontally-scrollable table wrapped in a GlassCard. Columns declare a\n * header, a render fn, optional alignment, and optionally a `sortValue` to make\n * the column click-sortable.\n */\n\nimport { useMemo, useState, type ReactNode } from 'react';\nimport { ChevronUp, ChevronDown, ChevronsUpDown } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\nexport interface Column<T> {\n key: string;\n header: ReactNode;\n render: (row: T) => ReactNode;\n align?: 'left' | 'right' | 'center';\n className?: string;\n /** Hide below the `md` breakpoint for a mobile-friendly layout. */\n hideOnMobile?: boolean;\n /** Provide to make this column click-sortable (returns a comparable value). */\n sortValue?: (row: T) => string | number;\n}\n\ninterface DataTableProps<T> {\n columns: Column<T>[];\n rows: T[];\n rowKey: (row: T) => string;\n onRowClick?: (row: T) => void;\n className?: string;\n /** Default sort: a column key + direction. */\n defaultSort?: { key: string; dir: 'asc' | 'desc' };\n}\n\nconst alignClass = {\n left: 'text-left',\n right: 'text-right',\n center: 'text-center',\n} as const;\n\nexport function DataTable<T>({\n columns,\n rows,\n rowKey,\n onRowClick,\n className,\n defaultSort,\n}: DataTableProps<T>) {\n const [sort, setSort] = useState<{ key: string; dir: 'asc' | 'desc' } | null>(\n defaultSort ?? null\n );\n\n const sortedRows = useMemo(() => {\n if (!sort) return rows;\n const col = columns.find((c) => c.key === sort.key);\n if (!col?.sortValue) return rows;\n const dir = sort.dir === 'asc' ? 1 : -1;\n return [...rows].sort((a, b) => {\n const va = col.sortValue!(a);\n const vb = col.sortValue!(b);\n if (va < vb) return -1 * dir;\n if (va > vb) return 1 * dir;\n return 0;\n });\n }, [rows, sort, columns]);\n\n const toggleSort = (key: string) => {\n setSort((prev) =>\n prev?.key === key ? { key, dir: prev.dir === 'asc' ? 'desc' : 'asc' } : { key, dir: 'asc' }\n );\n };\n\n return (\n <GlassCard treatment=\"plain\" className={cn('overflow-hidden', className)}>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam\">\n {columns.map((col) => {\n const sortable = Boolean(col.sortValue);\n const active = sort?.key === col.key;\n return (\n <th\n key={col.key}\n onClick={sortable ? () => toggleSort(col.key) : undefined}\n aria-sort={\n active ? (sort?.dir === 'asc' ? 'ascending' : 'descending') : undefined\n }\n className={cn(\n 'px-4 py-3 font-medium text-text-secondary whitespace-nowrap',\n alignClass[col.align ?? 'left'],\n col.hideOnMobile && 'hidden md:table-cell',\n sortable && 'cursor-pointer select-none hover:text-text-primary'\n )}\n >\n <span\n className={cn(\n 'inline-flex items-center gap-1',\n col.align === 'right' && 'flex-row-reverse'\n )}\n >\n {col.header}\n {sortable &&\n (active ? (\n sort?.dir === 'asc' ? (\n <ChevronUp className=\"h-3.5 w-3.5 text-accent\" />\n ) : (\n <ChevronDown className=\"h-3.5 w-3.5 text-accent\" />\n )\n ) : (\n <ChevronsUpDown className=\"h-3.5 w-3.5 opacity-40\" />\n ))}\n </span>\n </th>\n );\n })}\n </tr>\n </thead>\n <tbody>\n {sortedRows.map((row) => (\n <tr\n key={rowKey(row)}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n className={cn(\n 'group border-b border-border-seam/60 last:border-0',\n onRowClick && 'cursor-pointer transition-colors hover:bg-bg-sunken/60'\n )}\n >\n {columns.map((col) => (\n <td\n key={col.key}\n className={cn(\n 'px-4 py-3 text-text-primary align-middle',\n alignClass[col.align ?? 'left'],\n col.hideOnMobile && 'hidden md:table-cell',\n col.className\n )}\n >\n {col.render(row)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </GlassCard>\n );\n}\n"],"mappings":";;;;;;AAqCA,IAAM,IAAa;CACjB,MAAM;CACN,OAAO;CACP,QAAQ;AACV;AAEA,SAAgB,EAAa,EAC3B,YACA,SACA,WACA,eACA,cACA,kBACoB;CACpB,IAAM,CAAC,GAAM,KAAW,EACtB,KAAe,IACjB,GAEM,IAAa,QAAc;EAC/B,IAAI,CAAC,GAAM,OAAO;EAClB,IAAM,IAAM,EAAQ,MAAM,MAAM,EAAE,QAAQ,EAAK,GAAG;EAClD,IAAI,CAAC,GAAK,WAAW,OAAO;EAC5B,IAAM,IAAM,EAAK,QAAQ,QAAQ,IAAI;EACrC,OAAO,CAAC,GAAG,CAAI,EAAE,MAAM,GAAG,MAAM;GAC9B,IAAM,IAAK,EAAI,UAAW,CAAC,GACrB,IAAK,EAAI,UAAW,CAAC;GAG3B,OAFI,IAAK,IAAW,KAAK,IACrB,IAAK,IAAW,IAAI,IACjB;EACT,CAAC;CACH,GAAG;EAAC;EAAM;EAAM;CAAO,CAAC,GAElB,KAAc,MAAgB;EAClC,GAAS,MACP,GAAM,QAAQ,IAAM;GAAE;GAAK,KAAK,EAAK,QAAQ,QAAQ,SAAS;EAAM,IAAI;GAAE;GAAK,KAAK;EAAM,CAC5F;CACF;CAEA,OACE,kBAAC,GAAD;EAAW,WAAU;EAAQ,WAAW,EAAG,mBAAmB,CAAS;YACrE,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,SAAD;IAAO,WAAU;cAAjB,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAQ,KAAK,MAAQ;MACpB,IAAM,IAAW,EAAQ,EAAI,WACvB,IAAS,GAAM,QAAQ,EAAI;MACjC,OACE,kBAAC,MAAD;OAEE,SAAS,UAAiB,EAAW,EAAI,GAAG,IAAI,KAAA;OAChD,aACE,IAAU,GAAM,QAAQ,QAAQ,cAAc,eAAgB,KAAA;OAEhE,WAAW,EACT,+DACA,EAAW,EAAI,SAAS,SACxB,EAAI,gBAAgB,wBACpB,KAAY,oDACd;iBAEA,kBAAC,QAAD;QACE,WAAW,EACT,kCACA,EAAI,UAAU,WAAW,kBAC3B;kBAJF,CAMG,EAAI,QACJ,MACE,IACC,GAAM,QAAQ,QACZ,kBAAC,GAAD,EAAW,WAAU,0BAA2B,CAAA,IAEhD,kBAAC,GAAD,EAAa,WAAU,0BAA2B,CAAA,IAGpD,kBAAC,GAAD,EAAgB,WAAU,yBAA0B,CAAA,EAEpD;;MACJ,GA9BG,EAAI,GA8BP;KAER,CAAC;IACC,CAAA,EACC,CAAA,GACP,kBAAC,SAAD,EAAA,UACG,EAAW,KAAK,MACf,kBAAC,MAAD;KAEE,SAAS,UAAmB,EAAW,CAAG,IAAI,KAAA;KAC9C,WAAW,EACT,sDACA,KAAc,wDAChB;eAEC,EAAQ,KAAK,MACZ,kBAAC,MAAD;MAEE,WAAW,EACT,4CACA,EAAW,EAAI,SAAS,SACxB,EAAI,gBAAgB,wBACpB,EAAI,SACN;gBAEC,EAAI,OAAO,CAAG;KACb,GATG,EAAI,GASP,CACL;IACC,GApBG,EAAO,CAAG,CAoBb,CACL,EACI,CAAA,CACF;;EACJ,CAAA;CACI,CAAA;AAEf"}
@@ -1 +1 @@
1
- {"version":3,"file":"EcoDiscussion.js","names":[],"sources":["../../../src/ecoimpacthub/components/EcoDiscussion.tsx"],"sourcesContent":["/**\n * EcoDiscussion — a comment thread on any eco entity (Integration B).\n * @module ecoimpacthub/components/EcoDiscussion\n *\n * Reuses the platform EntityComment API (`getEntityComments` /\n * `createEntityComment`) keyed by `(entityType, entityId)` — no eco-svc change.\n * Renders root comments (author, body, time) + a composer. Robust to empty\n * state and errors.\n */\n\nimport { useState } from 'react';\nimport { MessageSquare, Send } from 'lucide-react';\nimport { Button, Textarea } from '@burdenoff/fe-libs/ui';\nimport { Section, LoadingView, ErrorView } from './StateViews';\nimport { EmptyState } from './EmptyState';\nimport { useEcoImpactHub } from '../context';\nimport { useEcoComments, useEcoCreateComment, type EcoComment } from '../hooks';\nimport { formatDateTime } from '../utils/formatters';\n\ninterface EcoDiscussionProps {\n entityType: string;\n entityId: string;\n title?: string;\n description?: string;\n}\n\nfunction displayName(user: ReturnType<typeof useEcoImpactHub>['currentUser']): string {\n if (!user) return 'You';\n const full = [user.firstName, user.lastName].filter(Boolean).join(' ').trim();\n return user.name || full || user.username || user.email || 'You';\n}\n\nfunction initialFor(label: string): string {\n const trimmed = label.trim();\n return trimmed ? trimmed[0]!.toUpperCase() : '?';\n}\n\nexport function EcoDiscussion({\n entityType,\n entityId,\n title = 'Discussion',\n description = 'Coordinate review and verification with your team.',\n}: EcoDiscussionProps) {\n const { currentUser } = useEcoImpactHub();\n const { data, isLoading, isError, refetch } = useEcoComments(entityType, entityId);\n const createComment = useEcoCreateComment(entityType, entityId);\n\n const [draft, setDraft] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n const selfName = displayName(currentUser);\n\n const authorLabel = (comment: EcoComment): string =>\n currentUser?.id && comment.authorId === currentUser.id ? selfName : 'Workspace member';\n\n const handleSubmit = async () => {\n const text = draft.trim();\n if (!text) return;\n setError(null);\n try {\n await createComment.mutateAsync(text);\n setDraft('');\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to post comment.');\n }\n };\n\n const comments = data?.items ?? [];\n\n return (\n <Section title={title} description={description}>\n <div className=\"rounded-xl border border-border-seam bg-bg-surface/40 p-4\">\n {/* Composer */}\n <div className=\"flex gap-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-action-primary-bg/15 text-sm font-semibold text-action-primary-bg\">\n {initialFor(selfName)}\n </div>\n <div className=\"flex-1\">\n <Textarea\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n placeholder=\"Add a comment for your team…\"\n rows={2}\n />\n <div className=\"mt-2 flex items-center justify-end gap-2\">\n {error && <span className=\"mr-auto text-xs text-status-error-text\">{error}</span>}\n <Button\n size=\"sm\"\n onClick={handleSubmit}\n disabled={!draft.trim() || createComment.isPending}\n >\n <Send className=\"mr-1.5 h-4 w-4\" />\n {createComment.isPending ? 'Posting…' : 'Comment'}\n </Button>\n </div>\n </div>\n </div>\n\n {/* Thread */}\n <div className=\"mt-4 border-t border-border-seam pt-4\">\n {isLoading ? (\n <LoadingView label=\"Loading discussion…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load the discussion.\" onRetry={() => refetch()} />\n ) : comments.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<MessageSquare className=\"h-9 w-9\" />}\n title=\"No comments yet\"\n description=\"Start the discussion by adding the first comment.\"\n />\n ) : (\n <ul className=\"flex flex-col gap-4\">\n {comments.map((comment) => {\n const label = authorLabel(comment);\n const body = comment.content.text ?? comment.content.markdown ?? '';\n return (\n <li key={comment.id} className=\"flex gap-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-sm font-semibold text-text-secondary\">\n {initialFor(label)}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-baseline gap-x-2\">\n <span className=\"text-sm font-semibold text-text-primary\">{label}</span>\n <span className=\"text-xs text-text-tertiary\">\n {formatDateTime(comment.createdAt)}\n {comment.edited ? ' · edited' : ''}\n </span>\n </div>\n <p className=\"mt-0.5 whitespace-pre-wrap break-words text-sm text-text-secondary\">\n {body}\n </p>\n </div>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n </div>\n </Section>\n );\n}\n"],"mappings":";;;;;;;;;;;;AA0BA,SAAS,EAAY,GAAiE;AACpF,KAAI,CAAC,EAAM,QAAO;CAClB,IAAM,IAAO,CAAC,EAAK,WAAW,EAAK,SAAS,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,CAAC,MAAM;AAC7E,QAAO,EAAK,QAAQ,KAAQ,EAAK,YAAY,EAAK,SAAS;;AAG7D,SAAS,EAAW,GAAuB;CACzC,IAAM,IAAU,EAAM,MAAM;AAC5B,QAAO,IAAU,EAAQ,GAAI,aAAa,GAAG;;AAG/C,SAAgB,EAAc,EAC5B,eACA,aACA,WAAQ,cACR,iBAAc,wDACO;CACrB,IAAM,EAAE,mBAAgB,GAAiB,EACnC,EAAE,SAAM,cAAW,YAAS,eAAY,EAAe,GAAY,EAAS,EAC5E,IAAgB,EAAoB,GAAY,EAAS,EAEzD,CAAC,GAAO,KAAY,EAAS,GAAG,EAChC,CAAC,GAAO,KAAY,EAAwB,KAAK,EAEjD,IAAW,EAAY,EAAY,EAEnC,KAAe,MACnB,GAAa,MAAM,EAAQ,aAAa,EAAY,KAAK,IAAW,oBAEhE,IAAe,YAAY;EAC/B,IAAM,IAAO,EAAM,MAAM;AACpB,SACL;KAAS,KAAK;AACd,OAAI;AAEF,IADA,MAAM,EAAc,YAAY,EAAK,EACrC,EAAS,GAAG;YACL,GAAK;AACZ,MAAS,aAAe,QAAQ,EAAI,UAAU,0BAA0B;;;IAItE,IAAW,GAAM,SAAS,EAAE;AAElC,QACE,kBAAC,GAAD;EAAgB;EAAoB;YAClC,kBAAC,OAAD;GAAK,WAAU;aAAf,CAEE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAW,EAAS;KACjB,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACE,OAAO;MACP,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;MACzC,aAAY;MACZ,MAAM;MACN,CAAA,EACF,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACG,KAAS,kBAAC,QAAD;OAAM,WAAU;iBAA0C;OAAa,CAAA,EACjF,kBAAC,GAAD;OACE,MAAK;OACL,SAAS;OACT,UAAU,CAAC,EAAM,MAAM,IAAI,EAAc;iBAH3C,CAKE,kBAAC,GAAD,EAAM,WAAU,kBAAmB,CAAA,EAClC,EAAc,YAAY,aAAa,UACjC;SACL;QACF;OACF;OAGN,kBAAC,OAAD;IAAK,WAAU;cACZ,IACC,kBAAC,GAAD,EAAa,OAAM,uBAAwB,CAAA,GACzC,IACF,kBAAC,GAAD;KAAW,SAAQ;KAAgC,eAAe,GAAS;KAAI,CAAA,GAC7E,EAAS,WAAW,IACtB,kBAAC,GAAD;KACE,cAAa;KACb,MAAM,kBAAC,GAAD,EAAe,WAAU,WAAY,CAAA;KAC3C,OAAM;KACN,aAAY;KACZ,CAAA,GAEF,kBAAC,MAAD;KAAI,WAAU;eACX,EAAS,KAAK,MAAY;MACzB,IAAM,IAAQ,EAAY,EAAQ,EAC5B,IAAO,EAAQ,QAAQ,QAAQ,EAAQ,QAAQ,YAAY;AACjE,aACE,kBAAC,MAAD;OAAqB,WAAU;iBAA/B,CACE,kBAAC,OAAD;QAAK,WAAU;kBACZ,EAAW,EAAM;QACd,CAAA,EACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBAA2C;UAAa,CAAA,EACxE,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CACG,EAAe,EAAQ,UAAU,EACjC,EAAQ,SAAS,cAAc,GAC3B;YACH;YACN,kBAAC,KAAD;SAAG,WAAU;mBACV;SACC,CAAA,CACA;UACH;SAhBI,EAAQ,GAgBZ;OAEP;KACC,CAAA;IAEH,CAAA,CACF;;EACE,CAAA"}
1
+ {"version":3,"file":"EcoDiscussion.js","names":[],"sources":["../../../src/ecoimpacthub/components/EcoDiscussion.tsx"],"sourcesContent":["/**\n * EcoDiscussion — a comment thread on any eco entity (Integration B).\n * @module ecoimpacthub/components/EcoDiscussion\n *\n * Reuses the platform EntityComment API (`getEntityComments` /\n * `createEntityComment`) keyed by `(entityType, entityId)` — no eco-svc change.\n * Renders root comments (author, body, time) + a composer. Robust to empty\n * state and errors.\n */\n\nimport { useState } from 'react';\nimport { MessageSquare, Send } from 'lucide-react';\nimport { Button, Textarea } from '@burdenoff/fe-libs/ui';\nimport { Section, LoadingView, ErrorView } from './StateViews';\nimport { EmptyState } from './EmptyState';\nimport { useEcoImpactHub } from '../context';\nimport { useEcoComments, useEcoCreateComment, type EcoComment } from '../hooks';\nimport { formatDateTime } from '../utils/formatters';\n\ninterface EcoDiscussionProps {\n entityType: string;\n entityId: string;\n title?: string;\n description?: string;\n}\n\nfunction displayName(user: ReturnType<typeof useEcoImpactHub>['currentUser']): string {\n if (!user) return 'You';\n const full = [user.firstName, user.lastName].filter(Boolean).join(' ').trim();\n return user.name || full || user.username || user.email || 'You';\n}\n\nfunction initialFor(label: string): string {\n const trimmed = label.trim();\n return trimmed ? trimmed[0]!.toUpperCase() : '?';\n}\n\nexport function EcoDiscussion({\n entityType,\n entityId,\n title = 'Discussion',\n description = 'Coordinate review and verification with your team.',\n}: EcoDiscussionProps) {\n const { currentUser } = useEcoImpactHub();\n const { data, isLoading, isError, refetch } = useEcoComments(entityType, entityId);\n const createComment = useEcoCreateComment(entityType, entityId);\n\n const [draft, setDraft] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n const selfName = displayName(currentUser);\n\n const authorLabel = (comment: EcoComment): string =>\n currentUser?.id && comment.authorId === currentUser.id ? selfName : 'Workspace member';\n\n const handleSubmit = async () => {\n const text = draft.trim();\n if (!text) return;\n setError(null);\n try {\n await createComment.mutateAsync(text);\n setDraft('');\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to post comment.');\n }\n };\n\n const comments = data?.items ?? [];\n\n return (\n <Section title={title} description={description}>\n <div className=\"rounded-xl border border-border-seam bg-bg-surface/40 p-4\">\n {/* Composer */}\n <div className=\"flex gap-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-action-primary-bg/15 text-sm font-semibold text-action-primary-bg\">\n {initialFor(selfName)}\n </div>\n <div className=\"flex-1\">\n <Textarea\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n placeholder=\"Add a comment for your team…\"\n rows={2}\n />\n <div className=\"mt-2 flex items-center justify-end gap-2\">\n {error && <span className=\"mr-auto text-xs text-status-error-text\">{error}</span>}\n <Button\n size=\"sm\"\n onClick={handleSubmit}\n disabled={!draft.trim() || createComment.isPending}\n >\n <Send className=\"mr-1.5 h-4 w-4\" />\n {createComment.isPending ? 'Posting…' : 'Comment'}\n </Button>\n </div>\n </div>\n </div>\n\n {/* Thread */}\n <div className=\"mt-4 border-t border-border-seam pt-4\">\n {isLoading ? (\n <LoadingView label=\"Loading discussion…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load the discussion.\" onRetry={() => refetch()} />\n ) : comments.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<MessageSquare className=\"h-9 w-9\" />}\n title=\"No comments yet\"\n description=\"Start the discussion by adding the first comment.\"\n />\n ) : (\n <ul className=\"flex flex-col gap-4\">\n {comments.map((comment) => {\n const label = authorLabel(comment);\n const body = comment.content.text ?? comment.content.markdown ?? '';\n return (\n <li key={comment.id} className=\"flex gap-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-sm font-semibold text-text-secondary\">\n {initialFor(label)}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-baseline gap-x-2\">\n <span className=\"text-sm font-semibold text-text-primary\">{label}</span>\n <span className=\"text-xs text-text-tertiary\">\n {formatDateTime(comment.createdAt)}\n {comment.edited ? ' · edited' : ''}\n </span>\n </div>\n <p className=\"mt-0.5 whitespace-pre-wrap break-words text-sm text-text-secondary\">\n {body}\n </p>\n </div>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n </div>\n </Section>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"EcoTags.js","names":[],"sources":["../../../src/ecoimpacthub/components/EcoTags.tsx"],"sourcesContent":["/**\n * EcoTags — a lightweight tag control for eco entities (Integration C).\n * @module ecoimpacthub/components/EcoTags\n *\n * The eco svc exposes no tags field, so this drives the platform tag store\n * directly: `getEntityTags` (display), `searchTags` (+ `createTag`) to pick or\n * create, `assignTag`/`removeTagAssignment` to link — all via the workspace\n * gateway. No eco-svc change.\n */\n\nimport { useEffect, useState } from 'react';\nimport { Loader2, Plus, Tag as TagIcon, X } from 'lucide-react';\nimport {\n Button,\n Input,\n Popover,\n PopoverContent,\n PopoverTrigger,\n Spinner,\n} from '@burdenoff/fe-libs/ui';\nimport {\n useEcoEntityTags,\n useEcoTagSearch,\n useEcoAssignTag,\n useEcoRemoveTagAssignment,\n useEcoCreateAndAssignTag,\n} from '../hooks';\n\ninterface EcoTagsProps {\n entityType: string;\n entityId: string;\n label?: string;\n}\n\nexport function EcoTags({ entityType, entityId, label = 'Tags' }: EcoTagsProps) {\n const tags = useEcoEntityTags(entityType, entityId);\n const assign = useEcoAssignTag(entityType, entityId);\n const remove = useEcoRemoveTagAssignment(entityType, entityId);\n const createAndAssign = useEcoCreateAndAssignTag(entityType, entityId);\n\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const [debounced, setDebounced] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const timer = setTimeout(() => setDebounced(query), 250);\n return () => clearTimeout(timer);\n }, [query]);\n\n const search = useEcoTagSearch(debounced);\n\n const assignments = tags.data ?? [];\n const assignedIds = new Set(assignments.map((a) => a.tag.id));\n const q = debounced.trim();\n const searchResults = (search.data ?? []).filter((t) => !assignedIds.has(t.id));\n const hasExact =\n q.length > 0 &&\n [...assignments.map((a) => a.tag.label), ...(search.data ?? []).map((t) => t.label)].some(\n (l) => l.toLowerCase() === q.toLowerCase()\n );\n const showCreate = q.length > 0 && !hasExact;\n const busy = assign.isPending || createAndAssign.isPending;\n\n const resetInput = () => {\n setQuery('');\n setDebounced('');\n setError(null);\n };\n\n const handleAssign = async (tagId: string) => {\n setError(null);\n try {\n await assign.mutateAsync(tagId);\n resetInput();\n setOpen(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to add tag.');\n }\n };\n\n const handleCreate = async () => {\n if (!q) return;\n setError(null);\n try {\n await createAndAssign.mutateAsync(q);\n resetInput();\n setOpen(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create tag.');\n }\n };\n\n const handleRemove = async (assignmentId: string) => {\n setError(null);\n try {\n await remove.mutateAsync(assignmentId);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to remove tag.');\n }\n };\n\n return (\n <div>\n <p className=\"mb-1.5 text-xs text-text-tertiary\">{label}</p>\n <div className=\"flex flex-wrap items-center gap-2\">\n {tags.isLoading ? (\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-tertiary\">\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" /> Loading tags…\n </span>\n ) : (\n assignments.map((assignment) => (\n <span\n key={assignment.id}\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border-seam bg-bg-sunken px-2.5 py-1 text-xs text-text-secondary\"\n >\n {assignment.tag.color ? (\n <span\n className=\"h-2 w-2 shrink-0 rounded-full\"\n style={{ backgroundColor: assignment.tag.color }}\n aria-hidden\n />\n ) : (\n <TagIcon className=\"h-3 w-3 text-text-tertiary\" />\n )}\n <span className=\"max-w-[10rem] truncate\">{assignment.tag.label}</span>\n <button\n type=\"button\"\n onClick={() => handleRemove(assignment.id)}\n disabled={remove.isPending}\n aria-label={`Remove tag ${assignment.tag.label}`}\n className=\"rounded-full p-0.5 text-text-tertiary hover:bg-bg-canvas hover:text-text-primary\"\n >\n <X className=\"h-3 w-3\" />\n </button>\n </span>\n ))\n )}\n\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) resetInput();\n }}\n >\n <PopoverTrigger asChild>\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 gap-1 px-2 text-xs\">\n <Plus className=\"h-3.5 w-3.5\" /> Add tag\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-64 p-2\">\n <Input\n autoFocus\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search or create a tag…\"\n className=\"h-8\"\n />\n <div className=\"mt-2 max-h-56 overflow-y-auto\">\n {search.isFetching && q.length > 0 ? (\n <div className=\"flex items-center gap-2 px-1 py-2 text-sm text-text-tertiary\">\n <Spinner size=\"sm\" /> Searching…\n </div>\n ) : (\n <>\n {searchResults.map((tag) => (\n <button\n key={tag.id}\n type=\"button\"\n onClick={() => handleAssign(tag.id)}\n disabled={busy}\n className=\"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm text-text-secondary hover:bg-bg-sunken disabled:opacity-60\"\n >\n {tag.color ? (\n <span\n className=\"h-2 w-2 shrink-0 rounded-full\"\n style={{ backgroundColor: tag.color }}\n aria-hidden\n />\n ) : (\n <TagIcon className=\"h-3.5 w-3.5 text-text-tertiary\" />\n )}\n <span className=\"truncate\">{tag.label}</span>\n </button>\n ))}\n\n {showCreate && (\n <button\n type=\"button\"\n onClick={handleCreate}\n disabled={busy}\n className=\"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm text-action-primary-bg hover:bg-bg-sunken disabled:opacity-60\"\n >\n <Plus className=\"h-3.5 w-3.5 shrink-0\" />\n <span className=\"truncate\">Create “{q}”</span>\n </button>\n )}\n\n {!showCreate && searchResults.length === 0 && q.length > 0 && (\n <p className=\"px-2 py-2 text-sm text-text-tertiary\">Already added.</p>\n )}\n {q.length === 0 && (\n <p className=\"px-2 py-2 text-sm text-text-tertiary\">\n Type to search existing tags or create a new one.\n </p>\n )}\n </>\n )}\n </div>\n </PopoverContent>\n </Popover>\n </div>\n\n {error && <p className=\"mt-1.5 text-xs text-status-error-text\">{error}</p>}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"EcoTags.js","names":[],"sources":["../../../src/ecoimpacthub/components/EcoTags.tsx"],"sourcesContent":["/**\n * EcoTags — a lightweight tag control for eco entities (Integration C).\n * @module ecoimpacthub/components/EcoTags\n *\n * The eco svc exposes no tags field, so this drives the platform tag store\n * directly: `getEntityTags` (display), `searchTags` (+ `createTag`) to pick or\n * create, `assignTag`/`removeTagAssignment` to link — all via the workspace\n * gateway. No eco-svc change.\n */\n\nimport { useEffect, useState } from 'react';\nimport { Loader2, Plus, Tag as TagIcon, X } from 'lucide-react';\nimport {\n Button,\n Input,\n Popover,\n PopoverContent,\n PopoverTrigger,\n Spinner,\n} from '@burdenoff/fe-libs/ui';\nimport {\n useEcoEntityTags,\n useEcoTagSearch,\n useEcoAssignTag,\n useEcoRemoveTagAssignment,\n useEcoCreateAndAssignTag,\n} from '../hooks';\n\ninterface EcoTagsProps {\n entityType: string;\n entityId: string;\n label?: string;\n}\n\nexport function EcoTags({ entityType, entityId, label = 'Tags' }: EcoTagsProps) {\n const tags = useEcoEntityTags(entityType, entityId);\n const assign = useEcoAssignTag(entityType, entityId);\n const remove = useEcoRemoveTagAssignment(entityType, entityId);\n const createAndAssign = useEcoCreateAndAssignTag(entityType, entityId);\n\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const [debounced, setDebounced] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const timer = setTimeout(() => setDebounced(query), 250);\n return () => clearTimeout(timer);\n }, [query]);\n\n const search = useEcoTagSearch(debounced);\n\n const assignments = tags.data ?? [];\n const assignedIds = new Set(assignments.map((a) => a.tag.id));\n const q = debounced.trim();\n const searchResults = (search.data ?? []).filter((t) => !assignedIds.has(t.id));\n const hasExact =\n q.length > 0 &&\n [...assignments.map((a) => a.tag.label), ...(search.data ?? []).map((t) => t.label)].some(\n (l) => l.toLowerCase() === q.toLowerCase()\n );\n const showCreate = q.length > 0 && !hasExact;\n const busy = assign.isPending || createAndAssign.isPending;\n\n const resetInput = () => {\n setQuery('');\n setDebounced('');\n setError(null);\n };\n\n const handleAssign = async (tagId: string) => {\n setError(null);\n try {\n await assign.mutateAsync(tagId);\n resetInput();\n setOpen(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to add tag.');\n }\n };\n\n const handleCreate = async () => {\n if (!q) return;\n setError(null);\n try {\n await createAndAssign.mutateAsync(q);\n resetInput();\n setOpen(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create tag.');\n }\n };\n\n const handleRemove = async (assignmentId: string) => {\n setError(null);\n try {\n await remove.mutateAsync(assignmentId);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to remove tag.');\n }\n };\n\n return (\n <div>\n <p className=\"mb-1.5 text-xs text-text-tertiary\">{label}</p>\n <div className=\"flex flex-wrap items-center gap-2\">\n {tags.isLoading ? (\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-tertiary\">\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" /> Loading tags…\n </span>\n ) : (\n assignments.map((assignment) => (\n <span\n key={assignment.id}\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border-seam bg-bg-sunken px-2.5 py-1 text-xs text-text-secondary\"\n >\n {assignment.tag.color ? (\n <span\n className=\"h-2 w-2 shrink-0 rounded-full\"\n style={{ backgroundColor: assignment.tag.color }}\n aria-hidden\n />\n ) : (\n <TagIcon className=\"h-3 w-3 text-text-tertiary\" />\n )}\n <span className=\"max-w-[10rem] truncate\">{assignment.tag.label}</span>\n <button\n type=\"button\"\n onClick={() => handleRemove(assignment.id)}\n disabled={remove.isPending}\n aria-label={`Remove tag ${assignment.tag.label}`}\n className=\"rounded-full p-0.5 text-text-tertiary hover:bg-bg-canvas hover:text-text-primary\"\n >\n <X className=\"h-3 w-3\" />\n </button>\n </span>\n ))\n )}\n\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) resetInput();\n }}\n >\n <PopoverTrigger asChild>\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 gap-1 px-2 text-xs\">\n <Plus className=\"h-3.5 w-3.5\" /> Add tag\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-64 p-2\">\n <Input\n autoFocus\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search or create a tag…\"\n className=\"h-8\"\n />\n <div className=\"mt-2 max-h-56 overflow-y-auto\">\n {search.isFetching && q.length > 0 ? (\n <div className=\"flex items-center gap-2 px-1 py-2 text-sm text-text-tertiary\">\n <Spinner size=\"sm\" /> Searching…\n </div>\n ) : (\n <>\n {searchResults.map((tag) => (\n <button\n key={tag.id}\n type=\"button\"\n onClick={() => handleAssign(tag.id)}\n disabled={busy}\n className=\"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm text-text-secondary hover:bg-bg-sunken disabled:opacity-60\"\n >\n {tag.color ? (\n <span\n className=\"h-2 w-2 shrink-0 rounded-full\"\n style={{ backgroundColor: tag.color }}\n aria-hidden\n />\n ) : (\n <TagIcon className=\"h-3.5 w-3.5 text-text-tertiary\" />\n )}\n <span className=\"truncate\">{tag.label}</span>\n </button>\n ))}\n\n {showCreate && (\n <button\n type=\"button\"\n onClick={handleCreate}\n disabled={busy}\n className=\"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm text-action-primary-bg hover:bg-bg-sunken disabled:opacity-60\"\n >\n <Plus className=\"h-3.5 w-3.5 shrink-0\" />\n <span className=\"truncate\">Create “{q}”</span>\n </button>\n )}\n\n {!showCreate && searchResults.length === 0 && q.length > 0 && (\n <p className=\"px-2 py-2 text-sm text-text-tertiary\">Already added.</p>\n )}\n {q.length === 0 && (\n <p className=\"px-2 py-2 text-sm text-text-tertiary\">\n Type to search existing tags or create a new one.\n </p>\n )}\n </>\n )}\n </div>\n </PopoverContent>\n </Popover>\n </div>\n\n {error && <p className=\"mt-1.5 text-xs text-status-error-text\">{error}</p>}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"EmptyState.js","names":[],"sources":["../../../src/ecoimpacthub/components/EmptyState.tsx"],"sourcesContent":["/**\n * Empty State Component\n * @module ecoimpacthub/components\n *\n * Boff UI 2.0 zero-state. When an `illustration` name is provided it renders the\n * fe-libs {@link IllustratedEmptyState} (on-brand glass illustration); otherwise\n * it falls back to the icon-based layout.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\ninterface EmptyStateProps {\n icon?: ReactNode;\n /**\n * On-brand illustration name → `/illustrations/<name>.webp`. Standard names:\n * empty-data, empty-search, empty-files, empty-people, empty-notifications,\n * onboarding, empty-generic.\n */\n illustration?: string;\n title: string;\n description?: string;\n action?: ReactNode;\n className?: string;\n}\n\nexport const EmptyState: FC<EmptyStateProps> = ({\n icon,\n illustration,\n title,\n description,\n action,\n className,\n}) => {\n if (illustration) {\n return (\n <IllustratedEmptyState\n illustration={illustration}\n title={title}\n description={description}\n action={action}\n className={className}\n />\n );\n }\n\n return (\n <div\n className={cn('flex flex-col items-center justify-center py-12 px-4 text-center', className)}\n >\n {icon && <div className=\"mb-4 text-text-secondary opacity-50\">{icon}</div>}\n <h3 className=\"text-lg font-medium text-text-primary\">{title}</h3>\n {description && <p className=\"mt-2 text-sm text-text-secondary max-w-sm\">{description}</p>}\n {action && <div className=\"mt-6\">{action}</div>}\n </div>\n );\n};\n"],"mappings":";;;;AA2BA,IAAa,KAAmC,EAC9C,SACA,iBACA,UACA,gBACA,WACA,mBAEI,IAEA,kBAAC,GAAD;CACgB;CACP;CACM;CACL;CACG;CACX,CAAA,GAKJ,kBAAC,OAAD;CACE,WAAW,EAAG,oEAAoE,EAAU;WAD9F;EAGG,KAAQ,kBAAC,OAAD;GAAK,WAAU;aAAuC;GAAW,CAAA;EAC1E,kBAAC,MAAD;GAAI,WAAU;aAAyC;GAAW,CAAA;EACjE,KAAe,kBAAC,KAAD;GAAG,WAAU;aAA6C;GAAgB,CAAA;EACzF,KAAU,kBAAC,OAAD;GAAK,WAAU;aAAQ;GAAa,CAAA;EAC3C"}
1
+ {"version":3,"file":"EmptyState.js","names":[],"sources":["../../../src/ecoimpacthub/components/EmptyState.tsx"],"sourcesContent":["/**\n * Empty State Component\n * @module ecoimpacthub/components\n *\n * Boff UI 2.0 zero-state. When an `illustration` name is provided it renders the\n * fe-libs {@link IllustratedEmptyState} (on-brand glass illustration); otherwise\n * it falls back to the icon-based layout.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\ninterface EmptyStateProps {\n icon?: ReactNode;\n /**\n * On-brand illustration name → `/illustrations/<name>.webp`. Standard names:\n * empty-data, empty-search, empty-files, empty-people, empty-notifications,\n * onboarding, empty-generic.\n */\n illustration?: string;\n title: string;\n description?: string;\n action?: ReactNode;\n className?: string;\n}\n\nexport const EmptyState: FC<EmptyStateProps> = ({\n icon,\n illustration,\n title,\n description,\n action,\n className,\n}) => {\n if (illustration) {\n return (\n <IllustratedEmptyState\n illustration={illustration}\n title={title}\n description={description}\n action={action}\n className={className}\n />\n );\n }\n\n return (\n <div\n className={cn('flex flex-col items-center justify-center py-12 px-4 text-center', className)}\n >\n {icon && <div className=\"mb-4 text-text-secondary opacity-50\">{icon}</div>}\n <h3 className=\"text-lg font-medium text-text-primary\">{title}</h3>\n {description && <p className=\"mt-2 text-sm text-text-secondary max-w-sm\">{description}</p>}\n {action && <div className=\"mt-6\">{action}</div>}\n </div>\n );\n};\n"],"mappings":";;;;AA2BA,IAAa,KAAmC,EAC9C,SACA,iBACA,UACA,gBACA,WACA,mBAEI,IAEA,kBAAC,GAAD;CACgB;CACP;CACM;CACL;CACG;AACZ,CAAA,IAKH,kBAAC,OAAD;CACE,WAAW,EAAG,oEAAoE,CAAS;WAD7F;EAGG,KAAQ,kBAAC,OAAD;GAAK,WAAU;aAAuC;EAAU,CAAA;EACzE,kBAAC,MAAD;GAAI,WAAU;aAAyC;EAAU,CAAA;EAChE,KAAe,kBAAC,KAAD;GAAG,WAAU;aAA6C;EAAe,CAAA;EACxF,KAAU,kBAAC,OAAD;GAAK,WAAU;aAAQ;EAAY,CAAA;CAC3C"}
@@ -1 +1 @@
1
- {"version":3,"file":"EvidenceUpload.js","names":[],"sources":["../../../src/ecoimpacthub/components/EvidenceUpload.tsx"],"sourcesContent":["/**\n * EvidenceUpload — a controlled file-attach control (Integration A).\n * @module ecoimpacthub/components/EvidenceUpload\n *\n * Wraps `useEcoFileUpload` (the wspace-files 3-step flow). On file select it\n * uploads, shows byte-progress + the filename, and emits `{ fileId, fileName }`\n * via `onChange`. The parent stores `fileId` and passes it to the eco mutation\n * (`ecoRecordObservation.evidenceFileId`, `ecoPublishReport.fileId`).\n */\n\nimport { useRef, type ChangeEvent } from 'react';\nimport { Paperclip, Upload, X } from 'lucide-react';\nimport { Button, Label, Spinner } from '@burdenoff/fe-libs/ui';\nimport { useEcoFileUpload, type UploadedEcoFile } from '../hooks';\n\ninterface EvidenceUploadProps {\n id: string;\n label: string;\n value: UploadedEcoFile | null;\n onChange: (value: UploadedEcoFile | null) => void;\n accept?: string;\n disabled?: boolean;\n hint?: string;\n}\n\nexport function EvidenceUpload({\n id,\n label,\n value,\n onChange,\n accept = 'image/*,application/pdf,audio/*',\n disabled = false,\n hint,\n}: EvidenceUploadProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n const { upload, isUploading, progress, error, reset } = useEcoFileUpload();\n\n const handleSelect = async (event: ChangeEvent<HTMLInputElement>) => {\n const file = event.target.files?.[0];\n // Clear the native input so the same file can be re-selected after a remove.\n event.target.value = '';\n if (!file) return;\n try {\n const uploaded = await upload(file);\n onChange(uploaded);\n } catch {\n // Error surfaced inline via `error`; keep the form usable.\n }\n };\n\n const handleRemove = () => {\n reset();\n onChange(null);\n };\n\n return (\n <div className=\"grid gap-1.5\">\n <Label htmlFor={id}>{label}</Label>\n\n <input\n ref={inputRef}\n id={id}\n type=\"file\"\n accept={accept}\n className=\"hidden\"\n disabled={disabled || isUploading}\n onChange={handleSelect}\n />\n\n {value ? (\n <div className=\"flex items-center gap-2 rounded-lg border border-border-seam bg-bg-sunken/60 px-3 py-2\">\n <Paperclip className=\"h-4 w-4 shrink-0 text-text-tertiary\" />\n <span\n className=\"min-w-0 flex-1 truncate text-sm text-text-primary\"\n title={value.fileName}\n >\n {value.fileName}\n </span>\n <button\n type=\"button\"\n onClick={handleRemove}\n disabled={disabled}\n aria-label=\"Remove attachment\"\n className=\"rounded-md p-1 text-text-tertiary hover:bg-bg-sunken hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n ) : isUploading ? (\n <div className=\"flex items-center gap-3 rounded-lg border border-border-seam bg-bg-sunken/60 px-3 py-2\">\n <Spinner size=\"sm\" />\n <span className=\"text-sm text-text-secondary\">Uploading… {progress}%</span>\n <div className=\"ml-auto h-1.5 w-24 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg transition-[width] duration-150\"\n style={{ width: `${progress}%` }}\n />\n </div>\n </div>\n ) : (\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={disabled}\n onClick={() => inputRef.current?.click()}\n className=\"justify-start\"\n >\n <Upload className=\"mr-1.5 h-4 w-4\" /> Choose file\n </Button>\n )}\n\n {hint && !error && <p className=\"text-xs text-text-tertiary\">{hint}</p>}\n {error && <p className=\"text-xs text-status-error-text\">{error}</p>}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAyBA,SAAgB,EAAe,EAC7B,OACA,UACA,UACA,aACA,YAAS,mCACT,cAAW,IACX,WACsB;CACtB,IAAM,IAAW,EAAyB,KAAK,EACzC,EAAE,WAAQ,gBAAa,aAAU,UAAO,aAAU,GAAkB;AAoB1E,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD;IAAO,SAAS;cAAK;IAAc,CAAA;GAEnC,kBAAC,SAAD;IACE,KAAK;IACD;IACJ,MAAK;IACG;IACR,WAAU;IACV,UAAU,KAAY;IACtB,UA7Be,OAAO,MAAyC;KACnE,IAAM,IAAO,EAAM,OAAO,QAAQ;AAElC,WAAM,OAAO,QAAQ,IAChB,EACL,KAAI;AAEF,QADiB,MAAM,EAAO,EAAK,CACjB;aACZ;;IAsBJ,CAAA;GAED,IACC,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAW,WAAU,uCAAwC,CAAA;KAC7D,kBAAC,QAAD;MACE,WAAU;MACV,OAAO,EAAM;gBAEZ,EAAM;MACF,CAAA;KACP,kBAAC,UAAD;MACE,MAAK;MACL,eA9BiB;AAEzB,OADA,GAAO,EACP,EAAS,KAAK;;MA6BI;MACV,cAAW;MACX,WAAU;gBAEV,kBAAC,GAAD,EAAG,WAAU,WAAY,CAAA;MAClB,CAAA;KACL;QACJ,IACF,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAS,MAAK,MAAO,CAAA;KACrB,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OAA8C;OAAY;OAAS;OAAQ;;KAC3E,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,OAAD;OACE,WAAU;OACV,OAAO,EAAE,OAAO,GAAG,EAAS,IAAI;OAChC,CAAA;MACE,CAAA;KACF;QAEN,kBAAC,GAAD;IACE,MAAK;IACL,SAAQ;IACE;IACV,eAAe,EAAS,SAAS,OAAO;IACxC,WAAU;cALZ,CAOE,kBAAC,GAAD,EAAQ,WAAU,kBAAmB,CAAA,EAAA,eAC9B;;GAGV,KAAQ,CAAC,KAAS,kBAAC,KAAD;IAAG,WAAU;cAA8B;IAAS,CAAA;GACtE,KAAS,kBAAC,KAAD;IAAG,WAAU;cAAkC;IAAU,CAAA;GAC/D"}
1
+ {"version":3,"file":"EvidenceUpload.js","names":[],"sources":["../../../src/ecoimpacthub/components/EvidenceUpload.tsx"],"sourcesContent":["/**\n * EvidenceUpload — a controlled file-attach control (Integration A).\n * @module ecoimpacthub/components/EvidenceUpload\n *\n * Wraps `useEcoFileUpload` (the wspace-files 3-step flow). On file select it\n * uploads, shows byte-progress + the filename, and emits `{ fileId, fileName }`\n * via `onChange`. The parent stores `fileId` and passes it to the eco mutation\n * (`ecoRecordObservation.evidenceFileId`, `ecoPublishReport.fileId`).\n */\n\nimport { useRef, type ChangeEvent } from 'react';\nimport { Paperclip, Upload, X } from 'lucide-react';\nimport { Button, Label, Spinner } from '@burdenoff/fe-libs/ui';\nimport { useEcoFileUpload, type UploadedEcoFile } from '../hooks';\n\ninterface EvidenceUploadProps {\n id: string;\n label: string;\n value: UploadedEcoFile | null;\n onChange: (value: UploadedEcoFile | null) => void;\n accept?: string;\n disabled?: boolean;\n hint?: string;\n}\n\nexport function EvidenceUpload({\n id,\n label,\n value,\n onChange,\n accept = 'image/*,application/pdf,audio/*',\n disabled = false,\n hint,\n}: EvidenceUploadProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n const { upload, isUploading, progress, error, reset } = useEcoFileUpload();\n\n const handleSelect = async (event: ChangeEvent<HTMLInputElement>) => {\n const file = event.target.files?.[0];\n // Clear the native input so the same file can be re-selected after a remove.\n event.target.value = '';\n if (!file) return;\n try {\n const uploaded = await upload(file);\n onChange(uploaded);\n } catch {\n // Error surfaced inline via `error`; keep the form usable.\n }\n };\n\n const handleRemove = () => {\n reset();\n onChange(null);\n };\n\n return (\n <div className=\"grid gap-1.5\">\n <Label htmlFor={id}>{label}</Label>\n\n <input\n ref={inputRef}\n id={id}\n type=\"file\"\n accept={accept}\n className=\"hidden\"\n disabled={disabled || isUploading}\n onChange={handleSelect}\n />\n\n {value ? (\n <div className=\"flex items-center gap-2 rounded-lg border border-border-seam bg-bg-sunken/60 px-3 py-2\">\n <Paperclip className=\"h-4 w-4 shrink-0 text-text-tertiary\" />\n <span\n className=\"min-w-0 flex-1 truncate text-sm text-text-primary\"\n title={value.fileName}\n >\n {value.fileName}\n </span>\n <button\n type=\"button\"\n onClick={handleRemove}\n disabled={disabled}\n aria-label=\"Remove attachment\"\n className=\"rounded-md p-1 text-text-tertiary hover:bg-bg-sunken hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n ) : isUploading ? (\n <div className=\"flex items-center gap-3 rounded-lg border border-border-seam bg-bg-sunken/60 px-3 py-2\">\n <Spinner size=\"sm\" />\n <span className=\"text-sm text-text-secondary\">Uploading… {progress}%</span>\n <div className=\"ml-auto h-1.5 w-24 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg transition-[width] duration-150\"\n style={{ width: `${progress}%` }}\n />\n </div>\n </div>\n ) : (\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={disabled}\n onClick={() => inputRef.current?.click()}\n className=\"justify-start\"\n >\n <Upload className=\"mr-1.5 h-4 w-4\" /> Choose file\n </Button>\n )}\n\n {hint && !error && <p className=\"text-xs text-text-tertiary\">{hint}</p>}\n {error && <p className=\"text-xs text-status-error-text\">{error}</p>}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAyBA,SAAgB,EAAe,EAC7B,OACA,UACA,UACA,aACA,YAAS,mCACT,cAAW,IACX,WACsB;CACtB,IAAM,IAAW,EAAyB,IAAI,GACxC,EAAE,WAAQ,gBAAa,aAAU,UAAO,aAAU,EAAiB;CAoBzE,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD;IAAO,SAAS;cAAK;GAAa,CAAA;GAElC,kBAAC,SAAD;IACE,KAAK;IACD;IACJ,MAAK;IACG;IACR,WAAU;IACV,UAAU,KAAY;IACtB,UAAU,OA7BY,MAAyC;KACnE,IAAM,IAAO,EAAM,OAAO,QAAQ;KAElC,MAAM,OAAO,QAAQ,IAChB,GACL,IAAI;MAEF,EAAS,MADc,EAAO,CAAI,CACjB;KACnB,QAAQ,CAER;IACF;GAmBK,CAAA;GAEA,IACC,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAW,WAAU,sCAAuC,CAAA;KAC5D,kBAAC,QAAD;MACE,WAAU;MACV,OAAO,EAAM;gBAEZ,EAAM;KACH,CAAA;KACN,kBAAC,UAAD;MACE,MAAK;MACL,eA9BiB;OAEzB,AADA,EAAM,GACN,EAAS,IAAI;MACf;MA4BoB;MACV,cAAW;MACX,WAAU;gBAEV,kBAAC,GAAD,EAAG,WAAU,UAAW,CAAA;KAClB,CAAA;IACL;QACH,IACF,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAS,MAAK,KAAM,CAAA;KACpB,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OAA8C;OAAY;OAAS;MAAO;;KAC1E,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,OAAD;OACE,WAAU;OACV,OAAO,EAAE,OAAO,GAAG,EAAS,GAAG;MAChC,CAAA;KACE,CAAA;IACF;QAEL,kBAAC,GAAD;IACE,MAAK;IACL,SAAQ;IACE;IACV,eAAe,EAAS,SAAS,MAAM;IACvC,WAAU;cALZ,CAOE,kBAAC,GAAD,EAAQ,WAAU,iBAAkB,CAAA,GAAC,cAC/B;;GAGT,KAAQ,CAAC,KAAS,kBAAC,KAAD;IAAG,WAAU;cAA8B;GAAQ,CAAA;GACrE,KAAS,kBAAC,KAAD;IAAG,WAAU;cAAkC;GAAS,CAAA;EAC/D;;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"FeatureFlagGate.js","names":[],"sources":["../../../src/ecoimpacthub/components/FeatureFlagGate.tsx"],"sourcesContent":["/**\n * Default-allow feature flag gate for EcoImpactHub routes and pages.\n *\n * Wraps a page or section so it can be remotely disabled via the platform\n * feature-flag service. When the flag is absent or the service is unreachable,\n * the gate defaults to **allowing** access so users are never locked out by\n * transient flag-evaluation failures.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { useFeatureFlag } from '@burdenoff/fe-libs/shared/feature-flags';\n\ninterface FeatureFlagGateProps {\n flag: string;\n children: ReactNode;\n fallback?: ReactNode;\n}\n\nexport const FeatureFlagGate: FC<FeatureFlagGateProps> = ({ flag, children, fallback = null }) => {\n const enabled = useFeatureFlag(flag, true);\n return enabled ? <>{children}</> : <>{fallback}</>;\n};\n"],"mappings":";;;AAkBA,IAAa,KAA6C,EAAE,SAAM,aAAU,cAAW,WACrE,EAAe,GAAM,GAAK,GACzB,kBAAA,GAAA,EAAG,aAAY,CAAA,GAAG,kBAAA,GAAA,EAAA,UAAG,GAAY,CAAA"}
1
+ {"version":3,"file":"FeatureFlagGate.js","names":[],"sources":["../../../src/ecoimpacthub/components/FeatureFlagGate.tsx"],"sourcesContent":["/**\n * Default-allow feature flag gate for EcoImpactHub routes and pages.\n *\n * Wraps a page or section so it can be remotely disabled via the platform\n * feature-flag service. When the flag is absent or the service is unreachable,\n * the gate defaults to **allowing** access so users are never locked out by\n * transient flag-evaluation failures.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { useFeatureFlag } from '@burdenoff/fe-libs/shared/feature-flags';\n\ninterface FeatureFlagGateProps {\n flag: string;\n children: ReactNode;\n fallback?: ReactNode;\n}\n\nexport const FeatureFlagGate: FC<FeatureFlagGateProps> = ({ flag, children, fallback = null }) => {\n const enabled = useFeatureFlag(flag, true);\n return enabled ? <>{children}</> : <>{fallback}</>;\n};\n"],"mappings":";;;AAkBA,IAAa,KAA6C,EAAE,SAAM,aAAU,cAAW,WACrE,EAAe,GAAM,EAC9B,IAAU,kBAAA,GAAA,EAAG,YAAW,CAAA,IAAI,kBAAA,GAAA,EAAA,UAAG,EAAW,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"FileLink.js","names":[],"sources":["../../../src/ecoimpacthub/components/FileLink.tsx"],"sourcesContent":["/**\n * FileLink — resolves a federated File id to a download link (Integration A).\n * @module ecoimpacthub/components/FileLink\n *\n * The eco queries select `evidence { id }` / `file { id }` (just the id). This\n * resolves the platform File via `getFile(id)` for its name + signed\n * `downloadUrl` so evidence/report artifacts render as a real link.\n */\n\nimport { FileText, Loader2 } from 'lucide-react';\nimport { useEcoFile } from '../hooks';\n\ninterface FileLinkProps {\n fileId: string | null | undefined;\n className?: string;\n}\n\nexport function FileLink({ fileId, className }: FileLinkProps) {\n const { data, isLoading, isError } = useEcoFile(fileId);\n\n if (!fileId) return null;\n\n if (isLoading) {\n return (\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-tertiary\">\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" /> Loading attachment…\n </span>\n );\n }\n\n if (isError || !data) {\n return (\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-tertiary\">\n <FileText className=\"h-3.5 w-3.5\" /> Attachment unavailable\n </span>\n );\n }\n\n const base =\n 'inline-flex items-center gap-1.5 text-sm font-medium text-action-primary-bg hover:underline';\n\n if (!data.downloadUrl) {\n return (\n <span className={className ?? 'inline-flex items-center gap-1.5 text-sm text-text-secondary'}>\n <FileText className=\"h-3.5 w-3.5\" /> {data.name}\n </span>\n );\n }\n\n return (\n <a\n href={data.downloadUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={className ?? base}\n >\n <FileText className=\"h-3.5 w-3.5\" /> {data.name}\n </a>\n );\n}\n"],"mappings":";;;;;AAiBA,SAAgB,EAAS,EAAE,WAAQ,gBAA4B;CAC7D,IAAM,EAAE,SAAM,cAAW,eAAY,EAAW,EAAO;AA+BvD,QA7BK,IAED,IAEA,kBAAC,QAAD;EAAM,WAAU;YAAhB,CACE,kBAAC,GAAD,EAAS,WAAU,4BAA6B,CAAA,EAAA,uBAC3C;MAIP,KAAW,CAAC,IAEZ,kBAAC,QAAD;EAAM,WAAU;YAAhB,CACE,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,EAAA,0BAC/B;MAON,EAAK,cASR,kBAAC,KAAD;EACE,MAAM,EAAK;EACX,QAAO;EACP,KAAI;EACJ,WAAW,KAAa;YAJ1B;GAME,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA;;GAAE,EAAK;GACzC;MAdF,kBAAC,QAAD;EAAM,WAAW,KAAa;YAA9B;GACE,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA;;GAAE,EAAK;GACtC;MAzBS"}
1
+ {"version":3,"file":"FileLink.js","names":[],"sources":["../../../src/ecoimpacthub/components/FileLink.tsx"],"sourcesContent":["/**\n * FileLink — resolves a federated File id to a download link (Integration A).\n * @module ecoimpacthub/components/FileLink\n *\n * The eco queries select `evidence { id }` / `file { id }` (just the id). This\n * resolves the platform File via `getFile(id)` for its name + signed\n * `downloadUrl` so evidence/report artifacts render as a real link.\n */\n\nimport { FileText, Loader2 } from 'lucide-react';\nimport { useEcoFile } from '../hooks';\n\ninterface FileLinkProps {\n fileId: string | null | undefined;\n className?: string;\n}\n\nexport function FileLink({ fileId, className }: FileLinkProps) {\n const { data, isLoading, isError } = useEcoFile(fileId);\n\n if (!fileId) return null;\n\n if (isLoading) {\n return (\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-tertiary\">\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" /> Loading attachment…\n </span>\n );\n }\n\n if (isError || !data) {\n return (\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-tertiary\">\n <FileText className=\"h-3.5 w-3.5\" /> Attachment unavailable\n </span>\n );\n }\n\n const base =\n 'inline-flex items-center gap-1.5 text-sm font-medium text-action-primary-bg hover:underline';\n\n if (!data.downloadUrl) {\n return (\n <span className={className ?? 'inline-flex items-center gap-1.5 text-sm text-text-secondary'}>\n <FileText className=\"h-3.5 w-3.5\" /> {data.name}\n </span>\n );\n }\n\n return (\n <a\n href={data.downloadUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={className ?? base}\n >\n <FileText className=\"h-3.5 w-3.5\" /> {data.name}\n </a>\n );\n}\n"],"mappings":";;;;;AAiBA,SAAgB,EAAS,EAAE,WAAQ,gBAA4B;CAC7D,IAAM,EAAE,SAAM,cAAW,eAAY,EAAW,CAAM;CA+BtD,OA7BK,IAED,IAEA,kBAAC,QAAD;EAAM,WAAU;YAAhB,CACE,kBAAC,GAAD,EAAS,WAAU,2BAA4B,CAAA,GAAC,sBAC5C;MAIN,KAAW,CAAC,IAEZ,kBAAC,QAAD;EAAM,WAAU;YAAhB,CACE,kBAAC,GAAD,EAAU,WAAU,cAAe,CAAA,GAAC,yBAChC;MAOL,EAAK,cASR,kBAAC,KAAD;EACE,MAAM,EAAK;EACX,QAAO;EACP,KAAI;EACJ,WAAW,KAAa;YAJ1B;GAME,kBAAC,GAAD,EAAU,WAAU,cAAe,CAAA;GAAC;GAAE,EAAK;EAC1C;MAdD,kBAAC,QAAD;EAAM,WAAW,KAAa;YAA9B;GACE,kBAAC,GAAD,EAAU,WAAU,cAAe,CAAA;GAAC;GAAE,EAAK;EACvC;MAzBU;AAuCtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"FilterTabs.js","names":[],"sources":["../../../src/ecoimpacthub/components/FilterTabs.tsx"],"sourcesContent":["/**\n * FilterTabs — a segmented status/enum filter control.\n * @module ecoimpacthub/components\n */\n\nimport { cn } from '../utils/cn';\n\nexport interface FilterOption<V extends string> {\n value: V;\n label: string;\n count?: number;\n}\n\ninterface FilterTabsProps<V extends string> {\n options: FilterOption<V>[];\n value: V;\n onChange: (value: V) => void;\n className?: string;\n}\n\nexport function FilterTabs<V extends string>({\n options,\n value,\n onChange,\n className,\n}: FilterTabsProps<V>) {\n return (\n <div\n role=\"tablist\"\n className={cn(\n 'inline-flex flex-wrap items-center gap-1 rounded-xl border border-border-seam bg-bg-surface p-1',\n className\n )}\n >\n {options.map((opt) => {\n const active = opt.value === value;\n return (\n <button\n key={opt.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n onClick={() => onChange(opt.value)}\n className={cn(\n 'rounded-lg px-3 py-1.5 text-sm font-medium transition-colors',\n active\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n {opt.label}\n {typeof opt.count === 'number' && (\n <span\n className={cn(\n 'ml-1.5 rounded-full px-1.5 py-0.5 text-xs tabular-nums',\n active ? 'bg-black/10 dark:bg-white/15' : 'bg-bg-sunken'\n )}\n >\n {opt.count}\n </span>\n )}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;AAoBA,SAAgB,EAA6B,EAC3C,YACA,UACA,aACA,gBACqB;AACrB,QACE,kBAAC,OAAD;EACE,MAAK;EACL,WAAW,EACT,mGACA,EACD;YAEA,EAAQ,KAAK,MAAQ;GACpB,IAAM,IAAS,EAAI,UAAU;AAC7B,UACE,kBAAC,UAAD;IAEE,MAAK;IACL,MAAK;IACL,iBAAe;IACf,eAAe,EAAS,EAAI,MAAM;IAClC,WAAW,EACT,gEACA,IACI,kDACA,iEACL;cAXH,CAaG,EAAI,OACJ,OAAO,EAAI,SAAU,YACpB,kBAAC,QAAD;KACE,WAAW,EACT,0DACA,IAAS,iCAAiC,eAC3C;eAEA,EAAI;KACA,CAAA,CAEF;MAvBF,EAAI,MAuBF;IAEX;EACE,CAAA"}
1
+ {"version":3,"file":"FilterTabs.js","names":[],"sources":["../../../src/ecoimpacthub/components/FilterTabs.tsx"],"sourcesContent":["/**\n * FilterTabs — a segmented status/enum filter control.\n * @module ecoimpacthub/components\n */\n\nimport { cn } from '../utils/cn';\n\nexport interface FilterOption<V extends string> {\n value: V;\n label: string;\n count?: number;\n}\n\ninterface FilterTabsProps<V extends string> {\n options: FilterOption<V>[];\n value: V;\n onChange: (value: V) => void;\n className?: string;\n}\n\nexport function FilterTabs<V extends string>({\n options,\n value,\n onChange,\n className,\n}: FilterTabsProps<V>) {\n return (\n <div\n role=\"tablist\"\n className={cn(\n 'inline-flex flex-wrap items-center gap-1 rounded-xl border border-border-seam bg-bg-surface p-1',\n className\n )}\n >\n {options.map((opt) => {\n const active = opt.value === value;\n return (\n <button\n key={opt.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n onClick={() => onChange(opt.value)}\n className={cn(\n 'rounded-lg px-3 py-1.5 text-sm font-medium transition-colors',\n active\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n {opt.label}\n {typeof opt.count === 'number' && (\n <span\n className={cn(\n 'ml-1.5 rounded-full px-1.5 py-0.5 text-xs tabular-nums',\n active ? 'bg-black/10 dark:bg-white/15' : 'bg-bg-sunken'\n )}\n >\n {opt.count}\n </span>\n )}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;AAoBA,SAAgB,EAA6B,EAC3C,YACA,UACA,aACA,gBACqB;CACrB,OACE,kBAAC,OAAD;EACE,MAAK;EACL,WAAW,EACT,mGACA,CACF;YAEC,EAAQ,KAAK,MAAQ;GACpB,IAAM,IAAS,EAAI,UAAU;GAC7B,OACE,kBAAC,UAAD;IAEE,MAAK;IACL,MAAK;IACL,iBAAe;IACf,eAAe,EAAS,EAAI,KAAK;IACjC,WAAW,EACT,gEACA,IACI,kDACA,gEACN;cAXF,CAaG,EAAI,OACJ,OAAO,EAAI,SAAU,YACpB,kBAAC,QAAD;KACE,WAAW,EACT,0DACA,IAAS,iCAAiC,cAC5C;eAEC,EAAI;IACD,CAAA,CAEF;MAvBD,EAAI,KAuBH;EAEZ,CAAC;CACE,CAAA;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"MetricsCard.js","names":[],"sources":["../../../src/ecoimpacthub/components/MetricsCard.tsx"],"sourcesContent":["/**\n * Metrics Card Component\n * @module ecoimpacthub/components\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { TrendingUp, TrendingDown, Minus } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\nimport type { TrendDirection } from '../types';\n\ntype Accent = 'success' | 'warning' | 'error';\n\ninterface MetricsCardProps {\n icon: ReactNode;\n value: string | number;\n label: string;\n trend?: TrendDirection;\n trendValue?: string;\n className?: string;\n /** Render as the page's hero metric (glass treatment + accent glow). */\n featured?: boolean;\n /** Severity accent — tints the icon and adds a soft top-edge glow. */\n accent?: Accent;\n /** Optional pill shown in the top-right (e.g. \"Critical\"). */\n pill?: ReactNode;\n /** Optional slot under the value (e.g. a MiniBar or sub-label). */\n footer?: ReactNode;\n}\n\nconst trendConfig: Record<TrendDirection, { icon: typeof TrendingUp; color: string }> = {\n up: { icon: TrendingUp, color: 'text-status-success-text' },\n down: { icon: TrendingDown, color: 'text-status-error-text' },\n neutral: { icon: Minus, color: 'text-text-secondary' },\n};\n\nconst accentIcon: Record<Accent, string> = {\n success: 'text-status-success-text',\n warning: 'text-status-warning-text',\n error: 'text-status-error-text',\n};\n\nconst accentGlow: Record<Accent, string> = {\n success: 'shadow-[inset_0_1px_0_0_var(--color-status-success-text)]',\n warning: 'shadow-[inset_0_1px_0_0_var(--color-status-warning-text)]',\n error: 'shadow-[inset_0_1px_0_0_var(--color-status-error-text)]',\n};\n\nexport const MetricsCard: FC<MetricsCardProps> = ({\n icon,\n value,\n label,\n trend,\n trendValue,\n className,\n featured = false,\n accent,\n pill,\n footer,\n}) => {\n const trendInfo = trend ? trendConfig[trend] : null;\n const TrendIcon = trendInfo?.icon;\n\n return (\n <GlassCard\n treatment={featured ? 'glass' : 'metric'}\n glow={featured}\n className={cn('p-6', accent && accentGlow[accent], className)}\n >\n <div className=\"flex items-center justify-between\">\n <div className={cn('text-text-secondary', accent && accentIcon[accent])}>{icon}</div>\n {pill ??\n (trend && trendInfo && TrendIcon ? (\n <div className={cn('flex items-center gap-1 text-xs font-medium', trendInfo.color)}>\n <TrendIcon className=\"h-3.5 w-3.5\" />\n {trendValue && <span>{trendValue}</span>}\n </div>\n ) : null)}\n </div>\n <div className=\"mt-3\">\n <p className=\"text-2xl font-bold text-text-primary tabular-nums\">{value}</p>\n <p className=\"mt-1 text-sm text-text-secondary\">{label}</p>\n {footer && <div className=\"mt-3\">{footer}</div>}\n </div>\n </GlassCard>\n );\n};\n"],"mappings":";;;;;AA8BA,IAAM,IAAkF;CACtF,IAAI;EAAE,MAAM;EAAY,OAAO;EAA4B;CAC3D,MAAM;EAAE,MAAM;EAAc,OAAO;EAA0B;CAC7D,SAAS;EAAE,MAAM;EAAO,OAAO;EAAuB;CACvD,EAEK,IAAqC;CACzC,SAAS;CACT,SAAS;CACT,OAAO;CACR,EAEK,IAAqC;CACzC,SAAS;CACT,SAAS;CACT,OAAO;CACR,EAEY,KAAqC,EAChD,SACA,UACA,UACA,UACA,eACA,cACA,cAAW,IACX,WACA,SACA,gBACI;CACJ,IAAM,IAAY,IAAQ,EAAY,KAAS,MACzC,IAAY,GAAW;AAE7B,QACE,kBAAC,GAAD;EACE,WAAW,IAAW,UAAU;EAChC,MAAM;EACN,WAAW,EAAG,OAAO,KAAU,EAAW,IAAS,EAAU;YAH/D,CAKE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAW,EAAG,uBAAuB,KAAU,EAAW,GAAQ;cAAG;IAAW,CAAA,EACpF,MACE,KAAS,KAAa,IACrB,kBAAC,OAAD;IAAK,WAAW,EAAG,+CAA+C,EAAU,MAAM;cAAlF,CACE,kBAAC,GAAD,EAAW,WAAU,eAAgB,CAAA,EACpC,KAAc,kBAAC,QAAD,EAAA,UAAO,GAAkB,CAAA,CACpC;QACJ,MACF;MACN,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,KAAD;KAAG,WAAU;eAAqD;KAAU,CAAA;IAC5E,kBAAC,KAAD;KAAG,WAAU;eAAoC;KAAU,CAAA;IAC1D,KAAU,kBAAC,OAAD;KAAK,WAAU;eAAQ;KAAa,CAAA;IAC3C;KACI"}
1
+ {"version":3,"file":"MetricsCard.js","names":[],"sources":["../../../src/ecoimpacthub/components/MetricsCard.tsx"],"sourcesContent":["/**\n * Metrics Card Component\n * @module ecoimpacthub/components\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { TrendingUp, TrendingDown, Minus } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\nimport type { TrendDirection } from '../types';\n\ntype Accent = 'success' | 'warning' | 'error';\n\ninterface MetricsCardProps {\n icon: ReactNode;\n value: string | number;\n label: string;\n trend?: TrendDirection;\n trendValue?: string;\n className?: string;\n /** Render as the page's hero metric (glass treatment + accent glow). */\n featured?: boolean;\n /** Severity accent — tints the icon and adds a soft top-edge glow. */\n accent?: Accent;\n /** Optional pill shown in the top-right (e.g. \"Critical\"). */\n pill?: ReactNode;\n /** Optional slot under the value (e.g. a MiniBar or sub-label). */\n footer?: ReactNode;\n}\n\nconst trendConfig: Record<TrendDirection, { icon: typeof TrendingUp; color: string }> = {\n up: { icon: TrendingUp, color: 'text-status-success-text' },\n down: { icon: TrendingDown, color: 'text-status-error-text' },\n neutral: { icon: Minus, color: 'text-text-secondary' },\n};\n\nconst accentIcon: Record<Accent, string> = {\n success: 'text-status-success-text',\n warning: 'text-status-warning-text',\n error: 'text-status-error-text',\n};\n\nconst accentGlow: Record<Accent, string> = {\n success: 'shadow-[inset_0_1px_0_0_var(--color-status-success-text)]',\n warning: 'shadow-[inset_0_1px_0_0_var(--color-status-warning-text)]',\n error: 'shadow-[inset_0_1px_0_0_var(--color-status-error-text)]',\n};\n\nexport const MetricsCard: FC<MetricsCardProps> = ({\n icon,\n value,\n label,\n trend,\n trendValue,\n className,\n featured = false,\n accent,\n pill,\n footer,\n}) => {\n const trendInfo = trend ? trendConfig[trend] : null;\n const TrendIcon = trendInfo?.icon;\n\n return (\n <GlassCard\n treatment={featured ? 'glass' : 'metric'}\n glow={featured}\n className={cn('p-6', accent && accentGlow[accent], className)}\n >\n <div className=\"flex items-center justify-between\">\n <div className={cn('text-text-secondary', accent && accentIcon[accent])}>{icon}</div>\n {pill ??\n (trend && trendInfo && TrendIcon ? (\n <div className={cn('flex items-center gap-1 text-xs font-medium', trendInfo.color)}>\n <TrendIcon className=\"h-3.5 w-3.5\" />\n {trendValue && <span>{trendValue}</span>}\n </div>\n ) : null)}\n </div>\n <div className=\"mt-3\">\n <p className=\"text-2xl font-bold text-text-primary tabular-nums\">{value}</p>\n <p className=\"mt-1 text-sm text-text-secondary\">{label}</p>\n {footer && <div className=\"mt-3\">{footer}</div>}\n </div>\n </GlassCard>\n );\n};\n"],"mappings":";;;;;AA8BA,IAAM,IAAkF;CACtF,IAAI;EAAE,MAAM;EAAY,OAAO;CAA2B;CAC1D,MAAM;EAAE,MAAM;EAAc,OAAO;CAAyB;CAC5D,SAAS;EAAE,MAAM;EAAO,OAAO;CAAsB;AACvD,GAEM,IAAqC;CACzC,SAAS;CACT,SAAS;CACT,OAAO;AACT,GAEM,IAAqC;CACzC,SAAS;CACT,SAAS;CACT,OAAO;AACT,GAEa,KAAqC,EAChD,SACA,UACA,UACA,UACA,eACA,cACA,cAAW,IACX,WACA,SACA,gBACI;CACJ,IAAM,IAAY,IAAQ,EAAY,KAAS,MACzC,IAAY,GAAW;CAE7B,OACE,kBAAC,GAAD;EACE,WAAW,IAAW,UAAU;EAChC,MAAM;EACN,WAAW,EAAG,OAAO,KAAU,EAAW,IAAS,CAAS;YAH9D,CAKE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAW,EAAG,uBAAuB,KAAU,EAAW,EAAO;cAAI;GAAU,CAAA,GACnF,MACE,KAAS,KAAa,IACrB,kBAAC,OAAD;IAAK,WAAW,EAAG,+CAA+C,EAAU,KAAK;cAAjF,CACE,kBAAC,GAAD,EAAW,WAAU,cAAe,CAAA,GACnC,KAAc,kBAAC,QAAD,EAAA,UAAO,EAAiB,CAAA,CACpC;QACH,KACH;MACL,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,KAAD;KAAG,WAAU;eAAqD;IAAS,CAAA;IAC3E,kBAAC,KAAD;KAAG,WAAU;eAAoC;IAAS,CAAA;IACzD,KAAU,kBAAC,OAAD;KAAK,WAAU;eAAQ;IAAY,CAAA;GAC3C;IACI;;AAEf"}
@@ -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.d.ts","sourceRoot":"","sources":["../../../src/ecoimpacthub/components/StatusBadge.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAIhC,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA0FD,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAsB5C,CAAC"}
1
+ {"version":3,"file":"StatusBadge.d.ts","sourceRoot":"","sources":["../../../src/ecoimpacthub/components/StatusBadge.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAIhC,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA6FD,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAsB5C,CAAC"}
@@ -60,6 +60,9 @@ var i = {
60
60
  TCFD: "outline",
61
61
  CDP: "outline",
62
62
  SASB: "outline",
63
+ CSRD: "outline",
64
+ ISSB: "outline",
65
+ EU_TAXONOMY: "outline",
63
66
  CUSTOM: "secondary"
64
67
  }, s = ({ status: s, className: c }) => {
65
68
  let l = s.toUpperCase(), u = o[l] ?? "secondary", d = a.has(l);
@@ -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 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,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"}
@@ -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"}