@burdenoff/microfe-assethandler 2026.826.2 → 2026.826.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.js +1 -1
- package/dist/assethandler/AssetHandlerRoot.js.map +1 -1
- package/dist/assethandler/AssetHandlerRoutes.js.map +1 -1
- package/dist/assethandler/components/ActivityTimeline.js.map +1 -1
- package/dist/assethandler/components/AttachmentsPanel.js.map +1 -1
- package/dist/assethandler/components/ChartCard.js.map +1 -1
- package/dist/assethandler/components/CommentsPanel.js.map +1 -1
- package/dist/assethandler/components/NotFoundState.js.map +1 -1
- package/dist/assethandler/components/Pagination.js.map +1 -1
- package/dist/assethandler/components/SectionHeader.js.map +1 -1
- package/dist/assethandler/components/StatTile.js.map +1 -1
- package/dist/assethandler/components/charts/BarsChart.js.map +1 -1
- package/dist/assethandler/components/charts/ChartParts.js.map +1 -1
- package/dist/assethandler/components/charts/DonutChart.js.map +1 -1
- package/dist/assethandler/components/charts/ProgressMeter.js.map +1 -1
- package/dist/assethandler/components/charts/RadialGauge.js.map +1 -1
- package/dist/assethandler/components/charts/Sparkline.js.map +1 -1
- package/dist/assethandler/components/charts/TrendChart.js.map +1 -1
- package/dist/assethandler/components/charts/chartTheme.js.map +1 -1
- package/dist/assethandler/hooks/useAssetHandlerNavigate.js.map +1 -1
- package/dist/assethandler/hooks/useCopy.js.map +1 -1
- package/dist/assethandler/hooks/useMaintenancePlans.js.map +1 -1
- package/dist/assethandler/ops/MaintenancePlanDialog.js.map +1 -1
- package/dist/assethandler/ops/NewWorkOrderDialog.js.map +1 -1
- package/dist/assethandler/ops/ScheduleMaintenanceDialog.js.map +1 -1
- package/dist/assethandler/pages/AiPredictionsPage.js.map +1 -1
- package/dist/assethandler/pages/AnalyticsPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetCategoriesPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetCheckInOutPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetCreatePage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetDetailPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetListPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetTrackingPage.js.map +1 -1
- package/dist/assethandler/pages/CmdbBrowserPage.js.map +1 -1
- package/dist/assethandler/pages/DashboardPage.js.map +1 -1
- package/dist/assethandler/pages/DigitalTwinPage.js.map +1 -1
- package/dist/assethandler/pages/DiscoveryJobsPage.js.map +1 -1
- package/dist/assethandler/pages/EsgDashboardPage.js.map +1 -1
- package/dist/assethandler/pages/FinanceBudgetDetailPage.js.map +1 -1
- package/dist/assethandler/pages/FinanceFinanceHubPage.js.map +1 -1
- package/dist/assethandler/pages/FinanceInvoiceDetailPage.js.map +1 -1
- package/dist/assethandler/pages/IotDevicesPage.js.map +1 -1
- package/dist/assethandler/pages/ItilChangeDetailPage.js.map +1 -1
- package/dist/assethandler/pages/ItilChangeManagementPage.js.map +1 -1
- package/dist/assethandler/pages/ItilDialogs.js.map +1 -1
- package/dist/assethandler/pages/ItilIncidentDetailPage.js.map +1 -1
- package/dist/assethandler/pages/ItilIncidentManagementPage.js.map +1 -1
- package/dist/assethandler/pages/ItilItilhubPage.js.map +1 -1
- package/dist/assethandler/pages/ItilProblemDetailPage.js.map +1 -1
- package/dist/assethandler/pages/ItilProblemManagementPage.js.map +1 -1
- package/dist/assethandler/pages/KnowledgeBasePage.js.map +1 -1
- package/dist/assethandler/pages/MaintenanceMaintenanceCalendarPage.js.map +1 -1
- package/dist/assethandler/pages/MaintenanceMaintenancePlansPage.d.ts.map +1 -1
- package/dist/assethandler/pages/MaintenanceMaintenancePlansPage.js +1 -1
- package/dist/assethandler/pages/MaintenanceMaintenancePlansPage.js.map +1 -1
- package/dist/assethandler/pages/MaintenanceMaintenanceSchedulerPage.js.map +1 -1
- package/dist/assethandler/pages/OperationsMaintenanceDetailPage.js.map +1 -1
- package/dist/assethandler/pages/OperationsOperationsHubPage.js.map +1 -1
- package/dist/assethandler/pages/OperationsWorkOrderDetailPage.js.map +1 -1
- package/dist/assethandler/pages/PortfolioPortfolioOverviewPage.js.map +1 -1
- package/dist/assethandler/pages/ProvenancePage.js.map +1 -1
- package/dist/assethandler/pages/ReportsDashboardPage.js.map +1 -1
- package/dist/assethandler/pages/SamLicensesPage.js.map +1 -1
- package/dist/assethandler/pages/SecurityComplianceDetailPage.js.map +1 -1
- package/dist/assethandler/pages/SecurityPolicyDetailPage.js.map +1 -1
- package/dist/assethandler/pages/SecuritySecurityEventDetailPage.js.map +1 -1
- package/dist/assethandler/pages/SecuritySecurityHubPage.js.map +1 -1
- package/dist/assethandler/pages/TransactionsTransactionDetailPage.js.map +1 -1
- package/dist/assethandler/pages/TransactionsTransactionListPage.js.map +1 -1
- package/dist/assethandler/providers/AssetHandlerProvider.js.map +1 -1
- package/dist/assethandler/store/assethandlerStore.js.map +1 -1
- package/dist/assethandler/utils/categoryPresentation.js.map +1 -1
- package/dist/assethandler/utils/cn.js.map +1 -1
- package/dist/assethandler/utils/csv.js.map +1 -1
- package/dist/assethandler/utils/i18n.js.map +1 -1
- package/dist/assethandler/utils/knowledgeBase.js.map +1 -1
- package/dist/assethandler/utils/meter.js.map +1 -1
- package/dist/assethandler/utils/money.js.map +1 -1
- package/dist/assethandler/utils/navigation.js.map +1 -1
- package/dist/assethandler/utils/printAssetTag.js.map +1 -1
- package/dist/assethandler/utils/toast.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/dijkstrajs/dijkstra.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/maxBy.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/minBy.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/qrcode/lib/browser.js.map +1 -1
- package/dist/node_modules/qrcode/lib/can-promise.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/alignment-pattern.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/alphanumeric-data.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/bit-buffer.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/bit-matrix.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/byte-data.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/error-correction-code.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/error-correction-level.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/finder-pattern.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/format-info.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/galois-field.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/kanji-data.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/mask-pattern.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/mode.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/numeric-data.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/polynomial.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/qrcode.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/reed-solomon-encoder.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/regex.js +1 -1
- package/dist/node_modules/qrcode/lib/core/regex.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/segments.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/utils.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/version-check.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/version.js.map +1 -1
- package/dist/node_modules/qrcode/lib/renderer/canvas.js.map +1 -1
- package/dist/node_modules/qrcode/lib/renderer/svg-tag.js.map +1 -1
- package/dist/node_modules/qrcode/lib/renderer/utils.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/Area.js +13 -13
- package/dist/node_modules/recharts/es6/cartesian/Area.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/Line.js +10 -10
- package/dist/node_modules/recharts/es6/cartesian/Line.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/AreaChart.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/BarChart.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/LineChart.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/PieChart.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/RadialBarChart.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/polar/Pie.js +13 -13
- package/dist/node_modules/recharts/es6/polar/Pie.js.map +1 -1
- package/dist/node_modules/recharts/es6/polar/PolarAngleAxis.js +8 -8
- package/dist/node_modules/recharts/es6/polar/PolarAngleAxis.js.map +1 -1
- package/dist/node_modules/recharts/es6/polar/PolarRadiusAxis.js +6 -6
- package/dist/node_modules/recharts/es6/polar/PolarRadiusAxis.js.map +1 -1
- package/dist/node_modules/recharts/es6/polar/RadialBar.js +6 -6
- package/dist/node_modules/recharts/es6/polar/RadialBar.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/Polygon.js +4 -4
- package/dist/node_modules/recharts/es6/shape/Polygon.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 +1 -1
- package/dist/node_modules/recharts/es6/util/PolarUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/RadialBarUtils.js +1 -1
- package/dist/node_modules/recharts/es6/util/RadialBarUtils.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/dist/services/createSandboxAssistantTransport.js.map +1 -1
- package/dist/utils/pageContext.js.map +1 -1
- package/package.json +4 -4
- package/dist/generated/global-operations.d.ts +0 -2
- package/dist/generated/global-operations.d.ts.map +0 -1
- package/dist/generated/global-types.d.ts +0 -23527
- package/dist/generated/global-types.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EsgDashboardPage.js","names":[],"sources":["../../../src/assethandler/pages/EsgDashboardPage.tsx"],"sourcesContent":["import { Archive, Leaf, Minus, Pencil, Plus, TrendingDown, TrendingUp } from 'lucide-react';\nimport type React from 'react';\nimport {\n Button,\n IllustratedEmptyState,\n GlassCard,\n PagePurpose,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Pagination,\n usePagination,\n SectionHeader,\n StatTile,\n ChartCard,\n DonutChart,\n BarsChart,\n seriesColor,\n formatNumber,\n type DonutSlice,\n} from '../components';\nimport { cn } from '../utils/cn';\nimport { notify } from '../utils/toast';\n\nconst ESG_METRICS_QUERY = gql`\n query AssetHandlerEsgMetrics {\n esgMetrics {\n id\n metricKey\n metricName\n category\n unit\n value\n target\n trend\n periodStart\n periodEnd\n }\n }\n`;\n\nconst CREATE_ESG_METRIC_MUTATION = gql`\n mutation AssetHandlerCreateEsgMetric($input: CreateEsgMetricInput!) {\n createEsgMetric(input: $input) {\n id\n metricName\n }\n }\n`;\n\nconst UPDATE_ESG_METRIC_MUTATION = gql`\n mutation AssetHandlerUpdateEsgMetric($id: ID!, $input: UpdateEsgMetricInput!) {\n updateEsgMetric(id: $id, input: $input) {\n id\n metricName\n }\n }\n`;\n\nconst ARCHIVE_ESG_METRIC_MUTATION = gql`\n mutation AssetHandlerArchiveEsgMetric($id: ID!) {\n archiveEsgMetric(id: $id)\n }\n`;\n\ninterface EcoMetric {\n id: string;\n metricKey: string;\n metricName: string;\n category: string;\n unit: string;\n value: number;\n target: number | null;\n trend: string | null;\n periodStart: string;\n periodEnd: string;\n}\n\ninterface CreateEsgMetricResult {\n createEsgMetric: { id: string; metricName: string };\n}\n\ninterface UpdateEsgMetricResult {\n updateEsgMetric: { id: string; metricName: string };\n}\n\nconst ESG_CATEGORIES = ['environment', 'social', 'governance'] as const;\nconst ESG_TRENDS = ['improving', 'stable', 'declining'] as const;\n\nconst TREND_META: Record<\n string,\n {\n label: string;\n icon: typeof TrendingUp;\n tone: 'positive' | 'negative' | 'neutral';\n dir: 'up' | 'down' | 'neutral';\n }\n> = {\n improving: { label: 'Improving', icon: TrendingUp, tone: 'positive', dir: 'up' },\n declining: { label: 'Declining', icon: TrendingDown, tone: 'negative', dir: 'down' },\n stable: { label: 'Stable', icon: Minus, tone: 'neutral', dir: 'neutral' },\n};\n\nconst TREND_PILL: Record<'positive' | 'negative' | 'neutral', string> = {\n positive: 'bg-status-success-bg-subtle text-status-success-text',\n negative: 'bg-status-error-bg-subtle text-status-error-text',\n neutral: 'bg-bg-sunken text-text-secondary',\n};\n\nconst slugify = (value: string): string =>\n value\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n\ninterface MetricFormValues {\n metricName: string;\n category: (typeof ESG_CATEGORIES)[number];\n unit: string;\n value: number;\n target: number | null;\n trend: (typeof ESG_TRENDS)[number];\n periodStart: string;\n periodEnd: string;\n}\n\nexport function buildMetricMutationVariables(metricId: string | null, form: MetricFormValues) {\n const mutableInput = {\n metricName: form.metricName.trim(),\n category: form.category,\n unit: form.unit.trim(),\n value: form.value,\n target: form.target,\n trend: form.trend,\n };\n if (metricId)\n return { kind: 'update' as const, variables: { id: metricId, input: mutableInput } };\n return {\n kind: 'create' as const,\n variables: {\n input: {\n ...mutableInput,\n metricKey: slugify(form.metricName),\n periodStart: new Date(form.periodStart).toISOString(),\n periodEnd: new Date(form.periodEnd).toISOString(),\n },\n },\n };\n}\n\nfunction firstOfMonthISO(): string {\n const now = new Date();\n return new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10);\n}\n\nfunction todayISO(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nfunction TrendBadge({ trend }: { trend: string | null }) {\n const meta = TREND_META[trend ?? 'stable'] ?? TREND_META.stable;\n const Icon = meta.icon;\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium',\n TREND_PILL[meta.tone]\n )}\n >\n <Icon className=\"h-3 w-3\" />\n {meta.label}\n </span>\n );\n}\n\nfunction RecordMetricDialog({\n open,\n metric,\n onOpenChange,\n onSaved,\n}: {\n open: boolean;\n metric: EcoMetric | null;\n onOpenChange: (open: boolean) => void;\n onSaved: () => void;\n}) {\n const [metricName, setMetricName] = useState(metric?.metricName ?? '');\n const [category, setCategory] = useState<(typeof ESG_CATEGORIES)[number]>(\n (metric?.category as (typeof ESG_CATEGORIES)[number]) ?? 'environment'\n );\n const [unit, setUnit] = useState(metric?.unit ?? '');\n const [value, setValue] = useState(metric ? String(metric.value) : '');\n const [target, setTarget] = useState(metric?.target == null ? '' : String(metric.target));\n const [trend, setTrend] = useState<(typeof ESG_TRENDS)[number]>(\n (metric?.trend as (typeof ESG_TRENDS)[number]) ?? 'stable'\n );\n const [periodStart, setPeriodStart] = useState(\n metric?.periodStart.slice(0, 10) ?? firstOfMonthISO()\n );\n const [periodEnd, setPeriodEnd] = useState(metric?.periodEnd.slice(0, 10) ?? todayISO());\n\n const mutationOptions = {\n onError: (error: Error) => notify.error('Could not save metric', error.message),\n };\n const [createEsgMetric, { loading: creating }] = useMutation<CreateEsgMetricResult>(\n CREATE_ESG_METRIC_MUTATION,\n {\n ...mutationOptions,\n onCompleted: (result) => {\n notify.success('Metric saved', `${result.createEsgMetric.metricName} was recorded.`);\n onOpenChange(false);\n onSaved();\n },\n }\n );\n const [updateEsgMetric, { loading: updating }] = useMutation<UpdateEsgMetricResult>(\n UPDATE_ESG_METRIC_MUTATION,\n {\n ...mutationOptions,\n onCompleted: (result) => {\n notify.success('Metric updated', `${result.updateEsgMetric.metricName} was updated.`);\n onOpenChange(false);\n onSaved();\n },\n }\n );\n const saving = creating || updating;\n\n const handleSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n const parsedValue = Number(value);\n if (!metricName.trim() || !unit.trim()) {\n notify.warning('Missing details', 'Metric name and unit are required.');\n return;\n }\n if (!Number.isFinite(parsedValue) || value.trim() === '') {\n notify.warning('Invalid value', 'Enter a numeric metric value.');\n return;\n }\n if (!periodStart || !periodEnd) {\n notify.warning('Missing period', 'Period start and end are required.');\n return;\n }\n const parsedTarget = target.trim() === '' ? null : Number(target);\n const mutation = buildMetricMutationVariables(metric?.id ?? null, {\n metricName,\n category,\n unit,\n value: parsedValue,\n target: parsedTarget != null && Number.isFinite(parsedTarget) ? parsedTarget : null,\n trend,\n periodStart,\n periodEnd,\n });\n if (mutation.kind === 'update') {\n void updateEsgMetric(mutation);\n } else {\n void createEsgMetric(mutation);\n }\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-2xl\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>{metric ? 'Edit Metric' : 'Save Metric'}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {metric\n ? 'Update this metric’s values. Its source identity and reporting period stay unchanged.'\n : 'Record an ESG metric to track progress toward your sustainability targets.'}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <form className=\"space-y-3\" onSubmit={handleSubmit}>\n <div className=\"grid gap-3 md:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label>Metric Name *</Label>\n <Input\n placeholder=\"e.g., Scope 2 carbon emissions\"\n value={metricName}\n onChange={(e) => setMetricName(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Category</Label>\n <Select value={category} onValueChange={(v) => setCategory(v as typeof category)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {ESG_CATEGORIES.map((c) => (\n <SelectItem key={c} value={c} className=\"capitalize\">\n {c}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Unit *</Label>\n <Input\n placeholder=\"e.g., tCO2e\"\n value={unit}\n onChange={(e) => setUnit(e.target.value)}\n />\n </div>\n </div>\n <div className=\"grid gap-3 md:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label>Value *</Label>\n <Input\n type=\"number\"\n step=\"any\"\n value={value}\n onChange={(e) => setValue(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Target</Label>\n <Input\n type=\"number\"\n step=\"any\"\n value={target}\n onChange={(e) => setTarget(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Trend</Label>\n <Select value={trend} onValueChange={(v) => setTrend(v as typeof trend)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {ESG_TRENDS.map((t) => (\n <SelectItem key={t} value={t} className=\"capitalize\">\n {t}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"grid gap-3 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Period Start *</Label>\n <Input\n type=\"date\"\n value={periodStart}\n onChange={(e) => setPeriodStart(e.target.value)}\n disabled={metric != null}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Period End *</Label>\n <Input\n type=\"date\"\n value={periodEnd}\n onChange={(e) => setPeriodEnd(e.target.value)}\n disabled={metric != null}\n />\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={saving}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={saving}>\n {saving ? 'Saving…' : metric ? 'Update Metric' : 'Save Metric'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport function EsgDashboardPage() {\n const [dialogOpen, setDialogOpen] = useState(false);\n const [editingMetric, setEditingMetric] = useState<EcoMetric | null>(null);\n const [archivingMetric, setArchivingMetric] = useState<EcoMetric | null>(null);\n const [category, setCategory] = useState<string>('ALL');\n\n const { data, loading, refetch } = useQuery<{ esgMetrics: EcoMetric[] }>(ESG_METRICS_QUERY, {\n fetchPolicy: 'cache-and-network',\n });\n\n const metrics = useMemo(() => data?.esgMetrics ?? [], [data?.esgMetrics]);\n\n const [archiveEsgMetric, { loading: archiving }] = useMutation<{ archiveEsgMetric: boolean }>(\n ARCHIVE_ESG_METRIC_MUTATION,\n {\n onCompleted: () => {\n notify.success('Metric archived', 'The metric was removed from the active ESG dashboard.');\n setArchivingMetric(null);\n void refetch();\n },\n onError: (error) => notify.error('Could not archive metric', error.message),\n }\n );\n\n const headline = useMemo(() => metrics.slice(0, 4), [metrics]);\n\n const filtered = useMemo(\n () => (category === 'ALL' ? metrics : metrics.filter((m) => m.category === category)),\n [metrics, category]\n );\n\n const categoryMix = useMemo<DonutSlice[]>(() => {\n const counts = metrics.reduce<Record<string, number>>((acc, m) => {\n acc[m.category] = (acc[m.category] ?? 0) + 1;\n return acc;\n }, {});\n return Object.entries(counts).map(([cat, value], i) => ({\n name: cat.charAt(0).toUpperCase() + cat.slice(1),\n value,\n color: seriesColor(i),\n }));\n }, [metrics]);\n\n const valueVsTarget = useMemo(\n () =>\n metrics\n .filter((m) => m.target != null)\n .slice(0, 8)\n .map((m) => ({ name: m.metricName, value: m.value, target: m.target as number })),\n [metrics]\n );\n\n const categoryCounts = useMemo(() => {\n const counts: Record<string, number> = { ALL: metrics.length };\n for (const m of metrics) counts[m.category] = (counts[m.category] ?? 0) + 1;\n return counts;\n }, [metrics]);\n\n const pagination = usePagination(filtered, { pageSize: 8, resetKey: category });\n\n return (\n <div className=\"space-y-5 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={Leaf}\n title=\"ESG Dashboard\"\n description=\"Measure the environmental and governance impact of your estate against targets.\"\n actions={\n <Button\n className=\"w-full sm:w-auto\"\n onClick={() => {\n setEditingMetric(null);\n setDialogOpen(true);\n }}\n >\n <Plus className=\"mr-2 h-4 w-4\" />\n Save Metric\n </Button>\n }\n />\n <PagePurpose>\n Track energy use, carbon emissions and responsible disposal against targets — and produce\n the evidence ESG reporting and audits require.\n </PagePurpose>\n\n {dialogOpen ? (\n <RecordMetricDialog\n open\n metric={editingMetric}\n onOpenChange={(nextOpen) => {\n setDialogOpen(nextOpen);\n if (!nextOpen) setEditingMetric(null);\n }}\n onSaved={() => void refetch()}\n />\n ) : null}\n\n <ResponsiveDialog\n open={archivingMetric != null}\n onOpenChange={(nextOpen) => {\n if (!nextOpen) setArchivingMetric(null);\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Archive metric</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Archive {archivingMetric?.metricName ?? 'this metric'}? It will leave the active ESG\n dashboard. Archiving does not refund monthly usage.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setArchivingMetric(null)} disabled={archiving}>\n Cancel\n </Button>\n <Button\n variant=\"destructive\"\n disabled={archiving || archivingMetric == null}\n onClick={() => {\n if (archivingMetric) {\n void archiveEsgMetric({ variables: { id: archivingMetric.id } });\n }\n }}\n >\n {archiving ? 'Archiving…' : 'Archive Metric'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n {loading && metrics.length === 0 ? (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"h-28 rounded-xl bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n\n {!loading && metrics.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No ESG metrics recorded yet\"\n description=\"Save a metric to start tracking sustainability progress against your targets.\"\n />\n ) : null}\n\n {headline.length > 0 ? (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {headline.map((m) => {\n const meta = TREND_META[m.trend ?? 'stable'] ?? TREND_META.stable;\n return (\n <StatTile\n key={m.id}\n label={`${m.metricName} (${m.unit})`}\n value={m.value}\n format={formatNumber}\n delta={meta.label}\n deltaDirection={meta.dir}\n deltaTone={meta.tone}\n icon={Leaf}\n />\n );\n })}\n </div>\n ) : null}\n\n {metrics.length > 0 ? (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Value vs. target\" subtitle=\"Metrics measured against their targets\">\n {valueVsTarget.length > 0 ? (\n <BarsChart\n data={valueVsTarget}\n xKey=\"name\"\n series={[\n { key: 'value', label: 'Value' },\n { key: 'target', label: 'Target' },\n ]}\n orientation=\"horizontal\"\n height={240}\n categoryWidth={150}\n ariaLabel=\"Metric value versus target\"\n />\n ) : (\n <div className=\"flex h-[240px] items-center justify-center text-sm text-text-secondary\">\n Set a target on a metric to compare value against target.\n </div>\n )}\n </ChartCard>\n <ChartCard title=\"By category\" subtitle=\"Metrics across E / S / G\">\n <DonutChart\n data={categoryMix}\n height={240}\n centerLabel=\"Metrics\"\n centerValue={metrics.length}\n ariaLabel=\"Metrics by category\"\n />\n </ChartCard>\n </div>\n ) : null}\n\n {metrics.length > 0 ? (\n <>\n <div className=\"flex flex-wrap items-center gap-2\">\n {(['ALL', ...ESG_CATEGORIES] as const).map((c) => (\n <button\n key={c}\n type=\"button\"\n onClick={() => setCategory(c)}\n className={cn(\n 'rounded-full px-3.5 py-1.5 text-sm font-medium capitalize transition-colors',\n category === c\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {c === 'ALL' ? 'All' : c}\n <span className=\"ml-1.5 text-xs opacity-70 tabular-nums\">\n {categoryCounts[c] ?? 0}\n </span>\n </button>\n ))}\n </div>\n\n <div className=\"grid gap-4 sm:grid-cols-2\">\n {pagination.pageItems.map((metric) => {\n const pct =\n metric.target && metric.target > 0\n ? Math.min(100, Math.round((metric.value / metric.target) * 100))\n : null;\n return (\n <GlassCard key={metric.id} treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"space-y-3 p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">\n {metric.category}\n </p>\n <h2 className=\"mt-0.5 text-base font-semibold text-text-primary\">\n {metric.metricName}\n </h2>\n </div>\n <div className=\"flex items-center gap-1\">\n <TrendBadge trend={metric.trend} />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n aria-label={`Edit ${metric.metricName}`}\n onClick={() => {\n setEditingMetric(metric);\n setDialogOpen(true);\n }}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n aria-label={`Archive ${metric.metricName}`}\n onClick={() => setArchivingMetric(metric)}\n >\n <Archive className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n <div className=\"flex items-baseline gap-2\">\n <span className=\"text-2xl font-bold tabular-nums text-text-primary\">\n {formatNumber(metric.value)}\n </span>\n <span className=\"text-sm text-text-secondary\">{metric.unit}</span>\n {metric.target != null ? (\n <span className=\"text-xs text-text-muted\">\n target {formatNumber(metric.target)}\n </span>\n ) : null}\n </div>\n {pct != null ? (\n <div className=\"space-y-1\">\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span>Progress to target</span>\n <span className=\"font-medium tabular-nums\">{pct}%</span>\n </div>\n <div className=\"h-2 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg\"\n style={{ width: `${pct}%` }}\n />\n </div>\n </div>\n ) : null}\n </div>\n </GlassCard>\n );\n })}\n </div>\n\n <Pagination\n page={pagination.page}\n pageCount={pagination.pageCount}\n rangeStart={pagination.rangeStart}\n rangeEnd={pagination.rangeEnd}\n totalItems={pagination.totalItems}\n canPrev={pagination.canPrev}\n canNext={pagination.canNext}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"metrics\"\n />\n </>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAuCA,IAAM,IAAoB,CAAG;;;;;;;;;;;;;;;GAiBvB,IAA6B,CAAG;;;;;;;GAShC,IAA6B,CAAG;;;;;;;GAShC,IAA8B,CAAG;;;;GA2BjC,IAAiB;CAAC;CAAe;CAAU;CAAa,EACxD,IAAa;CAAC;CAAa;CAAU;CAAY,EAEjD,IAQF;CACF,WAAW;EAAE,OAAO;EAAa,MAAM;EAAY,MAAM;EAAY,KAAK;EAAM;CAChF,WAAW;EAAE,OAAO;EAAa,MAAM;EAAc,MAAM;EAAY,KAAK;EAAQ;CACpF,QAAQ;EAAE,OAAO;EAAU,MAAM;EAAO,MAAM;EAAW,KAAK;EAAW;CAC1E,EAEK,IAAkE;CACtE,UAAU;CACV,UAAU;CACV,SAAS;CACV,EAEK,KAAW,MACf,EACG,aAAa,CACb,MAAM,CACN,QAAQ,eAAe,IAAI,CAC3B,QAAQ,YAAY,GAAG;AAa5B,SAAgB,GAA6B,GAAyB,GAAwB;CAC5F,IAAM,IAAe;EACnB,YAAY,EAAK,WAAW,MAAM;EAClC,UAAU,EAAK;EACf,MAAM,EAAK,KAAK,MAAM;EACtB,OAAO,EAAK;EACZ,QAAQ,EAAK;EACb,OAAO,EAAK;EACb;AAGD,QAFI,IACK;EAAE,MAAM;EAAmB,WAAW;GAAE,IAAI;GAAU,OAAO;GAAc;EAAE,GAC/E;EACL,MAAM;EACN,WAAW,EACT,OAAO;GACL,GAAG;GACH,WAAW,EAAQ,EAAK,WAAW;GACnC,aAAa,IAAI,KAAK,EAAK,YAAY,CAAC,aAAa;GACrD,WAAW,IAAI,KAAK,EAAK,UAAU,CAAC,aAAa;GAClD,EACF;EACF;;AAGH,SAAS,IAA0B;CACjC,IAAM,oBAAM,IAAI,MAAM;AACtB,QAAO,IAAI,KAAK,EAAI,aAAa,EAAE,EAAI,UAAU,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,GAAG,GAAG;;AAGlF,SAAS,KAAmB;AAC1B,yBAAO,IAAI,MAAM,EAAC,aAAa,CAAC,MAAM,GAAG,GAAG;;AAG9C,SAAS,GAAW,EAAE,YAAmC;CACvD,IAAM,IAAO,EAAW,KAAS,aAAa,EAAW,QACnD,IAAO,EAAK;AAClB,QACE,kBAAC,QAAD;EACE,WAAW,EACT,+EACA,EAAW,EAAK,MACjB;YAJH,CAME,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAC3B,EAAK,MACD;;;AAIX,SAAS,GAAmB,EAC1B,SACA,WACA,iBACA,cAMC;CACD,IAAM,CAAC,GAAY,KAAiB,EAAS,GAAQ,cAAc,GAAG,EAChE,CAAC,GAAU,KAAe,EAC7B,GAAQ,YAAgD,cAC1D,EACK,CAAC,GAAM,KAAW,EAAS,GAAQ,QAAQ,GAAG,EAC9C,CAAC,GAAO,KAAY,EAAS,IAAS,OAAO,EAAO,MAAM,GAAG,GAAG,EAChE,CAAC,GAAQ,KAAa,EAAS,GAAQ,UAAU,OAAO,KAAK,OAAO,EAAO,OAAO,CAAC,EACnF,CAAC,GAAO,KAAY,EACvB,GAAQ,SAAyC,SACnD,EACK,CAAC,GAAa,KAAkB,EACpC,GAAQ,YAAY,MAAM,GAAG,GAAG,IAAI,GAAiB,CACtD,EACK,CAAC,GAAW,KAAgB,EAAS,GAAQ,UAAU,MAAM,GAAG,GAAG,IAAI,IAAU,CAAC,EAElF,IAAkB,EACtB,UAAU,MAAiB,EAAO,MAAM,yBAAyB,EAAM,QAAQ,EAChF,EACK,CAAC,GAAiB,EAAE,SAAS,OAAc,EAC/C,GACA;EACE,GAAG;EACH,cAAc,MAAW;AAGvB,GAFA,EAAO,QAAQ,gBAAgB,GAAG,EAAO,gBAAgB,WAAW,gBAAgB,EACpF,EAAa,GAAM,EACnB,GAAS;;EAEZ,CACF,EACK,CAAC,GAAiB,EAAE,SAAS,OAAc,EAC/C,GACA;EACE,GAAG;EACH,cAAc,MAAW;AAGvB,GAFA,EAAO,QAAQ,kBAAkB,GAAG,EAAO,gBAAgB,WAAW,eAAe,EACrF,EAAa,GAAM,EACnB,GAAS;;EAEZ,CACF,EACK,IAAS,KAAY;AAmC3B,QACE,kBAAC,GAAD;EAAwB;EAAoB;YAC1C,kBAAC,GAAD;GAAyB,WAAU;aAAnC,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAwB,IAAS,gBAAgB,eAAsC,CAAA,EACvF,kBAAC,GAAD,EAAA,UACG,IACG,0FACA,8EACwB,CAAA,CACP,EAAA,CAAA,EACzB,kBAAC,QAAD;IAAM,WAAU;IAAY,WA5CZ,MAA2B;AAC/C,OAAM,gBAAgB;KACtB,IAAM,IAAc,OAAO,EAAM;AACjC,SAAI,CAAC,EAAW,MAAM,IAAI,CAAC,EAAK,MAAM,EAAE;AACtC,QAAO,QAAQ,mBAAmB,qCAAqC;AACvE;;AAEF,SAAI,CAAC,OAAO,SAAS,EAAY,IAAI,EAAM,MAAM,KAAK,IAAI;AACxD,QAAO,QAAQ,iBAAiB,gCAAgC;AAChE;;AAEF,SAAI,CAAC,KAAe,CAAC,GAAW;AAC9B,QAAO,QAAQ,kBAAkB,qCAAqC;AACtE;;KAEF,IAAM,IAAe,EAAO,MAAM,KAAK,KAAK,OAAO,OAAO,EAAO,EAC3D,IAAW,GAA6B,GAAQ,MAAM,MAAM;MAChE;MACA;MACA;MACA,OAAO;MACP,QAAQ,KAAgB,QAAQ,OAAO,SAAS,EAAa,GAAG,IAAe;MAC/E;MACA;MACA;MACD,CAAC;AACF,KAAI,EAAS,SAAS,WACf,EAAgB,EAAS,GAEzB,EAAgB,EAAS;;cAe5B;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,iBAAqB,CAAA,EAC5B,kBAAC,GAAD;SACE,aAAY;SACZ,OAAO;SACP,WAAW,MAAM,EAAc,EAAE,OAAO,MAAM;SAC9C,CAAA,CACE;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,YAAgB,CAAA,EACvB,kBAAC,GAAD;SAAQ,OAAO;SAAU,gBAAgB,MAAM,EAAY,EAAqB;mBAAhF,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAe,CAAA,EACD,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,EAAe,KAAK,MACnB,kBAAC,GAAD;UAAoB,OAAO;UAAG,WAAU;oBACrC;UACU,EAFI,EAEJ,CACb,EACY,CAAA,CACT;WACL;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,UAAc,CAAA,EACrB,kBAAC,GAAD;SACE,aAAY;SACZ,OAAO;SACP,WAAW,MAAM,EAAQ,EAAE,OAAO,MAAM;SACxC,CAAA,CACE;;OACF;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,WAAe,CAAA,EACtB,kBAAC,GAAD;SACE,MAAK;SACL,MAAK;SACE;SACP,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;SACzC,CAAA,CACE;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,UAAc,CAAA,EACrB,kBAAC,GAAD;SACE,MAAK;SACL,MAAK;SACL,OAAO;SACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;SAC1C,CAAA,CACE;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,SAAa,CAAA,EACpB,kBAAC,GAAD;SAAQ,OAAO;SAAO,gBAAgB,MAAM,EAAS,EAAkB;mBAAvE,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAe,CAAA,EACD,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,EAAW,KAAK,MACf,kBAAC,GAAD;UAAoB,OAAO;UAAG,WAAU;oBACrC;UACU,EAFI,EAEJ,CACb,EACY,CAAA,CACT;WACL;;OACF;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,kBAAsB,CAAA,EAC7B,kBAAC,GAAD;QACE,MAAK;QACL,OAAO;QACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;QAC/C,UAAU,KAAU;QACpB,CAAA,CACE;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,gBAAoB,CAAA,EAC3B,kBAAC,GAAD;QACE,MAAK;QACL,OAAO;QACP,WAAW,MAAM,EAAa,EAAE,OAAO,MAAM;QAC7C,UAAU,KAAU;QACpB,CAAA,CACE;SACF;;KACN,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;MACE,MAAK;MACL,SAAQ;MACR,eAAe,EAAa,GAAM;MAClC,UAAU;gBACX;MAEQ,CAAA,EACT,kBAAC,GAAD;MAAQ,MAAK;MAAS,UAAU;gBAC7B,IAAS,YAAY,IAAS,kBAAkB;MAC1C,CAAA,CACc,EAAA,CAAA;KACpB;MACiB;;EACT,CAAA;;AAIvB,SAAgB,IAAmB;CACjC,IAAM,CAAC,GAAY,KAAiB,EAAS,GAAM,EAC7C,CAAC,GAAe,KAAoB,EAA2B,KAAK,EACpE,CAAC,GAAiB,KAAsB,EAA2B,KAAK,EACxE,CAAC,GAAU,KAAe,EAAiB,MAAM,EAEjD,EAAE,SAAM,YAAS,eAAY,EAAsC,GAAmB,EAC1F,aAAa,qBACd,CAAC,EAEI,IAAU,QAAc,GAAM,cAAc,EAAE,EAAE,CAAC,GAAM,WAAW,CAAC,EAEnE,CAAC,GAAkB,EAAE,SAAS,OAAe,EACjD,GACA;EACE,mBAAmB;AAGZ,GAFL,EAAO,QAAQ,mBAAmB,wDAAwD,EAC1F,EAAmB,KAAK,EACnB,GAAS;;EAEhB,UAAU,MAAU,EAAO,MAAM,4BAA4B,EAAM,QAAQ;EAC5E,CACF,EAEK,IAAW,QAAc,EAAQ,MAAM,GAAG,EAAE,EAAE,CAAC,EAAQ,CAAC,EAExD,IAAW,QACR,MAAa,QAAQ,IAAU,EAAQ,QAAQ,MAAM,EAAE,aAAa,EAAS,EACpF,CAAC,GAAS,EAAS,CACpB,EAEK,KAAc,QAA4B;EAC9C,IAAM,IAAS,EAAQ,QAAgC,GAAK,OAC1D,EAAI,EAAE,aAAa,EAAI,EAAE,aAAa,KAAK,GACpC,IACN,EAAE,CAAC;AACN,SAAO,OAAO,QAAQ,EAAO,CAAC,KAAK,CAAC,GAAK,IAAQ,OAAO;GACtD,MAAM,EAAI,OAAO,EAAE,CAAC,aAAa,GAAG,EAAI,MAAM,EAAE;GAChD;GACA,OAAO,EAAY,EAAE;GACtB,EAAE;IACF,CAAC,EAAQ,CAAC,EAEP,IAAgB,QAElB,EACG,QAAQ,MAAM,EAAE,UAAU,KAAK,CAC/B,MAAM,GAAG,EAAE,CACX,KAAK,OAAO;EAAE,MAAM,EAAE;EAAY,OAAO,EAAE;EAAO,QAAQ,EAAE;EAAkB,EAAE,EACrF,CAAC,EAAQ,CACV,EAEK,KAAiB,QAAc;EACnC,IAAM,IAAiC,EAAE,KAAK,EAAQ,QAAQ;AAC9D,OAAK,IAAM,KAAK,EAAS,GAAO,EAAE,aAAa,EAAO,EAAE,aAAa,KAAK;AAC1E,SAAO;IACN,CAAC,EAAQ,CAAC,EAEP,IAAa,EAAc,GAAU;EAAE,UAAU;EAAG,UAAU;EAAU,CAAC;AAE/E,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD;IACE,MAAA;IACA,MAAM;IACN,OAAM;IACN,aAAY;IACZ,SACE,kBAAC,GAAD;KACE,WAAU;KACV,eAAe;AAEb,MADA,EAAiB,KAAK,EACtB,EAAc,GAAK;;eAJvB,CAOE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,cAE1B;;IAEX,CAAA;GACF,kBAAC,GAAD,EAAA,UAAa,4IAGC,CAAA;GAEb,IACC,kBAAC,IAAD;IACE,MAAA;IACA,QAAQ;IACR,eAAe,MAAa;AAE1B,KADA,EAAc,EAAS,EAClB,KAAU,EAAiB,KAAK;;IAEvC,eAAe,KAAK,GAAS;IAC7B,CAAA,GACA;GAEJ,kBAAC,GAAD;IACE,MAAM,KAAmB;IACzB,eAAe,MAAa;AAC1B,KAAK,KAAU,EAAmB,KAAK;;cAGzC,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAuB,kBAAsC,CAAA,EAC7D,kBAAC,GAAD,EAAA,UAAA;KAA6B;KAClB,GAAiB,cAAc;KAAc;KAE1B,EAAA,CAAA,CACP,EAAA,CAAA,EACzB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;KAAQ,SAAQ;KAAU,eAAe,EAAmB,KAAK;KAAE,UAAU;eAAW;KAE/E,CAAA,EACT,kBAAC,GAAD;KACE,SAAQ;KACR,UAAU,KAAa,KAAmB;KAC1C,eAAe;AACb,MAAI,KACG,EAAiB,EAAE,WAAW,EAAE,IAAI,EAAgB,IAAI,EAAE,CAAC;;eAInE,IAAY,eAAe;KACrB,CAAA,CACc,EAAA,CAAA,CACD,EAAA,CAAA;IACT,CAAA;GAElB,KAAW,EAAQ,WAAW,IAC7B,kBAAC,OAAD;IAAK,WAAU;cACZ,MAAM,KAAK,EAAE,QAAQ,GAAG,CAAC,CAAC,KAAK,GAAG,MACjC,kBAAC,OAAD,EAAa,WAAU,+DAAgE,EAA7E,EAA6E,CACvF;IACE,CAAA,GACJ;GAEH,CAAC,KAAW,EAAQ,WAAW,IAC9B,kBAAC,GAAD;IACE,cAAa;IACb,OAAM;IACN,aAAY;IACZ,CAAA,GACA;GAEH,EAAS,SAAS,IACjB,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAS,KAAK,MAAM;KACnB,IAAM,IAAO,EAAW,EAAE,SAAS,aAAa,EAAW;AAC3D,YACE,kBAAC,GAAD;MAEE,OAAO,GAAG,EAAE,WAAW,IAAI,EAAE,KAAK;MAClC,OAAO,EAAE;MACT,QAAQ;MACR,OAAO,EAAK;MACZ,gBAAgB,EAAK;MACrB,WAAW,EAAK;MAChB,MAAM;MACN,EARK,EAAE,GAQP;MAEJ;IACE,CAAA,GACJ;GAEH,EAAQ,SAAS,IAChB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAW,OAAM;KAAmB,UAAS;eAC1C,EAAc,SAAS,IACtB,kBAAC,GAAD;MACE,MAAM;MACN,MAAK;MACL,QAAQ,CACN;OAAE,KAAK;OAAS,OAAO;OAAS,EAChC;OAAE,KAAK;OAAU,OAAO;OAAU,CACnC;MACD,aAAY;MACZ,QAAQ;MACR,eAAe;MACf,WAAU;MACV,CAAA,GAEF,kBAAC,OAAD;MAAK,WAAU;gBAAyE;MAElF,CAAA;KAEE,CAAA,EACZ,kBAAC,GAAD;KAAW,OAAM;KAAc,UAAS;eACtC,kBAAC,GAAD;MACE,MAAM;MACN,QAAQ;MACR,aAAY;MACZ,aAAa,EAAQ;MACrB,WAAU;MACV,CAAA;KACQ,CAAA,CACR;QACJ;GAEH,EAAQ,SAAS,IAChB,kBAAA,GAAA,EAAA,UAAA;IACE,kBAAC,OAAD;KAAK,WAAU;eACX,CAAC,OAAO,GAAG,EAAe,CAAW,KAAK,MAC1C,kBAAC,UAAD;MAEE,MAAK;MACL,eAAe,EAAY,EAAE;MAC7B,WAAW,EACT,+EACA,MAAa,IACT,kDACA,2DACL;gBATH,CAWG,MAAM,QAAQ,QAAQ,GACvB,kBAAC,QAAD;OAAM,WAAU;iBACb,GAAe,MAAM;OACjB,CAAA,CACA;QAdF,EAcE,CACT;KACE,CAAA;IAEN,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAW,UAAU,KAAK,MAAW;MACpC,IAAM,IACJ,EAAO,UAAU,EAAO,SAAS,IAC7B,KAAK,IAAI,KAAK,KAAK,MAAO,EAAO,QAAQ,EAAO,SAAU,IAAI,CAAC,GAC/D;AACN,aACE,kBAAC,GAAD;OAA2B,WAAU;OAAQ,WAAU;iBACrD,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,KAAD;YAAG,WAAU;sBACV,EAAO;YACN,CAAA,EACJ,kBAAC,MAAD;YAAI,WAAU;sBACX,EAAO;YACL,CAAA,CACD;cACN,kBAAC,OAAD;WAAK,WAAU;qBAAf;YACE,kBAAC,IAAD,EAAY,OAAO,EAAO,OAAS,CAAA;YACnC,kBAAC,GAAD;aACE,MAAK;aACL,SAAQ;aACR,MAAK;aACL,cAAY,QAAQ,EAAO;aAC3B,eAAe;AAEb,cADA,EAAiB,EAAO,EACxB,EAAc,GAAK;;uBAGrB,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;aACvB,CAAA;YACT,kBAAC,GAAD;aACE,MAAK;aACL,SAAQ;aACR,MAAK;aACL,cAAY,WAAW,EAAO;aAC9B,eAAe,EAAmB,EAAO;uBAEzC,kBAAC,GAAD,EAAS,WAAU,WAAY,CAAA;aACxB,CAAA;YACL;aACF;;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf;WACE,kBAAC,QAAD;YAAM,WAAU;sBACb,EAAa,EAAO,MAAM;YACtB,CAAA;WACP,kBAAC,QAAD;YAAM,WAAU;sBAA+B,EAAO;YAAY,CAAA;WACjE,EAAO,UAAU,OAId,OAHF,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CAA0C,WAChC,EAAa,EAAO,OAAO,CAC9B;;WAEL;;SACL,KAAO,OAaJ,OAZF,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD,EAAA,UAAM,sBAAyB,CAAA,EAC/B,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CAA4C,GAAI,IAAQ;cACpD;cACN,kBAAC,OAAD;WAAK,WAAU;qBACb,kBAAC,OAAD;YACE,WAAU;YACV,OAAO,EAAE,OAAO,GAAG,EAAI,IAAI;YAC3B,CAAA;WACE,CAAA,CACF;;SAEJ;;OACI,EA9DI,EAAO,GA8DX;OAEd;KACE,CAAA;IAEN,kBAAC,GAAD;KACE,MAAM,EAAW;KACjB,WAAW,EAAW;KACtB,YAAY,EAAW;KACvB,UAAU,EAAW;KACrB,YAAY,EAAW;KACvB,SAAS,EAAW;KACpB,SAAS,EAAW;KACpB,QAAQ,EAAW;KACnB,QAAQ,EAAW;KACnB,WAAU;KACV,CAAA;IACD,EAAA,CAAA,GACD;GACA"}
|
|
1
|
+
{"version":3,"file":"EsgDashboardPage.js","names":[],"sources":["../../../src/assethandler/pages/EsgDashboardPage.tsx"],"sourcesContent":["import { Archive, Leaf, Minus, Pencil, Plus, TrendingDown, TrendingUp } from 'lucide-react';\nimport type React from 'react';\nimport {\n Button,\n IllustratedEmptyState,\n GlassCard,\n PagePurpose,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Pagination,\n usePagination,\n SectionHeader,\n StatTile,\n ChartCard,\n DonutChart,\n BarsChart,\n seriesColor,\n formatNumber,\n type DonutSlice,\n} from '../components';\nimport { cn } from '../utils/cn';\nimport { notify } from '../utils/toast';\n\nconst ESG_METRICS_QUERY = gql`\n query AssetHandlerEsgMetrics {\n esgMetrics {\n id\n metricKey\n metricName\n category\n unit\n value\n target\n trend\n periodStart\n periodEnd\n }\n }\n`;\n\nconst CREATE_ESG_METRIC_MUTATION = gql`\n mutation AssetHandlerCreateEsgMetric($input: CreateEsgMetricInput!) {\n createEsgMetric(input: $input) {\n id\n metricName\n }\n }\n`;\n\nconst UPDATE_ESG_METRIC_MUTATION = gql`\n mutation AssetHandlerUpdateEsgMetric($id: ID!, $input: UpdateEsgMetricInput!) {\n updateEsgMetric(id: $id, input: $input) {\n id\n metricName\n }\n }\n`;\n\nconst ARCHIVE_ESG_METRIC_MUTATION = gql`\n mutation AssetHandlerArchiveEsgMetric($id: ID!) {\n archiveEsgMetric(id: $id)\n }\n`;\n\ninterface EcoMetric {\n id: string;\n metricKey: string;\n metricName: string;\n category: string;\n unit: string;\n value: number;\n target: number | null;\n trend: string | null;\n periodStart: string;\n periodEnd: string;\n}\n\ninterface CreateEsgMetricResult {\n createEsgMetric: { id: string; metricName: string };\n}\n\ninterface UpdateEsgMetricResult {\n updateEsgMetric: { id: string; metricName: string };\n}\n\nconst ESG_CATEGORIES = ['environment', 'social', 'governance'] as const;\nconst ESG_TRENDS = ['improving', 'stable', 'declining'] as const;\n\nconst TREND_META: Record<\n string,\n {\n label: string;\n icon: typeof TrendingUp;\n tone: 'positive' | 'negative' | 'neutral';\n dir: 'up' | 'down' | 'neutral';\n }\n> = {\n improving: { label: 'Improving', icon: TrendingUp, tone: 'positive', dir: 'up' },\n declining: { label: 'Declining', icon: TrendingDown, tone: 'negative', dir: 'down' },\n stable: { label: 'Stable', icon: Minus, tone: 'neutral', dir: 'neutral' },\n};\n\nconst TREND_PILL: Record<'positive' | 'negative' | 'neutral', string> = {\n positive: 'bg-status-success-bg-subtle text-status-success-text',\n negative: 'bg-status-error-bg-subtle text-status-error-text',\n neutral: 'bg-bg-sunken text-text-secondary',\n};\n\nconst slugify = (value: string): string =>\n value\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n\ninterface MetricFormValues {\n metricName: string;\n category: (typeof ESG_CATEGORIES)[number];\n unit: string;\n value: number;\n target: number | null;\n trend: (typeof ESG_TRENDS)[number];\n periodStart: string;\n periodEnd: string;\n}\n\nexport function buildMetricMutationVariables(metricId: string | null, form: MetricFormValues) {\n const mutableInput = {\n metricName: form.metricName.trim(),\n category: form.category,\n unit: form.unit.trim(),\n value: form.value,\n target: form.target,\n trend: form.trend,\n };\n if (metricId)\n return { kind: 'update' as const, variables: { id: metricId, input: mutableInput } };\n return {\n kind: 'create' as const,\n variables: {\n input: {\n ...mutableInput,\n metricKey: slugify(form.metricName),\n periodStart: new Date(form.periodStart).toISOString(),\n periodEnd: new Date(form.periodEnd).toISOString(),\n },\n },\n };\n}\n\nfunction firstOfMonthISO(): string {\n const now = new Date();\n return new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10);\n}\n\nfunction todayISO(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nfunction TrendBadge({ trend }: { trend: string | null }) {\n const meta = TREND_META[trend ?? 'stable'] ?? TREND_META.stable;\n const Icon = meta.icon;\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium',\n TREND_PILL[meta.tone]\n )}\n >\n <Icon className=\"h-3 w-3\" />\n {meta.label}\n </span>\n );\n}\n\nfunction RecordMetricDialog({\n open,\n metric,\n onOpenChange,\n onSaved,\n}: {\n open: boolean;\n metric: EcoMetric | null;\n onOpenChange: (open: boolean) => void;\n onSaved: () => void;\n}) {\n const [metricName, setMetricName] = useState(metric?.metricName ?? '');\n const [category, setCategory] = useState<(typeof ESG_CATEGORIES)[number]>(\n (metric?.category as (typeof ESG_CATEGORIES)[number]) ?? 'environment'\n );\n const [unit, setUnit] = useState(metric?.unit ?? '');\n const [value, setValue] = useState(metric ? String(metric.value) : '');\n const [target, setTarget] = useState(metric?.target == null ? '' : String(metric.target));\n const [trend, setTrend] = useState<(typeof ESG_TRENDS)[number]>(\n (metric?.trend as (typeof ESG_TRENDS)[number]) ?? 'stable'\n );\n const [periodStart, setPeriodStart] = useState(\n metric?.periodStart.slice(0, 10) ?? firstOfMonthISO()\n );\n const [periodEnd, setPeriodEnd] = useState(metric?.periodEnd.slice(0, 10) ?? todayISO());\n\n const mutationOptions = {\n onError: (error: Error) => notify.error('Could not save metric', error.message),\n };\n const [createEsgMetric, { loading: creating }] = useMutation<CreateEsgMetricResult>(\n CREATE_ESG_METRIC_MUTATION,\n {\n ...mutationOptions,\n onCompleted: (result) => {\n notify.success('Metric saved', `${result.createEsgMetric.metricName} was recorded.`);\n onOpenChange(false);\n onSaved();\n },\n }\n );\n const [updateEsgMetric, { loading: updating }] = useMutation<UpdateEsgMetricResult>(\n UPDATE_ESG_METRIC_MUTATION,\n {\n ...mutationOptions,\n onCompleted: (result) => {\n notify.success('Metric updated', `${result.updateEsgMetric.metricName} was updated.`);\n onOpenChange(false);\n onSaved();\n },\n }\n );\n const saving = creating || updating;\n\n const handleSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n const parsedValue = Number(value);\n if (!metricName.trim() || !unit.trim()) {\n notify.warning('Missing details', 'Metric name and unit are required.');\n return;\n }\n if (!Number.isFinite(parsedValue) || value.trim() === '') {\n notify.warning('Invalid value', 'Enter a numeric metric value.');\n return;\n }\n if (!periodStart || !periodEnd) {\n notify.warning('Missing period', 'Period start and end are required.');\n return;\n }\n const parsedTarget = target.trim() === '' ? null : Number(target);\n const mutation = buildMetricMutationVariables(metric?.id ?? null, {\n metricName,\n category,\n unit,\n value: parsedValue,\n target: parsedTarget != null && Number.isFinite(parsedTarget) ? parsedTarget : null,\n trend,\n periodStart,\n periodEnd,\n });\n if (mutation.kind === 'update') {\n void updateEsgMetric(mutation);\n } else {\n void createEsgMetric(mutation);\n }\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-2xl\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>{metric ? 'Edit Metric' : 'Save Metric'}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {metric\n ? 'Update this metric’s values. Its source identity and reporting period stay unchanged.'\n : 'Record an ESG metric to track progress toward your sustainability targets.'}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <form className=\"space-y-3\" onSubmit={handleSubmit}>\n <div className=\"grid gap-3 md:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label>Metric Name *</Label>\n <Input\n placeholder=\"e.g., Scope 2 carbon emissions\"\n value={metricName}\n onChange={(e) => setMetricName(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Category</Label>\n <Select value={category} onValueChange={(v) => setCategory(v as typeof category)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {ESG_CATEGORIES.map((c) => (\n <SelectItem key={c} value={c} className=\"capitalize\">\n {c}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Unit *</Label>\n <Input\n placeholder=\"e.g., tCO2e\"\n value={unit}\n onChange={(e) => setUnit(e.target.value)}\n />\n </div>\n </div>\n <div className=\"grid gap-3 md:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label>Value *</Label>\n <Input\n type=\"number\"\n step=\"any\"\n value={value}\n onChange={(e) => setValue(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Target</Label>\n <Input\n type=\"number\"\n step=\"any\"\n value={target}\n onChange={(e) => setTarget(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Trend</Label>\n <Select value={trend} onValueChange={(v) => setTrend(v as typeof trend)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {ESG_TRENDS.map((t) => (\n <SelectItem key={t} value={t} className=\"capitalize\">\n {t}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"grid gap-3 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Period Start *</Label>\n <Input\n type=\"date\"\n value={periodStart}\n onChange={(e) => setPeriodStart(e.target.value)}\n disabled={metric != null}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Period End *</Label>\n <Input\n type=\"date\"\n value={periodEnd}\n onChange={(e) => setPeriodEnd(e.target.value)}\n disabled={metric != null}\n />\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={saving}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={saving}>\n {saving ? 'Saving…' : metric ? 'Update Metric' : 'Save Metric'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport function EsgDashboardPage() {\n const [dialogOpen, setDialogOpen] = useState(false);\n const [editingMetric, setEditingMetric] = useState<EcoMetric | null>(null);\n const [archivingMetric, setArchivingMetric] = useState<EcoMetric | null>(null);\n const [category, setCategory] = useState<string>('ALL');\n\n const { data, loading, refetch } = useQuery<{ esgMetrics: EcoMetric[] }>(ESG_METRICS_QUERY, {\n fetchPolicy: 'cache-and-network',\n });\n\n const metrics = useMemo(() => data?.esgMetrics ?? [], [data?.esgMetrics]);\n\n const [archiveEsgMetric, { loading: archiving }] = useMutation<{ archiveEsgMetric: boolean }>(\n ARCHIVE_ESG_METRIC_MUTATION,\n {\n onCompleted: () => {\n notify.success('Metric archived', 'The metric was removed from the active ESG dashboard.');\n setArchivingMetric(null);\n void refetch();\n },\n onError: (error) => notify.error('Could not archive metric', error.message),\n }\n );\n\n const headline = useMemo(() => metrics.slice(0, 4), [metrics]);\n\n const filtered = useMemo(\n () => (category === 'ALL' ? metrics : metrics.filter((m) => m.category === category)),\n [metrics, category]\n );\n\n const categoryMix = useMemo<DonutSlice[]>(() => {\n const counts = metrics.reduce<Record<string, number>>((acc, m) => {\n acc[m.category] = (acc[m.category] ?? 0) + 1;\n return acc;\n }, {});\n return Object.entries(counts).map(([cat, value], i) => ({\n name: cat.charAt(0).toUpperCase() + cat.slice(1),\n value,\n color: seriesColor(i),\n }));\n }, [metrics]);\n\n const valueVsTarget = useMemo(\n () =>\n metrics\n .filter((m) => m.target != null)\n .slice(0, 8)\n .map((m) => ({ name: m.metricName, value: m.value, target: m.target as number })),\n [metrics]\n );\n\n const categoryCounts = useMemo(() => {\n const counts: Record<string, number> = { ALL: metrics.length };\n for (const m of metrics) counts[m.category] = (counts[m.category] ?? 0) + 1;\n return counts;\n }, [metrics]);\n\n const pagination = usePagination(filtered, { pageSize: 8, resetKey: category });\n\n return (\n <div className=\"space-y-5 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={Leaf}\n title=\"ESG Dashboard\"\n description=\"Measure the environmental and governance impact of your estate against targets.\"\n actions={\n <Button\n className=\"w-full sm:w-auto\"\n onClick={() => {\n setEditingMetric(null);\n setDialogOpen(true);\n }}\n >\n <Plus className=\"mr-2 h-4 w-4\" />\n Save Metric\n </Button>\n }\n />\n <PagePurpose>\n Track energy use, carbon emissions and responsible disposal against targets — and produce\n the evidence ESG reporting and audits require.\n </PagePurpose>\n\n {dialogOpen ? (\n <RecordMetricDialog\n open\n metric={editingMetric}\n onOpenChange={(nextOpen) => {\n setDialogOpen(nextOpen);\n if (!nextOpen) setEditingMetric(null);\n }}\n onSaved={() => void refetch()}\n />\n ) : null}\n\n <ResponsiveDialog\n open={archivingMetric != null}\n onOpenChange={(nextOpen) => {\n if (!nextOpen) setArchivingMetric(null);\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Archive metric</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Archive {archivingMetric?.metricName ?? 'this metric'}? It will leave the active ESG\n dashboard. Archiving does not refund monthly usage.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setArchivingMetric(null)} disabled={archiving}>\n Cancel\n </Button>\n <Button\n variant=\"destructive\"\n disabled={archiving || archivingMetric == null}\n onClick={() => {\n if (archivingMetric) {\n void archiveEsgMetric({ variables: { id: archivingMetric.id } });\n }\n }}\n >\n {archiving ? 'Archiving…' : 'Archive Metric'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n {loading && metrics.length === 0 ? (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"h-28 rounded-xl bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n\n {!loading && metrics.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No ESG metrics recorded yet\"\n description=\"Save a metric to start tracking sustainability progress against your targets.\"\n />\n ) : null}\n\n {headline.length > 0 ? (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {headline.map((m) => {\n const meta = TREND_META[m.trend ?? 'stable'] ?? TREND_META.stable;\n return (\n <StatTile\n key={m.id}\n label={`${m.metricName} (${m.unit})`}\n value={m.value}\n format={formatNumber}\n delta={meta.label}\n deltaDirection={meta.dir}\n deltaTone={meta.tone}\n icon={Leaf}\n />\n );\n })}\n </div>\n ) : null}\n\n {metrics.length > 0 ? (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Value vs. target\" subtitle=\"Metrics measured against their targets\">\n {valueVsTarget.length > 0 ? (\n <BarsChart\n data={valueVsTarget}\n xKey=\"name\"\n series={[\n { key: 'value', label: 'Value' },\n { key: 'target', label: 'Target' },\n ]}\n orientation=\"horizontal\"\n height={240}\n categoryWidth={150}\n ariaLabel=\"Metric value versus target\"\n />\n ) : (\n <div className=\"flex h-[240px] items-center justify-center text-sm text-text-secondary\">\n Set a target on a metric to compare value against target.\n </div>\n )}\n </ChartCard>\n <ChartCard title=\"By category\" subtitle=\"Metrics across E / S / G\">\n <DonutChart\n data={categoryMix}\n height={240}\n centerLabel=\"Metrics\"\n centerValue={metrics.length}\n ariaLabel=\"Metrics by category\"\n />\n </ChartCard>\n </div>\n ) : null}\n\n {metrics.length > 0 ? (\n <>\n <div className=\"flex flex-wrap items-center gap-2\">\n {(['ALL', ...ESG_CATEGORIES] as const).map((c) => (\n <button\n key={c}\n type=\"button\"\n onClick={() => setCategory(c)}\n className={cn(\n 'rounded-full px-3.5 py-1.5 text-sm font-medium capitalize transition-colors',\n category === c\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {c === 'ALL' ? 'All' : c}\n <span className=\"ml-1.5 text-xs opacity-70 tabular-nums\">\n {categoryCounts[c] ?? 0}\n </span>\n </button>\n ))}\n </div>\n\n <div className=\"grid gap-4 sm:grid-cols-2\">\n {pagination.pageItems.map((metric) => {\n const pct =\n metric.target && metric.target > 0\n ? Math.min(100, Math.round((metric.value / metric.target) * 100))\n : null;\n return (\n <GlassCard key={metric.id} treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"space-y-3 p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">\n {metric.category}\n </p>\n <h2 className=\"mt-0.5 text-base font-semibold text-text-primary\">\n {metric.metricName}\n </h2>\n </div>\n <div className=\"flex items-center gap-1\">\n <TrendBadge trend={metric.trend} />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n aria-label={`Edit ${metric.metricName}`}\n onClick={() => {\n setEditingMetric(metric);\n setDialogOpen(true);\n }}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n aria-label={`Archive ${metric.metricName}`}\n onClick={() => setArchivingMetric(metric)}\n >\n <Archive className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n <div className=\"flex items-baseline gap-2\">\n <span className=\"text-2xl font-bold tabular-nums text-text-primary\">\n {formatNumber(metric.value)}\n </span>\n <span className=\"text-sm text-text-secondary\">{metric.unit}</span>\n {metric.target != null ? (\n <span className=\"text-xs text-text-muted\">\n target {formatNumber(metric.target)}\n </span>\n ) : null}\n </div>\n {pct != null ? (\n <div className=\"space-y-1\">\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span>Progress to target</span>\n <span className=\"font-medium tabular-nums\">{pct}%</span>\n </div>\n <div className=\"h-2 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg\"\n style={{ width: `${pct}%` }}\n />\n </div>\n </div>\n ) : null}\n </div>\n </GlassCard>\n );\n })}\n </div>\n\n <Pagination\n page={pagination.page}\n pageCount={pagination.pageCount}\n rangeStart={pagination.rangeStart}\n rangeEnd={pagination.rangeEnd}\n totalItems={pagination.totalItems}\n canPrev={pagination.canPrev}\n canNext={pagination.canNext}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"metrics\"\n />\n </>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FinanceBudgetDetailPage.js","names":[],"sources":["../../../src/assethandler/pages/FinanceBudgetDetailPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useAssetMoney } from '../providers/AssetHandlerProvider';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n IllustratedEmptyState,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, Edit, Loader2 } from 'lucide-react';\nimport { useParams } from 'react-router';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { NotFoundState } from '../components';\nimport { notify } from '../utils/toast';\n\n// ─── Backend types ────────────────────────────────────────────────────────────\ntype AssetBudgetStatus = 'ON_TRACK' | 'OVER_BUDGET' | 'UNDER_BUDGET';\n\ninterface AssetBudget {\n id: string;\n name: string;\n category: string;\n allocated: number;\n spent: number;\n remaining: number;\n period: string;\n department: string;\n status: AssetBudgetStatus;\n createdAt: string;\n updatedAt: string;\n}\n\nconst BUDGET_QUERY = gql`\n query AssetHandlerBudget($id: ID!) {\n budget(id: $id) {\n id\n name\n category\n allocated\n spent\n remaining\n period\n department\n status\n createdAt\n updatedAt\n }\n }\n`;\n\nconst UPDATE_BUDGET_MUTATION = gql`\n mutation AssetHandlerUpdateBudget($id: ID!, $input: AssetHandlerUpdateBudgetInput!) {\n updateBudget(id: $id, input: $input) {\n id\n name\n }\n }\n`;\n\ninterface BudgetQueryResult {\n budget: AssetBudget | null;\n}\ninterface UpdateBudgetResult {\n updateBudget: { id: string; name: string };\n}\n\nconst BUDGET_STATUSES: AssetBudgetStatus[] = ['ON_TRACK', 'OVER_BUDGET', 'UNDER_BUDGET'];\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\nconst statusVariant = (status: string): 'default' | 'secondary' | 'destructive' | 'outline' =>\n status === 'OVER_BUDGET' ? 'destructive' : status === 'UNDER_BUDGET' ? 'secondary' : 'default';\n\nexport function FinanceBudgetDetailPage() {\n const { format: money } = useAssetMoney();\n const navigate = useAssetHandlerNavigate();\n const { budgetId } = useParams<{ budgetId: string }>();\n const { transactions } = useAssetHandlerStore();\n\n const { data, loading, refetch } = useQuery<BudgetQueryResult>(BUDGET_QUERY, {\n variables: { id: budgetId ?? '' },\n skip: !budgetId,\n fetchPolicy: 'cache-and-network',\n });\n\n const budget = data?.budget ?? null;\n\n const [editOpen, setEditOpen] = useState(false);\n const [form, setForm] = useState({\n name: '',\n category: '',\n department: '',\n period: '',\n allocated: '',\n spent: '',\n status: 'ON_TRACK' as AssetBudgetStatus,\n });\n\n const openEdit = () => {\n if (!budget) return;\n setForm({\n name: budget.name,\n category: budget.category,\n department: budget.department,\n period: budget.period,\n allocated: String(budget.allocated),\n spent: String(budget.spent),\n status: budget.status,\n });\n setEditOpen(true);\n };\n\n const [updateBudget, { loading: saving }] = useMutation<UpdateBudgetResult>(\n UPDATE_BUDGET_MUTATION,\n {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: () => {\n notify.success('Budget updated', 'Your changes have been saved.');\n setEditOpen(false);\n void refetch();\n },\n onError: (error) => notify.error('Could not update budget', error.message),\n }\n );\n\n const handleSave = () => {\n if (!budgetId) return;\n const parsedAllocated = Number(form.allocated);\n const parsedSpent = Number(form.spent);\n if (\n !form.name.trim() ||\n !form.category.trim() ||\n !form.department.trim() ||\n !form.period.trim()\n ) {\n notify.warning('Missing details', 'Name, category, department and period are required.');\n return;\n }\n if (!Number.isFinite(parsedAllocated) || !Number.isFinite(parsedSpent)) {\n notify.warning('Invalid numbers', 'Allocated and spent must be numeric.');\n return;\n }\n void updateBudget({\n variables: {\n id: budgetId,\n input: {\n name: form.name.trim(),\n category: form.category.trim(),\n department: form.department.trim(),\n period: form.period.trim(),\n allocated: parsedAllocated,\n spent: parsedSpent,\n status: form.status,\n },\n },\n });\n };\n\n if (loading && !budget) {\n return (\n <div className=\"flex min-h-[320px] items-center justify-center p-6\">\n <Loader2 className=\"h-8 w-8 animate-spin text-primary\" />\n </div>\n );\n }\n\n if (!budget) {\n return (\n <NotFoundState\n entityLabel=\"Budget\"\n onBack={() => navigate('/finance/finance-hub')}\n backLabel=\"Back to finance\"\n />\n );\n }\n\n const relatedTxns = transactions.filter((t) => t.category === budget.category);\n const utilizationPct = budget.allocated ? Math.round((budget.spent / budget.allocated) * 100) : 0;\n\n return (\n <div className=\"space-y-6 p-6\">\n <ResponsiveDialog open={editOpen} onOpenChange={setEditOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Edit Budget</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Update the allocation and status for this budget.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Name *</Label>\n <Input\n value={form.name}\n onChange={(e) => setForm((p) => ({ ...p, name: e.target.value }))}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Category *</Label>\n <Input\n value={form.category}\n onChange={(e) => setForm((p) => ({ ...p, category: e.target.value }))}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Department *</Label>\n <Input\n value={form.department}\n onChange={(e) => setForm((p) => ({ ...p, department: e.target.value }))}\n />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Period *</Label>\n <Input\n value={form.period}\n onChange={(e) => setForm((p) => ({ ...p, period: e.target.value }))}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Status</Label>\n <Select\n value={form.status}\n onValueChange={(v) => setForm((p) => ({ ...p, status: v as AssetBudgetStatus }))}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {BUDGET_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Allocated *</Label>\n <Input\n type=\"number\"\n value={form.allocated}\n onChange={(e) => setForm((p) => ({ ...p, allocated: e.target.value }))}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Spent *</Label>\n <Input\n type=\"number\"\n value={form.spent}\n onChange={(e) => setForm((p) => ({ ...p, spent: e.target.value }))}\n />\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setEditOpen(false)} disabled={saving}>\n Cancel\n </Button>\n <Button onClick={handleSave} disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {saving ? 'Saving…' : 'Save Changes'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Go back\"\n onClick={() => navigate('/finance/finance-hub')}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-bold\">\n <GradientText>{budget.name}</GradientText>\n </h1>\n <Badge variant={statusVariant(budget.status)}>{humanize(budget.status)}</Badge>\n </div>\n <p className=\"text-sm text-text-secondary mt-1\">\n {budget.department} · {budget.period}\n </p>\n </div>\n </div>\n <Button size=\"sm\" onClick={openEdit}>\n <Edit className=\"mr-2 h-4 w-4\" />\n Edit Budget\n </Button>\n </div>\n\n <PagePurpose>\n Drill into a single budget to see exactly how it is being consumed: what was allocated, what\n has been spent, what remains, and every transaction charged against it. Use it to catch\n overruns early and decide whether to reallocate, cut spend or top up.\n </PagePurpose>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-sm text-text-secondary\">Allocated</p>\n <p className=\"text-2xl font-bold tabular-nums\">{money(budget.allocated)}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-sm text-text-secondary\">Spent</p>\n <p className=\"text-2xl font-bold tabular-nums\">{money(budget.spent)}</p>\n <p className=\"text-xs text-text-secondary\">{utilizationPct}% utilized</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-sm text-text-secondary\">Remaining</p>\n <p\n className={`text-2xl font-bold ${budget.remaining < 0 ? 'text-status-error-text' : 'text-status-success-text'}`}\n >\n {money(budget.remaining)}\n </p>\n </CardContent>\n </Card>\n </div>\n\n <EmphasisPanel>\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>Budget Utilization</CardTitle>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <div className=\"h-4 rounded-full bg-bg-sunken overflow-hidden\">\n <div\n className={`h-full rounded-full transition-all ${budget.status === 'OVER_BUDGET' ? 'bg-status-error-bg' : 'bg-action-primary-bg'}`}\n style={{ width: `${Math.min(utilizationPct, 100)}%` }}\n />\n </div>\n <p className=\"text-sm text-text-secondary mt-2\">\n {utilizationPct}% of {money(budget.allocated)} allocated budget consumed\n </p>\n </CardContent>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle>Related Transactions</CardTitle>\n <CardDescription>Transactions in {budget.category} category</CardDescription>\n </CardHeader>\n <CardContent className=\"p-0\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-bg-sunken/50\">\n <th className=\"text-left p-3 font-medium\">ID</th>\n <th className=\"text-left p-3 font-medium\">Description</th>\n <th className=\"text-right p-3 font-medium\">Amount</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n <th className=\"text-left p-3 font-medium\">Date</th>\n </tr>\n </thead>\n <tbody>\n {relatedTxns.map((txn) => (\n <tr\n key={txn.id}\n className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\"\n onClick={() => navigate('/transactions/' + txn.id)}\n >\n <td className=\"p-3 font-mono text-xs\">{txn.id}</td>\n <td className=\"p-3 truncate max-w-xs\">{txn.description}</td>\n <td className=\"p-3 text-right font-medium\">{money(Math.abs(txn.amount))}</td>\n <td className=\"p-3\">\n <Badge variant=\"outline\">{txn.status}</Badge>\n </td>\n <td className=\"p-3 text-xs\">{new Date(txn.date).toLocaleDateString()}</td>\n </tr>\n ))}\n </tbody>\n </table>\n {relatedTxns.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No related transactions\"\n description={`No spend has been charged to the ${budget.category} category yet.`}\n />\n )}\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FinanceBudgetDetailPage.js","names":[],"sources":["../../../src/assethandler/pages/FinanceBudgetDetailPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useAssetMoney } from '../providers/AssetHandlerProvider';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n IllustratedEmptyState,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, Edit, Loader2 } from 'lucide-react';\nimport { useParams } from 'react-router';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { NotFoundState } from '../components';\nimport { notify } from '../utils/toast';\n\n// ─── Backend types ────────────────────────────────────────────────────────────\ntype AssetBudgetStatus = 'ON_TRACK' | 'OVER_BUDGET' | 'UNDER_BUDGET';\n\ninterface AssetBudget {\n id: string;\n name: string;\n category: string;\n allocated: number;\n spent: number;\n remaining: number;\n period: string;\n department: string;\n status: AssetBudgetStatus;\n createdAt: string;\n updatedAt: string;\n}\n\nconst BUDGET_QUERY = gql`\n query AssetHandlerBudget($id: ID!) {\n budget(id: $id) {\n id\n name\n category\n allocated\n spent\n remaining\n period\n department\n status\n createdAt\n updatedAt\n }\n }\n`;\n\nconst UPDATE_BUDGET_MUTATION = gql`\n mutation AssetHandlerUpdateBudget($id: ID!, $input: AssetHandlerUpdateBudgetInput!) {\n updateBudget(id: $id, input: $input) {\n id\n name\n }\n }\n`;\n\ninterface BudgetQueryResult {\n budget: AssetBudget | null;\n}\ninterface UpdateBudgetResult {\n updateBudget: { id: string; name: string };\n}\n\nconst BUDGET_STATUSES: AssetBudgetStatus[] = ['ON_TRACK', 'OVER_BUDGET', 'UNDER_BUDGET'];\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\nconst statusVariant = (status: string): 'default' | 'secondary' | 'destructive' | 'outline' =>\n status === 'OVER_BUDGET' ? 'destructive' : status === 'UNDER_BUDGET' ? 'secondary' : 'default';\n\nexport function FinanceBudgetDetailPage() {\n const { format: money } = useAssetMoney();\n const navigate = useAssetHandlerNavigate();\n const { budgetId } = useParams<{ budgetId: string }>();\n const { transactions } = useAssetHandlerStore();\n\n const { data, loading, refetch } = useQuery<BudgetQueryResult>(BUDGET_QUERY, {\n variables: { id: budgetId ?? '' },\n skip: !budgetId,\n fetchPolicy: 'cache-and-network',\n });\n\n const budget = data?.budget ?? null;\n\n const [editOpen, setEditOpen] = useState(false);\n const [form, setForm] = useState({\n name: '',\n category: '',\n department: '',\n period: '',\n allocated: '',\n spent: '',\n status: 'ON_TRACK' as AssetBudgetStatus,\n });\n\n const openEdit = () => {\n if (!budget) return;\n setForm({\n name: budget.name,\n category: budget.category,\n department: budget.department,\n period: budget.period,\n allocated: String(budget.allocated),\n spent: String(budget.spent),\n status: budget.status,\n });\n setEditOpen(true);\n };\n\n const [updateBudget, { loading: saving }] = useMutation<UpdateBudgetResult>(\n UPDATE_BUDGET_MUTATION,\n {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: () => {\n notify.success('Budget updated', 'Your changes have been saved.');\n setEditOpen(false);\n void refetch();\n },\n onError: (error) => notify.error('Could not update budget', error.message),\n }\n );\n\n const handleSave = () => {\n if (!budgetId) return;\n const parsedAllocated = Number(form.allocated);\n const parsedSpent = Number(form.spent);\n if (\n !form.name.trim() ||\n !form.category.trim() ||\n !form.department.trim() ||\n !form.period.trim()\n ) {\n notify.warning('Missing details', 'Name, category, department and period are required.');\n return;\n }\n if (!Number.isFinite(parsedAllocated) || !Number.isFinite(parsedSpent)) {\n notify.warning('Invalid numbers', 'Allocated and spent must be numeric.');\n return;\n }\n void updateBudget({\n variables: {\n id: budgetId,\n input: {\n name: form.name.trim(),\n category: form.category.trim(),\n department: form.department.trim(),\n period: form.period.trim(),\n allocated: parsedAllocated,\n spent: parsedSpent,\n status: form.status,\n },\n },\n });\n };\n\n if (loading && !budget) {\n return (\n <div className=\"flex min-h-[320px] items-center justify-center p-6\">\n <Loader2 className=\"h-8 w-8 animate-spin text-primary\" />\n </div>\n );\n }\n\n if (!budget) {\n return (\n <NotFoundState\n entityLabel=\"Budget\"\n onBack={() => navigate('/finance/finance-hub')}\n backLabel=\"Back to finance\"\n />\n );\n }\n\n const relatedTxns = transactions.filter((t) => t.category === budget.category);\n const utilizationPct = budget.allocated ? Math.round((budget.spent / budget.allocated) * 100) : 0;\n\n return (\n <div className=\"space-y-6 p-6\">\n <ResponsiveDialog open={editOpen} onOpenChange={setEditOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Edit Budget</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Update the allocation and status for this budget.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Name *</Label>\n <Input\n value={form.name}\n onChange={(e) => setForm((p) => ({ ...p, name: e.target.value }))}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Category *</Label>\n <Input\n value={form.category}\n onChange={(e) => setForm((p) => ({ ...p, category: e.target.value }))}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Department *</Label>\n <Input\n value={form.department}\n onChange={(e) => setForm((p) => ({ ...p, department: e.target.value }))}\n />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Period *</Label>\n <Input\n value={form.period}\n onChange={(e) => setForm((p) => ({ ...p, period: e.target.value }))}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Status</Label>\n <Select\n value={form.status}\n onValueChange={(v) => setForm((p) => ({ ...p, status: v as AssetBudgetStatus }))}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {BUDGET_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Allocated *</Label>\n <Input\n type=\"number\"\n value={form.allocated}\n onChange={(e) => setForm((p) => ({ ...p, allocated: e.target.value }))}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Spent *</Label>\n <Input\n type=\"number\"\n value={form.spent}\n onChange={(e) => setForm((p) => ({ ...p, spent: e.target.value }))}\n />\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setEditOpen(false)} disabled={saving}>\n Cancel\n </Button>\n <Button onClick={handleSave} disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {saving ? 'Saving…' : 'Save Changes'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Go back\"\n onClick={() => navigate('/finance/finance-hub')}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-bold\">\n <GradientText>{budget.name}</GradientText>\n </h1>\n <Badge variant={statusVariant(budget.status)}>{humanize(budget.status)}</Badge>\n </div>\n <p className=\"text-sm text-text-secondary mt-1\">\n {budget.department} · {budget.period}\n </p>\n </div>\n </div>\n <Button size=\"sm\" onClick={openEdit}>\n <Edit className=\"mr-2 h-4 w-4\" />\n Edit Budget\n </Button>\n </div>\n\n <PagePurpose>\n Drill into a single budget to see exactly how it is being consumed: what was allocated, what\n has been spent, what remains, and every transaction charged against it. Use it to catch\n overruns early and decide whether to reallocate, cut spend or top up.\n </PagePurpose>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-sm text-text-secondary\">Allocated</p>\n <p className=\"text-2xl font-bold tabular-nums\">{money(budget.allocated)}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-sm text-text-secondary\">Spent</p>\n <p className=\"text-2xl font-bold tabular-nums\">{money(budget.spent)}</p>\n <p className=\"text-xs text-text-secondary\">{utilizationPct}% utilized</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-sm text-text-secondary\">Remaining</p>\n <p\n className={`text-2xl font-bold ${budget.remaining < 0 ? 'text-status-error-text' : 'text-status-success-text'}`}\n >\n {money(budget.remaining)}\n </p>\n </CardContent>\n </Card>\n </div>\n\n <EmphasisPanel>\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>Budget Utilization</CardTitle>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <div className=\"h-4 rounded-full bg-bg-sunken overflow-hidden\">\n <div\n className={`h-full rounded-full transition-all ${budget.status === 'OVER_BUDGET' ? 'bg-status-error-bg' : 'bg-action-primary-bg'}`}\n style={{ width: `${Math.min(utilizationPct, 100)}%` }}\n />\n </div>\n <p className=\"text-sm text-text-secondary mt-2\">\n {utilizationPct}% of {money(budget.allocated)} allocated budget consumed\n </p>\n </CardContent>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle>Related Transactions</CardTitle>\n <CardDescription>Transactions in {budget.category} category</CardDescription>\n </CardHeader>\n <CardContent className=\"p-0\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-bg-sunken/50\">\n <th className=\"text-left p-3 font-medium\">ID</th>\n <th className=\"text-left p-3 font-medium\">Description</th>\n <th className=\"text-right p-3 font-medium\">Amount</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n <th className=\"text-left p-3 font-medium\">Date</th>\n </tr>\n </thead>\n <tbody>\n {relatedTxns.map((txn) => (\n <tr\n key={txn.id}\n className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\"\n onClick={() => navigate('/transactions/' + txn.id)}\n >\n <td className=\"p-3 font-mono text-xs\">{txn.id}</td>\n <td className=\"p-3 truncate max-w-xs\">{txn.description}</td>\n <td className=\"p-3 text-right font-medium\">{money(Math.abs(txn.amount))}</td>\n <td className=\"p-3\">\n <Badge variant=\"outline\">{txn.status}</Badge>\n </td>\n <td className=\"p-3 text-xs\">{new Date(txn.date).toLocaleDateString()}</td>\n </tr>\n ))}\n </tbody>\n </table>\n {relatedTxns.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No related transactions\"\n description={`No spend has been charged to the ${budget.category} category yet.`}\n />\n )}\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|