@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":"MaintenanceMaintenanceCalendarPage.js","names":[],"sources":["../../../src/assethandler/pages/MaintenanceMaintenanceCalendarPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { Button, GlassCard, PagePurpose, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\nimport {\n Calendar,\n Wrench,\n Clock,\n CheckCircle,\n AlertTriangle,\n ChevronLeft,\n ChevronRight,\n} from 'lucide-react';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport { useAssetHandlerStore, type MaintenanceRecord } from '../store/assethandlerStore';\nimport {\n Pagination,\n usePagination,\n SectionHeader,\n StatTile,\n ChartCard,\n DonutChart,\n BarsChart,\n} from '../components';\nimport { cn } from '../utils/cn';\nimport { ScheduleMaintenanceDialog } from '../ops/ScheduleMaintenanceDialog';\n\n/**\n * Real month calendar built from maintenanceRecords (scheduledDate) with a\n * Monday-first grid, adjacent-month day fill, type-coloured event pills, a\n * legend, overdue/completed-this-month KPIs and an insights strip — all derived\n * from real store data (no fabricated series).\n *\n * Reuse note: a wspace-calendar-svc CalendarEvent projection is deferred —\n * createEvent requires a calendarId the MFE cannot resolve in this context — so\n * this renders the product's own maintenance records rather than shared-platform\n * CalendarEvents. See ScheduleMaintenanceDialog for the same note on the create side.\n */\n\n// Event colour is by maintenance TYPE (calm categorical), not priority.\nconst TYPE_COLOR: Record<string, string> = {\n preventive: 'var(--color-chart-1)',\n corrective: 'var(--color-chart-3)',\n inspection: 'var(--color-chart-2)',\n calibration: 'var(--color-chart-4)',\n emergency: 'var(--color-status-error-bg)',\n};\nconst typeColor = (type: string): string =>\n TYPE_COLOR[type.toLowerCase()] ?? 'var(--color-chart-6)';\n\nconst PRIORITY_PILL: Record<string, string> = {\n critical: 'bg-status-error-subtle text-status-error-text',\n high: 'bg-status-warning-subtle text-status-warning-text',\n medium: 'bg-status-info-subtle text-status-info-text',\n low: 'bg-bg-sunken text-text-secondary',\n};\n\nconst STATUS_PILL: Record<string, string> = {\n scheduled: 'bg-status-warning-subtle text-status-warning-text',\n in_progress: 'bg-status-info-subtle text-status-info-text',\n completed: 'bg-status-success-subtle text-status-success-text',\n cancelled: 'bg-bg-sunken text-text-secondary',\n};\n\nconst STATUS_DONUT_COLOR: Record<string, string> = {\n scheduled: 'var(--color-status-warning-bg)',\n in_progress: 'var(--color-status-info-bg)',\n completed: 'var(--color-status-success-bg)',\n cancelled: 'var(--color-status-neutral-bg)',\n};\n\n// Monday-first week.\nconst WEEKDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];\nconst MONTHS = [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December',\n];\n\nconst humanize = (value: string): string =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\n// Local YYYY-MM-DD key so calendar cells (local) line up with scheduled dates.\nconst dateKey = (year: number, month: number, day: number): string =>\n `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;\n\nconst keyFromIso = (iso: string): string | null => {\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return null;\n return dateKey(d.getFullYear(), d.getMonth(), d.getDate());\n};\n\ninterface Cell {\n key: string;\n day: number;\n muted: boolean;\n}\n\nfunction TypeDot({ type }: { type: string }) {\n return (\n <span\n aria-hidden=\"true\"\n className=\"inline-block h-2.5 w-2.5 shrink-0 rounded-full\"\n style={{ backgroundColor: typeColor(type) }}\n />\n );\n}\n\nfunction Pill({ tone, children }: { tone: string; children: React.ReactNode }) {\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize',\n tone\n )}\n >\n {children}\n </span>\n );\n}\n\nexport function MaintenanceMaintenanceCalendarPage() {\n const navigate = useAssetHandlerNavigate();\n const { maintenanceRecords } = useAssetHandlerStore();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [expandedDays, setExpandedDays] = useState<Set<string>>(new Set());\n\n const now = new Date();\n const [viewMonth, setViewMonth] = useState<{ year: number; month: number }>({\n year: now.getFullYear(),\n month: now.getMonth(),\n });\n const { year, month } = viewMonth;\n\n const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const todayKey = dateKey(now.getFullYear(), now.getMonth(), now.getDate());\n\n const isOverdue = (m: MaintenanceRecord): boolean => {\n if (!m.scheduledDate) return false;\n const d = new Date(m.scheduledDate);\n if (Number.isNaN(d.getTime())) return false;\n return (\n d.getTime() < todayStart.getTime() && m.status !== 'completed' && m.status !== 'cancelled'\n );\n };\n\n const scheduled = maintenanceRecords.filter((m) => m.status === 'scheduled');\n const overdueRecords = maintenanceRecords.filter(isOverdue);\n const completedThisMonth = maintenanceRecords.filter((m) => {\n if (!m.completedDate) return false;\n const d = new Date(m.completedDate);\n return !Number.isNaN(d.getTime()) && d.getFullYear() === year && d.getMonth() === month;\n });\n\n // Group records by local date key for O(1) day lookups.\n const recordsByDay = useMemo(() => {\n const map = new Map<string, MaintenanceRecord[]>();\n for (const record of maintenanceRecords) {\n if (!record.scheduledDate) continue;\n const key = keyFromIso(record.scheduledDate);\n if (!key) continue;\n const bucket = map.get(key);\n if (bucket) bucket.push(record);\n else map.set(key, [record]);\n }\n return map;\n }, [maintenanceRecords]);\n\n // Monday-first grid with leading/trailing adjacent-month day fill.\n const cells = useMemo<Cell[]>(() => {\n const firstWeekday = new Date(year, month, 1).getDay(); // 0 = Sun\n const offset = (firstWeekday + 6) % 7; // Monday-first leading blanks\n const daysInMonth = new Date(year, month + 1, 0).getDate();\n const prevMonthDays = new Date(year, month, 0).getDate();\n const out: Cell[] = [];\n const prevMonth = month === 0 ? 11 : month - 1;\n const prevYear = month === 0 ? year - 1 : year;\n for (let i = 0; i < offset; i += 1) {\n const day = prevMonthDays - offset + 1 + i;\n out.push({ key: dateKey(prevYear, prevMonth, day), day, muted: true });\n }\n for (let day = 1; day <= daysInMonth; day += 1) {\n out.push({ key: dateKey(year, month, day), day, muted: false });\n }\n const totalCells = Math.ceil(out.length / 7) * 7;\n const nextMonth = month === 11 ? 0 : month + 1;\n const nextYear = month === 11 ? year + 1 : year;\n for (let day = 1; out.length < totalCells; day += 1) {\n out.push({ key: dateKey(nextYear, nextMonth, day), day, muted: true });\n }\n return out;\n }, [year, month]);\n\n const monthRecords = useMemo(\n () =>\n maintenanceRecords\n .filter((m) => {\n if (!m.scheduledDate) return false;\n const d = new Date(m.scheduledDate);\n return !Number.isNaN(d.getTime()) && d.getFullYear() === year && d.getMonth() === month;\n })\n .sort((a, b) => (a.scheduledDate ?? '').localeCompare(b.scheduledDate ?? '')),\n [maintenanceRecords, year, month]\n );\n\n const monthPlannedCost = monthRecords.reduce((sum, m) => sum + (m.estimatedCost ?? 0), 0);\n\n // Legend: the maintenance types actually present, in a stable order.\n const legendTypes = useMemo(() => {\n const seen = new Set<string>();\n for (const m of maintenanceRecords) seen.add(m.type.toLowerCase());\n return Array.from(seen).sort();\n }, [maintenanceRecords]);\n\n // Insights (real counts only).\n const statusMix = useMemo(() => {\n const counts = new Map<string, number>();\n for (const m of maintenanceRecords) counts.set(m.status, (counts.get(m.status) ?? 0) + 1);\n return Array.from(counts.entries())\n .map(([status, value]) => ({\n name: humanize(status),\n value,\n color: STATUS_DONUT_COLOR[status] ?? 'var(--color-status-neutral-bg)',\n }))\n .sort((a, b) => b.value - a.value);\n }, [maintenanceRecords]);\n\n const typeMix = useMemo(() => {\n const counts = new Map<string, number>();\n for (const m of maintenanceRecords) {\n const key = m.type.toLowerCase();\n counts.set(key, (counts.get(key) ?? 0) + 1);\n }\n return Array.from(counts.entries())\n .map(([type, count]) => ({ type: humanize(type), count }))\n .sort((a, b) => b.count - a.count);\n }, [maintenanceRecords]);\n\n const goPrev = () =>\n setViewMonth(({ year: y, month: m }) =>\n m === 0 ? { year: y - 1, month: 11 } : { year: y, month: m - 1 }\n );\n const goNext = () =>\n setViewMonth(({ year: y, month: m }) =>\n m === 11 ? { year: y + 1, month: 0 } : { year: y, month: m + 1 }\n );\n const goToday = () => setViewMonth({ year: now.getFullYear(), month: now.getMonth() });\n\n const toggleDay = (key: string) =>\n setExpandedDays((prev) => {\n const next = new Set(prev);\n if (next.has(key)) next.delete(key);\n else next.add(key);\n return next;\n });\n\n const listPage = usePagination(maintenanceRecords, { pageSize: 10 });\n const hasData = maintenanceRecords.length > 0;\n\n const eventPill = (r: MaintenanceRecord) => {\n const color = typeColor(r.type);\n return (\n <button\n key={r.id}\n type=\"button\"\n className=\"block w-full\"\n onClick={() => navigate('/operations/maintenance/' + r.id)}\n title={`${r.title} · ${humanize(r.type)}`}\n >\n <span\n className=\"flex items-center gap-1 truncate rounded px-1.5 py-0.5 text-left text-[11px] font-medium text-text-primary\"\n style={{\n backgroundColor: `color-mix(in oklab, ${color} 16%, transparent)`,\n borderLeft: `2px solid ${color}`,\n }}\n >\n <span className=\"truncate\">{r.title}</span>\n </span>\n </button>\n );\n };\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={Calendar}\n title=\"Maintenance Calendar\"\n description={`${maintenanceRecords.length} maintenance activities tracked`}\n actions={\n <Button size=\"sm\" onClick={() => setDialogOpen(true)}>\n <Wrench className=\"mr-2 h-4 w-4\" />\n Schedule Maintenance\n </Button>\n }\n />\n\n <ScheduleMaintenanceDialog open={dialogOpen} onOpenChange={setDialogOpen} />\n\n <PagePurpose>\n See all planned, in-progress and completed maintenance on one calendar so you can spot\n clashes, balance the workload and never miss a due service. Use it to plan the month at a\n glance and keep assets healthy before they fail.\n </PagePurpose>\n\n <div className=\"grid gap-4 sm:grid-cols-3\">\n <StatTile label=\"Scheduled\" value={scheduled.length} icon={Clock} hero />\n <StatTile\n label=\"Overdue\"\n value={overdueRecords.length}\n icon={AlertTriangle}\n delta={overdueRecords.length > 0 ? 'action needed' : undefined}\n deltaTone=\"negative\"\n deltaDirection=\"up\"\n />\n <StatTile\n label=\"Completed this month\"\n value={completedThisMonth.length}\n icon={CheckCircle}\n />\n </div>\n\n {/* Month calendar */}\n <GlassCard treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"p-4 sm:p-5\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2 text-base font-semibold text-text-primary\">\n <Calendar className=\"h-4 w-4 text-text-secondary\" />\n {MONTHS[month]} {year}\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n {monthPlannedCost > 0 && (\n <span className=\"rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs text-text-secondary tabular-nums\">\n Planned spend ${monthPlannedCost.toLocaleString()}\n </span>\n )}\n <span className=\"text-xs text-text-secondary tabular-nums\">\n {monthRecords.length} this month\n </span>\n <Button size=\"sm\" variant=\"outline\" onClick={goToday}>\n Today\n </Button>\n <Button size=\"sm\" variant=\"outline\" onClick={goPrev} aria-label=\"Previous month\">\n <ChevronLeft className=\"h-4 w-4\" />\n </Button>\n <Button size=\"sm\" variant=\"outline\" onClick={goNext} aria-label=\"Next month\">\n <ChevronRight className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n\n {/* Legend */}\n {legendTypes.length > 0 && (\n <div className=\"mt-3 flex flex-wrap items-center gap-x-4 gap-y-1.5\">\n {legendTypes.map((t) => (\n <span key={t} className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <TypeDot type={t} />\n {humanize(t)}\n </span>\n ))}\n </div>\n )}\n\n {/* Desktop month grid */}\n <div className=\"mt-4 hidden md:block\">\n <div className=\"grid grid-cols-7 gap-1 text-center text-sm\">\n {WEEKDAYS.map((d) => (\n <div key={d} className=\"p-2 text-xs font-medium text-text-secondary\">\n {d}\n </div>\n ))}\n {cells.map((cell) => {\n if (cell.muted) {\n return (\n <div\n key={cell.key}\n className=\"min-h-[92px] rounded border border-transparent p-1.5 text-left\"\n >\n <span className=\"text-xs text-text-muted\">{cell.day}</span>\n </div>\n );\n }\n const dayRecords = recordsByDay.get(cell.key) ?? [];\n const isToday = cell.key === todayKey;\n const expanded = expandedDays.has(cell.key);\n const visible = expanded ? dayRecords : dayRecords.slice(0, 3);\n const hidden = dayRecords.length - visible.length;\n return (\n <div\n key={cell.key}\n className={cn(\n 'min-h-[92px] rounded border p-1.5 text-left',\n dayRecords.length > 0\n ? 'border-border-seam bg-bg-sunken/30'\n : 'border-border-seam/40',\n isToday && 'ring-2 ring-action-primary-bg'\n )}\n >\n <span\n className={cn(\n 'inline-flex h-6 min-w-6 items-center justify-center rounded-full px-1.5 text-xs',\n isToday\n ? 'bg-action-primary-bg font-semibold text-action-primary-text'\n : 'text-text-secondary'\n )}\n >\n {cell.day}\n </span>\n <div className=\"mt-1 space-y-1\">\n {visible.map((r) => eventPill(r))}\n {hidden > 0 && (\n <button\n type=\"button\"\n className=\"w-full rounded px-1.5 py-0.5 text-left text-[11px] font-medium text-action-primary-text hover:bg-bg-sunken\"\n onClick={() => toggleDay(cell.key)}\n >\n +{hidden} more\n </button>\n )}\n {expanded && dayRecords.length > 3 && (\n <button\n type=\"button\"\n className=\"w-full rounded px-1.5 py-0.5 text-left text-[11px] text-text-secondary hover:bg-bg-sunken\"\n onClick={() => toggleDay(cell.key)}\n >\n Show less\n </button>\n )}\n </div>\n </div>\n );\n })}\n </div>\n </div>\n\n {/* Mobile agenda fallback */}\n <div className=\"mt-4 md:hidden\">\n {monthRecords.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam/60 p-4 text-center text-sm text-text-secondary\">\n Nothing scheduled in {MONTHS[month]}.\n </p>\n ) : (\n <ul className=\"space-y-2\">\n {monthRecords.map((r) => (\n <li key={r.id}>\n <button\n type=\"button\"\n className=\"flex w-full items-center gap-3 rounded-lg border border-border-seam/60 p-3 text-left hover:bg-bg-sunken/50\"\n onClick={() => navigate('/operations/maintenance/' + r.id)}\n >\n <TypeDot type={r.type} />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{r.title}</p>\n <p className=\"text-xs text-text-secondary\">\n {r.scheduledDate\n ? new Date(r.scheduledDate).toLocaleDateString(undefined, {\n weekday: 'short',\n day: 'numeric',\n })\n : '—'}{' '}\n · {humanize(r.type)}\n </p>\n </div>\n <Pill tone={STATUS_PILL[r.status] ?? 'bg-bg-sunken text-text-secondary'}>\n {r.status.replace(/_/g, ' ')}\n </Pill>\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n </div>\n </GlassCard>\n\n {/* Insights strip */}\n {hasData && (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard\n title=\"Status mix\"\n subtitle=\"Every maintenance activity by status\"\n icon={Wrench}\n >\n <DonutChart\n data={statusMix}\n centerLabel=\"Activities\"\n centerValue={maintenanceRecords.length}\n ariaLabel=\"Maintenance status mix\"\n />\n </ChartCard>\n <ChartCard title=\"Workload by type\" subtitle=\"Maintenance composition\" icon={Wrench}>\n <BarsChart\n data={typeMix}\n xKey=\"type\"\n series={[{ key: 'count', label: 'Activities' }]}\n orientation=\"horizontal\"\n height={Math.max(160, typeMix.length * 44)}\n ariaLabel=\"Maintenance activities by type\"\n />\n </ChartCard>\n </div>\n )}\n\n {/* All activities list */}\n <GlassCard treatment=\"glass\" className=\"overflow-hidden border-border-seam\">\n <div className=\"border-b border-border-seam p-4 sm:p-5\">\n <h3 className=\"text-base font-semibold text-text-primary\">All Maintenance Activities</h3>\n </div>\n {maintenanceRecords.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No maintenance activities\"\n description=\"Schedule maintenance and it will show up on the calendar and in this list.\"\n action={\n <Button size=\"sm\" onClick={() => setDialogOpen(true)}>\n <Wrench className=\"mr-2 h-4 w-4\" />\n Schedule Maintenance\n </Button>\n }\n />\n ) : (\n <>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam bg-bg-sunken/40\">\n <th className=\"p-3 text-left font-medium text-text-secondary\">ID</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Title</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Type</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Priority</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Date</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Status</th>\n </tr>\n </thead>\n <tbody>\n {listPage.pageItems.map((rec) => (\n <tr\n key={rec.id}\n className=\"cursor-pointer border-b border-border-seam/70 hover:bg-bg-sunken/50\"\n onClick={() => navigate('/operations/maintenance/' + rec.id)}\n >\n <td className=\"p-3 font-mono text-xs text-text-secondary\">{rec.id}</td>\n <td className=\"p-3 font-medium text-text-primary\">{rec.title}</td>\n <td className=\"p-3\">\n <span className=\"flex items-center gap-2 text-xs capitalize text-text-secondary\">\n <TypeDot type={rec.type} />\n {rec.type}\n </span>\n </td>\n <td className=\"p-3\">\n <Pill\n tone={PRIORITY_PILL[rec.priority] ?? 'bg-bg-sunken text-text-secondary'}\n >\n {rec.priority}\n </Pill>\n </td>\n <td className=\"p-3 text-xs text-text-secondary\">\n {rec.scheduledDate ? new Date(rec.scheduledDate).toLocaleDateString() : '—'}\n </td>\n <td className=\"p-3\">\n <Pill tone={STATUS_PILL[rec.status] ?? 'bg-bg-sunken text-text-secondary'}>\n {rec.status.replace(/_/g, ' ')}\n </Pill>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n <div className=\"px-3 pb-3\">\n <Pagination\n page={listPage.page}\n pageCount={listPage.pageCount}\n rangeStart={listPage.rangeStart}\n rangeEnd={listPage.rangeEnd}\n totalItems={listPage.totalItems}\n canPrev={listPage.canPrev}\n canNext={listPage.canNext}\n onPrev={listPage.prevPage}\n onNext={listPage.nextPage}\n itemLabel=\"activities\"\n />\n </div>\n </>\n )}\n </GlassCard>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MaintenanceMaintenanceCalendarPage.js","names":[],"sources":["../../../src/assethandler/pages/MaintenanceMaintenanceCalendarPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { Button, GlassCard, PagePurpose, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\nimport {\n Calendar,\n Wrench,\n Clock,\n CheckCircle,\n AlertTriangle,\n ChevronLeft,\n ChevronRight,\n} from 'lucide-react';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport { useAssetHandlerStore, type MaintenanceRecord } from '../store/assethandlerStore';\nimport {\n Pagination,\n usePagination,\n SectionHeader,\n StatTile,\n ChartCard,\n DonutChart,\n BarsChart,\n} from '../components';\nimport { cn } from '../utils/cn';\nimport { ScheduleMaintenanceDialog } from '../ops/ScheduleMaintenanceDialog';\n\n/**\n * Real month calendar built from maintenanceRecords (scheduledDate) with a\n * Monday-first grid, adjacent-month day fill, type-coloured event pills, a\n * legend, overdue/completed-this-month KPIs and an insights strip — all derived\n * from real store data (no fabricated series).\n *\n * Reuse note: a wspace-calendar-svc CalendarEvent projection is deferred —\n * createEvent requires a calendarId the MFE cannot resolve in this context — so\n * this renders the product's own maintenance records rather than shared-platform\n * CalendarEvents. See ScheduleMaintenanceDialog for the same note on the create side.\n */\n\n// Event colour is by maintenance TYPE (calm categorical), not priority.\nconst TYPE_COLOR: Record<string, string> = {\n preventive: 'var(--color-chart-1)',\n corrective: 'var(--color-chart-3)',\n inspection: 'var(--color-chart-2)',\n calibration: 'var(--color-chart-4)',\n emergency: 'var(--color-status-error-bg)',\n};\nconst typeColor = (type: string): string =>\n TYPE_COLOR[type.toLowerCase()] ?? 'var(--color-chart-6)';\n\nconst PRIORITY_PILL: Record<string, string> = {\n critical: 'bg-status-error-subtle text-status-error-text',\n high: 'bg-status-warning-subtle text-status-warning-text',\n medium: 'bg-status-info-subtle text-status-info-text',\n low: 'bg-bg-sunken text-text-secondary',\n};\n\nconst STATUS_PILL: Record<string, string> = {\n scheduled: 'bg-status-warning-subtle text-status-warning-text',\n in_progress: 'bg-status-info-subtle text-status-info-text',\n completed: 'bg-status-success-subtle text-status-success-text',\n cancelled: 'bg-bg-sunken text-text-secondary',\n};\n\nconst STATUS_DONUT_COLOR: Record<string, string> = {\n scheduled: 'var(--color-status-warning-bg)',\n in_progress: 'var(--color-status-info-bg)',\n completed: 'var(--color-status-success-bg)',\n cancelled: 'var(--color-status-neutral-bg)',\n};\n\n// Monday-first week.\nconst WEEKDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];\nconst MONTHS = [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December',\n];\n\nconst humanize = (value: string): string =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\n// Local YYYY-MM-DD key so calendar cells (local) line up with scheduled dates.\nconst dateKey = (year: number, month: number, day: number): string =>\n `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;\n\nconst keyFromIso = (iso: string): string | null => {\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return null;\n return dateKey(d.getFullYear(), d.getMonth(), d.getDate());\n};\n\ninterface Cell {\n key: string;\n day: number;\n muted: boolean;\n}\n\nfunction TypeDot({ type }: { type: string }) {\n return (\n <span\n aria-hidden=\"true\"\n className=\"inline-block h-2.5 w-2.5 shrink-0 rounded-full\"\n style={{ backgroundColor: typeColor(type) }}\n />\n );\n}\n\nfunction Pill({ tone, children }: { tone: string; children: React.ReactNode }) {\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize',\n tone\n )}\n >\n {children}\n </span>\n );\n}\n\nexport function MaintenanceMaintenanceCalendarPage() {\n const navigate = useAssetHandlerNavigate();\n const { maintenanceRecords } = useAssetHandlerStore();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [expandedDays, setExpandedDays] = useState<Set<string>>(new Set());\n\n const now = new Date();\n const [viewMonth, setViewMonth] = useState<{ year: number; month: number }>({\n year: now.getFullYear(),\n month: now.getMonth(),\n });\n const { year, month } = viewMonth;\n\n const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const todayKey = dateKey(now.getFullYear(), now.getMonth(), now.getDate());\n\n const isOverdue = (m: MaintenanceRecord): boolean => {\n if (!m.scheduledDate) return false;\n const d = new Date(m.scheduledDate);\n if (Number.isNaN(d.getTime())) return false;\n return (\n d.getTime() < todayStart.getTime() && m.status !== 'completed' && m.status !== 'cancelled'\n );\n };\n\n const scheduled = maintenanceRecords.filter((m) => m.status === 'scheduled');\n const overdueRecords = maintenanceRecords.filter(isOverdue);\n const completedThisMonth = maintenanceRecords.filter((m) => {\n if (!m.completedDate) return false;\n const d = new Date(m.completedDate);\n return !Number.isNaN(d.getTime()) && d.getFullYear() === year && d.getMonth() === month;\n });\n\n // Group records by local date key for O(1) day lookups.\n const recordsByDay = useMemo(() => {\n const map = new Map<string, MaintenanceRecord[]>();\n for (const record of maintenanceRecords) {\n if (!record.scheduledDate) continue;\n const key = keyFromIso(record.scheduledDate);\n if (!key) continue;\n const bucket = map.get(key);\n if (bucket) bucket.push(record);\n else map.set(key, [record]);\n }\n return map;\n }, [maintenanceRecords]);\n\n // Monday-first grid with leading/trailing adjacent-month day fill.\n const cells = useMemo<Cell[]>(() => {\n const firstWeekday = new Date(year, month, 1).getDay(); // 0 = Sun\n const offset = (firstWeekday + 6) % 7; // Monday-first leading blanks\n const daysInMonth = new Date(year, month + 1, 0).getDate();\n const prevMonthDays = new Date(year, month, 0).getDate();\n const out: Cell[] = [];\n const prevMonth = month === 0 ? 11 : month - 1;\n const prevYear = month === 0 ? year - 1 : year;\n for (let i = 0; i < offset; i += 1) {\n const day = prevMonthDays - offset + 1 + i;\n out.push({ key: dateKey(prevYear, prevMonth, day), day, muted: true });\n }\n for (let day = 1; day <= daysInMonth; day += 1) {\n out.push({ key: dateKey(year, month, day), day, muted: false });\n }\n const totalCells = Math.ceil(out.length / 7) * 7;\n const nextMonth = month === 11 ? 0 : month + 1;\n const nextYear = month === 11 ? year + 1 : year;\n for (let day = 1; out.length < totalCells; day += 1) {\n out.push({ key: dateKey(nextYear, nextMonth, day), day, muted: true });\n }\n return out;\n }, [year, month]);\n\n const monthRecords = useMemo(\n () =>\n maintenanceRecords\n .filter((m) => {\n if (!m.scheduledDate) return false;\n const d = new Date(m.scheduledDate);\n return !Number.isNaN(d.getTime()) && d.getFullYear() === year && d.getMonth() === month;\n })\n .sort((a, b) => (a.scheduledDate ?? '').localeCompare(b.scheduledDate ?? '')),\n [maintenanceRecords, year, month]\n );\n\n const monthPlannedCost = monthRecords.reduce((sum, m) => sum + (m.estimatedCost ?? 0), 0);\n\n // Legend: the maintenance types actually present, in a stable order.\n const legendTypes = useMemo(() => {\n const seen = new Set<string>();\n for (const m of maintenanceRecords) seen.add(m.type.toLowerCase());\n return Array.from(seen).sort();\n }, [maintenanceRecords]);\n\n // Insights (real counts only).\n const statusMix = useMemo(() => {\n const counts = new Map<string, number>();\n for (const m of maintenanceRecords) counts.set(m.status, (counts.get(m.status) ?? 0) + 1);\n return Array.from(counts.entries())\n .map(([status, value]) => ({\n name: humanize(status),\n value,\n color: STATUS_DONUT_COLOR[status] ?? 'var(--color-status-neutral-bg)',\n }))\n .sort((a, b) => b.value - a.value);\n }, [maintenanceRecords]);\n\n const typeMix = useMemo(() => {\n const counts = new Map<string, number>();\n for (const m of maintenanceRecords) {\n const key = m.type.toLowerCase();\n counts.set(key, (counts.get(key) ?? 0) + 1);\n }\n return Array.from(counts.entries())\n .map(([type, count]) => ({ type: humanize(type), count }))\n .sort((a, b) => b.count - a.count);\n }, [maintenanceRecords]);\n\n const goPrev = () =>\n setViewMonth(({ year: y, month: m }) =>\n m === 0 ? { year: y - 1, month: 11 } : { year: y, month: m - 1 }\n );\n const goNext = () =>\n setViewMonth(({ year: y, month: m }) =>\n m === 11 ? { year: y + 1, month: 0 } : { year: y, month: m + 1 }\n );\n const goToday = () => setViewMonth({ year: now.getFullYear(), month: now.getMonth() });\n\n const toggleDay = (key: string) =>\n setExpandedDays((prev) => {\n const next = new Set(prev);\n if (next.has(key)) next.delete(key);\n else next.add(key);\n return next;\n });\n\n const listPage = usePagination(maintenanceRecords, { pageSize: 10 });\n const hasData = maintenanceRecords.length > 0;\n\n const eventPill = (r: MaintenanceRecord) => {\n const color = typeColor(r.type);\n return (\n <button\n key={r.id}\n type=\"button\"\n className=\"block w-full\"\n onClick={() => navigate('/operations/maintenance/' + r.id)}\n title={`${r.title} · ${humanize(r.type)}`}\n >\n <span\n className=\"flex items-center gap-1 truncate rounded px-1.5 py-0.5 text-left text-[11px] font-medium text-text-primary\"\n style={{\n backgroundColor: `color-mix(in oklab, ${color} 16%, transparent)`,\n borderLeft: `2px solid ${color}`,\n }}\n >\n <span className=\"truncate\">{r.title}</span>\n </span>\n </button>\n );\n };\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={Calendar}\n title=\"Maintenance Calendar\"\n description={`${maintenanceRecords.length} maintenance activities tracked`}\n actions={\n <Button size=\"sm\" onClick={() => setDialogOpen(true)}>\n <Wrench className=\"mr-2 h-4 w-4\" />\n Schedule Maintenance\n </Button>\n }\n />\n\n <ScheduleMaintenanceDialog open={dialogOpen} onOpenChange={setDialogOpen} />\n\n <PagePurpose>\n See all planned, in-progress and completed maintenance on one calendar so you can spot\n clashes, balance the workload and never miss a due service. Use it to plan the month at a\n glance and keep assets healthy before they fail.\n </PagePurpose>\n\n <div className=\"grid gap-4 sm:grid-cols-3\">\n <StatTile label=\"Scheduled\" value={scheduled.length} icon={Clock} hero />\n <StatTile\n label=\"Overdue\"\n value={overdueRecords.length}\n icon={AlertTriangle}\n delta={overdueRecords.length > 0 ? 'action needed' : undefined}\n deltaTone=\"negative\"\n deltaDirection=\"up\"\n />\n <StatTile\n label=\"Completed this month\"\n value={completedThisMonth.length}\n icon={CheckCircle}\n />\n </div>\n\n {/* Month calendar */}\n <GlassCard treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"p-4 sm:p-5\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2 text-base font-semibold text-text-primary\">\n <Calendar className=\"h-4 w-4 text-text-secondary\" />\n {MONTHS[month]} {year}\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n {monthPlannedCost > 0 && (\n <span className=\"rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs text-text-secondary tabular-nums\">\n Planned spend ${monthPlannedCost.toLocaleString()}\n </span>\n )}\n <span className=\"text-xs text-text-secondary tabular-nums\">\n {monthRecords.length} this month\n </span>\n <Button size=\"sm\" variant=\"outline\" onClick={goToday}>\n Today\n </Button>\n <Button size=\"sm\" variant=\"outline\" onClick={goPrev} aria-label=\"Previous month\">\n <ChevronLeft className=\"h-4 w-4\" />\n </Button>\n <Button size=\"sm\" variant=\"outline\" onClick={goNext} aria-label=\"Next month\">\n <ChevronRight className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n\n {/* Legend */}\n {legendTypes.length > 0 && (\n <div className=\"mt-3 flex flex-wrap items-center gap-x-4 gap-y-1.5\">\n {legendTypes.map((t) => (\n <span key={t} className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <TypeDot type={t} />\n {humanize(t)}\n </span>\n ))}\n </div>\n )}\n\n {/* Desktop month grid */}\n <div className=\"mt-4 hidden md:block\">\n <div className=\"grid grid-cols-7 gap-1 text-center text-sm\">\n {WEEKDAYS.map((d) => (\n <div key={d} className=\"p-2 text-xs font-medium text-text-secondary\">\n {d}\n </div>\n ))}\n {cells.map((cell) => {\n if (cell.muted) {\n return (\n <div\n key={cell.key}\n className=\"min-h-[92px] rounded border border-transparent p-1.5 text-left\"\n >\n <span className=\"text-xs text-text-muted\">{cell.day}</span>\n </div>\n );\n }\n const dayRecords = recordsByDay.get(cell.key) ?? [];\n const isToday = cell.key === todayKey;\n const expanded = expandedDays.has(cell.key);\n const visible = expanded ? dayRecords : dayRecords.slice(0, 3);\n const hidden = dayRecords.length - visible.length;\n return (\n <div\n key={cell.key}\n className={cn(\n 'min-h-[92px] rounded border p-1.5 text-left',\n dayRecords.length > 0\n ? 'border-border-seam bg-bg-sunken/30'\n : 'border-border-seam/40',\n isToday && 'ring-2 ring-action-primary-bg'\n )}\n >\n <span\n className={cn(\n 'inline-flex h-6 min-w-6 items-center justify-center rounded-full px-1.5 text-xs',\n isToday\n ? 'bg-action-primary-bg font-semibold text-action-primary-text'\n : 'text-text-secondary'\n )}\n >\n {cell.day}\n </span>\n <div className=\"mt-1 space-y-1\">\n {visible.map((r) => eventPill(r))}\n {hidden > 0 && (\n <button\n type=\"button\"\n className=\"w-full rounded px-1.5 py-0.5 text-left text-[11px] font-medium text-action-primary-text hover:bg-bg-sunken\"\n onClick={() => toggleDay(cell.key)}\n >\n +{hidden} more\n </button>\n )}\n {expanded && dayRecords.length > 3 && (\n <button\n type=\"button\"\n className=\"w-full rounded px-1.5 py-0.5 text-left text-[11px] text-text-secondary hover:bg-bg-sunken\"\n onClick={() => toggleDay(cell.key)}\n >\n Show less\n </button>\n )}\n </div>\n </div>\n );\n })}\n </div>\n </div>\n\n {/* Mobile agenda fallback */}\n <div className=\"mt-4 md:hidden\">\n {monthRecords.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam/60 p-4 text-center text-sm text-text-secondary\">\n Nothing scheduled in {MONTHS[month]}.\n </p>\n ) : (\n <ul className=\"space-y-2\">\n {monthRecords.map((r) => (\n <li key={r.id}>\n <button\n type=\"button\"\n className=\"flex w-full items-center gap-3 rounded-lg border border-border-seam/60 p-3 text-left hover:bg-bg-sunken/50\"\n onClick={() => navigate('/operations/maintenance/' + r.id)}\n >\n <TypeDot type={r.type} />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{r.title}</p>\n <p className=\"text-xs text-text-secondary\">\n {r.scheduledDate\n ? new Date(r.scheduledDate).toLocaleDateString(undefined, {\n weekday: 'short',\n day: 'numeric',\n })\n : '—'}{' '}\n · {humanize(r.type)}\n </p>\n </div>\n <Pill tone={STATUS_PILL[r.status] ?? 'bg-bg-sunken text-text-secondary'}>\n {r.status.replace(/_/g, ' ')}\n </Pill>\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n </div>\n </GlassCard>\n\n {/* Insights strip */}\n {hasData && (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard\n title=\"Status mix\"\n subtitle=\"Every maintenance activity by status\"\n icon={Wrench}\n >\n <DonutChart\n data={statusMix}\n centerLabel=\"Activities\"\n centerValue={maintenanceRecords.length}\n ariaLabel=\"Maintenance status mix\"\n />\n </ChartCard>\n <ChartCard title=\"Workload by type\" subtitle=\"Maintenance composition\" icon={Wrench}>\n <BarsChart\n data={typeMix}\n xKey=\"type\"\n series={[{ key: 'count', label: 'Activities' }]}\n orientation=\"horizontal\"\n height={Math.max(160, typeMix.length * 44)}\n ariaLabel=\"Maintenance activities by type\"\n />\n </ChartCard>\n </div>\n )}\n\n {/* All activities list */}\n <GlassCard treatment=\"glass\" className=\"overflow-hidden border-border-seam\">\n <div className=\"border-b border-border-seam p-4 sm:p-5\">\n <h3 className=\"text-base font-semibold text-text-primary\">All Maintenance Activities</h3>\n </div>\n {maintenanceRecords.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No maintenance activities\"\n description=\"Schedule maintenance and it will show up on the calendar and in this list.\"\n action={\n <Button size=\"sm\" onClick={() => setDialogOpen(true)}>\n <Wrench className=\"mr-2 h-4 w-4\" />\n Schedule Maintenance\n </Button>\n }\n />\n ) : (\n <>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam bg-bg-sunken/40\">\n <th className=\"p-3 text-left font-medium text-text-secondary\">ID</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Title</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Type</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Priority</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Date</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Status</th>\n </tr>\n </thead>\n <tbody>\n {listPage.pageItems.map((rec) => (\n <tr\n key={rec.id}\n className=\"cursor-pointer border-b border-border-seam/70 hover:bg-bg-sunken/50\"\n onClick={() => navigate('/operations/maintenance/' + rec.id)}\n >\n <td className=\"p-3 font-mono text-xs text-text-secondary\">{rec.id}</td>\n <td className=\"p-3 font-medium text-text-primary\">{rec.title}</td>\n <td className=\"p-3\">\n <span className=\"flex items-center gap-2 text-xs capitalize text-text-secondary\">\n <TypeDot type={rec.type} />\n {rec.type}\n </span>\n </td>\n <td className=\"p-3\">\n <Pill\n tone={PRIORITY_PILL[rec.priority] ?? 'bg-bg-sunken text-text-secondary'}\n >\n {rec.priority}\n </Pill>\n </td>\n <td className=\"p-3 text-xs text-text-secondary\">\n {rec.scheduledDate ? new Date(rec.scheduledDate).toLocaleDateString() : '—'}\n </td>\n <td className=\"p-3\">\n <Pill tone={STATUS_PILL[rec.status] ?? 'bg-bg-sunken text-text-secondary'}>\n {rec.status.replace(/_/g, ' ')}\n </Pill>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n <div className=\"px-3 pb-3\">\n <Pagination\n page={listPage.page}\n pageCount={listPage.pageCount}\n rangeStart={listPage.rangeStart}\n rangeEnd={listPage.rangeEnd}\n totalItems={listPage.totalItems}\n canPrev={listPage.canPrev}\n canNext={listPage.canNext}\n onPrev={listPage.prevPage}\n onNext={listPage.nextPage}\n itemLabel=\"activities\"\n />\n </div>\n </>\n )}\n </GlassCard>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MaintenanceMaintenancePlansPage.d.ts","sourceRoot":"","sources":["../../../src/assethandler/pages/MaintenanceMaintenancePlansPage.tsx"],"names":[],"mappings":"AAkHA,wBAAgB,+BAA+B,
|
|
1
|
+
{"version":3,"file":"MaintenanceMaintenancePlansPage.d.ts","sourceRoot":"","sources":["../../../src/assethandler/pages/MaintenanceMaintenancePlansPage.tsx"],"names":[],"mappings":"AAkHA,wBAAgB,+BAA+B,gCAwU9C"}
|
|
@@ -100,7 +100,7 @@ function j() {
|
|
|
100
100
|
children: [/* @__PURE__ */ h(f, { className: "mr-2 size-4" }), "New plan"]
|
|
101
101
|
})
|
|
102
102
|
}),
|
|
103
|
-
/* @__PURE__ */ h(x, { children: "Say “service the tractor every 90 days” or “every 250 engine hours” once, and let the schedule do the remembering. When a plan falls due it
|
|
103
|
+
/* @__PURE__ */ h(x, { children: "Say “service the tractor every 90 days” or “every 250 engine hours” once, and let the schedule do the remembering. When a plan falls due, preview it and choose when to raise a maintenance job with its own checklist; completing that job starts the next cycle." }),
|
|
104
104
|
/* @__PURE__ */ g("div", {
|
|
105
105
|
className: "grid gap-4 sm:grid-cols-3",
|
|
106
106
|
children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MaintenanceMaintenancePlansPage.js","names":[],"sources":["../../../src/assethandler/pages/MaintenanceMaintenancePlansPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\n\nimport { formatMeter } from '../utils/meter';\nimport {\n Button,\n GlassCard,\n Input,\n PagePurpose,\n IllustratedEmptyState,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@burdenoff/fe-libs/ui';\nimport {\n AlertTriangle,\n CalendarClock,\n Gauge,\n Loader2,\n Pencil,\n Play,\n Plus,\n Search,\n Trash2,\n} from 'lucide-react';\nimport { SectionHeader, StatTile } from '../components';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { cn } from '../utils/cn';\nimport { notify } from '../utils/toast';\nimport { MaintenancePlanDialog } from '../ops/MaintenancePlanDialog';\nimport {\n useMaintenancePlans,\n type DueMaintenancePlan,\n type MaintenancePlan,\n} from '../hooks/useMaintenancePlans';\n\n/**\n * Recurring preventive-maintenance plans (BOFF-6031).\n *\n * The screen answers the question the product could not previously ask: WHAT\n * NEEDS SERVICING? Before plans existed, every service was logged after the\n * fact and nothing was ever due.\n *\n * ── Null is not zero, anywhere on this page ──────────────────────────────────\n *\n * `currentMeter`, `nextDueMeter`, `daysUntilDue` and `meterUntilDue` are all\n * genuinely nullable, and null means \"does not apply\". A plan that counts only\n * in days has no meter due point; an asset nobody meters has no reading. Both\n * render as an em dash. Showing 0 would claim a machine sitting at zero hours,\n * or a service due today.\n */\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\nconst PRIORITY_PILL: Record<string, string> = {\n CRITICAL: 'bg-status-error-subtle text-status-error-text',\n HIGH: 'bg-status-warning-subtle text-status-warning-text',\n MEDIUM: 'bg-status-info-subtle text-status-info-text',\n LOW: 'bg-bg-sunken text-text-secondary',\n};\n\nfunction Pill({ tone, children }: { tone: string; children: React.ReactNode }) {\n return (\n <span\n className={cn('inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium', tone)}\n >\n {children}\n </span>\n );\n}\n\nconst formatDate = (iso: string | null): string =>\n iso ? new Date(iso).toLocaleDateString(undefined, { dateStyle: 'medium' }) : '—';\n\n/**\n * How a plan's recurrence reads in one line.\n *\n * The meter unit belongs to the ASSET, not the plan, so it is passed in: \"every 250\"\n * is only meaningful once you know whether that is hours, kilometres or cycles\n * (BOFF-6032). Null renders as the previous bare \"units\" wording.\n */\nfunction describeInterval(plan: MaintenancePlan, meterUnit?: string | null): string {\n const parts: string[] = [];\n if (plan.intervalDays != null) parts.push(`every ${plan.intervalDays} days`);\n if (plan.intervalMeter != null) parts.push(`every ${formatMeter(plan.intervalMeter, meterUnit)}`);\n // A plan with neither cannot be created any more, but one could predate the\n // guard — say so plainly rather than rendering an empty cell.\n return parts.length > 0 ? parts.join(' or ') : 'no interval — never comes due';\n}\n\n/** The due state, in the words a farmer would use. */\nfunction describeDue(entry: DueMaintenancePlan): string {\n if (entry.isOverdue) {\n if (entry.daysUntilDue != null && entry.daysUntilDue < 0) {\n const days = Math.abs(entry.daysUntilDue);\n return `${days} day${days === 1 ? '' : 's'} overdue`;\n }\n if (entry.meterUntilDue != null && entry.meterUntilDue <= 0) {\n return `${formatMeter(Math.abs(entry.meterUntilDue), entry.meterUnit)} past due`;\n }\n return 'Overdue';\n }\n if (entry.daysUntilDue != null) {\n if (entry.daysUntilDue === 0) return 'Due today';\n return `Due in ${entry.daysUntilDue} day${entry.daysUntilDue === 1 ? '' : 's'}`;\n }\n return 'Due now';\n}\n\nexport function MaintenanceMaintenancePlansPage() {\n const { assets } = useAssetHandlerStore();\n const [search, setSearch] = useState('');\n const [horizon, setHorizon] = useState('0');\n const [includeInactive, setIncludeInactive] = useState(false);\n const [dialogOpen, setDialogOpen] = useState(false);\n const [editing, setEditing] = useState<MaintenancePlan | null>(null);\n\n const { plans, duePlans, loading, error, updatePlan, deletePlan, generateRecords, busy } =\n useMaintenancePlans({ includeInactive, withinDays: Number(horizon) });\n\n const assetName = useMemo(() => {\n const byId = new Map(assets.map((asset) => [asset.id, asset.name]));\n return (id: string) => byId.get(id) ?? 'Unknown asset';\n }, [assets]);\n\n // Due rows carry the unit on the entry; plan-table rows have to look it up.\n const assetMeterUnit = useMemo(() => {\n const byId = new Map(assets.map((asset) => [asset.id, asset.meterUnit ?? null]));\n return (id: string) => byId.get(id) ?? null;\n }, [assets]);\n\n const filteredPlans = useMemo(() => {\n const needle = search.trim().toLowerCase();\n if (!needle) return plans;\n return plans.filter(\n (plan) =>\n plan.title.toLowerCase().includes(needle) ||\n assetName(plan.assetId).toLowerCase().includes(needle)\n );\n }, [plans, search, assetName]);\n\n const overdueCount = duePlans.filter((entry) => entry.isOverdue).length;\n\n const openCreate = () => {\n setEditing(null);\n setDialogOpen(true);\n };\n const openEdit = (plan: MaintenancePlan) => {\n setEditing(plan);\n setDialogOpen(true);\n };\n\n const handleDelete = (plan: MaintenancePlan) => {\n void deletePlan({ variables: { id: plan.id } });\n };\n\n const handleToggleActive = (plan: MaintenancePlan) => {\n void updatePlan({ variables: { id: plan.id, input: { isActive: !plan.isActive } } });\n };\n\n const handleGenerate = (dryRun: boolean) => {\n void generateRecords({\n variables: { input: { withinDays: Number(horizon), dryRun } },\n }).then((result) => {\n const outcome = result.data?.generateDueMaintenanceRecords;\n if (!outcome) return;\n if (dryRun) {\n notify.info(\n `${outcome.generated} job${outcome.generated === 1 ? '' : 's'} would be raised`,\n outcome.skipped > 0\n ? `${outcome.skipped} plan${outcome.skipped === 1 ? '' : 's'} skipped — their previous job is still open.`\n : 'Nothing is waiting on an open job.'\n );\n return;\n }\n if (outcome.generated === 0 && outcome.skipped === 0) {\n notify.info('Nothing was due', 'No plan has reached its next service point.');\n return;\n }\n notify.success(\n `${outcome.generated} job${outcome.generated === 1 ? '' : 's'} raised`,\n outcome.skipped > 0\n ? `${outcome.skipped} skipped — their previous job is still open.`\n : undefined\n );\n });\n };\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={CalendarClock}\n title=\"Maintenance Plans\"\n description=\"Recurring service schedules for your machinery\"\n actions={\n <Button size=\"sm\" onClick={openCreate}>\n <Plus className=\"mr-2 size-4\" />\n New plan\n </Button>\n }\n />\n\n <PagePurpose>\n Say “service the tractor every 90 days” or “every 250 engine hours”\n once, and let the schedule do the remembering. When a plan falls due it raises a maintenance\n job with its own checklist; completing that job starts the next cycle.\n </PagePurpose>\n\n <div className=\"grid gap-4 sm:grid-cols-3\">\n <StatTile\n label=\"Active plans\"\n value={plans.filter((plan) => plan.isActive).length}\n icon={CalendarClock}\n />\n <StatTile label=\"Due now or soon\" value={duePlans.length} icon={Gauge} />\n <StatTile\n label=\"Overdue\"\n value={overdueCount}\n icon={AlertTriangle}\n {...(overdueCount > 0\n ? { delta: 'needs attention', deltaTone: 'negative' as const }\n : {})}\n />\n </div>\n\n {error && (\n <GlassCard className=\"p-4\">\n <p className=\"text-sm text-status-error-text\">\n Could not load maintenance plans: {error.message}\n </p>\n </GlassCard>\n )}\n\n {/* ── What needs servicing ───────────────────────────────────────── */}\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"What needs servicing\"\n description=\"Plans that have reached their next service point.\"\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <Select value={horizon} onValueChange={setHorizon}>\n <SelectTrigger className=\"w-44\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"0\">Due now</SelectItem>\n <SelectItem value=\"7\">Within a week</SelectItem>\n <SelectItem value=\"14\">Within a fortnight</SelectItem>\n <SelectItem value=\"30\">Within a month</SelectItem>\n </SelectContent>\n </Select>\n <Button variant=\"outline\" onClick={() => handleGenerate(true)} disabled={busy}>\n Preview\n </Button>\n <Button\n onClick={() => handleGenerate(false)}\n disabled={busy || duePlans.length === 0}\n >\n {busy ? (\n <Loader2 className=\"mr-2 size-4 animate-spin\" />\n ) : (\n <Play className=\"mr-2 size-4\" />\n )}\n Raise the work\n </Button>\n </div>\n }\n />\n\n {loading && duePlans.length === 0 ? (\n <p className=\"py-6 text-center text-sm text-text-secondary\">Loading…</p>\n ) : duePlans.length === 0 ? (\n <p className=\"py-6 text-center text-sm text-text-secondary\">\n Nothing is due{horizon === '0' ? ' right now' : ` in the next ${horizon} days`}.\n </p>\n ) : (\n <ul className=\"divide-y divide-border-subtle\">\n {duePlans.map((entry) => (\n <li key={entry.plan.id} className=\"flex flex-wrap items-center gap-3 py-3\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {entry.plan.title}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">\n {assetName(entry.plan.assetId)} ·{' '}\n {describeInterval(entry.plan, entry.meterUnit)}\n </p>\n </div>\n <div className=\"text-right text-xs text-text-secondary\">\n <p\n className={cn(\n 'font-medium',\n entry.isOverdue ? 'text-status-error-text' : 'text-text-primary'\n )}\n >\n {describeDue(entry)}\n </p>\n <p>\n {entry.dueReason === 'METER'\n ? `Meter ${entry.currentMeter ?? '—'} of ${entry.nextDueMeter ?? '—'}`\n : `Due ${formatDate(entry.nextDueAt)}`}\n </p>\n </div>\n </li>\n ))}\n </ul>\n )}\n </GlassCard>\n\n {/* ── All plans ──────────────────────────────────────────────────── */}\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"All plans\"\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"relative\">\n <Search className=\"absolute left-2 top-1/2 size-4 -translate-y-1/2 text-text-tertiary\" />\n <Input\n className=\"w-56 pl-8\"\n placeholder=\"Search plans or assets\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n <Button variant=\"outline\" onClick={() => setIncludeInactive((prev) => !prev)}>\n {includeInactive ? 'Hide paused' : 'Show paused'}\n </Button>\n <Button onClick={openCreate}>\n <Plus className=\"mr-1 size-4\" /> New plan\n </Button>\n </div>\n }\n />\n\n {filteredPlans.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title={plans.length === 0 ? 'No maintenance plans yet' : 'No plans match that search'}\n description={\n plans.length === 0\n ? 'Create a plan to service a machine every so many days or usage units, instead of remembering by hand.'\n : 'Try a different asset or plan name.'\n }\n action={\n plans.length === 0 ? (\n <Button onClick={openCreate}>\n <Plus className=\"mr-1 size-4\" /> New plan\n </Button>\n ) : undefined\n }\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-subtle text-left text-xs text-text-secondary\">\n <th className=\"py-2 pr-4 font-medium\">Plan</th>\n <th className=\"py-2 pr-4 font-medium\">Asset</th>\n <th className=\"py-2 pr-4 font-medium\">Recurs</th>\n <th className=\"py-2 pr-4 font-medium\">Last serviced</th>\n <th className=\"py-2 pr-4 font-medium\">Priority</th>\n <th className=\"py-2 pr-4 font-medium\">Status</th>\n <th className=\"py-2 font-medium text-right\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {filteredPlans.map((plan) => (\n <tr key={plan.id} className=\"border-b border-border-subtle last:border-0\">\n <td className=\"py-3 pr-4\">\n <p className=\"font-medium text-text-primary\">{plan.title}</p>\n <p className=\"text-xs text-text-secondary\">{humanize(plan.type)}</p>\n </td>\n <td className=\"py-3 pr-4 text-text-secondary\">{assetName(plan.assetId)}</td>\n <td className=\"py-3 pr-4 text-text-secondary\">\n {describeInterval(plan, assetMeterUnit(plan.assetId))}\n </td>\n <td className=\"py-3 pr-4 text-text-secondary\">\n {formatDate(plan.lastServiceAt)}\n </td>\n <td className=\"py-3 pr-4\">\n <Pill tone={PRIORITY_PILL[plan.priority] ?? PRIORITY_PILL.LOW!}>\n {humanize(plan.priority)}\n </Pill>\n </td>\n <td className=\"py-3 pr-4\">\n <Pill\n tone={\n plan.isActive\n ? 'bg-status-success-subtle text-status-success-text'\n : 'bg-bg-sunken text-text-secondary'\n }\n >\n {plan.isActive ? 'Active' : 'Paused'}\n </Pill>\n </td>\n <td className=\"py-3 text-right\">\n <div className=\"flex justify-end gap-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => handleToggleActive(plan)}\n disabled={busy}\n >\n {plan.isActive ? 'Pause' : 'Resume'}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => openEdit(plan)}\n aria-label={`Edit ${plan.title}`}\n >\n <Pencil className=\"size-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => handleDelete(plan)}\n disabled={busy}\n aria-label={`Delete ${plan.title}`}\n >\n <Trash2 className=\"size-4\" />\n </Button>\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </GlassCard>\n\n <MaintenancePlanDialog open={dialogOpen} onOpenChange={setDialogOpen} plan={editing} />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MaintenanceMaintenancePlansPage.js","names":[],"sources":["../../../src/assethandler/pages/MaintenanceMaintenancePlansPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\n\nimport { formatMeter } from '../utils/meter';\nimport {\n Button,\n GlassCard,\n Input,\n PagePurpose,\n IllustratedEmptyState,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@burdenoff/fe-libs/ui';\nimport {\n AlertTriangle,\n CalendarClock,\n Gauge,\n Loader2,\n Pencil,\n Play,\n Plus,\n Search,\n Trash2,\n} from 'lucide-react';\nimport { SectionHeader, StatTile } from '../components';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { cn } from '../utils/cn';\nimport { notify } from '../utils/toast';\nimport { MaintenancePlanDialog } from '../ops/MaintenancePlanDialog';\nimport {\n useMaintenancePlans,\n type DueMaintenancePlan,\n type MaintenancePlan,\n} from '../hooks/useMaintenancePlans';\n\n/**\n * Recurring preventive-maintenance plans (BOFF-6031).\n *\n * The screen answers the question the product could not previously ask: WHAT\n * NEEDS SERVICING? Before plans existed, every service was logged after the\n * fact and nothing was ever due.\n *\n * ── Null is not zero, anywhere on this page ──────────────────────────────────\n *\n * `currentMeter`, `nextDueMeter`, `daysUntilDue` and `meterUntilDue` are all\n * genuinely nullable, and null means \"does not apply\". A plan that counts only\n * in days has no meter due point; an asset nobody meters has no reading. Both\n * render as an em dash. Showing 0 would claim a machine sitting at zero hours,\n * or a service due today.\n */\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\nconst PRIORITY_PILL: Record<string, string> = {\n CRITICAL: 'bg-status-error-subtle text-status-error-text',\n HIGH: 'bg-status-warning-subtle text-status-warning-text',\n MEDIUM: 'bg-status-info-subtle text-status-info-text',\n LOW: 'bg-bg-sunken text-text-secondary',\n};\n\nfunction Pill({ tone, children }: { tone: string; children: React.ReactNode }) {\n return (\n <span\n className={cn('inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium', tone)}\n >\n {children}\n </span>\n );\n}\n\nconst formatDate = (iso: string | null): string =>\n iso ? new Date(iso).toLocaleDateString(undefined, { dateStyle: 'medium' }) : '—';\n\n/**\n * How a plan's recurrence reads in one line.\n *\n * The meter unit belongs to the ASSET, not the plan, so it is passed in: \"every 250\"\n * is only meaningful once you know whether that is hours, kilometres or cycles\n * (BOFF-6032). Null renders as the previous bare \"units\" wording.\n */\nfunction describeInterval(plan: MaintenancePlan, meterUnit?: string | null): string {\n const parts: string[] = [];\n if (plan.intervalDays != null) parts.push(`every ${plan.intervalDays} days`);\n if (plan.intervalMeter != null) parts.push(`every ${formatMeter(plan.intervalMeter, meterUnit)}`);\n // A plan with neither cannot be created any more, but one could predate the\n // guard — say so plainly rather than rendering an empty cell.\n return parts.length > 0 ? parts.join(' or ') : 'no interval — never comes due';\n}\n\n/** The due state, in the words a farmer would use. */\nfunction describeDue(entry: DueMaintenancePlan): string {\n if (entry.isOverdue) {\n if (entry.daysUntilDue != null && entry.daysUntilDue < 0) {\n const days = Math.abs(entry.daysUntilDue);\n return `${days} day${days === 1 ? '' : 's'} overdue`;\n }\n if (entry.meterUntilDue != null && entry.meterUntilDue <= 0) {\n return `${formatMeter(Math.abs(entry.meterUntilDue), entry.meterUnit)} past due`;\n }\n return 'Overdue';\n }\n if (entry.daysUntilDue != null) {\n if (entry.daysUntilDue === 0) return 'Due today';\n return `Due in ${entry.daysUntilDue} day${entry.daysUntilDue === 1 ? '' : 's'}`;\n }\n return 'Due now';\n}\n\nexport function MaintenanceMaintenancePlansPage() {\n const { assets } = useAssetHandlerStore();\n const [search, setSearch] = useState('');\n const [horizon, setHorizon] = useState('0');\n const [includeInactive, setIncludeInactive] = useState(false);\n const [dialogOpen, setDialogOpen] = useState(false);\n const [editing, setEditing] = useState<MaintenancePlan | null>(null);\n\n const { plans, duePlans, loading, error, updatePlan, deletePlan, generateRecords, busy } =\n useMaintenancePlans({ includeInactive, withinDays: Number(horizon) });\n\n const assetName = useMemo(() => {\n const byId = new Map(assets.map((asset) => [asset.id, asset.name]));\n return (id: string) => byId.get(id) ?? 'Unknown asset';\n }, [assets]);\n\n // Due rows carry the unit on the entry; plan-table rows have to look it up.\n const assetMeterUnit = useMemo(() => {\n const byId = new Map(assets.map((asset) => [asset.id, asset.meterUnit ?? null]));\n return (id: string) => byId.get(id) ?? null;\n }, [assets]);\n\n const filteredPlans = useMemo(() => {\n const needle = search.trim().toLowerCase();\n if (!needle) return plans;\n return plans.filter(\n (plan) =>\n plan.title.toLowerCase().includes(needle) ||\n assetName(plan.assetId).toLowerCase().includes(needle)\n );\n }, [plans, search, assetName]);\n\n const overdueCount = duePlans.filter((entry) => entry.isOverdue).length;\n\n const openCreate = () => {\n setEditing(null);\n setDialogOpen(true);\n };\n const openEdit = (plan: MaintenancePlan) => {\n setEditing(plan);\n setDialogOpen(true);\n };\n\n const handleDelete = (plan: MaintenancePlan) => {\n void deletePlan({ variables: { id: plan.id } });\n };\n\n const handleToggleActive = (plan: MaintenancePlan) => {\n void updatePlan({ variables: { id: plan.id, input: { isActive: !plan.isActive } } });\n };\n\n const handleGenerate = (dryRun: boolean) => {\n void generateRecords({\n variables: { input: { withinDays: Number(horizon), dryRun } },\n }).then((result) => {\n const outcome = result.data?.generateDueMaintenanceRecords;\n if (!outcome) return;\n if (dryRun) {\n notify.info(\n `${outcome.generated} job${outcome.generated === 1 ? '' : 's'} would be raised`,\n outcome.skipped > 0\n ? `${outcome.skipped} plan${outcome.skipped === 1 ? '' : 's'} skipped — their previous job is still open.`\n : 'Nothing is waiting on an open job.'\n );\n return;\n }\n if (outcome.generated === 0 && outcome.skipped === 0) {\n notify.info('Nothing was due', 'No plan has reached its next service point.');\n return;\n }\n notify.success(\n `${outcome.generated} job${outcome.generated === 1 ? '' : 's'} raised`,\n outcome.skipped > 0\n ? `${outcome.skipped} skipped — their previous job is still open.`\n : undefined\n );\n });\n };\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={CalendarClock}\n title=\"Maintenance Plans\"\n description=\"Recurring service schedules for your machinery\"\n actions={\n <Button size=\"sm\" onClick={openCreate}>\n <Plus className=\"mr-2 size-4\" />\n New plan\n </Button>\n }\n />\n\n <PagePurpose>\n Say “service the tractor every 90 days” or “every 250 engine hours”\n once, and let the schedule do the remembering. When a plan falls due, preview it and choose\n when to raise a maintenance job with its own checklist; completing that job starts the next\n cycle.\n </PagePurpose>\n\n <div className=\"grid gap-4 sm:grid-cols-3\">\n <StatTile\n label=\"Active plans\"\n value={plans.filter((plan) => plan.isActive).length}\n icon={CalendarClock}\n />\n <StatTile label=\"Due now or soon\" value={duePlans.length} icon={Gauge} />\n <StatTile\n label=\"Overdue\"\n value={overdueCount}\n icon={AlertTriangle}\n {...(overdueCount > 0\n ? { delta: 'needs attention', deltaTone: 'negative' as const }\n : {})}\n />\n </div>\n\n {error && (\n <GlassCard className=\"p-4\">\n <p className=\"text-sm text-status-error-text\">\n Could not load maintenance plans: {error.message}\n </p>\n </GlassCard>\n )}\n\n {/* ── What needs servicing ───────────────────────────────────────── */}\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"What needs servicing\"\n description=\"Plans that have reached their next service point.\"\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <Select value={horizon} onValueChange={setHorizon}>\n <SelectTrigger className=\"w-44\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"0\">Due now</SelectItem>\n <SelectItem value=\"7\">Within a week</SelectItem>\n <SelectItem value=\"14\">Within a fortnight</SelectItem>\n <SelectItem value=\"30\">Within a month</SelectItem>\n </SelectContent>\n </Select>\n <Button variant=\"outline\" onClick={() => handleGenerate(true)} disabled={busy}>\n Preview\n </Button>\n <Button\n onClick={() => handleGenerate(false)}\n disabled={busy || duePlans.length === 0}\n >\n {busy ? (\n <Loader2 className=\"mr-2 size-4 animate-spin\" />\n ) : (\n <Play className=\"mr-2 size-4\" />\n )}\n Raise the work\n </Button>\n </div>\n }\n />\n\n {loading && duePlans.length === 0 ? (\n <p className=\"py-6 text-center text-sm text-text-secondary\">Loading…</p>\n ) : duePlans.length === 0 ? (\n <p className=\"py-6 text-center text-sm text-text-secondary\">\n Nothing is due{horizon === '0' ? ' right now' : ` in the next ${horizon} days`}.\n </p>\n ) : (\n <ul className=\"divide-y divide-border-subtle\">\n {duePlans.map((entry) => (\n <li key={entry.plan.id} className=\"flex flex-wrap items-center gap-3 py-3\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {entry.plan.title}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">\n {assetName(entry.plan.assetId)} ·{' '}\n {describeInterval(entry.plan, entry.meterUnit)}\n </p>\n </div>\n <div className=\"text-right text-xs text-text-secondary\">\n <p\n className={cn(\n 'font-medium',\n entry.isOverdue ? 'text-status-error-text' : 'text-text-primary'\n )}\n >\n {describeDue(entry)}\n </p>\n <p>\n {entry.dueReason === 'METER'\n ? `Meter ${entry.currentMeter ?? '—'} of ${entry.nextDueMeter ?? '—'}`\n : `Due ${formatDate(entry.nextDueAt)}`}\n </p>\n </div>\n </li>\n ))}\n </ul>\n )}\n </GlassCard>\n\n {/* ── All plans ──────────────────────────────────────────────────── */}\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"All plans\"\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"relative\">\n <Search className=\"absolute left-2 top-1/2 size-4 -translate-y-1/2 text-text-tertiary\" />\n <Input\n className=\"w-56 pl-8\"\n placeholder=\"Search plans or assets\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n <Button variant=\"outline\" onClick={() => setIncludeInactive((prev) => !prev)}>\n {includeInactive ? 'Hide paused' : 'Show paused'}\n </Button>\n <Button onClick={openCreate}>\n <Plus className=\"mr-1 size-4\" /> New plan\n </Button>\n </div>\n }\n />\n\n {filteredPlans.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title={plans.length === 0 ? 'No maintenance plans yet' : 'No plans match that search'}\n description={\n plans.length === 0\n ? 'Create a plan to service a machine every so many days or usage units, instead of remembering by hand.'\n : 'Try a different asset or plan name.'\n }\n action={\n plans.length === 0 ? (\n <Button onClick={openCreate}>\n <Plus className=\"mr-1 size-4\" /> New plan\n </Button>\n ) : undefined\n }\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-subtle text-left text-xs text-text-secondary\">\n <th className=\"py-2 pr-4 font-medium\">Plan</th>\n <th className=\"py-2 pr-4 font-medium\">Asset</th>\n <th className=\"py-2 pr-4 font-medium\">Recurs</th>\n <th className=\"py-2 pr-4 font-medium\">Last serviced</th>\n <th className=\"py-2 pr-4 font-medium\">Priority</th>\n <th className=\"py-2 pr-4 font-medium\">Status</th>\n <th className=\"py-2 font-medium text-right\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {filteredPlans.map((plan) => (\n <tr key={plan.id} className=\"border-b border-border-subtle last:border-0\">\n <td className=\"py-3 pr-4\">\n <p className=\"font-medium text-text-primary\">{plan.title}</p>\n <p className=\"text-xs text-text-secondary\">{humanize(plan.type)}</p>\n </td>\n <td className=\"py-3 pr-4 text-text-secondary\">{assetName(plan.assetId)}</td>\n <td className=\"py-3 pr-4 text-text-secondary\">\n {describeInterval(plan, assetMeterUnit(plan.assetId))}\n </td>\n <td className=\"py-3 pr-4 text-text-secondary\">\n {formatDate(plan.lastServiceAt)}\n </td>\n <td className=\"py-3 pr-4\">\n <Pill tone={PRIORITY_PILL[plan.priority] ?? PRIORITY_PILL.LOW!}>\n {humanize(plan.priority)}\n </Pill>\n </td>\n <td className=\"py-3 pr-4\">\n <Pill\n tone={\n plan.isActive\n ? 'bg-status-success-subtle text-status-success-text'\n : 'bg-bg-sunken text-text-secondary'\n }\n >\n {plan.isActive ? 'Active' : 'Paused'}\n </Pill>\n </td>\n <td className=\"py-3 text-right\">\n <div className=\"flex justify-end gap-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => handleToggleActive(plan)}\n disabled={busy}\n >\n {plan.isActive ? 'Pause' : 'Resume'}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => openEdit(plan)}\n aria-label={`Edit ${plan.title}`}\n >\n <Pencil className=\"size-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => handleDelete(plan)}\n disabled={busy}\n aria-label={`Delete ${plan.title}`}\n >\n <Trash2 className=\"size-4\" />\n </Button>\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </GlassCard>\n\n <MaintenancePlanDialog open={dialogOpen} onOpenChange={setDialogOpen} plan={editing} />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MaintenanceMaintenanceSchedulerPage.js","names":[],"sources":["../../../src/assethandler/pages/MaintenanceMaintenanceSchedulerPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useAssetMoney } from '../providers/AssetHandlerProvider';\nimport {\n Button,\n Input,\n GlassCard,\n PagePurpose,\n IllustratedEmptyState,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Plus,\n Search,\n CalendarClock,\n AlertTriangle,\n CalendarDays,\n DollarSign,\n Repeat,\n} from 'lucide-react';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport { useAssetHandlerStore, type MaintenanceRecord } from '../store/assethandlerStore';\nimport { SectionHeader, StatTile, ChartCard, DonutChart, BarsChart } from '../components';\nimport { cn } from '../utils/cn';\nimport { ScheduleMaintenanceDialog } from '../ops/ScheduleMaintenanceDialog';\n\nconst PRIORITY_PILL: Record<string, string> = {\n critical: 'bg-status-error-subtle text-status-error-text',\n high: 'bg-status-warning-subtle text-status-warning-text',\n medium: 'bg-status-info-subtle text-status-info-text',\n low: 'bg-bg-sunken text-text-secondary',\n};\n\nconst TYPE_COLOR: Record<string, string> = {\n preventive: 'var(--color-chart-1)',\n corrective: 'var(--color-chart-3)',\n inspection: 'var(--color-chart-2)',\n calibration: 'var(--color-chart-4)',\n emergency: 'var(--color-status-error-bg)',\n};\nconst typeColor = (type: string): string =>\n TYPE_COLOR[type.toLowerCase()] ?? 'var(--color-chart-6)';\n\nconst humanize = (value: string): string =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\nconst PRIORITIES = ['critical', 'high', 'medium', 'low'] as const;\n\nconst dayStartMs = (iso?: string): number | null => {\n if (!iso) return null;\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return null;\n return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\n};\n\nfunction Pill({ tone, children }: { tone: string; children: React.ReactNode }) {\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize',\n tone\n )}\n >\n {children}\n </span>\n );\n}\n\nfunction TypeBadge({ type }: { type: string }) {\n const color = typeColor(type);\n return (\n <span\n className=\"inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium capitalize text-text-primary\"\n style={{ backgroundColor: `color-mix(in oklab, ${color} 16%, transparent)` }}\n >\n <span\n aria-hidden=\"true\"\n className=\"h-2 w-2 rounded-full\"\n style={{ backgroundColor: color }}\n />\n {type}\n </span>\n );\n}\n\nfunction ChecklistProgress({ items }: { items: MaintenanceRecord['checklist'] }) {\n const total = items.length;\n const done = items.filter((c) => c.completed).length;\n if (total === 0) {\n return <span className=\"text-xs text-text-muted\">No checklist</span>;\n }\n const pct = Math.round((done / total) * 100);\n return (\n <div className=\"min-w-[7rem] space-y-1\">\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span className=\"tabular-nums\">\n {done}/{total}\n </span>\n <span className=\"tabular-nums\">{pct}%</span>\n </div>\n <div className=\"h-1.5 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg transition-[width]\"\n style={{ width: `${pct}%` }}\n />\n </div>\n </div>\n );\n}\n\ninterface Group {\n key: string;\n label: string;\n records: MaintenanceRecord[];\n overdue: boolean;\n}\n\nexport function MaintenanceMaintenanceSchedulerPage() {\n const { compact: moneyCompact, format: money } = useAssetMoney();\n const navigate = useAssetHandlerNavigate();\n const { maintenanceRecords, assets, hydrated } = useAssetHandlerStore();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [search, setSearch] = useState('');\n const [typeFilter, setTypeFilter] = useState('all');\n const [priorityFilter, setPriorityFilter] = useState('all');\n\n const assetName = useMemo(() => {\n const byId = new Map(assets.map((a) => [a.id, a.name]));\n return (id: string) => (id ? (byId.get(id) ?? id) : '—');\n }, [assets]);\n\n const todayMs = useMemo(() => {\n const d = new Date();\n return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\n }, []);\n const weekEndMs = todayMs + 7 * 86_400_000;\n\n const scheduled = useMemo(\n () => maintenanceRecords.filter((m) => m.status === 'scheduled'),\n [maintenanceRecords]\n );\n\n const scheduledTypes = useMemo(() => {\n const seen = new Set<string>();\n for (const m of scheduled) seen.add(m.type.toLowerCase());\n return Array.from(seen).sort();\n }, [scheduled]);\n\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n return scheduled.filter((m) => {\n if (typeFilter !== 'all' && m.type.toLowerCase() !== typeFilter) return false;\n if (priorityFilter !== 'all' && m.priority !== priorityFilter) return false;\n if (q) {\n const hay = `${m.title} ${assetName(m.assetId)}`.toLowerCase();\n if (!hay.includes(q)) return false;\n }\n return true;\n });\n }, [scheduled, search, typeFilter, priorityFilter, assetName]);\n\n // Sorted, urgency-grouped horizon.\n const groups = useMemo<Group[]>(() => {\n const overdue: MaintenanceRecord[] = [];\n const thisWeek: MaintenanceRecord[] = [];\n const upcoming: MaintenanceRecord[] = [];\n const unscheduled: MaintenanceRecord[] = [];\n for (const m of filtered) {\n const ms = dayStartMs(m.scheduledDate);\n if (ms === null) unscheduled.push(m);\n else if (ms < todayMs) overdue.push(m);\n else if (ms < weekEndMs) thisWeek.push(m);\n else upcoming.push(m);\n }\n const byDate = (a: MaintenanceRecord, b: MaintenanceRecord) =>\n (dayStartMs(a.scheduledDate) ?? 0) - (dayStartMs(b.scheduledDate) ?? 0);\n overdue.sort(byDate);\n thisWeek.sort(byDate);\n upcoming.sort(byDate);\n return [\n { key: 'overdue', label: 'Overdue', records: overdue, overdue: true },\n { key: 'week', label: 'Due this week', records: thisWeek, overdue: false },\n { key: 'upcoming', label: 'Upcoming', records: upcoming, overdue: false },\n { key: 'unscheduled', label: 'Unscheduled', records: unscheduled, overdue: false },\n ].filter((g) => g.records.length > 0);\n }, [filtered, todayMs, weekEndMs]);\n\n // KPIs (from full scheduled scope, real fields only).\n const dueThisWeek = scheduled.filter((m) => {\n const ms = dayStartMs(m.scheduledDate);\n return ms !== null && ms >= todayMs && ms < weekEndMs;\n }).length;\n const overdueCount = scheduled.filter((m) => {\n const ms = dayStartMs(m.scheduledDate);\n return ms !== null && ms < todayMs;\n }).length;\n const totalEstimated = scheduled.reduce((sum, m) => sum + (m.estimatedCost ?? 0), 0);\n\n // Insights (real).\n const typeMix = useMemo(() => {\n const counts = new Map<string, number>();\n for (const m of scheduled) {\n const key = m.type.toLowerCase();\n counts.set(key, (counts.get(key) ?? 0) + 1);\n }\n return Array.from(counts.entries())\n .map(([type, value]) => ({ name: humanize(type), value, color: typeColor(type) }))\n .sort((a, b) => b.value - a.value);\n }, [scheduled]);\n\n const weekBuckets = useMemo(() => {\n const buckets = Array.from({ length: 6 }, (_, i) => {\n const d = new Date(todayMs + i * 7 * 86_400_000);\n return { week: d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }), jobs: 0 };\n });\n for (const m of scheduled) {\n const ms = dayStartMs(m.scheduledDate);\n if (ms === null || ms < todayMs) continue;\n const wk = Math.floor((ms - todayMs) / (7 * 86_400_000));\n if (wk < 6) buckets[wk].jobs += 1;\n }\n return buckets;\n }, [scheduled, todayMs]);\n\n const hasData = scheduled.length > 0;\n const hasUpcoming = weekBuckets.some((b) => b.jobs > 0);\n\n const renderRow = (rec: MaintenanceRecord, overdue: boolean) => (\n <tr\n key={rec.id}\n className={cn(\n 'cursor-pointer border-b border-border-seam/70',\n overdue\n ? 'border-l-2 border-l-status-warning-text bg-status-warning-subtle/40 hover:bg-status-warning-subtle/60'\n : 'hover:bg-bg-sunken/50'\n )}\n onClick={() => navigate('/operations/maintenance/' + rec.id)}\n >\n <td className=\"p-3\">\n <p className=\"font-medium text-text-primary\">{rec.title}</p>\n <p className=\"font-mono text-xs text-text-secondary\">{rec.id}</p>\n </td>\n <td className=\"p-3 text-sm text-text-secondary\">{assetName(rec.assetId)}</td>\n <td className=\"p-3\">\n <TypeBadge type={rec.type} />\n </td>\n <td className=\"p-3\">\n <Pill tone={PRIORITY_PILL[rec.priority] ?? 'bg-bg-sunken text-text-secondary'}>\n {rec.priority}\n </Pill>\n </td>\n <td className=\"p-3 text-xs text-text-secondary\">\n {rec.scheduledDate ? new Date(rec.scheduledDate).toLocaleDateString() : 'Not scheduled'}\n </td>\n <td className=\"p-3 text-xs tabular-nums text-text-secondary\">{money(rec.estimatedCost)}</td>\n <td className=\"p-3\">\n <ChecklistProgress items={rec.checklist} />\n </td>\n </tr>\n );\n\n const renderCard = (rec: MaintenanceRecord, overdue: boolean) => (\n <button\n key={rec.id}\n type=\"button\"\n className={cn(\n 'w-full space-y-3 rounded-lg border p-4 text-left',\n overdue\n ? 'border-l-2 border-l-status-warning-text border-border-seam bg-status-warning-subtle/30'\n : 'border-border-seam hover:bg-bg-sunken/50'\n )}\n onClick={() => navigate('/operations/maintenance/' + rec.id)}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium text-text-primary\">{rec.title}</p>\n <p className=\"truncate text-sm text-text-secondary\">{assetName(rec.assetId)}</p>\n </div>\n <Pill tone={PRIORITY_PILL[rec.priority] ?? 'bg-bg-sunken text-text-secondary'}>\n {rec.priority}\n </Pill>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <TypeBadge type={rec.type} />\n <span className=\"text-xs text-text-secondary\">\n {rec.scheduledDate ? new Date(rec.scheduledDate).toLocaleDateString() : 'Not scheduled'}\n </span>\n {rec.estimatedCost != null && (\n <span className=\"text-xs tabular-nums text-text-secondary\">\n Est. ${rec.estimatedCost.toLocaleString()}\n </span>\n )}\n </div>\n <ChecklistProgress items={rec.checklist} />\n </button>\n );\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={CalendarClock}\n title=\"Maintenance Scheduler\"\n description=\"Schedule and manage preventive maintenance tasks\"\n actions={\n <div className=\"flex items-center gap-2\">\n {/* Recurring schedules live next door (BOFF-6031). This page shows\n one-off jobs; a plan is what makes them come round again. */}\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigate('/maintenance/maintenance-plans')}\n >\n <Repeat className=\"mr-2 h-4 w-4\" />\n Recurring plans\n </Button>\n <Button size=\"sm\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Schedule New\n </Button>\n </div>\n }\n />\n\n <ScheduleMaintenanceDialog open={dialogOpen} onOpenChange={setDialogOpen} />\n\n <PagePurpose>\n Plan maintenance before things break. Schedule jobs against an asset (each with its own\n checklist and cost estimate), then track the upcoming work here — turning reactive\n firefighting into predictable preventive upkeep.\n </PagePurpose>\n\n {/* KPI band */}\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n <StatTile label=\"Scheduled\" value={scheduled.length} icon={CalendarClock} hero />\n <StatTile label=\"Due this week\" value={dueThisWeek} icon={CalendarDays} />\n <StatTile\n label=\"Overdue\"\n value={overdueCount}\n icon={AlertTriangle}\n delta={overdueCount > 0 ? 'reschedule' : undefined}\n deltaTone=\"negative\"\n deltaDirection=\"up\"\n />\n <StatTile\n label=\"Est. planned cost\"\n value={totalEstimated}\n format={moneyCompact}\n icon={DollarSign}\n />\n </div>\n\n {/* Insights */}\n {hasData && (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard\n title=\"Scheduled by type\"\n subtitle=\"Preventive workload mix\"\n icon={CalendarClock}\n >\n <DonutChart\n data={typeMix}\n centerLabel=\"Scheduled\"\n centerValue={scheduled.length}\n ariaLabel=\"Scheduled maintenance by type\"\n />\n </ChartCard>\n <ChartCard\n title=\"Coming up\"\n subtitle=\"Jobs scheduled over the next 6 weeks\"\n icon={CalendarDays}\n >\n {hasUpcoming ? (\n <BarsChart\n data={weekBuckets}\n xKey=\"week\"\n series={[{ key: 'jobs', label: 'Jobs' }]}\n height={220}\n ariaLabel=\"Scheduled jobs per week\"\n />\n ) : (\n <div className=\"flex h-[220px] items-center justify-center text-sm text-text-secondary\">\n No scheduled jobs in the next six weeks.\n </div>\n )}\n </ChartCard>\n </div>\n )}\n\n {/* Toolbar */}\n {hasData && (\n <div className=\"flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center\">\n <div className=\"relative sm:max-w-xs sm:flex-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search by title or asset…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <Select value={typeFilter} onValueChange={setTypeFilter}>\n <SelectTrigger className=\"w-full sm:w-44\">\n <SelectValue placeholder=\"All types\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All types</SelectItem>\n {scheduledTypes.map((t) => (\n <SelectItem key={t} value={t} className=\"capitalize\">\n {humanize(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select value={priorityFilter} onValueChange={setPriorityFilter}>\n <SelectTrigger className=\"w-full sm:w-44\">\n <SelectValue placeholder=\"All priorities\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All priorities</SelectItem>\n {PRIORITIES.map((p) => (\n <SelectItem key={p} value={p} className=\"capitalize\">\n {humanize(p)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n\n {/* Grouped horizon */}\n {!hydrated && scheduled.length === 0 ? (\n <div className=\"space-y-3\">\n {Array.from({ length: 5 }).map((_, i) => (\n <div key={i} className=\"h-16 rounded-lg bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : scheduled.length === 0 ? (\n <GlassCard treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"p-2\">\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"Nothing scheduled\"\n description=\"Schedule maintenance for a specific asset to see it here.\"\n action={\n <Button size=\"sm\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Schedule New\n </Button>\n }\n />\n </div>\n </GlassCard>\n ) : groups.length === 0 ? (\n <GlassCard treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"p-2\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No matching jobs\"\n description=\"No scheduled jobs match your search or filters — try relaxing them.\"\n />\n </div>\n </GlassCard>\n ) : (\n <div className=\"space-y-6\">\n {groups.map((group) => (\n <div key={group.key} className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n {group.overdue ? (\n <AlertTriangle className=\"h-4 w-4 text-status-warning-text\" />\n ) : null}\n <h3\n className={cn(\n 'text-sm font-semibold',\n group.overdue ? 'text-status-warning-text' : 'text-text-primary'\n )}\n >\n {group.label}\n </h3>\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary tabular-nums\">\n {group.records.length}\n </span>\n </div>\n\n <GlassCard treatment=\"glass\" className=\"overflow-hidden border-border-seam\">\n {/* Desktop table */}\n <div className=\"hidden overflow-x-auto md:block\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam bg-bg-sunken/40\">\n <th className=\"p-3 text-left font-medium text-text-secondary\">Plan</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Asset</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Type</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Priority</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Scheduled</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Est. cost</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Checklist</th>\n </tr>\n </thead>\n <tbody>{group.records.map((rec) => renderRow(rec, group.overdue))}</tbody>\n </table>\n </div>\n {/* Mobile cards */}\n <div className=\"space-y-3 p-3 md:hidden\">\n {group.records.map((rec) => renderCard(rec, group.overdue))}\n </div>\n </GlassCard>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MaintenanceMaintenanceSchedulerPage.js","names":[],"sources":["../../../src/assethandler/pages/MaintenanceMaintenanceSchedulerPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useAssetMoney } from '../providers/AssetHandlerProvider';\nimport {\n Button,\n Input,\n GlassCard,\n PagePurpose,\n IllustratedEmptyState,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Plus,\n Search,\n CalendarClock,\n AlertTriangle,\n CalendarDays,\n DollarSign,\n Repeat,\n} from 'lucide-react';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport { useAssetHandlerStore, type MaintenanceRecord } from '../store/assethandlerStore';\nimport { SectionHeader, StatTile, ChartCard, DonutChart, BarsChart } from '../components';\nimport { cn } from '../utils/cn';\nimport { ScheduleMaintenanceDialog } from '../ops/ScheduleMaintenanceDialog';\n\nconst PRIORITY_PILL: Record<string, string> = {\n critical: 'bg-status-error-subtle text-status-error-text',\n high: 'bg-status-warning-subtle text-status-warning-text',\n medium: 'bg-status-info-subtle text-status-info-text',\n low: 'bg-bg-sunken text-text-secondary',\n};\n\nconst TYPE_COLOR: Record<string, string> = {\n preventive: 'var(--color-chart-1)',\n corrective: 'var(--color-chart-3)',\n inspection: 'var(--color-chart-2)',\n calibration: 'var(--color-chart-4)',\n emergency: 'var(--color-status-error-bg)',\n};\nconst typeColor = (type: string): string =>\n TYPE_COLOR[type.toLowerCase()] ?? 'var(--color-chart-6)';\n\nconst humanize = (value: string): string =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\nconst PRIORITIES = ['critical', 'high', 'medium', 'low'] as const;\n\nconst dayStartMs = (iso?: string): number | null => {\n if (!iso) return null;\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return null;\n return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\n};\n\nfunction Pill({ tone, children }: { tone: string; children: React.ReactNode }) {\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize',\n tone\n )}\n >\n {children}\n </span>\n );\n}\n\nfunction TypeBadge({ type }: { type: string }) {\n const color = typeColor(type);\n return (\n <span\n className=\"inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium capitalize text-text-primary\"\n style={{ backgroundColor: `color-mix(in oklab, ${color} 16%, transparent)` }}\n >\n <span\n aria-hidden=\"true\"\n className=\"h-2 w-2 rounded-full\"\n style={{ backgroundColor: color }}\n />\n {type}\n </span>\n );\n}\n\nfunction ChecklistProgress({ items }: { items: MaintenanceRecord['checklist'] }) {\n const total = items.length;\n const done = items.filter((c) => c.completed).length;\n if (total === 0) {\n return <span className=\"text-xs text-text-muted\">No checklist</span>;\n }\n const pct = Math.round((done / total) * 100);\n return (\n <div className=\"min-w-[7rem] space-y-1\">\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span className=\"tabular-nums\">\n {done}/{total}\n </span>\n <span className=\"tabular-nums\">{pct}%</span>\n </div>\n <div className=\"h-1.5 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg transition-[width]\"\n style={{ width: `${pct}%` }}\n />\n </div>\n </div>\n );\n}\n\ninterface Group {\n key: string;\n label: string;\n records: MaintenanceRecord[];\n overdue: boolean;\n}\n\nexport function MaintenanceMaintenanceSchedulerPage() {\n const { compact: moneyCompact, format: money } = useAssetMoney();\n const navigate = useAssetHandlerNavigate();\n const { maintenanceRecords, assets, hydrated } = useAssetHandlerStore();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [search, setSearch] = useState('');\n const [typeFilter, setTypeFilter] = useState('all');\n const [priorityFilter, setPriorityFilter] = useState('all');\n\n const assetName = useMemo(() => {\n const byId = new Map(assets.map((a) => [a.id, a.name]));\n return (id: string) => (id ? (byId.get(id) ?? id) : '—');\n }, [assets]);\n\n const todayMs = useMemo(() => {\n const d = new Date();\n return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\n }, []);\n const weekEndMs = todayMs + 7 * 86_400_000;\n\n const scheduled = useMemo(\n () => maintenanceRecords.filter((m) => m.status === 'scheduled'),\n [maintenanceRecords]\n );\n\n const scheduledTypes = useMemo(() => {\n const seen = new Set<string>();\n for (const m of scheduled) seen.add(m.type.toLowerCase());\n return Array.from(seen).sort();\n }, [scheduled]);\n\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n return scheduled.filter((m) => {\n if (typeFilter !== 'all' && m.type.toLowerCase() !== typeFilter) return false;\n if (priorityFilter !== 'all' && m.priority !== priorityFilter) return false;\n if (q) {\n const hay = `${m.title} ${assetName(m.assetId)}`.toLowerCase();\n if (!hay.includes(q)) return false;\n }\n return true;\n });\n }, [scheduled, search, typeFilter, priorityFilter, assetName]);\n\n // Sorted, urgency-grouped horizon.\n const groups = useMemo<Group[]>(() => {\n const overdue: MaintenanceRecord[] = [];\n const thisWeek: MaintenanceRecord[] = [];\n const upcoming: MaintenanceRecord[] = [];\n const unscheduled: MaintenanceRecord[] = [];\n for (const m of filtered) {\n const ms = dayStartMs(m.scheduledDate);\n if (ms === null) unscheduled.push(m);\n else if (ms < todayMs) overdue.push(m);\n else if (ms < weekEndMs) thisWeek.push(m);\n else upcoming.push(m);\n }\n const byDate = (a: MaintenanceRecord, b: MaintenanceRecord) =>\n (dayStartMs(a.scheduledDate) ?? 0) - (dayStartMs(b.scheduledDate) ?? 0);\n overdue.sort(byDate);\n thisWeek.sort(byDate);\n upcoming.sort(byDate);\n return [\n { key: 'overdue', label: 'Overdue', records: overdue, overdue: true },\n { key: 'week', label: 'Due this week', records: thisWeek, overdue: false },\n { key: 'upcoming', label: 'Upcoming', records: upcoming, overdue: false },\n { key: 'unscheduled', label: 'Unscheduled', records: unscheduled, overdue: false },\n ].filter((g) => g.records.length > 0);\n }, [filtered, todayMs, weekEndMs]);\n\n // KPIs (from full scheduled scope, real fields only).\n const dueThisWeek = scheduled.filter((m) => {\n const ms = dayStartMs(m.scheduledDate);\n return ms !== null && ms >= todayMs && ms < weekEndMs;\n }).length;\n const overdueCount = scheduled.filter((m) => {\n const ms = dayStartMs(m.scheduledDate);\n return ms !== null && ms < todayMs;\n }).length;\n const totalEstimated = scheduled.reduce((sum, m) => sum + (m.estimatedCost ?? 0), 0);\n\n // Insights (real).\n const typeMix = useMemo(() => {\n const counts = new Map<string, number>();\n for (const m of scheduled) {\n const key = m.type.toLowerCase();\n counts.set(key, (counts.get(key) ?? 0) + 1);\n }\n return Array.from(counts.entries())\n .map(([type, value]) => ({ name: humanize(type), value, color: typeColor(type) }))\n .sort((a, b) => b.value - a.value);\n }, [scheduled]);\n\n const weekBuckets = useMemo(() => {\n const buckets = Array.from({ length: 6 }, (_, i) => {\n const d = new Date(todayMs + i * 7 * 86_400_000);\n return { week: d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }), jobs: 0 };\n });\n for (const m of scheduled) {\n const ms = dayStartMs(m.scheduledDate);\n if (ms === null || ms < todayMs) continue;\n const wk = Math.floor((ms - todayMs) / (7 * 86_400_000));\n if (wk < 6) buckets[wk].jobs += 1;\n }\n return buckets;\n }, [scheduled, todayMs]);\n\n const hasData = scheduled.length > 0;\n const hasUpcoming = weekBuckets.some((b) => b.jobs > 0);\n\n const renderRow = (rec: MaintenanceRecord, overdue: boolean) => (\n <tr\n key={rec.id}\n className={cn(\n 'cursor-pointer border-b border-border-seam/70',\n overdue\n ? 'border-l-2 border-l-status-warning-text bg-status-warning-subtle/40 hover:bg-status-warning-subtle/60'\n : 'hover:bg-bg-sunken/50'\n )}\n onClick={() => navigate('/operations/maintenance/' + rec.id)}\n >\n <td className=\"p-3\">\n <p className=\"font-medium text-text-primary\">{rec.title}</p>\n <p className=\"font-mono text-xs text-text-secondary\">{rec.id}</p>\n </td>\n <td className=\"p-3 text-sm text-text-secondary\">{assetName(rec.assetId)}</td>\n <td className=\"p-3\">\n <TypeBadge type={rec.type} />\n </td>\n <td className=\"p-3\">\n <Pill tone={PRIORITY_PILL[rec.priority] ?? 'bg-bg-sunken text-text-secondary'}>\n {rec.priority}\n </Pill>\n </td>\n <td className=\"p-3 text-xs text-text-secondary\">\n {rec.scheduledDate ? new Date(rec.scheduledDate).toLocaleDateString() : 'Not scheduled'}\n </td>\n <td className=\"p-3 text-xs tabular-nums text-text-secondary\">{money(rec.estimatedCost)}</td>\n <td className=\"p-3\">\n <ChecklistProgress items={rec.checklist} />\n </td>\n </tr>\n );\n\n const renderCard = (rec: MaintenanceRecord, overdue: boolean) => (\n <button\n key={rec.id}\n type=\"button\"\n className={cn(\n 'w-full space-y-3 rounded-lg border p-4 text-left',\n overdue\n ? 'border-l-2 border-l-status-warning-text border-border-seam bg-status-warning-subtle/30'\n : 'border-border-seam hover:bg-bg-sunken/50'\n )}\n onClick={() => navigate('/operations/maintenance/' + rec.id)}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium text-text-primary\">{rec.title}</p>\n <p className=\"truncate text-sm text-text-secondary\">{assetName(rec.assetId)}</p>\n </div>\n <Pill tone={PRIORITY_PILL[rec.priority] ?? 'bg-bg-sunken text-text-secondary'}>\n {rec.priority}\n </Pill>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <TypeBadge type={rec.type} />\n <span className=\"text-xs text-text-secondary\">\n {rec.scheduledDate ? new Date(rec.scheduledDate).toLocaleDateString() : 'Not scheduled'}\n </span>\n {rec.estimatedCost != null && (\n <span className=\"text-xs tabular-nums text-text-secondary\">\n Est. ${rec.estimatedCost.toLocaleString()}\n </span>\n )}\n </div>\n <ChecklistProgress items={rec.checklist} />\n </button>\n );\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={CalendarClock}\n title=\"Maintenance Scheduler\"\n description=\"Schedule and manage preventive maintenance tasks\"\n actions={\n <div className=\"flex items-center gap-2\">\n {/* Recurring schedules live next door (BOFF-6031). This page shows\n one-off jobs; a plan is what makes them come round again. */}\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigate('/maintenance/maintenance-plans')}\n >\n <Repeat className=\"mr-2 h-4 w-4\" />\n Recurring plans\n </Button>\n <Button size=\"sm\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Schedule New\n </Button>\n </div>\n }\n />\n\n <ScheduleMaintenanceDialog open={dialogOpen} onOpenChange={setDialogOpen} />\n\n <PagePurpose>\n Plan maintenance before things break. Schedule jobs against an asset (each with its own\n checklist and cost estimate), then track the upcoming work here — turning reactive\n firefighting into predictable preventive upkeep.\n </PagePurpose>\n\n {/* KPI band */}\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n <StatTile label=\"Scheduled\" value={scheduled.length} icon={CalendarClock} hero />\n <StatTile label=\"Due this week\" value={dueThisWeek} icon={CalendarDays} />\n <StatTile\n label=\"Overdue\"\n value={overdueCount}\n icon={AlertTriangle}\n delta={overdueCount > 0 ? 'reschedule' : undefined}\n deltaTone=\"negative\"\n deltaDirection=\"up\"\n />\n <StatTile\n label=\"Est. planned cost\"\n value={totalEstimated}\n format={moneyCompact}\n icon={DollarSign}\n />\n </div>\n\n {/* Insights */}\n {hasData && (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard\n title=\"Scheduled by type\"\n subtitle=\"Preventive workload mix\"\n icon={CalendarClock}\n >\n <DonutChart\n data={typeMix}\n centerLabel=\"Scheduled\"\n centerValue={scheduled.length}\n ariaLabel=\"Scheduled maintenance by type\"\n />\n </ChartCard>\n <ChartCard\n title=\"Coming up\"\n subtitle=\"Jobs scheduled over the next 6 weeks\"\n icon={CalendarDays}\n >\n {hasUpcoming ? (\n <BarsChart\n data={weekBuckets}\n xKey=\"week\"\n series={[{ key: 'jobs', label: 'Jobs' }]}\n height={220}\n ariaLabel=\"Scheduled jobs per week\"\n />\n ) : (\n <div className=\"flex h-[220px] items-center justify-center text-sm text-text-secondary\">\n No scheduled jobs in the next six weeks.\n </div>\n )}\n </ChartCard>\n </div>\n )}\n\n {/* Toolbar */}\n {hasData && (\n <div className=\"flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center\">\n <div className=\"relative sm:max-w-xs sm:flex-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search by title or asset…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <Select value={typeFilter} onValueChange={setTypeFilter}>\n <SelectTrigger className=\"w-full sm:w-44\">\n <SelectValue placeholder=\"All types\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All types</SelectItem>\n {scheduledTypes.map((t) => (\n <SelectItem key={t} value={t} className=\"capitalize\">\n {humanize(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select value={priorityFilter} onValueChange={setPriorityFilter}>\n <SelectTrigger className=\"w-full sm:w-44\">\n <SelectValue placeholder=\"All priorities\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All priorities</SelectItem>\n {PRIORITIES.map((p) => (\n <SelectItem key={p} value={p} className=\"capitalize\">\n {humanize(p)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n\n {/* Grouped horizon */}\n {!hydrated && scheduled.length === 0 ? (\n <div className=\"space-y-3\">\n {Array.from({ length: 5 }).map((_, i) => (\n <div key={i} className=\"h-16 rounded-lg bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : scheduled.length === 0 ? (\n <GlassCard treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"p-2\">\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"Nothing scheduled\"\n description=\"Schedule maintenance for a specific asset to see it here.\"\n action={\n <Button size=\"sm\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Schedule New\n </Button>\n }\n />\n </div>\n </GlassCard>\n ) : groups.length === 0 ? (\n <GlassCard treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"p-2\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No matching jobs\"\n description=\"No scheduled jobs match your search or filters — try relaxing them.\"\n />\n </div>\n </GlassCard>\n ) : (\n <div className=\"space-y-6\">\n {groups.map((group) => (\n <div key={group.key} className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n {group.overdue ? (\n <AlertTriangle className=\"h-4 w-4 text-status-warning-text\" />\n ) : null}\n <h3\n className={cn(\n 'text-sm font-semibold',\n group.overdue ? 'text-status-warning-text' : 'text-text-primary'\n )}\n >\n {group.label}\n </h3>\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary tabular-nums\">\n {group.records.length}\n </span>\n </div>\n\n <GlassCard treatment=\"glass\" className=\"overflow-hidden border-border-seam\">\n {/* Desktop table */}\n <div className=\"hidden overflow-x-auto md:block\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam bg-bg-sunken/40\">\n <th className=\"p-3 text-left font-medium text-text-secondary\">Plan</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Asset</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Type</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Priority</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Scheduled</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Est. cost</th>\n <th className=\"p-3 text-left font-medium text-text-secondary\">Checklist</th>\n </tr>\n </thead>\n <tbody>{group.records.map((rec) => renderRow(rec, group.overdue))}</tbody>\n </table>\n </div>\n {/* Mobile cards */}\n <div className=\"space-y-3 p-3 md:hidden\">\n {group.records.map((rec) => renderCard(rec, group.overdue))}\n </div>\n </GlassCard>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|