@optifye/dashboard-core 6.11.37 → 6.11.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +142 -25
  2. package/dist/index.mjs +142 -25
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -78909,6 +78909,12 @@ var buildDeltaBadge = (delta, options) => {
78909
78909
  text: `${options.formatter(delta)} vs ${options.comparisonLabel}`
78910
78910
  };
78911
78911
  };
78912
+ var parseSpecificShiftId = (shiftMode) => {
78913
+ const rawMode = String(shiftMode || "").trim().toLowerCase();
78914
+ if (!rawMode.startsWith("shift:")) return null;
78915
+ const parsed = Number(rawMode.split(":", 2)[1]);
78916
+ return Number.isFinite(parsed) ? parsed : null;
78917
+ };
78912
78918
  var normalizeShiftLabel = (shiftName, shiftMode) => {
78913
78919
  if (shiftMode === "all") {
78914
78920
  return "All Shifts";
@@ -78920,6 +78926,10 @@ var normalizeShiftLabel = (shiftName, shiftMode) => {
78920
78926
  if (normalizedName === "night") return "Night Shift";
78921
78927
  return /shift/i.test(trimmedName) ? trimmedName : `${trimmedName} Shift`;
78922
78928
  }
78929
+ const specificShiftId = parseSpecificShiftId(shiftMode);
78930
+ if (specificShiftId !== null) {
78931
+ return `Shift ${specificShiftId}`;
78932
+ }
78923
78933
  if (shiftMode === "night") return "Night Shift";
78924
78934
  return "Day Shift";
78925
78935
  };
@@ -78992,6 +79002,7 @@ var OperationsOverviewHeader = React143__namespace.default.memo(({
78992
79002
  dateRange,
78993
79003
  displayDateRange,
78994
79004
  trendMode,
79005
+ shiftFilterOptions,
78995
79006
  isLiveScope,
78996
79007
  liveShiftName,
78997
79008
  lineOptions,
@@ -79245,7 +79256,7 @@ var OperationsOverviewHeader = React143__namespace.default.memo(({
79245
79256
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
79246
79257
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
79247
79258
  /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: "Shift" }),
79248
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
79259
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsx(
79249
79260
  "select",
79250
79261
  {
79251
79262
  value: trendMode,
@@ -79257,11 +79268,7 @@ var OperationsOverviewHeader = React143__namespace.default.memo(({
79257
79268
  backgroundRepeat: "no-repeat",
79258
79269
  backgroundSize: "1.2em 1.2em"
79259
79270
  },
79260
- children: [
79261
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "all", children: "All Shifts" }),
79262
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "day", children: "Day Shift" }),
79263
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "night", children: "Night Shift" })
79264
- ]
79271
+ children: shiftFilterOptions.map((option) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: option.value, children: option.label }, option.value))
79265
79272
  }
79266
79273
  ) })
79267
79274
  ] }),
@@ -80331,6 +80338,24 @@ var normalizeShiftId = (value) => {
80331
80338
  }
80332
80339
  return null;
80333
80340
  };
80341
+ var buildSpecificShiftMode = (value) => {
80342
+ const normalizedShiftId = normalizeShiftId(value);
80343
+ return normalizedShiftId === null ? null : `shift:${normalizedShiftId}`;
80344
+ };
80345
+ var parseSpecificShiftMode = (value) => {
80346
+ const rawValue = String(value || "").trim().toLowerCase();
80347
+ if (!rawValue.startsWith("shift:")) return null;
80348
+ const parsed = Number(rawValue.split(":", 2)[1]);
80349
+ return Number.isFinite(parsed) ? parsed : null;
80350
+ };
80351
+ var formatShiftOptionLabel = (shiftName, shiftId) => {
80352
+ const trimmedName = shiftName?.trim();
80353
+ if (trimmedName) {
80354
+ return /shift/i.test(trimmedName) ? trimmedName : `${trimmedName} Shift`;
80355
+ }
80356
+ const normalizedShiftId = normalizeShiftId(shiftId);
80357
+ return normalizedShiftId === null ? "Unknown Shift" : `Shift ${normalizedShiftId}`;
80358
+ };
80334
80359
  var classifyShiftBucket = ({
80335
80360
  shiftName,
80336
80361
  shiftId,
@@ -80417,6 +80442,26 @@ var normalizeShiftWindowMinutes = (startTime, endTime) => {
80417
80442
  }
80418
80443
  return { startMinutes, endMinutes };
80419
80444
  };
80445
+ var getOperationalSortStartMinutes = (startTime, endTime) => {
80446
+ const normalizedWindow = normalizeShiftWindowMinutes(startTime, endTime);
80447
+ if (!normalizedWindow) return null;
80448
+ return normalizedWindow.startMinutes < 6 * 60 ? normalizedWindow.startMinutes + 24 * 60 : normalizedWindow.startMinutes;
80449
+ };
80450
+ var doesShiftMatchTrendMode = ({
80451
+ trendMode,
80452
+ shiftName,
80453
+ shiftId,
80454
+ startTime,
80455
+ endTime
80456
+ }) => {
80457
+ if (trendMode === "all") return true;
80458
+ const specificShiftId = parseSpecificShiftMode(trendMode);
80459
+ if (specificShiftId !== null) {
80460
+ return normalizeShiftId(shiftId) === specificShiftId;
80461
+ }
80462
+ const bucket = classifyShiftBucket({ shiftName, shiftId, startTime, endTime });
80463
+ return bucket === trendMode;
80464
+ };
80420
80465
  var PlantHeadView = () => {
80421
80466
  const supabase = useSupabase();
80422
80467
  const entityConfig = useEntityConfig();
@@ -80547,6 +80592,45 @@ var PlantHeadView = () => {
80547
80592
  shiftConfigMap,
80548
80593
  isLoading: isShiftConfigLoading
80549
80594
  } = useMultiLineShiftConfigs(scopedLineIds, staticShiftConfig);
80595
+ const shiftFilterOptions = React143__namespace.default.useMemo(() => {
80596
+ const optionsById = /* @__PURE__ */ new Map();
80597
+ scopedLineIds.forEach((lineId) => {
80598
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
80599
+ getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
80600
+ const shiftId = normalizeShiftId(shift.shiftId);
80601
+ if (shiftId === null) return;
80602
+ const sortKey = getOperationalSortStartMinutes(shift.startTime, shift.endTime) ?? 24 * 60 + shiftId;
80603
+ const existing = optionsById.get(shiftId);
80604
+ const label = formatShiftOptionLabel(shift.shiftName, shiftId);
80605
+ if (!existing) {
80606
+ optionsById.set(shiftId, {
80607
+ value: buildSpecificShiftMode(shiftId),
80608
+ label,
80609
+ shiftId,
80610
+ shiftName: shift.shiftName || null,
80611
+ startTime: shift.startTime || null,
80612
+ endTime: shift.endTime || null,
80613
+ sortKey
80614
+ });
80615
+ return;
80616
+ }
80617
+ if ((!existing.shiftName || existing.shiftName === `Shift ${shiftId}`) && shift.shiftName) {
80618
+ existing.shiftName = shift.shiftName;
80619
+ existing.label = label;
80620
+ }
80621
+ if (sortKey < existing.sortKey) {
80622
+ existing.sortKey = sortKey;
80623
+ existing.startTime = shift.startTime || null;
80624
+ existing.endTime = shift.endTime || null;
80625
+ }
80626
+ });
80627
+ });
80628
+ const dynamicOptions = Array.from(optionsById.values()).sort((a, b) => a.sortKey - b.sortKey || (a.shiftId || 0) - (b.shiftId || 0)).map(({ sortKey, ...option }) => option);
80629
+ return [
80630
+ { value: "all", label: "All Shifts" },
80631
+ ...dynamicOptions
80632
+ ];
80633
+ }, [appTimezone, scopedLineIds, shiftConfigMap, staticShiftConfig]);
80550
80634
  React143__namespace.default.useEffect(() => {
80551
80635
  if (scopedLineIds.length === 0 || isShiftConfigLoading) {
80552
80636
  return;
@@ -80609,18 +80693,20 @@ var PlantHeadView = () => {
80609
80693
  if (!activeShift) {
80610
80694
  return [];
80611
80695
  }
80612
- const trendBucket = classifyShiftBucket({
80696
+ const bucketTrendMode = classifyShiftBucket({
80613
80697
  shiftName: activeShift.shiftName,
80614
80698
  shiftId: activeShift.shiftId,
80615
80699
  startTime: activeShift.startTime,
80616
80700
  endTime: activeShift.endTime
80617
80701
  });
80618
- if (!trendBucket || trendBucket === "all") {
80702
+ const exactTrendMode = buildSpecificShiftMode(activeShift.shiftId);
80703
+ if (!bucketTrendMode && !exactTrendMode) {
80619
80704
  return [];
80620
80705
  }
80621
80706
  return [{
80622
80707
  lineId,
80623
- trendMode: trendBucket,
80708
+ exactTrendMode,
80709
+ bucketTrendMode,
80624
80710
  shiftId: activeShift.shiftId,
80625
80711
  shiftName: activeShift.shiftName || null,
80626
80712
  startTime: activeShift.startTime || null,
@@ -80629,14 +80715,12 @@ var PlantHeadView = () => {
80629
80715
  }];
80630
80716
  });
80631
80717
  }, [appTimezone, scopedLineIds, shiftConfigMap, shiftResolutionNow, staticShiftConfig]);
80632
- const hasActiveDayShiftLine = React143__namespace.default.useMemo(
80633
- () => activeLineShiftStates.some((shift) => shift.trendMode === "day" && shift.date === resolvedOperationalToday),
80634
- [activeLineShiftStates, resolvedOperationalToday]
80635
- );
80636
- const hasActiveNightShiftLine = React143__namespace.default.useMemo(
80637
- () => activeLineShiftStates.some((shift) => shift.trendMode === "night" && shift.date === resolvedOperationalToday),
80638
- [activeLineShiftStates, resolvedOperationalToday]
80639
- );
80718
+ const uniformActiveTrendMode = React143__namespace.default.useMemo(() => {
80719
+ const activeModes = Array.from(new Set(
80720
+ activeLineShiftStates.filter((shift) => shift.date === resolvedOperationalToday).map((shift) => shift.exactTrendMode).filter((mode) => !!mode)
80721
+ ));
80722
+ return activeModes.length === 1 ? activeModes[0] : null;
80723
+ }, [activeLineShiftStates, resolvedOperationalToday]);
80640
80724
  const resolvedTrendMode = isInitialScopeReady ? trendMode : "all";
80641
80725
  const hourlyWindowStartTime = React143__namespace.default.useMemo(() => {
80642
80726
  if (scopedLineIds.length === 0) {
@@ -80647,13 +80731,19 @@ var PlantHeadView = () => {
80647
80731
  scopedLineIds.forEach((lineId) => {
80648
80732
  const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
80649
80733
  getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
80650
- const bucket = classifyShiftBucket({
80734
+ classifyShiftBucket({
80651
80735
  shiftName: shift.shiftName,
80652
80736
  shiftId: shift.shiftId,
80653
80737
  startTime: shift.startTime,
80654
80738
  endTime: shift.endTime
80655
80739
  });
80656
- if (resolvedTrendMode !== "all" && bucket !== resolvedTrendMode) {
80740
+ if (!doesShiftMatchTrendMode({
80741
+ trendMode: resolvedTrendMode,
80742
+ shiftName: shift.shiftName,
80743
+ shiftId: shift.shiftId,
80744
+ startTime: shift.startTime,
80745
+ endTime: shift.endTime
80746
+ })) {
80657
80747
  return;
80658
80748
  }
80659
80749
  const normalizedWindow = normalizeShiftWindowMinutes(shift.startTime, shift.endTime);
@@ -80727,11 +80817,11 @@ var PlantHeadView = () => {
80727
80817
  endKey: nextStartKey
80728
80818
  };
80729
80819
  });
80730
- setTrendMode("all");
80820
+ setTrendMode(uniformActiveTrendMode || "all");
80731
80821
  setUsesThisWeekComparison(false);
80732
80822
  hasAutoInitializedScopeRef.current = true;
80733
80823
  setIsInitialScopeReady(true);
80734
- }, [fallbackOperationalDate, isShiftScopeResolved, resolvedOperationalToday, scopedLineIds.length]);
80824
+ }, [fallbackOperationalDate, isShiftScopeResolved, resolvedOperationalToday, scopedLineIds.length, uniformActiveTrendMode]);
80735
80825
  const handleDateRangeChange = React143__namespace.default.useCallback((range, meta) => {
80736
80826
  hasUserAdjustedScopeRef.current = true;
80737
80827
  setIsInitialScopeReady(true);
@@ -80818,6 +80908,33 @@ var PlantHeadView = () => {
80818
80908
  () => resolvedTrendMode,
80819
80909
  [resolvedTrendMode]
80820
80910
  );
80911
+ const hasActiveSelectedShiftLine = React143__namespace.default.useMemo(
80912
+ () => activeLineShiftStates.some((shift) => {
80913
+ if (shift.date !== resolvedOperationalToday) return false;
80914
+ if (effectiveTrendMode === "all") return true;
80915
+ const specificShiftId = parseSpecificShiftMode(effectiveTrendMode);
80916
+ if (specificShiftId !== null) {
80917
+ return shift.exactTrendMode === effectiveTrendMode;
80918
+ }
80919
+ return shift.bucketTrendMode === effectiveTrendMode;
80920
+ }),
80921
+ [activeLineShiftStates, effectiveTrendMode, resolvedOperationalToday]
80922
+ );
80923
+ const activeLiveShiftName = React143__namespace.default.useMemo(
80924
+ () => {
80925
+ if (effectiveTrendMode === "all") return null;
80926
+ const matchingShift = activeLineShiftStates.find((shift) => {
80927
+ if (shift.date !== resolvedOperationalToday) return false;
80928
+ const specificShiftId = parseSpecificShiftMode(effectiveTrendMode);
80929
+ if (specificShiftId !== null) {
80930
+ return shift.exactTrendMode === effectiveTrendMode;
80931
+ }
80932
+ return shift.bucketTrendMode === effectiveTrendMode;
80933
+ });
80934
+ return matchingShift?.shiftName || null;
80935
+ },
80936
+ [activeLineShiftStates, effectiveTrendMode, resolvedOperationalToday]
80937
+ );
80821
80938
  const hourlyLabelStartTime = React143__namespace.default.useMemo(() => {
80822
80939
  if (scopedLineIds.length === 0) {
80823
80940
  return null;
@@ -80829,12 +80946,11 @@ var PlantHeadView = () => {
80829
80946
  [effectiveDateRange.endKey, effectiveDateRange.startKey]
80830
80947
  );
80831
80948
  const isLiveScope = React143__namespace.default.useMemo(
80832
- () => isSingleDayScope && effectiveDateRange.startKey === resolvedOperationalToday && (effectiveTrendMode === "all" || effectiveTrendMode === "day" && hasActiveDayShiftLine || effectiveTrendMode === "night" && hasActiveNightShiftLine),
80949
+ () => isSingleDayScope && effectiveDateRange.startKey === resolvedOperationalToday && hasActiveSelectedShiftLine,
80833
80950
  [
80834
80951
  effectiveDateRange.startKey,
80835
80952
  effectiveTrendMode,
80836
- hasActiveDayShiftLine,
80837
- hasActiveNightShiftLine,
80953
+ hasActiveSelectedShiftLine,
80838
80954
  isSingleDayScope,
80839
80955
  resolvedOperationalToday
80840
80956
  ]
@@ -80871,8 +80987,9 @@ var PlantHeadView = () => {
80871
80987
  dateRange,
80872
80988
  displayDateRange: headerDateRange,
80873
80989
  trendMode,
80990
+ shiftFilterOptions,
80874
80991
  isLiveScope,
80875
- liveShiftName: isLiveScope && trendMode !== "all" ? trendMode : null,
80992
+ liveShiftName: isLiveScope && trendMode !== "all" ? activeLiveShiftName : null,
80876
80993
  lineOptions,
80877
80994
  supervisorOptions,
80878
80995
  selectedSupervisorId,
package/dist/index.mjs CHANGED
@@ -78880,6 +78880,12 @@ var buildDeltaBadge = (delta, options) => {
78880
78880
  text: `${options.formatter(delta)} vs ${options.comparisonLabel}`
78881
78881
  };
78882
78882
  };
78883
+ var parseSpecificShiftId = (shiftMode) => {
78884
+ const rawMode = String(shiftMode || "").trim().toLowerCase();
78885
+ if (!rawMode.startsWith("shift:")) return null;
78886
+ const parsed = Number(rawMode.split(":", 2)[1]);
78887
+ return Number.isFinite(parsed) ? parsed : null;
78888
+ };
78883
78889
  var normalizeShiftLabel = (shiftName, shiftMode) => {
78884
78890
  if (shiftMode === "all") {
78885
78891
  return "All Shifts";
@@ -78891,6 +78897,10 @@ var normalizeShiftLabel = (shiftName, shiftMode) => {
78891
78897
  if (normalizedName === "night") return "Night Shift";
78892
78898
  return /shift/i.test(trimmedName) ? trimmedName : `${trimmedName} Shift`;
78893
78899
  }
78900
+ const specificShiftId = parseSpecificShiftId(shiftMode);
78901
+ if (specificShiftId !== null) {
78902
+ return `Shift ${specificShiftId}`;
78903
+ }
78894
78904
  if (shiftMode === "night") return "Night Shift";
78895
78905
  return "Day Shift";
78896
78906
  };
@@ -78963,6 +78973,7 @@ var OperationsOverviewHeader = React143__default.memo(({
78963
78973
  dateRange,
78964
78974
  displayDateRange,
78965
78975
  trendMode,
78976
+ shiftFilterOptions,
78966
78977
  isLiveScope,
78967
78978
  liveShiftName,
78968
78979
  lineOptions,
@@ -79216,7 +79227,7 @@ var OperationsOverviewHeader = React143__default.memo(({
79216
79227
  /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
79217
79228
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
79218
79229
  /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: "Shift" }),
79219
- /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
79230
+ /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
79220
79231
  "select",
79221
79232
  {
79222
79233
  value: trendMode,
@@ -79228,11 +79239,7 @@ var OperationsOverviewHeader = React143__default.memo(({
79228
79239
  backgroundRepeat: "no-repeat",
79229
79240
  backgroundSize: "1.2em 1.2em"
79230
79241
  },
79231
- children: [
79232
- /* @__PURE__ */ jsx("option", { value: "all", children: "All Shifts" }),
79233
- /* @__PURE__ */ jsx("option", { value: "day", children: "Day Shift" }),
79234
- /* @__PURE__ */ jsx("option", { value: "night", children: "Night Shift" })
79235
- ]
79242
+ children: shiftFilterOptions.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
79236
79243
  }
79237
79244
  ) })
79238
79245
  ] }),
@@ -80302,6 +80309,24 @@ var normalizeShiftId = (value) => {
80302
80309
  }
80303
80310
  return null;
80304
80311
  };
80312
+ var buildSpecificShiftMode = (value) => {
80313
+ const normalizedShiftId = normalizeShiftId(value);
80314
+ return normalizedShiftId === null ? null : `shift:${normalizedShiftId}`;
80315
+ };
80316
+ var parseSpecificShiftMode = (value) => {
80317
+ const rawValue = String(value || "").trim().toLowerCase();
80318
+ if (!rawValue.startsWith("shift:")) return null;
80319
+ const parsed = Number(rawValue.split(":", 2)[1]);
80320
+ return Number.isFinite(parsed) ? parsed : null;
80321
+ };
80322
+ var formatShiftOptionLabel = (shiftName, shiftId) => {
80323
+ const trimmedName = shiftName?.trim();
80324
+ if (trimmedName) {
80325
+ return /shift/i.test(trimmedName) ? trimmedName : `${trimmedName} Shift`;
80326
+ }
80327
+ const normalizedShiftId = normalizeShiftId(shiftId);
80328
+ return normalizedShiftId === null ? "Unknown Shift" : `Shift ${normalizedShiftId}`;
80329
+ };
80305
80330
  var classifyShiftBucket = ({
80306
80331
  shiftName,
80307
80332
  shiftId,
@@ -80388,6 +80413,26 @@ var normalizeShiftWindowMinutes = (startTime, endTime) => {
80388
80413
  }
80389
80414
  return { startMinutes, endMinutes };
80390
80415
  };
80416
+ var getOperationalSortStartMinutes = (startTime, endTime) => {
80417
+ const normalizedWindow = normalizeShiftWindowMinutes(startTime, endTime);
80418
+ if (!normalizedWindow) return null;
80419
+ return normalizedWindow.startMinutes < 6 * 60 ? normalizedWindow.startMinutes + 24 * 60 : normalizedWindow.startMinutes;
80420
+ };
80421
+ var doesShiftMatchTrendMode = ({
80422
+ trendMode,
80423
+ shiftName,
80424
+ shiftId,
80425
+ startTime,
80426
+ endTime
80427
+ }) => {
80428
+ if (trendMode === "all") return true;
80429
+ const specificShiftId = parseSpecificShiftMode(trendMode);
80430
+ if (specificShiftId !== null) {
80431
+ return normalizeShiftId(shiftId) === specificShiftId;
80432
+ }
80433
+ const bucket = classifyShiftBucket({ shiftName, shiftId, startTime, endTime });
80434
+ return bucket === trendMode;
80435
+ };
80391
80436
  var PlantHeadView = () => {
80392
80437
  const supabase = useSupabase();
80393
80438
  const entityConfig = useEntityConfig();
@@ -80518,6 +80563,45 @@ var PlantHeadView = () => {
80518
80563
  shiftConfigMap,
80519
80564
  isLoading: isShiftConfigLoading
80520
80565
  } = useMultiLineShiftConfigs(scopedLineIds, staticShiftConfig);
80566
+ const shiftFilterOptions = React143__default.useMemo(() => {
80567
+ const optionsById = /* @__PURE__ */ new Map();
80568
+ scopedLineIds.forEach((lineId) => {
80569
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
80570
+ getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
80571
+ const shiftId = normalizeShiftId(shift.shiftId);
80572
+ if (shiftId === null) return;
80573
+ const sortKey = getOperationalSortStartMinutes(shift.startTime, shift.endTime) ?? 24 * 60 + shiftId;
80574
+ const existing = optionsById.get(shiftId);
80575
+ const label = formatShiftOptionLabel(shift.shiftName, shiftId);
80576
+ if (!existing) {
80577
+ optionsById.set(shiftId, {
80578
+ value: buildSpecificShiftMode(shiftId),
80579
+ label,
80580
+ shiftId,
80581
+ shiftName: shift.shiftName || null,
80582
+ startTime: shift.startTime || null,
80583
+ endTime: shift.endTime || null,
80584
+ sortKey
80585
+ });
80586
+ return;
80587
+ }
80588
+ if ((!existing.shiftName || existing.shiftName === `Shift ${shiftId}`) && shift.shiftName) {
80589
+ existing.shiftName = shift.shiftName;
80590
+ existing.label = label;
80591
+ }
80592
+ if (sortKey < existing.sortKey) {
80593
+ existing.sortKey = sortKey;
80594
+ existing.startTime = shift.startTime || null;
80595
+ existing.endTime = shift.endTime || null;
80596
+ }
80597
+ });
80598
+ });
80599
+ const dynamicOptions = Array.from(optionsById.values()).sort((a, b) => a.sortKey - b.sortKey || (a.shiftId || 0) - (b.shiftId || 0)).map(({ sortKey, ...option }) => option);
80600
+ return [
80601
+ { value: "all", label: "All Shifts" },
80602
+ ...dynamicOptions
80603
+ ];
80604
+ }, [appTimezone, scopedLineIds, shiftConfigMap, staticShiftConfig]);
80521
80605
  React143__default.useEffect(() => {
80522
80606
  if (scopedLineIds.length === 0 || isShiftConfigLoading) {
80523
80607
  return;
@@ -80580,18 +80664,20 @@ var PlantHeadView = () => {
80580
80664
  if (!activeShift) {
80581
80665
  return [];
80582
80666
  }
80583
- const trendBucket = classifyShiftBucket({
80667
+ const bucketTrendMode = classifyShiftBucket({
80584
80668
  shiftName: activeShift.shiftName,
80585
80669
  shiftId: activeShift.shiftId,
80586
80670
  startTime: activeShift.startTime,
80587
80671
  endTime: activeShift.endTime
80588
80672
  });
80589
- if (!trendBucket || trendBucket === "all") {
80673
+ const exactTrendMode = buildSpecificShiftMode(activeShift.shiftId);
80674
+ if (!bucketTrendMode && !exactTrendMode) {
80590
80675
  return [];
80591
80676
  }
80592
80677
  return [{
80593
80678
  lineId,
80594
- trendMode: trendBucket,
80679
+ exactTrendMode,
80680
+ bucketTrendMode,
80595
80681
  shiftId: activeShift.shiftId,
80596
80682
  shiftName: activeShift.shiftName || null,
80597
80683
  startTime: activeShift.startTime || null,
@@ -80600,14 +80686,12 @@ var PlantHeadView = () => {
80600
80686
  }];
80601
80687
  });
80602
80688
  }, [appTimezone, scopedLineIds, shiftConfigMap, shiftResolutionNow, staticShiftConfig]);
80603
- const hasActiveDayShiftLine = React143__default.useMemo(
80604
- () => activeLineShiftStates.some((shift) => shift.trendMode === "day" && shift.date === resolvedOperationalToday),
80605
- [activeLineShiftStates, resolvedOperationalToday]
80606
- );
80607
- const hasActiveNightShiftLine = React143__default.useMemo(
80608
- () => activeLineShiftStates.some((shift) => shift.trendMode === "night" && shift.date === resolvedOperationalToday),
80609
- [activeLineShiftStates, resolvedOperationalToday]
80610
- );
80689
+ const uniformActiveTrendMode = React143__default.useMemo(() => {
80690
+ const activeModes = Array.from(new Set(
80691
+ activeLineShiftStates.filter((shift) => shift.date === resolvedOperationalToday).map((shift) => shift.exactTrendMode).filter((mode) => !!mode)
80692
+ ));
80693
+ return activeModes.length === 1 ? activeModes[0] : null;
80694
+ }, [activeLineShiftStates, resolvedOperationalToday]);
80611
80695
  const resolvedTrendMode = isInitialScopeReady ? trendMode : "all";
80612
80696
  const hourlyWindowStartTime = React143__default.useMemo(() => {
80613
80697
  if (scopedLineIds.length === 0) {
@@ -80618,13 +80702,19 @@ var PlantHeadView = () => {
80618
80702
  scopedLineIds.forEach((lineId) => {
80619
80703
  const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
80620
80704
  getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
80621
- const bucket = classifyShiftBucket({
80705
+ classifyShiftBucket({
80622
80706
  shiftName: shift.shiftName,
80623
80707
  shiftId: shift.shiftId,
80624
80708
  startTime: shift.startTime,
80625
80709
  endTime: shift.endTime
80626
80710
  });
80627
- if (resolvedTrendMode !== "all" && bucket !== resolvedTrendMode) {
80711
+ if (!doesShiftMatchTrendMode({
80712
+ trendMode: resolvedTrendMode,
80713
+ shiftName: shift.shiftName,
80714
+ shiftId: shift.shiftId,
80715
+ startTime: shift.startTime,
80716
+ endTime: shift.endTime
80717
+ })) {
80628
80718
  return;
80629
80719
  }
80630
80720
  const normalizedWindow = normalizeShiftWindowMinutes(shift.startTime, shift.endTime);
@@ -80698,11 +80788,11 @@ var PlantHeadView = () => {
80698
80788
  endKey: nextStartKey
80699
80789
  };
80700
80790
  });
80701
- setTrendMode("all");
80791
+ setTrendMode(uniformActiveTrendMode || "all");
80702
80792
  setUsesThisWeekComparison(false);
80703
80793
  hasAutoInitializedScopeRef.current = true;
80704
80794
  setIsInitialScopeReady(true);
80705
- }, [fallbackOperationalDate, isShiftScopeResolved, resolvedOperationalToday, scopedLineIds.length]);
80795
+ }, [fallbackOperationalDate, isShiftScopeResolved, resolvedOperationalToday, scopedLineIds.length, uniformActiveTrendMode]);
80706
80796
  const handleDateRangeChange = React143__default.useCallback((range, meta) => {
80707
80797
  hasUserAdjustedScopeRef.current = true;
80708
80798
  setIsInitialScopeReady(true);
@@ -80789,6 +80879,33 @@ var PlantHeadView = () => {
80789
80879
  () => resolvedTrendMode,
80790
80880
  [resolvedTrendMode]
80791
80881
  );
80882
+ const hasActiveSelectedShiftLine = React143__default.useMemo(
80883
+ () => activeLineShiftStates.some((shift) => {
80884
+ if (shift.date !== resolvedOperationalToday) return false;
80885
+ if (effectiveTrendMode === "all") return true;
80886
+ const specificShiftId = parseSpecificShiftMode(effectiveTrendMode);
80887
+ if (specificShiftId !== null) {
80888
+ return shift.exactTrendMode === effectiveTrendMode;
80889
+ }
80890
+ return shift.bucketTrendMode === effectiveTrendMode;
80891
+ }),
80892
+ [activeLineShiftStates, effectiveTrendMode, resolvedOperationalToday]
80893
+ );
80894
+ const activeLiveShiftName = React143__default.useMemo(
80895
+ () => {
80896
+ if (effectiveTrendMode === "all") return null;
80897
+ const matchingShift = activeLineShiftStates.find((shift) => {
80898
+ if (shift.date !== resolvedOperationalToday) return false;
80899
+ const specificShiftId = parseSpecificShiftMode(effectiveTrendMode);
80900
+ if (specificShiftId !== null) {
80901
+ return shift.exactTrendMode === effectiveTrendMode;
80902
+ }
80903
+ return shift.bucketTrendMode === effectiveTrendMode;
80904
+ });
80905
+ return matchingShift?.shiftName || null;
80906
+ },
80907
+ [activeLineShiftStates, effectiveTrendMode, resolvedOperationalToday]
80908
+ );
80792
80909
  const hourlyLabelStartTime = React143__default.useMemo(() => {
80793
80910
  if (scopedLineIds.length === 0) {
80794
80911
  return null;
@@ -80800,12 +80917,11 @@ var PlantHeadView = () => {
80800
80917
  [effectiveDateRange.endKey, effectiveDateRange.startKey]
80801
80918
  );
80802
80919
  const isLiveScope = React143__default.useMemo(
80803
- () => isSingleDayScope && effectiveDateRange.startKey === resolvedOperationalToday && (effectiveTrendMode === "all" || effectiveTrendMode === "day" && hasActiveDayShiftLine || effectiveTrendMode === "night" && hasActiveNightShiftLine),
80920
+ () => isSingleDayScope && effectiveDateRange.startKey === resolvedOperationalToday && hasActiveSelectedShiftLine,
80804
80921
  [
80805
80922
  effectiveDateRange.startKey,
80806
80923
  effectiveTrendMode,
80807
- hasActiveDayShiftLine,
80808
- hasActiveNightShiftLine,
80924
+ hasActiveSelectedShiftLine,
80809
80925
  isSingleDayScope,
80810
80926
  resolvedOperationalToday
80811
80927
  ]
@@ -80842,8 +80958,9 @@ var PlantHeadView = () => {
80842
80958
  dateRange,
80843
80959
  displayDateRange: headerDateRange,
80844
80960
  trendMode,
80961
+ shiftFilterOptions,
80845
80962
  isLiveScope,
80846
- liveShiftName: isLiveScope && trendMode !== "all" ? trendMode : null,
80963
+ liveShiftName: isLiveScope && trendMode !== "all" ? activeLiveShiftName : null,
80847
80964
  lineOptions,
80848
80965
  supervisorOptions,
80849
80966
  selectedSupervisorId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optifye/dashboard-core",
3
- "version": "6.11.37",
3
+ "version": "6.11.38",
4
4
  "description": "Reusable UI & logic for Optifye dashboard",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",