@burdenoff/microfe-ecoimpacthub 2026.720.3 → 2026.720.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.js +1 -1
- package/dist/ecoimpacthub/EcoImpactHubRoot.js.map +1 -1
- package/dist/ecoimpacthub/EcoImpactHubRoutes.js.map +1 -1
- package/dist/ecoimpacthub/components/DashboardCustomizerDialog.d.ts +11 -0
- package/dist/ecoimpacthub/components/DashboardCustomizerDialog.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/DashboardCustomizerDialog.js +182 -0
- package/dist/ecoimpacthub/components/DashboardCustomizerDialog.js.map +1 -0
- package/dist/ecoimpacthub/components/DataTable.js.map +1 -1
- package/dist/ecoimpacthub/components/EcoDiscussion.js.map +1 -1
- package/dist/ecoimpacthub/components/EcoTags.js.map +1 -1
- package/dist/ecoimpacthub/components/EmptyState.js.map +1 -1
- package/dist/ecoimpacthub/components/EvidenceUpload.js.map +1 -1
- package/dist/ecoimpacthub/components/FeatureFlagGate.js.map +1 -1
- package/dist/ecoimpacthub/components/FileLink.js.map +1 -1
- package/dist/ecoimpacthub/components/FilterTabs.js.map +1 -1
- package/dist/ecoimpacthub/components/MetricsCard.js.map +1 -1
- package/dist/ecoimpacthub/components/MiniBar.js.map +1 -1
- package/dist/ecoimpacthub/components/PageLayout.js.map +1 -1
- package/dist/ecoimpacthub/components/Pagination.js.map +1 -1
- package/dist/ecoimpacthub/components/StateViews.js.map +1 -1
- package/dist/ecoimpacthub/components/StatusBadge.js.map +1 -1
- package/dist/ecoimpacthub/components/Tabs.js.map +1 -1
- package/dist/ecoimpacthub/context/EcoImpactHubContext.js.map +1 -1
- package/dist/ecoimpacthub/hooks/index.d.ts +1 -0
- package/dist/ecoimpacthub/hooks/index.d.ts.map +1 -1
- package/dist/ecoimpacthub/hooks/index.js +1 -0
- package/dist/ecoimpacthub/hooks/useCursorPager.js.map +1 -1
- package/dist/ecoimpacthub/hooks/useDashboardLayout.d.ts +29 -0
- package/dist/ecoimpacthub/hooks/useDashboardLayout.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/useDashboardLayout.js +95 -0
- package/dist/ecoimpacthub/hooks/useDashboardLayout.js.map +1 -0
- package/dist/ecoimpacthub/hooks/useEcoComments.js.map +1 -1
- package/dist/ecoimpacthub/hooks/useEcoFiles.js.map +1 -1
- package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.js.map +1 -1
- package/dist/ecoimpacthub/hooks/useEcoTags.js.map +1 -1
- package/dist/ecoimpacthub/pages/DashboardPage.d.ts +7 -0
- package/dist/ecoimpacthub/pages/DashboardPage.d.ts.map +1 -1
- package/dist/ecoimpacthub/pages/DashboardPage.js +505 -447
- package/dist/ecoimpacthub/pages/DashboardPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/_shared/ConservationBadge.js.map +1 -1
- package/dist/ecoimpacthub/pages/_shared/EvidenceThumb.js.map +1 -1
- package/dist/ecoimpacthub/pages/_shared/MethodBadge.js.map +1 -1
- package/dist/ecoimpacthub/pages/_shared/TaxonChip.js.map +1 -1
- package/dist/ecoimpacthub/pages/badges.js.map +1 -1
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/carbonVisuals.js.map +1 -1
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/habitat/LifecycleProgress.js.map +1 -1
- package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/observations/ObservationsPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/reports/ReportDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/reports/ReportsPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/sites/SiteDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/sites/SitesPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/sites/siteTypeVisuals.js.map +1 -1
- package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/species/SpeciesPage.js.map +1 -1
- package/dist/ecoimpacthub/services/createSandboxAssistantTransport.d.ts.map +1 -1
- package/dist/ecoimpacthub/services/createSandboxAssistantTransport.js.map +1 -1
- package/dist/ecoimpacthub/types/index.d.ts.map +1 -1
- package/dist/ecoimpacthub/utils/cn.js.map +1 -1
- package/dist/ecoimpacthub/utils/formatters.js.map +1 -1
- package/dist/ecoimpacthub/utils/navigation.js.map +1 -1
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -1
- package/dist/node_modules/d3-array/src/ascending.js.map +1 -1
- package/dist/node_modules/d3-array/src/bisect.js.map +1 -1
- package/dist/node_modules/d3-array/src/bisector.js.map +1 -1
- package/dist/node_modules/d3-array/src/descending.js.map +1 -1
- package/dist/node_modules/d3-array/src/max.js.map +1 -1
- package/dist/node_modules/d3-array/src/min.js.map +1 -1
- package/dist/node_modules/d3-array/src/number.js.map +1 -1
- package/dist/node_modules/d3-array/src/quantile.js.map +1 -1
- package/dist/node_modules/d3-array/src/quickselect.js.map +1 -1
- package/dist/node_modules/d3-array/src/range.js.map +1 -1
- package/dist/node_modules/d3-array/src/sort.js.map +1 -1
- package/dist/node_modules/d3-array/src/ticks.js.map +1 -1
- package/dist/node_modules/d3-color/src/color.js.map +1 -1
- package/dist/node_modules/d3-color/src/define.js.map +1 -1
- package/dist/node_modules/d3-format/src/defaultLocale.js.map +1 -1
- package/dist/node_modules/d3-format/src/exponent.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatDecimal.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatGroup.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatNumerals.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatPrefixAuto.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatRounded.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatSpecifier.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatTrim.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatTypes.js.map +1 -1
- package/dist/node_modules/d3-format/src/identity.js.map +1 -1
- package/dist/node_modules/d3-format/src/locale.js.map +1 -1
- package/dist/node_modules/d3-format/src/precisionFixed.js.map +1 -1
- package/dist/node_modules/d3-format/src/precisionPrefix.js.map +1 -1
- package/dist/node_modules/d3-format/src/precisionRound.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/array.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/basis.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/basisClosed.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/color.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/date.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/number.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/numberArray.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/object.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/piecewise.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/rgb.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/round.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/string.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/value.js.map +1 -1
- package/dist/node_modules/d3-path/src/path.js.map +1 -1
- package/dist/node_modules/d3-scale/src/band.js.map +1 -1
- package/dist/node_modules/d3-scale/src/constant.js.map +1 -1
- package/dist/node_modules/d3-scale/src/continuous.js.map +1 -1
- package/dist/node_modules/d3-scale/src/diverging.js.map +1 -1
- package/dist/node_modules/d3-scale/src/identity.js.map +1 -1
- package/dist/node_modules/d3-scale/src/init.js.map +1 -1
- package/dist/node_modules/d3-scale/src/linear.js.map +1 -1
- package/dist/node_modules/d3-scale/src/log.js.map +1 -1
- package/dist/node_modules/d3-scale/src/nice.js.map +1 -1
- package/dist/node_modules/d3-scale/src/number.js.map +1 -1
- package/dist/node_modules/d3-scale/src/ordinal.js.map +1 -1
- package/dist/node_modules/d3-scale/src/pow.js.map +1 -1
- package/dist/node_modules/d3-scale/src/quantile.js.map +1 -1
- package/dist/node_modules/d3-scale/src/quantize.js.map +1 -1
- package/dist/node_modules/d3-scale/src/radial.js.map +1 -1
- package/dist/node_modules/d3-scale/src/sequential.js.map +1 -1
- package/dist/node_modules/d3-scale/src/sequentialQuantile.js.map +1 -1
- package/dist/node_modules/d3-scale/src/symlog.js.map +1 -1
- package/dist/node_modules/d3-scale/src/threshold.js.map +1 -1
- package/dist/node_modules/d3-scale/src/tickFormat.js.map +1 -1
- package/dist/node_modules/d3-scale/src/time.js.map +1 -1
- package/dist/node_modules/d3-scale/src/utcTime.js.map +1 -1
- package/dist/node_modules/d3-shape/src/area.js.map +1 -1
- package/dist/node_modules/d3-shape/src/array.js.map +1 -1
- package/dist/node_modules/d3-shape/src/constant.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/basis.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/basisClosed.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/basisOpen.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/bump.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/linear.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/linearClosed.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/monotone.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/natural.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/step.js.map +1 -1
- package/dist/node_modules/d3-shape/src/line.js.map +1 -1
- package/dist/node_modules/d3-shape/src/noop.js.map +1 -1
- package/dist/node_modules/d3-shape/src/offset/expand.js.map +1 -1
- package/dist/node_modules/d3-shape/src/offset/none.js.map +1 -1
- package/dist/node_modules/d3-shape/src/offset/silhouette.js.map +1 -1
- package/dist/node_modules/d3-shape/src/offset/wiggle.js.map +1 -1
- package/dist/node_modules/d3-shape/src/order/none.js.map +1 -1
- package/dist/node_modules/d3-shape/src/path.js.map +1 -1
- package/dist/node_modules/d3-shape/src/point.js.map +1 -1
- package/dist/node_modules/d3-shape/src/stack.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/circle.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/cross.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/diamond.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/square.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/star.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/triangle.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/wye.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol.js.map +1 -1
- package/dist/node_modules/d3-time/src/day.js.map +1 -1
- package/dist/node_modules/d3-time/src/hour.js.map +1 -1
- package/dist/node_modules/d3-time/src/interval.js.map +1 -1
- package/dist/node_modules/d3-time/src/millisecond.js.map +1 -1
- package/dist/node_modules/d3-time/src/minute.js.map +1 -1
- package/dist/node_modules/d3-time/src/month.js.map +1 -1
- package/dist/node_modules/d3-time/src/second.js.map +1 -1
- package/dist/node_modules/d3-time/src/ticks.js.map +1 -1
- package/dist/node_modules/d3-time/src/week.js.map +1 -1
- package/dist/node_modules/d3-time/src/year.js.map +1 -1
- package/dist/node_modules/d3-time-format/src/defaultLocale.js.map +1 -1
- package/dist/node_modules/d3-time-format/src/locale.js.map +1 -1
- package/dist/node_modules/decimal.js-light/decimal.js.map +1 -1
- package/dist/node_modules/eventemitter3/index.js.map +1 -1
- package/dist/node_modules/fast-equals/dist/es/index.js.map +1 -1
- package/dist/node_modules/internmap/src/index.js.map +1 -1
- package/dist/node_modules/lodash/_DataView.js.map +1 -1
- package/dist/node_modules/lodash/_Hash.js.map +1 -1
- package/dist/node_modules/lodash/_ListCache.js.map +1 -1
- package/dist/node_modules/lodash/_Map.js.map +1 -1
- package/dist/node_modules/lodash/_MapCache.js.map +1 -1
- package/dist/node_modules/lodash/_Promise.js.map +1 -1
- package/dist/node_modules/lodash/_Set.js.map +1 -1
- package/dist/node_modules/lodash/_SetCache.js.map +1 -1
- package/dist/node_modules/lodash/_Stack.js +2 -1
- package/dist/node_modules/lodash/_Stack.js.map +1 -1
- package/dist/node_modules/lodash/_Symbol.js.map +1 -1
- package/dist/node_modules/lodash/_Uint8Array.js.map +1 -1
- package/dist/node_modules/lodash/_WeakMap.js.map +1 -1
- package/dist/node_modules/lodash/_apply.js.map +1 -1
- package/dist/node_modules/lodash/_arrayEvery.js.map +1 -1
- package/dist/node_modules/lodash/_arrayFilter.js.map +1 -1
- package/dist/node_modules/lodash/_arrayIncludes.js.map +1 -1
- package/dist/node_modules/lodash/_arrayIncludesWith.js.map +1 -1
- package/dist/node_modules/lodash/_arrayLikeKeys.js.map +1 -1
- package/dist/node_modules/lodash/_arrayMap.js.map +1 -1
- package/dist/node_modules/lodash/_arrayPush.js.map +1 -1
- package/dist/node_modules/lodash/_arraySome.js.map +1 -1
- package/dist/node_modules/lodash/_asciiToArray.js.map +1 -1
- package/dist/node_modules/lodash/_assocIndexOf.js.map +1 -1
- package/dist/node_modules/lodash/_baseAssignValue.js.map +1 -1
- package/dist/node_modules/lodash/_baseEach.js.map +1 -1
- package/dist/node_modules/lodash/_baseEvery.js.map +1 -1
- package/dist/node_modules/lodash/_baseExtremum.js.map +1 -1
- package/dist/node_modules/lodash/_baseFindIndex.js.map +1 -1
- package/dist/node_modules/lodash/_baseFlatten.js.map +1 -1
- package/dist/node_modules/lodash/_baseFor.js.map +1 -1
- package/dist/node_modules/lodash/_baseForOwn.js.map +1 -1
- package/dist/node_modules/lodash/_baseGet.js.map +1 -1
- package/dist/node_modules/lodash/_baseGetAllKeys.js.map +1 -1
- package/dist/node_modules/lodash/_baseGetTag.js.map +1 -1
- package/dist/node_modules/lodash/_baseGt.js.map +1 -1
- package/dist/node_modules/lodash/_baseHasIn.js.map +1 -1
- package/dist/node_modules/lodash/_baseIndexOf.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsArguments.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsEqual.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsEqualDeep.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsMatch.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsNaN.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsNative.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsTypedArray.js.map +1 -1
- package/dist/node_modules/lodash/_baseIteratee.js.map +1 -1
- package/dist/node_modules/lodash/_baseKeys.js.map +1 -1
- package/dist/node_modules/lodash/_baseLt.js.map +1 -1
- package/dist/node_modules/lodash/_baseMap.js.map +1 -1
- package/dist/node_modules/lodash/_baseMatches.js.map +1 -1
- package/dist/node_modules/lodash/_baseMatchesProperty.js.map +1 -1
- package/dist/node_modules/lodash/_baseOrderBy.js.map +1 -1
- package/dist/node_modules/lodash/_baseProperty.js.map +1 -1
- package/dist/node_modules/lodash/_basePropertyDeep.js.map +1 -1
- package/dist/node_modules/lodash/_baseRange.js.map +1 -1
- package/dist/node_modules/lodash/_baseRest.js.map +1 -1
- package/dist/node_modules/lodash/_baseSetToString.js.map +1 -1
- package/dist/node_modules/lodash/_baseSlice.js.map +1 -1
- package/dist/node_modules/lodash/_baseSome.js.map +1 -1
- package/dist/node_modules/lodash/_baseSortBy.js.map +1 -1
- package/dist/node_modules/lodash/_baseTimes.js.map +1 -1
- package/dist/node_modules/lodash/_baseToString.js.map +1 -1
- package/dist/node_modules/lodash/_baseTrim.js.map +1 -1
- package/dist/node_modules/lodash/_baseUnary.js.map +1 -1
- package/dist/node_modules/lodash/_baseUniq.js.map +1 -1
- package/dist/node_modules/lodash/_cacheHas.js.map +1 -1
- package/dist/node_modules/lodash/_castPath.js.map +1 -1
- package/dist/node_modules/lodash/_castSlice.js.map +1 -1
- package/dist/node_modules/lodash/_compareAscending.js.map +1 -1
- package/dist/node_modules/lodash/_compareMultiple.js.map +1 -1
- package/dist/node_modules/lodash/_coreJsData.js.map +1 -1
- package/dist/node_modules/lodash/_createBaseEach.js.map +1 -1
- package/dist/node_modules/lodash/_createBaseFor.js.map +1 -1
- package/dist/node_modules/lodash/_createCaseFirst.js.map +1 -1
- package/dist/node_modules/lodash/_createFind.js.map +1 -1
- package/dist/node_modules/lodash/_createRange.js.map +1 -1
- package/dist/node_modules/lodash/_createSet.js.map +1 -1
- package/dist/node_modules/lodash/_defineProperty.js.map +1 -1
- package/dist/node_modules/lodash/_equalArrays.js.map +1 -1
- package/dist/node_modules/lodash/_equalByTag.js.map +1 -1
- package/dist/node_modules/lodash/_equalObjects.js.map +1 -1
- package/dist/node_modules/lodash/_freeGlobal.js.map +1 -1
- package/dist/node_modules/lodash/_getAllKeys.js.map +1 -1
- package/dist/node_modules/lodash/_getMapData.js.map +1 -1
- package/dist/node_modules/lodash/_getMatchData.js.map +1 -1
- package/dist/node_modules/lodash/_getNative.js.map +1 -1
- package/dist/node_modules/lodash/_getPrototype.js.map +1 -1
- package/dist/node_modules/lodash/_getRawTag.js.map +1 -1
- package/dist/node_modules/lodash/_getSymbols.js.map +1 -1
- package/dist/node_modules/lodash/_getTag.js.map +1 -1
- package/dist/node_modules/lodash/_getValue.js.map +1 -1
- package/dist/node_modules/lodash/_hasPath.js.map +1 -1
- package/dist/node_modules/lodash/_hasUnicode.js.map +1 -1
- package/dist/node_modules/lodash/_hashClear.js.map +1 -1
- package/dist/node_modules/lodash/_hashDelete.js.map +1 -1
- package/dist/node_modules/lodash/_hashGet.js.map +1 -1
- package/dist/node_modules/lodash/_hashHas.js.map +1 -1
- package/dist/node_modules/lodash/_hashSet.js.map +1 -1
- package/dist/node_modules/lodash/_isFlattenable.js.map +1 -1
- package/dist/node_modules/lodash/_isIndex.js.map +1 -1
- package/dist/node_modules/lodash/_isIterateeCall.js.map +1 -1
- package/dist/node_modules/lodash/_isKey.js.map +1 -1
- package/dist/node_modules/lodash/_isKeyable.js.map +1 -1
- package/dist/node_modules/lodash/_isMasked.js.map +1 -1
- package/dist/node_modules/lodash/_isPrototype.js.map +1 -1
- package/dist/node_modules/lodash/_isStrictComparable.js.map +1 -1
- package/dist/node_modules/lodash/_listCacheClear.js.map +1 -1
- package/dist/node_modules/lodash/_listCacheDelete.js.map +1 -1
- package/dist/node_modules/lodash/_listCacheGet.js.map +1 -1
- package/dist/node_modules/lodash/_listCacheHas.js.map +1 -1
- package/dist/node_modules/lodash/_listCacheSet.js.map +1 -1
- package/dist/node_modules/lodash/_mapCacheClear.js.map +1 -1
- package/dist/node_modules/lodash/_mapCacheDelete.js.map +1 -1
- package/dist/node_modules/lodash/_mapCacheGet.js.map +1 -1
- package/dist/node_modules/lodash/_mapCacheHas.js.map +1 -1
- package/dist/node_modules/lodash/_mapCacheSet.js.map +1 -1
- package/dist/node_modules/lodash/_mapToArray.js.map +1 -1
- package/dist/node_modules/lodash/_matchesStrictComparable.js.map +1 -1
- package/dist/node_modules/lodash/_memoizeCapped.js.map +1 -1
- package/dist/node_modules/lodash/_nativeCreate.js.map +1 -1
- package/dist/node_modules/lodash/_nativeKeys.js.map +1 -1
- package/dist/node_modules/lodash/_nodeUtil.js.map +1 -1
- package/dist/node_modules/lodash/_objectToString.js.map +1 -1
- package/dist/node_modules/lodash/_overArg.js.map +1 -1
- package/dist/node_modules/lodash/_overRest.js.map +1 -1
- package/dist/node_modules/lodash/_root.js.map +1 -1
- package/dist/node_modules/lodash/_setCacheAdd.js.map +1 -1
- package/dist/node_modules/lodash/_setCacheHas.js.map +1 -1
- package/dist/node_modules/lodash/_setToArray.js.map +1 -1
- package/dist/node_modules/lodash/_setToString.js.map +1 -1
- package/dist/node_modules/lodash/_shortOut.js.map +1 -1
- package/dist/node_modules/lodash/_stackClear.js.map +1 -1
- package/dist/node_modules/lodash/_stackDelete.js.map +1 -1
- package/dist/node_modules/lodash/_stackGet.js.map +1 -1
- package/dist/node_modules/lodash/_stackHas.js.map +1 -1
- package/dist/node_modules/lodash/_stackSet.js.map +1 -1
- package/dist/node_modules/lodash/_strictIndexOf.js.map +1 -1
- package/dist/node_modules/lodash/_stringToArray.js.map +1 -1
- package/dist/node_modules/lodash/_stringToPath.js.map +1 -1
- package/dist/node_modules/lodash/_toKey.js.map +1 -1
- package/dist/node_modules/lodash/_toSource.js.map +1 -1
- package/dist/node_modules/lodash/_trimmedEndIndex.js.map +1 -1
- package/dist/node_modules/lodash/_unicodeToArray.js.map +1 -1
- package/dist/node_modules/lodash/constant.js.map +1 -1
- package/dist/node_modules/lodash/debounce.js.map +1 -1
- package/dist/node_modules/lodash/eq.js.map +1 -1
- package/dist/node_modules/lodash/every.js.map +1 -1
- package/dist/node_modules/lodash/find.js.map +1 -1
- package/dist/node_modules/lodash/findIndex.js.map +1 -1
- package/dist/node_modules/lodash/flatMap.js.map +1 -1
- package/dist/node_modules/lodash/get.js.map +1 -1
- package/dist/node_modules/lodash/hasIn.js.map +1 -1
- package/dist/node_modules/lodash/identity.js.map +1 -1
- package/dist/node_modules/lodash/isArguments.js.map +1 -1
- package/dist/node_modules/lodash/isArray.js.map +1 -1
- package/dist/node_modules/lodash/isArrayLike.js.map +1 -1
- package/dist/node_modules/lodash/isBoolean.js.map +1 -1
- package/dist/node_modules/lodash/isBuffer.js.map +1 -1
- package/dist/node_modules/lodash/isEqual.js.map +1 -1
- package/dist/node_modules/lodash/isFunction.js.map +1 -1
- package/dist/node_modules/lodash/isLength.js.map +1 -1
- package/dist/node_modules/lodash/isNaN.js.map +1 -1
- package/dist/node_modules/lodash/isNil.js.map +1 -1
- package/dist/node_modules/lodash/isNumber.js.map +1 -1
- package/dist/node_modules/lodash/isObject.js.map +1 -1
- package/dist/node_modules/lodash/isObjectLike.js.map +1 -1
- package/dist/node_modules/lodash/isPlainObject.js.map +1 -1
- package/dist/node_modules/lodash/isString.js.map +1 -1
- package/dist/node_modules/lodash/isSymbol.js.map +1 -1
- package/dist/node_modules/lodash/isTypedArray.js.map +1 -1
- package/dist/node_modules/lodash/keys.js.map +1 -1
- package/dist/node_modules/lodash/last.js.map +1 -1
- package/dist/node_modules/lodash/map.js.map +1 -1
- package/dist/node_modules/lodash/mapValues.js.map +1 -1
- package/dist/node_modules/lodash/max.js.map +1 -1
- package/dist/node_modules/lodash/memoize.js.map +1 -1
- package/dist/node_modules/lodash/min.js.map +1 -1
- package/dist/node_modules/lodash/noop.js.map +1 -1
- package/dist/node_modules/lodash/now.js.map +1 -1
- package/dist/node_modules/lodash/property.js.map +1 -1
- package/dist/node_modules/lodash/range.js.map +1 -1
- package/dist/node_modules/lodash/some.js.map +1 -1
- package/dist/node_modules/lodash/sortBy.js.map +1 -1
- package/dist/node_modules/lodash/stubArray.js.map +1 -1
- package/dist/node_modules/lodash/stubFalse.js.map +1 -1
- package/dist/node_modules/lodash/throttle.js.map +1 -1
- package/dist/node_modules/lodash/toFinite.js.map +1 -1
- package/dist/node_modules/lodash/toInteger.js.map +1 -1
- package/dist/node_modules/lodash/toNumber.js.map +1 -1
- package/dist/node_modules/lodash/toString.js.map +1 -1
- package/dist/node_modules/lodash/uniqBy.js.map +1 -1
- package/dist/node_modules/lodash/upperFirst.js.map +1 -1
- package/dist/node_modules/object-assign/index.js.map +1 -1
- package/dist/node_modules/prop-types/checkPropTypes.js.map +1 -1
- package/dist/node_modules/prop-types/factoryWithThrowingShims.js.map +1 -1
- package/dist/node_modules/prop-types/factoryWithTypeCheckers.js.map +1 -1
- package/dist/node_modules/prop-types/index.js.map +1 -1
- package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js.map +1 -1
- package/dist/node_modules/prop-types/lib/has.js.map +1 -1
- package/dist/node_modules/prop-types/node_modules/react-is/cjs/react-is.development.js.map +1 -1
- package/dist/node_modules/prop-types/node_modules/react-is/cjs/react-is.production.min.js.map +1 -1
- package/dist/node_modules/prop-types/node_modules/react-is/index.js.map +1 -1
- package/dist/node_modules/react-is/cjs/react-is.development.js.map +1 -1
- package/dist/node_modules/react-is/cjs/react-is.production.min.js.map +1 -1
- package/dist/node_modules/react-is/index.js.map +1 -1
- package/dist/node_modules/react-smooth/es6/Animate.js +2 -2
- package/dist/node_modules/react-smooth/es6/Animate.js.map +1 -1
- package/dist/node_modules/react-smooth/es6/AnimateManager.js.map +1 -1
- package/dist/node_modules/react-smooth/es6/configUpdate.js.map +1 -1
- package/dist/node_modules/react-smooth/es6/easing.js.map +1 -1
- package/dist/node_modules/react-smooth/es6/setRafTimeout.js.map +1 -1
- package/dist/node_modules/react-smooth/es6/util.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/Bar.js +9 -9
- package/dist/node_modules/recharts/es6/cartesian/Bar.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/Brush.js +12 -12
- package/dist/node_modules/recharts/es6/cartesian/Brush.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js +7 -7
- package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js +13 -13
- package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js +4 -4
- package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js +3 -3
- package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js +3 -3
- package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js +4 -4
- package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/XAxis.js +3 -3
- package/dist/node_modules/recharts/es6/cartesian/XAxis.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/YAxis.js +3 -3
- package/dist/node_modules/recharts/es6/cartesian/YAxis.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/getEquidistantTicks.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/getTicks.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js +1 -1
- package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/BarChart.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js +22 -22
- package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/Cell.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/Cursor.js +1 -1
- package/dist/node_modules/recharts/es6/component/Cursor.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js +11 -11
- package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js +6 -6
- package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/Label.js +14 -14
- package/dist/node_modules/recharts/es6/component/Label.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/LabelList.js +6 -6
- package/dist/node_modules/recharts/es6/component/LabelList.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/Legend.js +5 -5
- package/dist/node_modules/recharts/es6/component/Legend.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js +3 -3
- package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/Text.js +2 -2
- package/dist/node_modules/recharts/es6/component/Text.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/Tooltip.js +3 -3
- package/dist/node_modules/recharts/es6/component/Tooltip.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js +2 -2
- package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js.map +1 -1
- package/dist/node_modules/recharts/es6/container/Layer.js +2 -2
- package/dist/node_modules/recharts/es6/container/Layer.js.map +1 -1
- package/dist/node_modules/recharts/es6/container/Surface.js +2 -2
- package/dist/node_modules/recharts/es6/container/Surface.js.map +1 -1
- package/dist/node_modules/recharts/es6/context/chartLayoutContext.js +2 -2
- package/dist/node_modules/recharts/es6/context/chartLayoutContext.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Cross.js +1 -1
- package/dist/node_modules/recharts/es6/shape/Cross.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Curve.js +1 -1
- package/dist/node_modules/recharts/es6/shape/Curve.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Dot.js +1 -1
- package/dist/node_modules/recharts/es6/shape/Dot.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Rectangle.js +4 -4
- package/dist/node_modules/recharts/es6/shape/Rectangle.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Sector.js +1 -1
- package/dist/node_modules/recharts/es6/shape/Sector.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Symbols.js +1 -1
- package/dist/node_modules/recharts/es6/shape/Symbols.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Trapezoid.js +4 -4
- package/dist/node_modules/recharts/es6/shape/Trapezoid.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js +9 -9
- package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/BarUtils.js +1 -1
- package/dist/node_modules/recharts/es6/util/BarUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/CartesianUtils.js +1 -1
- package/dist/node_modules/recharts/es6/util/CartesianUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/ChartUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/CssPrefixUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/DOMUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/DataUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/DetectReferenceElementsDomain.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/Events.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/Global.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/IfOverflowMatches.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/LogUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/PolarUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/ReactUtils.js +1 -1
- package/dist/node_modules/recharts/es6/util/ReactUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js +1 -1
- package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/ShallowEqual.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/TickUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/calculateViewBox.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/cursor/getCursorPoints.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/cursor/getCursorRectangle.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/cursor/getRadialCursorPoints.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/getEveryNthWithCondition.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/getLegendProps.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/isDomainSpecifiedByUser.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/payload/getUniqPayload.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/tooltip/translate.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/types.js +1 -1
- package/dist/node_modules/recharts/es6/util/types.js.map +1 -1
- package/dist/node_modules/recharts-scale/es6/getNiceTickValues.js.map +1 -1
- package/dist/node_modules/recharts-scale/es6/util/arithmetic.js.map +1 -1
- package/dist/node_modules/recharts-scale/es6/util/utils.js.map +1 -1
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1 -1
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -1
- package/dist/node_modules/tiny-invariant/dist/esm/tiny-invariant.js.map +1 -1
- 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;
|
|
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":";;;;;;;;AAkBA,IAAM,IAAY,QAChB,OAAO,8BAA2B,MAAM,OAAO,EAAE,SAAS,EAAE,
|
|
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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { DashboardWidgetId, UseDashboardLayoutResult } from '../hooks/useDashboardLayout';
|
|
3
|
+
|
|
4
|
+
interface DashboardCustomizerDialogProps {
|
|
5
|
+
open: boolean;
|
|
6
|
+
onOpenChange: (open: boolean) => void;
|
|
7
|
+
layout: UseDashboardLayoutResult;
|
|
8
|
+
}
|
|
9
|
+
export declare const DashboardCustomizerDialog: FC<DashboardCustomizerDialogProps>;
|
|
10
|
+
export type { DashboardWidgetId };
|
|
11
|
+
//# sourceMappingURL=DashboardCustomizerDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DashboardCustomizerDialog.d.ts","sourceRoot":"","sources":["../../../src/ecoimpacthub/components/DashboardCustomizerDialog.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,KAAK,EAAE,EAAY,MAAM,OAAO,CAAC;AAe1C,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC9B,MAAM,6BAA6B,CAAC;AAErC,UAAU,8BAA8B;IACtC,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,MAAM,EAAE,wBAAwB,CAAC;CAClC;AAED,eAAO,MAAM,yBAAyB,EAAE,EAAE,CAAC,8BAA8B,CAwMxE,CAAC;AAEF,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { DASHBOARD_WIDGET_DEFS as e } from "../hooks/useDashboardLayout.js";
|
|
2
|
+
import { useState as t } from "react";
|
|
3
|
+
import { ArrowDown as n, ArrowUp as r, Plus as i, StickyNote as a, Trash2 as o } from "lucide-react";
|
|
4
|
+
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
5
|
+
import { Button as l, Checkbox as u, Input as d, Label as f, ResponsiveDialog as p, ResponsiveDialogContent as m, ResponsiveDialogDescription as h, ResponsiveDialogFooter as g, ResponsiveDialogHeader as _, ResponsiveDialogTitle as v, Textarea as y } from "@burdenoff/fe-libs/ui";
|
|
6
|
+
//#region src/ecoimpacthub/components/DashboardCustomizerDialog.tsx
|
|
7
|
+
var b = ({ open: b, onOpenChange: x, layout: S }) => {
|
|
8
|
+
let { layout: C, isWidgetVisible: w, toggleWidget: T, moveWidget: E, addNote: D, removeNote: O, resetToDefault: k } = S, [A, j] = t(""), [M, N] = t(""), P = C.widgetOrder.map((t) => e.find((e) => e.id === t)).filter((e) => !!e), F = e.filter((e) => !w(e.id));
|
|
9
|
+
return /* @__PURE__ */ s(p, {
|
|
10
|
+
open: b,
|
|
11
|
+
onOpenChange: x,
|
|
12
|
+
children: /* @__PURE__ */ c(m, {
|
|
13
|
+
className: "sm:max-w-lg",
|
|
14
|
+
children: [
|
|
15
|
+
/* @__PURE__ */ c(_, { children: [/* @__PURE__ */ s(v, { children: "Customize dashboard" }), /* @__PURE__ */ s(h, { children: "Show, hide, and reorder widgets, or add a custom note. Changes save automatically for you on this workspace." })] }),
|
|
16
|
+
/* @__PURE__ */ c("div", {
|
|
17
|
+
className: "grid gap-5 py-2",
|
|
18
|
+
children: [
|
|
19
|
+
/* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("p", {
|
|
20
|
+
className: "mb-2 text-xs font-medium uppercase tracking-wide text-text-tertiary",
|
|
21
|
+
children: "Visible widgets"
|
|
22
|
+
}), /* @__PURE__ */ c("ul", {
|
|
23
|
+
className: "space-y-1.5",
|
|
24
|
+
children: [P.map((e, t) => /* @__PURE__ */ c("li", {
|
|
25
|
+
className: "flex items-center gap-2.5 rounded-lg border border-border-seam bg-bg-sunken/40 px-3 py-2",
|
|
26
|
+
children: [
|
|
27
|
+
/* @__PURE__ */ s(u, {
|
|
28
|
+
checked: !0,
|
|
29
|
+
onCheckedChange: () => T(e.id),
|
|
30
|
+
"aria-label": `Hide ${e.label}`
|
|
31
|
+
}),
|
|
32
|
+
/* @__PURE__ */ c("div", {
|
|
33
|
+
className: "min-w-0 flex-1",
|
|
34
|
+
children: [/* @__PURE__ */ s("p", {
|
|
35
|
+
className: "text-sm font-medium text-text-primary",
|
|
36
|
+
children: e.label
|
|
37
|
+
}), /* @__PURE__ */ s("p", {
|
|
38
|
+
className: "truncate text-xs text-text-tertiary",
|
|
39
|
+
children: e.description
|
|
40
|
+
})]
|
|
41
|
+
}),
|
|
42
|
+
/* @__PURE__ */ c("div", {
|
|
43
|
+
className: "flex shrink-0 items-center gap-1",
|
|
44
|
+
children: [/* @__PURE__ */ s(l, {
|
|
45
|
+
type: "button",
|
|
46
|
+
variant: "ghost",
|
|
47
|
+
size: "icon",
|
|
48
|
+
className: "h-7 w-7",
|
|
49
|
+
disabled: t === 0,
|
|
50
|
+
onClick: () => E(e.id, "up"),
|
|
51
|
+
"aria-label": `Move ${e.label} up`,
|
|
52
|
+
children: /* @__PURE__ */ s(r, { className: "h-3.5 w-3.5" })
|
|
53
|
+
}), /* @__PURE__ */ s(l, {
|
|
54
|
+
type: "button",
|
|
55
|
+
variant: "ghost",
|
|
56
|
+
size: "icon",
|
|
57
|
+
className: "h-7 w-7",
|
|
58
|
+
disabled: t === P.length - 1,
|
|
59
|
+
onClick: () => E(e.id, "down"),
|
|
60
|
+
"aria-label": `Move ${e.label} down`,
|
|
61
|
+
children: /* @__PURE__ */ s(n, { className: "h-3.5 w-3.5" })
|
|
62
|
+
})]
|
|
63
|
+
})
|
|
64
|
+
]
|
|
65
|
+
}, e.id)), P.length === 0 && /* @__PURE__ */ s("li", {
|
|
66
|
+
className: "rounded-lg border border-dashed border-border-seam px-3 py-4 text-center text-xs text-text-tertiary",
|
|
67
|
+
children: "All widgets hidden — add one back below."
|
|
68
|
+
})]
|
|
69
|
+
})] }),
|
|
70
|
+
F.length > 0 && /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("p", {
|
|
71
|
+
className: "mb-2 text-xs font-medium uppercase tracking-wide text-text-tertiary",
|
|
72
|
+
children: "Hidden widgets"
|
|
73
|
+
}), /* @__PURE__ */ s("ul", {
|
|
74
|
+
className: "space-y-1.5",
|
|
75
|
+
children: F.map((e) => /* @__PURE__ */ c("li", {
|
|
76
|
+
className: "flex items-center gap-2.5 rounded-lg border border-dashed border-border-seam px-3 py-2 opacity-70",
|
|
77
|
+
children: [/* @__PURE__ */ s(u, {
|
|
78
|
+
checked: !1,
|
|
79
|
+
onCheckedChange: () => T(e.id),
|
|
80
|
+
"aria-label": `Show ${e.label}`
|
|
81
|
+
}), /* @__PURE__ */ c("div", {
|
|
82
|
+
className: "min-w-0 flex-1",
|
|
83
|
+
children: [/* @__PURE__ */ s("p", {
|
|
84
|
+
className: "text-sm font-medium text-text-primary",
|
|
85
|
+
children: e.label
|
|
86
|
+
}), /* @__PURE__ */ s("p", {
|
|
87
|
+
className: "truncate text-xs text-text-tertiary",
|
|
88
|
+
children: e.description
|
|
89
|
+
})]
|
|
90
|
+
})]
|
|
91
|
+
}, e.id))
|
|
92
|
+
})] }),
|
|
93
|
+
/* @__PURE__ */ c("div", { children: [
|
|
94
|
+
/* @__PURE__ */ s("p", {
|
|
95
|
+
className: "mb-2 text-xs font-medium uppercase tracking-wide text-text-tertiary",
|
|
96
|
+
children: "Custom notes"
|
|
97
|
+
}),
|
|
98
|
+
C.notes.length > 0 && /* @__PURE__ */ s("ul", {
|
|
99
|
+
className: "mb-2.5 space-y-1.5",
|
|
100
|
+
children: C.notes.map((e) => /* @__PURE__ */ c("li", {
|
|
101
|
+
className: "flex items-start gap-2.5 rounded-lg border border-border-seam bg-bg-sunken/40 px-3 py-2",
|
|
102
|
+
children: [
|
|
103
|
+
/* @__PURE__ */ s(a, { className: "mt-0.5 h-4 w-4 shrink-0 text-accent" }),
|
|
104
|
+
/* @__PURE__ */ c("div", {
|
|
105
|
+
className: "min-w-0 flex-1",
|
|
106
|
+
children: [e.title && /* @__PURE__ */ s("p", {
|
|
107
|
+
className: "truncate text-sm font-medium text-text-primary",
|
|
108
|
+
children: e.title
|
|
109
|
+
}), e.body && /* @__PURE__ */ s("p", {
|
|
110
|
+
className: "line-clamp-2 text-xs text-text-tertiary",
|
|
111
|
+
children: e.body
|
|
112
|
+
})]
|
|
113
|
+
}),
|
|
114
|
+
/* @__PURE__ */ s(l, {
|
|
115
|
+
type: "button",
|
|
116
|
+
variant: "ghost",
|
|
117
|
+
size: "icon",
|
|
118
|
+
className: "h-7 w-7 shrink-0",
|
|
119
|
+
onClick: () => O(e.id),
|
|
120
|
+
"aria-label": "Remove note",
|
|
121
|
+
children: /* @__PURE__ */ s(o, { className: "h-3.5 w-3.5" })
|
|
122
|
+
})
|
|
123
|
+
]
|
|
124
|
+
}, e.id))
|
|
125
|
+
}),
|
|
126
|
+
/* @__PURE__ */ c("div", {
|
|
127
|
+
className: "grid gap-1.5",
|
|
128
|
+
children: [/* @__PURE__ */ s(f, {
|
|
129
|
+
htmlFor: "dashboard-note-title",
|
|
130
|
+
children: "Note title"
|
|
131
|
+
}), /* @__PURE__ */ s(d, {
|
|
132
|
+
id: "dashboard-note-title",
|
|
133
|
+
value: A,
|
|
134
|
+
onChange: (e) => j(e.target.value),
|
|
135
|
+
placeholder: "e.g. Q3 audit reminder"
|
|
136
|
+
})]
|
|
137
|
+
}),
|
|
138
|
+
/* @__PURE__ */ c("div", {
|
|
139
|
+
className: "mt-2 grid gap-1.5",
|
|
140
|
+
children: [/* @__PURE__ */ s(f, {
|
|
141
|
+
htmlFor: "dashboard-note-body",
|
|
142
|
+
children: "Note"
|
|
143
|
+
}), /* @__PURE__ */ s(y, {
|
|
144
|
+
id: "dashboard-note-body",
|
|
145
|
+
value: M,
|
|
146
|
+
onChange: (e) => N(e.target.value),
|
|
147
|
+
placeholder: "Optional detail for this note.",
|
|
148
|
+
rows: 2
|
|
149
|
+
})]
|
|
150
|
+
}),
|
|
151
|
+
/* @__PURE__ */ c(l, {
|
|
152
|
+
type: "button",
|
|
153
|
+
variant: "outline",
|
|
154
|
+
size: "sm",
|
|
155
|
+
className: "mt-2",
|
|
156
|
+
onClick: () => {
|
|
157
|
+
!A.trim() && !M.trim() || (D(A, M), j(""), N(""));
|
|
158
|
+
},
|
|
159
|
+
disabled: !A.trim() && !M.trim(),
|
|
160
|
+
children: [/* @__PURE__ */ s(i, { className: "mr-1.5 h-3.5 w-3.5" }), "Add note"]
|
|
161
|
+
})
|
|
162
|
+
] })
|
|
163
|
+
]
|
|
164
|
+
}),
|
|
165
|
+
/* @__PURE__ */ c(g, { children: [/* @__PURE__ */ s(l, {
|
|
166
|
+
type: "button",
|
|
167
|
+
variant: "ghost",
|
|
168
|
+
onClick: k,
|
|
169
|
+
children: "Reset to default"
|
|
170
|
+
}), /* @__PURE__ */ s(l, {
|
|
171
|
+
type: "button",
|
|
172
|
+
onClick: () => x(!1),
|
|
173
|
+
children: "Done"
|
|
174
|
+
})] })
|
|
175
|
+
]
|
|
176
|
+
})
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
//#endregion
|
|
180
|
+
export { b as DashboardCustomizerDialog };
|
|
181
|
+
|
|
182
|
+
//# sourceMappingURL=DashboardCustomizerDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DashboardCustomizerDialog.js","names":[],"sources":["../../../src/ecoimpacthub/components/DashboardCustomizerDialog.tsx"],"sourcesContent":["/**\n * Dashboard customizer — widget palette for the \"Create dashboard\" CTA (BOFF-3943).\n * @module ecoimpacthub/components\n *\n * Lets a user show/hide/reorder the built-in dashboard widgets and add\n * freeform note widgets. Persisted per user/workspace via\n * {@link useDashboardLayout} (client-side; no backend model exists yet — see\n * that hook's doc comment for why).\n */\nimport { type FC, useState } from 'react';\nimport { ArrowDown, ArrowUp, Plus, StickyNote, Trash2 } from 'lucide-react';\nimport {\n Button,\n Checkbox,\n Input,\n Label,\n Textarea,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport {\n DASHBOARD_WIDGET_DEFS,\n type DashboardWidgetId,\n type UseDashboardLayoutResult,\n} from '../hooks/useDashboardLayout';\n\ninterface DashboardCustomizerDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n layout: UseDashboardLayoutResult;\n}\n\nexport const DashboardCustomizerDialog: FC<DashboardCustomizerDialogProps> = ({\n open,\n onOpenChange,\n layout,\n}) => {\n const {\n layout: current,\n isWidgetVisible,\n toggleWidget,\n moveWidget,\n addNote,\n removeNote,\n resetToDefault,\n } = layout;\n const [noteTitle, setNoteTitle] = useState('');\n const [noteBody, setNoteBody] = useState('');\n\n const orderedWidgetDefs = current.widgetOrder\n .map((id) => DASHBOARD_WIDGET_DEFS.find((w) => w.id === id))\n .filter((w): w is (typeof DASHBOARD_WIDGET_DEFS)[number] => Boolean(w));\n const hiddenWidgetDefs = DASHBOARD_WIDGET_DEFS.filter((w) => !isWidgetVisible(w.id));\n\n const handleAddNote = () => {\n if (!noteTitle.trim() && !noteBody.trim()) return;\n addNote(noteTitle, noteBody);\n setNoteTitle('');\n setNoteBody('');\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"sm:max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Customize dashboard</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Show, hide, and reorder widgets, or add a custom note. Changes save automatically for\n you on this workspace.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-5 py-2\">\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-tertiary\">\n Visible widgets\n </p>\n <ul className=\"space-y-1.5\">\n {orderedWidgetDefs.map((widget, index) => (\n <li\n key={widget.id}\n className=\"flex items-center gap-2.5 rounded-lg border border-border-seam bg-bg-sunken/40 px-3 py-2\"\n >\n <Checkbox\n checked\n onCheckedChange={() => toggleWidget(widget.id)}\n aria-label={`Hide ${widget.label}`}\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">{widget.label}</p>\n <p className=\"truncate text-xs text-text-tertiary\">{widget.description}</p>\n </div>\n <div className=\"flex shrink-0 items-center gap-1\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n disabled={index === 0}\n onClick={() => moveWidget(widget.id, 'up')}\n aria-label={`Move ${widget.label} up`}\n >\n <ArrowUp className=\"h-3.5 w-3.5\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n disabled={index === orderedWidgetDefs.length - 1}\n onClick={() => moveWidget(widget.id, 'down')}\n aria-label={`Move ${widget.label} down`}\n >\n <ArrowDown className=\"h-3.5 w-3.5\" />\n </Button>\n </div>\n </li>\n ))}\n {orderedWidgetDefs.length === 0 && (\n <li className=\"rounded-lg border border-dashed border-border-seam px-3 py-4 text-center text-xs text-text-tertiary\">\n All widgets hidden — add one back below.\n </li>\n )}\n </ul>\n </div>\n\n {hiddenWidgetDefs.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-tertiary\">\n Hidden widgets\n </p>\n <ul className=\"space-y-1.5\">\n {hiddenWidgetDefs.map((widget) => (\n <li\n key={widget.id}\n className=\"flex items-center gap-2.5 rounded-lg border border-dashed border-border-seam px-3 py-2 opacity-70\"\n >\n <Checkbox\n checked={false}\n onCheckedChange={() => toggleWidget(widget.id)}\n aria-label={`Show ${widget.label}`}\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">{widget.label}</p>\n <p className=\"truncate text-xs text-text-tertiary\">{widget.description}</p>\n </div>\n </li>\n ))}\n </ul>\n </div>\n )}\n\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-tertiary\">\n Custom notes\n </p>\n {current.notes.length > 0 && (\n <ul className=\"mb-2.5 space-y-1.5\">\n {current.notes.map((note) => (\n <li\n key={note.id}\n className=\"flex items-start gap-2.5 rounded-lg border border-border-seam bg-bg-sunken/40 px-3 py-2\"\n >\n <StickyNote className=\"mt-0.5 h-4 w-4 shrink-0 text-accent\" />\n <div className=\"min-w-0 flex-1\">\n {note.title && (\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {note.title}\n </p>\n )}\n {note.body && (\n <p className=\"line-clamp-2 text-xs text-text-tertiary\">{note.body}</p>\n )}\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7 shrink-0\"\n onClick={() => removeNote(note.id)}\n aria-label=\"Remove note\"\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n </Button>\n </li>\n ))}\n </ul>\n )}\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"dashboard-note-title\">Note title</Label>\n <Input\n id=\"dashboard-note-title\"\n value={noteTitle}\n onChange={(e) => setNoteTitle(e.target.value)}\n placeholder=\"e.g. Q3 audit reminder\"\n />\n </div>\n <div className=\"mt-2 grid gap-1.5\">\n <Label htmlFor=\"dashboard-note-body\">Note</Label>\n <Textarea\n id=\"dashboard-note-body\"\n value={noteBody}\n onChange={(e) => setNoteBody(e.target.value)}\n placeholder=\"Optional detail for this note.\"\n rows={2}\n />\n </div>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-2\"\n onClick={handleAddNote}\n disabled={!noteTitle.trim() && !noteBody.trim()}\n >\n <Plus className=\"mr-1.5 h-3.5 w-3.5\" />\n Add note\n </Button>\n </div>\n </div>\n\n <ResponsiveDialogFooter>\n <Button type=\"button\" variant=\"ghost\" onClick={resetToDefault}>\n Reset to default\n </Button>\n <Button type=\"button\" onClick={() => onOpenChange(false)}>\n Done\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n};\n\nexport type { DashboardWidgetId };\n"],"mappings":"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"}
|
|
@@ -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;
|
|
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;
|
|
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;
|
|
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,
|
|
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,
|
|
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,
|
|
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;
|
|
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;
|
|
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"}
|