@optifye/dashboard-core 6.11.16 → 6.11.17

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/index.js CHANGED
@@ -3295,11 +3295,9 @@ var normalizeShiftDefinitions = (timezone, shiftConfig) => {
3295
3295
  }
3296
3296
  return { shifts: legacyShifts, timezone: fallbackTimezone };
3297
3297
  };
3298
- var determineShiftFromDefinitions = (timezone, shifts, now4 = /* @__PURE__ */ new Date()) => {
3298
+ var determineActiveShiftFromDefinitions = (timezone, shifts, now4 = /* @__PURE__ */ new Date()) => {
3299
3299
  const zonedNow = dateFnsTz.toZonedTime(now4, timezone);
3300
3300
  const currentMinutes = zonedNow.getHours() * 60 + zonedNow.getMinutes();
3301
- let chosen;
3302
- let operationalDate = getOperationalDate(timezone, now4, shifts[0].startTime);
3303
3301
  for (const shift of shifts) {
3304
3302
  const start = parseTimeToMinutes(shift.startTime);
3305
3303
  const endRaw = parseTimeToMinutes(shift.endTime);
@@ -3307,32 +3305,47 @@ var determineShiftFromDefinitions = (timezone, shifts, now4 = /* @__PURE__ */ ne
3307
3305
  const wraps = end <= start;
3308
3306
  if (wraps) end += 1440;
3309
3307
  if (start <= currentMinutes && currentMinutes < end) {
3310
- chosen = shift;
3311
- operationalDate = getOperationalDate(timezone, now4, shift.startTime);
3312
- break;
3308
+ return {
3309
+ shiftId: shift.shiftId,
3310
+ shiftName: shift.shiftName,
3311
+ startTime: shift.startTime,
3312
+ endTime: shift.endTime,
3313
+ timezone,
3314
+ date: getOperationalDate(timezone, now4, shift.startTime)
3315
+ };
3313
3316
  }
3314
3317
  if (start <= currentMinutes + 1440 && currentMinutes + 1440 < end) {
3315
- chosen = shift;
3316
- operationalDate = getOperationalDate(timezone, now4, shift.startTime);
3317
- break;
3318
+ return {
3319
+ shiftId: shift.shiftId,
3320
+ shiftName: shift.shiftName,
3321
+ startTime: shift.startTime,
3322
+ endTime: shift.endTime,
3323
+ timezone,
3324
+ date: getOperationalDate(timezone, now4, shift.startTime)
3325
+ };
3318
3326
  }
3319
3327
  }
3320
- if (!chosen) {
3321
- chosen = shifts[0];
3322
- operationalDate = getOperationalDate(timezone, now4, chosen.startTime);
3328
+ return null;
3329
+ };
3330
+ var getCurrentShift = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
3331
+ const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
3332
+ const activeShift = determineActiveShiftFromDefinitions(effectiveTz, shifts, now4);
3333
+ if (activeShift) {
3334
+ return activeShift;
3323
3335
  }
3336
+ const fallbackShift = shifts[0];
3324
3337
  return {
3325
- shiftId: chosen.shiftId,
3326
- shiftName: chosen.shiftName,
3327
- startTime: chosen.startTime,
3328
- endTime: chosen.endTime,
3329
- timezone,
3330
- date: operationalDate
3338
+ shiftId: fallbackShift.shiftId,
3339
+ shiftName: fallbackShift.shiftName,
3340
+ startTime: fallbackShift.startTime,
3341
+ endTime: fallbackShift.endTime,
3342
+ timezone: effectiveTz,
3343
+ date: getOperationalDate(effectiveTz, now4, fallbackShift.startTime)
3331
3344
  };
3332
3345
  };
3333
- var getCurrentShift = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
3346
+ var getActiveShift = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
3334
3347
  const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
3335
- return determineShiftFromDefinitions(effectiveTz, shifts, now4);
3348
+ return determineActiveShiftFromDefinitions(effectiveTz, shifts, now4);
3336
3349
  };
3337
3350
  var isTransitionPeriod = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
3338
3351
  const transitionMinutes = shiftConfig?.transitionPeriodMinutes ?? DEFAULT_TRANSITION_MINUTES;
@@ -32203,6 +32216,7 @@ var LineChartComponent = ({
32203
32216
  xAxisLabel,
32204
32217
  xAxisTickFormatter,
32205
32218
  // Pass through for X-axis tick formatting
32219
+ xAxisInterval,
32206
32220
  yAxisLabel,
32207
32221
  yAxisUnit,
32208
32222
  yAxisDomain,
@@ -32285,6 +32299,7 @@ var LineChartComponent = ({
32285
32299
  dataKey: xAxisDataKey,
32286
32300
  label: xAxisLabel ? { value: xAxisLabel, position: "insideBottom", offset: -10 } : void 0,
32287
32301
  tickFormatter: xAxisTickFormatter,
32302
+ interval: xAxisInterval,
32288
32303
  tick: { fontSize: 12, fill: axisTickFillColor },
32289
32304
  stroke: axisStrokeColor
32290
32305
  }
@@ -34028,8 +34043,9 @@ var VideoCard = React141__namespace.default.memo(({
34028
34043
  const isRecentFlowCard = isVideoGridRecentFlowEnabled(workspace);
34029
34044
  const hasDisplayMetric = typeof videoGridDisplayValue === "number" && Number.isFinite(videoGridDisplayValue);
34030
34045
  const hasBarMetric = typeof videoGridMetricValue === "number" && Number.isFinite(videoGridMetricValue);
34046
+ const shouldRenderMetricBadge = hasDisplayMetric;
34031
34047
  const badgeTitle = hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
34032
- const badgeLabel = hasDisplayMetric ? `${Math.round(videoGridDisplayValue)}%` : "X";
34048
+ const badgeLabel = `${Math.round(videoGridDisplayValue ?? 0)}%`;
34033
34049
  const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
34034
34050
  const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
34035
34051
  const efficiencyStatus = videoGridColorState === "green" ? "High" : videoGridColorState === "yellow" ? "Medium" : videoGridColorState === "red" ? "Low" : "Neutral";
@@ -34105,7 +34121,7 @@ var VideoCard = React141__namespace.default.memo(({
34105
34121
  lastSeenText
34106
34122
  ] })
34107
34123
  ] }) }),
34108
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute ${compact ? "top-1 right-1" : "top-2 right-2"} z-30`, children: /* @__PURE__ */ jsxRuntime.jsx(
34124
+ shouldRenderMetricBadge && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute ${compact ? "top-1 right-1" : "top-2 right-2"} z-30`, children: /* @__PURE__ */ jsxRuntime.jsx(
34109
34125
  "div",
34110
34126
  {
34111
34127
  "data-testid": "video-card-metric-badge",
@@ -49832,8 +49848,7 @@ var WorkspaceCycleTimeMetricCards = ({
49832
49848
  {
49833
49849
  data: idleTimeData.chartData,
49834
49850
  isLoading: idleTimeData.isLoading,
49835
- error: idleTimeData.error,
49836
- variant: "bar"
49851
+ error: idleTimeData.error
49837
49852
  }
49838
49853
  ) })
49839
49854
  ] })
@@ -76453,7 +76468,7 @@ var formatComparisonWindow = ({
76453
76468
  shiftMode
76454
76469
  }) => {
76455
76470
  if (comparisonStrategy === "previous_full_week") return "last week";
76456
- if (comparisonStrategy === "matched_range" && shiftMode !== "all" && currentDayCount === 1 && previousDayCount === 1) {
76471
+ if (comparisonStrategy === "matched_range" && currentDayCount === 1 && previousDayCount === 1) {
76457
76472
  return "previous day";
76458
76473
  }
76459
76474
  if (!previousDayCount || !Number.isFinite(previousDayCount)) return "previous range";
@@ -76476,8 +76491,14 @@ var buildDeltaBadge = (delta, options) => {
76476
76491
  };
76477
76492
  };
76478
76493
  var normalizeShiftLabel = (shiftName, shiftMode) => {
76494
+ if (shiftMode === "all") {
76495
+ return "All Shifts";
76496
+ }
76479
76497
  const trimmedName = shiftName?.trim();
76480
76498
  if (trimmedName) {
76499
+ const normalizedName = trimmedName.toLowerCase();
76500
+ if (normalizedName === "day") return "Day Shift";
76501
+ if (normalizedName === "night") return "Night Shift";
76481
76502
  return /shift/i.test(trimmedName) ? trimmedName : `${trimmedName} Shift`;
76482
76503
  }
76483
76504
  if (shiftMode === "night") return "Night Shift";
@@ -76486,6 +76507,9 @@ var normalizeShiftLabel = (shiftName, shiftMode) => {
76486
76507
  var getShiftIcon = (shiftName, shiftMode) => {
76487
76508
  const normalizedName = (shiftName || "").toLowerCase();
76488
76509
  const normalizedMode = shiftMode || "day";
76510
+ if (normalizedMode === "all") {
76511
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
76512
+ }
76489
76513
  if (normalizedName.includes("day") || normalizedName.includes("morning") || normalizedMode === "day") {
76490
76514
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
76491
76515
  }
@@ -76564,6 +76588,7 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
76564
76588
  }) => {
76565
76589
  bumpRenderCounter();
76566
76590
  const subtitleRange = displayDateRange || dateRange;
76591
+ const showLiveShiftMeta = isLiveScope && trendMode !== "all";
76567
76592
  const liveShiftLabel = React141__namespace.default.useMemo(
76568
76593
  () => normalizeShiftLabel(liveShiftName, trendMode),
76569
76594
  [liveShiftName, trendMode]
@@ -76701,8 +76726,8 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
76701
76726
  ] }),
76702
76727
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex flex-wrap items-center justify-center gap-x-2 gap-y-1 text-[11px] font-medium text-slate-500 min-w-0", children: [
76703
76728
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-center", children: mobileSubtitle }),
76704
- isLiveScope ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-300", children: "|" }) : null,
76705
- isLiveScope ? /* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 justify-center truncate", children: [
76729
+ showLiveShiftMeta ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-300", children: "|" }) : null,
76730
+ showLiveShiftMeta ? /* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 justify-center truncate", children: [
76706
76731
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75 shrink-0", children: liveShiftIcon }),
76707
76732
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: liveShiftLabel })
76708
76733
  ] }) }) : null
@@ -76749,7 +76774,7 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
76749
76774
  ] }),
76750
76775
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-center gap-x-3 gap-y-1 text-xs sm:text-sm font-medium text-slate-500 text-center", children: [
76751
76776
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: desktopSubtitle }),
76752
- isLiveScope ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
76777
+ showLiveShiftMeta ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
76753
76778
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-300", children: "|" }),
76754
76779
  /* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 justify-center", children: [
76755
76780
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75", children: liveShiftIcon }),
@@ -77323,18 +77348,18 @@ var EfficiencyTrendCard = React141__namespace.default.memo(({
77323
77348
  return (trend.data.points || []).map((point, index) => ({
77324
77349
  name: (() => {
77325
77350
  const rawLabel = point.label?.trim() || "";
77326
- if (!hourlyLabelStartTime) {
77327
- return rawLabel || `Hour ${index + 1}`;
77328
- }
77329
- if (rawLabel && !/^Hour\s+\d+$/i.test(rawLabel)) {
77351
+ if (rawLabel) {
77330
77352
  return rawLabel;
77331
77353
  }
77354
+ if (!hourlyLabelStartTime) {
77355
+ return "";
77356
+ }
77332
77357
  const hourIndex = typeof point.hour_index === "number" ? point.hour_index : index;
77333
77358
  const [hoursPart, minutesPart] = hourlyLabelStartTime.split(":");
77334
77359
  const startHours = Number(hoursPart);
77335
77360
  const startMinutes = Number(minutesPart);
77336
77361
  if (!Number.isFinite(startHours) || !Number.isFinite(startMinutes)) {
77337
- return rawLabel || `Hour ${index + 1}`;
77362
+ return "";
77338
77363
  }
77339
77364
  const totalMinutes = startHours * 60 + startMinutes + hourIndex * 60;
77340
77365
  const hour24 = Math.floor(totalMinutes / 60) % 24;
@@ -77396,6 +77421,12 @@ var EfficiencyTrendCard = React141__namespace.default.memo(({
77396
77421
  if (!dayOfWeek || typeof label !== "string") return label;
77397
77422
  return `${label} (${dayOfWeek})`;
77398
77423
  }, [isHourlyTrend]);
77424
+ const trendXAxisTickFormatter = React141__namespace.default.useCallback((value, index) => {
77425
+ if (!isHourlyTrend) {
77426
+ return typeof value === "string" ? value : String(value ?? "");
77427
+ }
77428
+ return index % 2 === 0 ? typeof value === "string" ? value : String(value ?? "") : "";
77429
+ }, [isHourlyTrend]);
77399
77430
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-[0_2px_10px_-3px_rgba(6,81,237,0.1)] border border-slate-100 flex flex-col overflow-hidden text-left", children: [
77400
77431
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-5 flex-none flex justify-between items-center border-b border-slate-50/50", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Efficiency Trend" }) }),
77401
77432
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-[250px] w-full p-4 pt-4 relative", children: showInitialSkeleton ? /* @__PURE__ */ jsxRuntime.jsx(OverviewChartSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 pb-2 pr-4 pl-1", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -77404,6 +77435,8 @@ var EfficiencyTrendCard = React141__namespace.default.memo(({
77404
77435
  data: trendData,
77405
77436
  lines: efficiencyLineConfig,
77406
77437
  xAxisDataKey: "name",
77438
+ xAxisInterval: isHourlyTrend ? 0 : void 0,
77439
+ xAxisTickFormatter: trendXAxisTickFormatter,
77407
77440
  yAxisUnit: "%",
77408
77441
  yAxisDomain: [0, 100],
77409
77442
  showLegend: false,
@@ -77909,6 +77942,62 @@ var classifyShiftBucket = ({
77909
77942
  if (normalizedShiftId === 1) return "night";
77910
77943
  return null;
77911
77944
  };
77945
+ var getShiftWindowsForConfig = (shiftConfig, timezone) => {
77946
+ if (shiftConfig?.shifts && shiftConfig.shifts.length > 0) {
77947
+ return shiftConfig.shifts.map((shift) => ({
77948
+ shiftId: shift.shiftId,
77949
+ shiftName: shift.shiftName,
77950
+ startTime: shift.startTime,
77951
+ endTime: shift.endTime
77952
+ }));
77953
+ }
77954
+ const windows = [];
77955
+ if (shiftConfig?.dayShift) {
77956
+ windows.push({
77957
+ shiftId: shiftConfig.dayShift.id ?? 0,
77958
+ shiftName: shiftConfig.dayShift.name || "Day Shift",
77959
+ startTime: shiftConfig.dayShift.startTime || "06:00",
77960
+ endTime: shiftConfig.dayShift.endTime || "18:00"
77961
+ });
77962
+ }
77963
+ if (shiftConfig?.nightShift) {
77964
+ windows.push({
77965
+ shiftId: shiftConfig.nightShift.id ?? 1,
77966
+ shiftName: shiftConfig.nightShift.name || "Night Shift",
77967
+ startTime: shiftConfig.nightShift.startTime || "18:00",
77968
+ endTime: shiftConfig.nightShift.endTime || "06:00"
77969
+ });
77970
+ }
77971
+ if (windows.length > 0) {
77972
+ return windows;
77973
+ }
77974
+ return [
77975
+ {
77976
+ shiftId: 0,
77977
+ shiftName: "Day Shift",
77978
+ startTime: "06:00",
77979
+ endTime: "18:00"
77980
+ },
77981
+ {
77982
+ shiftId: 1,
77983
+ shiftName: "Night Shift",
77984
+ startTime: "18:00",
77985
+ endTime: "06:00"
77986
+ }
77987
+ ];
77988
+ };
77989
+ var normalizeShiftWindowMinutes = (startTime, endTime) => {
77990
+ const startMinutes = parseTimeToMinutes3(startTime);
77991
+ const endMinutesRaw = parseTimeToMinutes3(endTime);
77992
+ if (startMinutes === null || endMinutesRaw === null) {
77993
+ return null;
77994
+ }
77995
+ let endMinutes = endMinutesRaw;
77996
+ if (endMinutes <= startMinutes) {
77997
+ endMinutes += 24 * 60;
77998
+ }
77999
+ return { startMinutes, endMinutes };
78000
+ };
77912
78001
  var PlantHeadView = () => {
77913
78002
  const supabase = useSupabase();
77914
78003
  const entityConfig = useEntityConfig();
@@ -77934,6 +78023,7 @@ var PlantHeadView = () => {
77934
78023
  const [selectedSupervisorId, setSelectedSupervisorId] = React141__namespace.default.useState("all");
77935
78024
  const [selectedLineIds, setSelectedLineIds] = React141__namespace.default.useState([]);
77936
78025
  const [isInitialScopeReady, setIsInitialScopeReady] = React141__namespace.default.useState(false);
78026
+ const [shiftResolutionTick, setShiftResolutionTick] = React141__namespace.default.useState(0);
77937
78027
  const hasAutoInitializedScopeRef = React141__namespace.default.useRef(false);
77938
78028
  const hasUserAdjustedScopeRef = React141__namespace.default.useRef(false);
77939
78029
  React141__namespace.default.useEffect(() => {
@@ -78038,34 +78128,151 @@ var PlantHeadView = () => {
78038
78128
  shiftConfigMap,
78039
78129
  isLoading: isShiftConfigLoading
78040
78130
  } = useMultiLineShiftConfigs(scopedLineIds, staticShiftConfig);
78041
- const { shiftGroups, hasComputed: hasComputedShiftGroups } = useShiftGroups({
78042
- enabled: scopedLineIds.length > 0 && !isShiftConfigLoading,
78043
- shiftConfigMap,
78044
- timezone: appTimezone
78045
- });
78046
- const currentShiftScope = React141__namespace.default.useMemo(() => {
78047
- if (shiftGroups.length !== 1) return null;
78048
- const group = shiftGroups[0];
78049
- const referenceLineId = group.lineIds[0];
78050
- const referenceShiftConfig = referenceLineId ? shiftConfigMap.get(referenceLineId) : null;
78051
- const normalizedGroupShiftId = normalizeShiftId(group.shiftId);
78052
- const shiftDefinition = referenceShiftConfig?.shifts?.find((shift) => normalizeShiftId(shift.shiftId) === normalizedGroupShiftId);
78053
- const resolvedMode = classifyShiftBucket({
78054
- shiftName: group.shiftName,
78055
- shiftId: normalizedGroupShiftId,
78056
- startTime: shiftDefinition?.startTime,
78057
- endTime: shiftDefinition?.endTime
78058
- });
78059
- if (!resolvedMode || resolvedMode === "all") return null;
78060
- return {
78061
- date: group.date,
78062
- trendMode: resolvedMode,
78063
- shiftName: shiftDefinition?.shiftName || group.shiftName || null
78131
+ React141__namespace.default.useEffect(() => {
78132
+ if (scopedLineIds.length === 0 || isShiftConfigLoading) {
78133
+ return;
78134
+ }
78135
+ const intervalId = window.setInterval(() => {
78136
+ setShiftResolutionTick((previous) => previous + 1);
78137
+ }, 6e4);
78138
+ return () => {
78139
+ clearInterval(intervalId);
78064
78140
  };
78065
- }, [shiftConfigMap, shiftGroups]);
78141
+ }, [isShiftConfigLoading, scopedLineIds.length]);
78142
+ const shiftResolutionNow = React141__namespace.default.useMemo(
78143
+ () => /* @__PURE__ */ new Date(),
78144
+ [shiftResolutionTick]
78145
+ );
78146
+ const earliestDayShiftStartTime = React141__namespace.default.useMemo(() => {
78147
+ const candidateStarts = [];
78148
+ scopedLineIds.forEach((lineId) => {
78149
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78150
+ getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
78151
+ const bucket = classifyShiftBucket({
78152
+ shiftName: shift.shiftName,
78153
+ shiftId: shift.shiftId,
78154
+ startTime: shift.startTime,
78155
+ endTime: shift.endTime
78156
+ });
78157
+ const startMinutes = parseTimeToMinutes3(shift.startTime);
78158
+ if (bucket === "day" && startMinutes !== null) {
78159
+ candidateStarts.push(startMinutes);
78160
+ }
78161
+ });
78162
+ });
78163
+ if (candidateStarts.length === 0) {
78164
+ scopedLineIds.forEach((lineId) => {
78165
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78166
+ getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
78167
+ const startMinutes = parseTimeToMinutes3(shift.startTime);
78168
+ if (startMinutes !== null) {
78169
+ candidateStarts.push(startMinutes);
78170
+ }
78171
+ });
78172
+ });
78173
+ }
78174
+ if (candidateStarts.length === 0) {
78175
+ return "06:00";
78176
+ }
78177
+ const earliestMinutes = Math.min(...candidateStarts);
78178
+ const hours = Math.floor(earliestMinutes / 60);
78179
+ const minutes = earliestMinutes % 60;
78180
+ return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
78181
+ }, [appTimezone, scopedLineIds, shiftConfigMap, staticShiftConfig]);
78182
+ const resolvedOperationalToday = React141__namespace.default.useMemo(
78183
+ () => getOperationalDate(appTimezone, shiftResolutionNow, earliestDayShiftStartTime),
78184
+ [appTimezone, earliestDayShiftStartTime, shiftResolutionNow]
78185
+ );
78186
+ const activeLineShiftStates = React141__namespace.default.useMemo(() => {
78187
+ return scopedLineIds.flatMap((lineId) => {
78188
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78189
+ const activeShift = getActiveShift(appTimezone, shiftConfig, shiftResolutionNow);
78190
+ if (!activeShift) {
78191
+ return [];
78192
+ }
78193
+ const trendBucket = classifyShiftBucket({
78194
+ shiftName: activeShift.shiftName,
78195
+ shiftId: activeShift.shiftId,
78196
+ startTime: activeShift.startTime,
78197
+ endTime: activeShift.endTime
78198
+ });
78199
+ if (!trendBucket || trendBucket === "all") {
78200
+ return [];
78201
+ }
78202
+ return [{
78203
+ lineId,
78204
+ trendMode: trendBucket,
78205
+ shiftId: activeShift.shiftId,
78206
+ shiftName: activeShift.shiftName || null,
78207
+ startTime: activeShift.startTime || null,
78208
+ endTime: activeShift.endTime || null,
78209
+ date: activeShift.date
78210
+ }];
78211
+ });
78212
+ }, [appTimezone, scopedLineIds, shiftConfigMap, shiftResolutionNow, staticShiftConfig]);
78213
+ const hasActiveDayShiftLine = React141__namespace.default.useMemo(
78214
+ () => activeLineShiftStates.some((shift) => shift.trendMode === "day" && shift.date === resolvedOperationalToday),
78215
+ [activeLineShiftStates, resolvedOperationalToday]
78216
+ );
78217
+ const hasActiveNightShiftLine = React141__namespace.default.useMemo(
78218
+ () => activeLineShiftStates.some((shift) => shift.trendMode === "night" && shift.date === resolvedOperationalToday),
78219
+ [activeLineShiftStates, resolvedOperationalToday]
78220
+ );
78221
+ const resolvedTrendMode = isInitialScopeReady ? trendMode : "all";
78222
+ const hourlyWindowStartTime = React141__namespace.default.useMemo(() => {
78223
+ if (scopedLineIds.length === 0) {
78224
+ return null;
78225
+ }
78226
+ const startCandidates = [];
78227
+ const endCandidates = [];
78228
+ scopedLineIds.forEach((lineId) => {
78229
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78230
+ getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
78231
+ const bucket = classifyShiftBucket({
78232
+ shiftName: shift.shiftName,
78233
+ shiftId: shift.shiftId,
78234
+ startTime: shift.startTime,
78235
+ endTime: shift.endTime
78236
+ });
78237
+ if (resolvedTrendMode !== "all" && bucket !== resolvedTrendMode) {
78238
+ return;
78239
+ }
78240
+ const normalizedWindow = normalizeShiftWindowMinutes(shift.startTime, shift.endTime);
78241
+ if (!normalizedWindow) {
78242
+ return;
78243
+ }
78244
+ startCandidates.push(normalizedWindow.startMinutes);
78245
+ endCandidates.push(normalizedWindow.endMinutes);
78246
+ });
78247
+ });
78248
+ if (resolvedTrendMode === "all") {
78249
+ const dayStartCandidates = startCandidates.length > 0 ? scopedLineIds.flatMap((lineId) => {
78250
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78251
+ return getShiftWindowsForConfig(shiftConfig).map((shift) => {
78252
+ const bucket = classifyShiftBucket({
78253
+ shiftName: shift.shiftName,
78254
+ shiftId: shift.shiftId,
78255
+ startTime: shift.startTime,
78256
+ endTime: shift.endTime
78257
+ });
78258
+ return bucket === "day" ? parseTimeToMinutes3(shift.startTime) : null;
78259
+ }).filter((value) => value !== null);
78260
+ }) : [];
78261
+ if (dayStartCandidates.length > 0) {
78262
+ startCandidates.splice(0, startCandidates.length, ...dayStartCandidates);
78263
+ }
78264
+ }
78265
+ if (startCandidates.length === 0 || endCandidates.length === 0) {
78266
+ return null;
78267
+ }
78268
+ const earliestMinutes = Math.min(...startCandidates);
78269
+ const hours = Math.floor(earliestMinutes / 60);
78270
+ const minutes = earliestMinutes % 60;
78271
+ return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
78272
+ }, [appTimezone, resolvedTrendMode, scopedLineIds, shiftConfigMap, staticShiftConfig]);
78066
78273
  const isShiftScopeResolved = React141__namespace.default.useMemo(
78067
- () => !isShiftConfigLoading && hasComputedShiftGroups,
78068
- [hasComputedShiftGroups, isShiftConfigLoading]
78274
+ () => !isShiftConfigLoading,
78275
+ [isShiftConfigLoading]
78069
78276
  );
78070
78277
  const initializedTimezoneRef = React141__namespace.default.useRef(appTimezone);
78071
78278
  React141__namespace.default.useEffect(() => {
@@ -78092,7 +78299,7 @@ var PlantHeadView = () => {
78092
78299
  return;
78093
78300
  }
78094
78301
  setDateRange((previous) => {
78095
- const nextStartKey = currentShiftScope?.date || fallbackOperationalDate;
78302
+ const nextStartKey = resolvedOperationalToday || fallbackOperationalDate;
78096
78303
  if (previous.startKey === nextStartKey && previous.endKey === nextStartKey) {
78097
78304
  return previous;
78098
78305
  }
@@ -78101,11 +78308,11 @@ var PlantHeadView = () => {
78101
78308
  endKey: nextStartKey
78102
78309
  };
78103
78310
  });
78104
- setTrendMode(currentShiftScope?.trendMode || "all");
78311
+ setTrendMode("all");
78105
78312
  setUsesThisWeekComparison(false);
78106
78313
  hasAutoInitializedScopeRef.current = true;
78107
78314
  setIsInitialScopeReady(true);
78108
- }, [currentShiftScope, fallbackOperationalDate, isShiftScopeResolved, scopedLineIds.length]);
78315
+ }, [fallbackOperationalDate, isShiftScopeResolved, resolvedOperationalToday, scopedLineIds.length]);
78109
78316
  const handleDateRangeChange = React141__namespace.default.useCallback((range, meta) => {
78110
78317
  hasUserAdjustedScopeRef.current = true;
78111
78318
  setIsInitialScopeReady(true);
@@ -78182,45 +78389,36 @@ var PlantHeadView = () => {
78182
78389
  if (isInitialScopeReady) {
78183
78390
  return dateRange;
78184
78391
  }
78185
- const nextStartKey = currentShiftScope?.date || fallbackOperationalDate;
78392
+ const nextStartKey = resolvedOperationalToday || fallbackOperationalDate;
78186
78393
  return {
78187
78394
  startKey: nextStartKey,
78188
78395
  endKey: nextStartKey
78189
78396
  };
78190
- }, [currentShiftScope, dateRange, fallbackOperationalDate, isInitialScopeReady]);
78397
+ }, [dateRange, fallbackOperationalDate, isInitialScopeReady, resolvedOperationalToday]);
78191
78398
  const effectiveTrendMode = React141__namespace.default.useMemo(
78192
- () => isInitialScopeReady ? trendMode : currentShiftScope?.trendMode || "all",
78193
- [currentShiftScope, isInitialScopeReady, trendMode]
78399
+ () => resolvedTrendMode,
78400
+ [resolvedTrendMode]
78194
78401
  );
78195
78402
  const hourlyLabelStartTime = React141__namespace.default.useMemo(() => {
78196
- if (effectiveTrendMode === "all" || scopedLineIds.length === 0) {
78197
- return null;
78198
- }
78199
- const shiftStartTimes = /* @__PURE__ */ new Set();
78200
- scopedLineIds.forEach((lineId) => {
78201
- const shiftConfig = shiftConfigMap.get(lineId);
78202
- const matchingShift = shiftConfig?.shifts?.find((shift) => classifyShiftBucket({
78203
- shiftName: shift.shiftName,
78204
- shiftId: shift.shiftId,
78205
- startTime: shift.startTime,
78206
- endTime: shift.endTime
78207
- }) === effectiveTrendMode);
78208
- if (matchingShift?.startTime) {
78209
- shiftStartTimes.add(matchingShift.startTime);
78210
- }
78211
- });
78212
- if (shiftStartTimes.size !== 1) {
78403
+ if (scopedLineIds.length === 0) {
78213
78404
  return null;
78214
78405
  }
78215
- return Array.from(shiftStartTimes)[0] || null;
78216
- }, [effectiveTrendMode, scopedLineIds, shiftConfigMap]);
78217
- const isSingleDayShiftScope = React141__namespace.default.useMemo(
78218
- () => effectiveDateRange.startKey === effectiveDateRange.endKey && effectiveTrendMode !== "all",
78219
- [effectiveDateRange.endKey, effectiveDateRange.startKey, effectiveTrendMode]
78406
+ return hourlyWindowStartTime;
78407
+ }, [hourlyWindowStartTime, scopedLineIds.length]);
78408
+ const isSingleDayScope = React141__namespace.default.useMemo(
78409
+ () => effectiveDateRange.startKey === effectiveDateRange.endKey,
78410
+ [effectiveDateRange.endKey, effectiveDateRange.startKey]
78220
78411
  );
78221
78412
  const isLiveScope = React141__namespace.default.useMemo(
78222
- () => isSingleDayShiftScope && currentShiftScope !== null && effectiveDateRange.startKey === currentShiftScope.date && effectiveTrendMode === currentShiftScope.trendMode,
78223
- [currentShiftScope, effectiveDateRange.startKey, effectiveTrendMode, isSingleDayShiftScope]
78413
+ () => isSingleDayScope && effectiveDateRange.startKey === resolvedOperationalToday && (effectiveTrendMode === "all" || effectiveTrendMode === "day" && hasActiveDayShiftLine || effectiveTrendMode === "night" && hasActiveNightShiftLine),
78414
+ [
78415
+ effectiveDateRange.startKey,
78416
+ effectiveTrendMode,
78417
+ hasActiveDayShiftLine,
78418
+ hasActiveNightShiftLine,
78419
+ isSingleDayScope,
78420
+ resolvedOperationalToday
78421
+ ]
78224
78422
  );
78225
78423
  const handleOpenLineDetails = React141__namespace.default.useCallback((lineId, lineName) => {
78226
78424
  trackCoreEvent("Operations Overview Line Clicked", {
@@ -78255,7 +78453,7 @@ var PlantHeadView = () => {
78255
78453
  displayDateRange: headerDateRange,
78256
78454
  trendMode,
78257
78455
  isLiveScope,
78258
- liveShiftName: currentShiftScope?.shiftName || null,
78456
+ liveShiftName: isLiveScope && trendMode !== "all" ? trendMode : null,
78259
78457
  lineOptions,
78260
78458
  supervisorOptions,
78261
78459
  selectedSupervisorId,
@@ -79086,6 +79284,7 @@ exports.formatRelativeTime = formatRelativeTime;
79086
79284
  exports.formatTimeInZone = formatTimeInZone;
79087
79285
  exports.fromUrlFriendlyName = fromUrlFriendlyName;
79088
79286
  exports.getActionDisplayName = getActionDisplayName;
79287
+ exports.getActiveShift = getActiveShift;
79089
79288
  exports.getAllLineDisplayNames = getAllLineDisplayNames;
79090
79289
  exports.getAllThreadMessages = getAllThreadMessages;
79091
79290
  exports.getAllWorkspaceDisplayNamesAsync = getAllWorkspaceDisplayNamesAsync;