@optifye/dashboard-core 6.10.29 → 6.10.31

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
@@ -2569,6 +2569,7 @@ var workspaceService = {
2569
2569
  }
2570
2570
  }
2571
2571
  };
2572
+ var DATA_PROCESSING_DELAY_MINUTES = 5;
2572
2573
  var WorkspaceHealthService = class _WorkspaceHealthService {
2573
2574
  constructor() {
2574
2575
  this.cache = /* @__PURE__ */ new Map();
@@ -2624,9 +2625,11 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2624
2625
  const totalMinutes = getShiftDurationMinutes(shiftStartStr, shiftEndStr);
2625
2626
  const shiftEndDate = dateFns.addMinutes(shiftStartDate, totalMinutes);
2626
2627
  const now4 = /* @__PURE__ */ new Date();
2627
- let completedMinutes = dateFns.differenceInMinutes(now4 < shiftEndDate ? now4 : shiftEndDate, shiftStartDate);
2628
- if (completedMinutes < 0) completedMinutes = 0;
2629
- if (completedMinutes > totalMinutes) completedMinutes = totalMinutes;
2628
+ let rawCompletedMinutes = dateFns.differenceInMinutes(now4 < shiftEndDate ? now4 : shiftEndDate, shiftStartDate);
2629
+ if (rawCompletedMinutes < 0) rawCompletedMinutes = 0;
2630
+ if (rawCompletedMinutes > totalMinutes) rawCompletedMinutes = totalMinutes;
2631
+ const isShiftComplete = shiftEndDate <= now4;
2632
+ const completedMinutes = isShiftComplete ? rawCompletedMinutes : Math.max(0, rawCompletedMinutes - DATA_PROCESSING_DELAY_MINUTES);
2630
2633
  const pendingMinutes = Math.max(0, totalMinutes - completedMinutes);
2631
2634
  return {
2632
2635
  shiftId,
@@ -2661,7 +2664,8 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2661
2664
  } else if (shiftStartDate > now4) {
2662
2665
  completedMinutes = 0;
2663
2666
  } else {
2664
- completedMinutes = Math.floor((now4.getTime() - shiftStartDate.getTime()) / (1e3 * 60));
2667
+ const rawCompleted = Math.floor((now4.getTime() - shiftStartDate.getTime()) / (1e3 * 60));
2668
+ completedMinutes = Math.max(0, rawCompleted - DATA_PROCESSING_DELAY_MINUTES);
2665
2669
  }
2666
2670
  const pendingMinutes = totalMinutes - completedMinutes;
2667
2671
  return {
@@ -4009,7 +4013,7 @@ var initializeCoreMixpanel = (token, debugOrOptions, trackPageViewArg) => {
4009
4013
  track_pageview: trackPageView ?? true,
4010
4014
  persistence: "localStorage"
4011
4015
  };
4012
- const recordSessionsPercent = sessionOpts.recordSessionsPercent ?? 0;
4016
+ const recordSessionsPercent = sessionOpts.recordSessionsPercent ?? 20;
4013
4017
  initOptions.record_sessions_percent = recordSessionsPercent;
4014
4018
  const defaultIdleTimeoutMs = 10 * 60 * 1e3;
4015
4019
  const recordIdleTimeoutMs = sessionOpts.recordIdleTimeoutMs ?? (recordSessionsPercent > 0 ? defaultIdleTimeoutMs : void 0);
@@ -11687,6 +11691,8 @@ var FAILURE_EXPIRY_MS = 5 * 60 * 1e3;
11687
11691
  var LIVE_RELOAD_MIN_INTERVAL_MS = 15 * 1e3;
11688
11692
  var DEFAULT_LIVE_OFFSET_SECONDS = 120;
11689
11693
  var DEFAULT_MAX_MANIFEST_AGE_MS = 10 * 60 * 1e3;
11694
+ var SEGMENT_MAX_AGE_MS = 10 * 60 * 1e3;
11695
+ var SEGMENT_TIMESTAMP_REGEX = /(\d{8}T\d{6}Z)(?=\.ts(?:$|[?#]))/;
11690
11696
  var STALE_MANIFEST_POLL_INITIAL_DELAY_MS = 15 * 1e3;
11691
11697
  var STALE_MANIFEST_POLL_MAX_DELAY_MS = 60 * 1e3;
11692
11698
  function resetFailedUrl(url) {
@@ -11722,6 +11728,8 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
11722
11728
  });
11723
11729
  };
11724
11730
  const [restartKey, setRestartKey] = React25.useState(0);
11731
+ const [isStale, setIsStale] = React25.useState(false);
11732
+ const [staleReason, setStaleReason] = React25.useState(null);
11725
11733
  const hlsRef = React25.useRef(null);
11726
11734
  const stallCheckIntervalRef = React25.useRef(null);
11727
11735
  const noProgressTimerRef = React25.useRef(null);
@@ -11733,6 +11741,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
11733
11741
  const playRetryTimerRef = React25.useRef(null);
11734
11742
  const playRetryCountRef = React25.useRef(0);
11735
11743
  const manifestWatchdogRef = React25.useRef(null);
11744
+ const nativeFreshnessIntervalRef = React25.useRef(null);
11736
11745
  const lastHiddenAtRef = React25.useRef(null);
11737
11746
  const manifestRetryTimerRef = React25.useRef(null);
11738
11747
  const manifestRetryDelayRef = React25.useRef(5e3);
@@ -11757,6 +11766,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
11757
11766
  const staleManifestEndSnRef = React25.useRef(null);
11758
11767
  const staleManifestPollTimerRef = React25.useRef(null);
11759
11768
  const staleManifestPollDelayRef = React25.useRef(STALE_MANIFEST_POLL_INITIAL_DELAY_MS);
11769
+ const lastSegmentTimestampMsRef = React25.useRef(null);
11760
11770
  const authTokenRef = React25.useRef(null);
11761
11771
  const proxyEnabled = process.env.NEXT_PUBLIC_HLS_PROXY_ENABLED === "true";
11762
11772
  const proxyBaseUrl = (process.env.NEXT_PUBLIC_HLS_PROXY_URL || "/api/stream").replace(/\/$/, "");
@@ -11766,6 +11776,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
11766
11776
  const parsed = raw ? Number(raw) : NaN;
11767
11777
  return Number.isFinite(parsed) ? parsed : DEFAULT_MAX_MANIFEST_AGE_MS;
11768
11778
  })();
11779
+ const manifestStaleThresholdMs = maxManifestAgeMs > 0 ? Math.min(maxManifestAgeMs, SEGMENT_MAX_AGE_MS) : SEGMENT_MAX_AGE_MS;
11769
11780
  const debugLog = (...args) => {
11770
11781
  if (debugEnabled) {
11771
11782
  console.log(...args);
@@ -11780,10 +11791,49 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
11780
11791
  }
11781
11792
  return null;
11782
11793
  };
11794
+ const parseSegmentTimestampMs = (value) => {
11795
+ const match = value.match(SEGMENT_TIMESTAMP_REGEX);
11796
+ if (!match) return null;
11797
+ const stamp = match[1];
11798
+ const year = Number(stamp.slice(0, 4));
11799
+ const month = Number(stamp.slice(4, 6));
11800
+ const day = Number(stamp.slice(6, 8));
11801
+ const hour = Number(stamp.slice(9, 11));
11802
+ const minute = Number(stamp.slice(11, 13));
11803
+ const second = Number(stamp.slice(13, 15));
11804
+ if (!Number.isFinite(year) || !Number.isFinite(month) || !Number.isFinite(day) || !Number.isFinite(hour) || !Number.isFinite(minute) || !Number.isFinite(second) || month < 1 || month > 12 || day < 1 || day > 31 || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) {
11805
+ return null;
11806
+ }
11807
+ const timestampMs = Date.UTC(year, month - 1, day, hour, minute, second);
11808
+ return Number.isNaN(timestampMs) ? null : timestampMs;
11809
+ };
11810
+ const getFragmentTimestampMs = (fragment, enforceSegmentAge = false) => {
11811
+ if (fragment?.relurl) {
11812
+ const parsed = parseSegmentTimestampMs(fragment.relurl);
11813
+ if (parsed !== null) return parsed;
11814
+ }
11815
+ if (fragment?.url) {
11816
+ const parsed = parseSegmentTimestampMs(fragment.url);
11817
+ if (parsed !== null) return parsed;
11818
+ }
11819
+ if (enforceSegmentAge) return null;
11820
+ return getProgramDateTimeMs(fragment?.programDateTime);
11821
+ };
11822
+ const getLatestFragmentTimestampMs = (fragments, enforceSegmentAge = false) => {
11823
+ if (!Array.isArray(fragments) || fragments.length === 0) return null;
11824
+ for (let i = fragments.length - 1; i >= 0; i -= 1) {
11825
+ const timestampMs = getFragmentTimestampMs(fragments[i], enforceSegmentAge);
11826
+ if (timestampMs !== null) {
11827
+ return timestampMs;
11828
+ }
11829
+ }
11830
+ return null;
11831
+ };
11783
11832
  const parseManifestStatus = (manifestText) => {
11784
11833
  let mediaSequence = null;
11785
11834
  let segmentCount = 0;
11786
11835
  let lastProgramDateTimeMs = null;
11836
+ let lastSegmentTimestampMs = null;
11787
11837
  const lines = manifestText.split(/\r?\n/);
11788
11838
  for (const rawLine of lines) {
11789
11839
  const line = rawLine.trim();
@@ -11801,13 +11851,60 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
11801
11851
  }
11802
11852
  } else if (line.startsWith("#EXTINF:")) {
11803
11853
  segmentCount += 1;
11854
+ } else if (!line.startsWith("#")) {
11855
+ const segmentTimestampMs = parseSegmentTimestampMs(line);
11856
+ if (segmentTimestampMs !== null) {
11857
+ lastSegmentTimestampMs = segmentTimestampMs;
11858
+ }
11804
11859
  }
11805
11860
  }
11806
11861
  let lastSequenceNumber = null;
11807
11862
  if (mediaSequence !== null && segmentCount > 0) {
11808
11863
  lastSequenceNumber = mediaSequence + segmentCount - 1;
11809
11864
  }
11810
- return { lastProgramDateTimeMs, lastSequenceNumber };
11865
+ return { lastProgramDateTimeMs, lastSequenceNumber, lastSegmentTimestampMs };
11866
+ };
11867
+ const evaluateSegmentFreshness = ({
11868
+ segmentTimestampMs,
11869
+ fallbackTimestampMs,
11870
+ enforceSegmentAge
11871
+ }) => {
11872
+ if (segmentTimestampMs !== null) {
11873
+ const ageMs = Date.now() - segmentTimestampMs;
11874
+ return {
11875
+ isFresh: ageMs <= SEGMENT_MAX_AGE_MS,
11876
+ ageMs,
11877
+ reason: `segment age ${Math.round(ageMs / 1e3)}s`
11878
+ };
11879
+ }
11880
+ if (enforceSegmentAge) {
11881
+ return { isFresh: false, ageMs: null, reason: "segment timestamp missing" };
11882
+ }
11883
+ if (fallbackTimestampMs !== null) {
11884
+ const ageMs = Date.now() - fallbackTimestampMs;
11885
+ return {
11886
+ isFresh: ageMs <= SEGMENT_MAX_AGE_MS,
11887
+ ageMs,
11888
+ reason: `program date time age ${Math.round(ageMs / 1e3)}s`
11889
+ };
11890
+ }
11891
+ return { isFresh: true, ageMs: null, reason: null };
11892
+ };
11893
+ const fetchManifestStatus = async (manifestUrl) => {
11894
+ const headers = {};
11895
+ if (authTokenRef.current) {
11896
+ headers.Authorization = `Bearer ${authTokenRef.current}`;
11897
+ }
11898
+ const response = await fetch(buildCacheBustedUrl(manifestUrl), {
11899
+ method: "GET",
11900
+ cache: "no-store",
11901
+ headers
11902
+ });
11903
+ if (!response.ok) {
11904
+ throw new Error(`Manifest fetch failed: ${response.status}`);
11905
+ }
11906
+ const manifestText = await response.text();
11907
+ return parseManifestStatus(manifestText);
11811
11908
  };
11812
11909
  const stopStaleManifestPolling = () => {
11813
11910
  if (staleManifestPollTimerRef.current) {
@@ -11818,6 +11915,8 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
11818
11915
  staleManifestUrlRef.current = null;
11819
11916
  staleManifestEndSnRef.current = null;
11820
11917
  staleManifestPollDelayRef.current = STALE_MANIFEST_POLL_INITIAL_DELAY_MS;
11918
+ setIsStale(false);
11919
+ setStaleReason(null);
11821
11920
  };
11822
11921
  const pollStaleManifestOnce = async () => {
11823
11922
  if (!staleManifestTriggeredRef.current) return;
@@ -11831,25 +11930,24 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
11831
11930
  return;
11832
11931
  }
11833
11932
  try {
11834
- const headers = {};
11835
- if (authTokenRef.current) {
11836
- headers.Authorization = `Bearer ${authTokenRef.current}`;
11837
- }
11838
- const response = await fetch(buildCacheBustedUrl(manifestUrl), {
11839
- method: "GET",
11840
- cache: "no-store",
11841
- headers
11933
+ const {
11934
+ lastProgramDateTimeMs,
11935
+ lastSequenceNumber,
11936
+ lastSegmentTimestampMs
11937
+ } = await fetchManifestStatus(manifestUrl);
11938
+ if (lastSegmentTimestampMs !== null) {
11939
+ lastSegmentTimestampMsRef.current = lastSegmentTimestampMs;
11940
+ }
11941
+ const enforceSegmentAge = isR2StreamRef.current;
11942
+ const hasAnyTimestamp = lastSegmentTimestampMs !== null || lastProgramDateTimeMs !== null;
11943
+ const freshness = evaluateSegmentFreshness({
11944
+ segmentTimestampMs: lastSegmentTimestampMs,
11945
+ fallbackTimestampMs: lastProgramDateTimeMs,
11946
+ enforceSegmentAge
11842
11947
  });
11843
- if (!response.ok) {
11844
- throw new Error(`Manifest poll failed: ${response.status}`);
11845
- }
11846
- const manifestText = await response.text();
11847
- const { lastProgramDateTimeMs, lastSequenceNumber } = parseManifestStatus(manifestText);
11848
- const now4 = Date.now();
11849
- const isFreshByProgramDateTime = lastProgramDateTimeMs !== null && now4 - lastProgramDateTimeMs <= maxManifestAgeMs;
11850
11948
  const priorEndSn = staleManifestEndSnRef.current;
11851
11949
  const isSequenceAdvanced = typeof lastSequenceNumber === "number" && (priorEndSn === null || lastSequenceNumber > priorEndSn);
11852
- if (isFreshByProgramDateTime || isSequenceAdvanced) {
11950
+ if (freshness.isFresh || !enforceSegmentAge && !hasAnyTimestamp && isSequenceAdvanced) {
11853
11951
  stopStaleManifestPolling();
11854
11952
  if (hlsRef.current) {
11855
11953
  hlsRef.current.startLoad(-1);
@@ -11884,6 +11982,8 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
11884
11982
  staleManifestUrlRef.current = activeStreamUrlRef.current || latestSrcRef.current;
11885
11983
  staleManifestEndSnRef.current = lastManifestEndSnRef.current;
11886
11984
  staleManifestPollDelayRef.current = STALE_MANIFEST_POLL_INITIAL_DELAY_MS;
11985
+ setIsStale(true);
11986
+ setStaleReason(reason);
11887
11987
  const hls = hlsRef.current;
11888
11988
  if (hls) {
11889
11989
  hls.stopLoad();
@@ -11941,6 +12041,10 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
11941
12041
  clearInterval(manifestWatchdogRef.current);
11942
12042
  manifestWatchdogRef.current = null;
11943
12043
  }
12044
+ if (nativeFreshnessIntervalRef.current) {
12045
+ clearInterval(nativeFreshnessIntervalRef.current);
12046
+ nativeFreshnessIntervalRef.current = null;
12047
+ }
11944
12048
  if (manifestRetryTimerRef.current) {
11945
12049
  clearTimeout(manifestRetryTimerRef.current);
11946
12050
  manifestRetryTimerRef.current = null;
@@ -11965,6 +12069,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
11965
12069
  lastManifestEndSnRef.current = null;
11966
12070
  lastManifestEndSnUpdatedAtRef.current = null;
11967
12071
  staleManifestTriggeredRef.current = false;
12072
+ lastSegmentTimestampMsRef.current = null;
11968
12073
  manifestRetryDelayRef.current = 5e3;
11969
12074
  playRetryCountRef.current = 0;
11970
12075
  if (hlsRef.current) {
@@ -12084,6 +12189,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
12084
12189
  const attemptPlay = (reason) => {
12085
12190
  const video = videoRef.current;
12086
12191
  if (!video || !shouldPlayRef.current) return;
12192
+ if (staleManifestTriggeredRef.current) return;
12087
12193
  if (!video.paused || video.seeking) return;
12088
12194
  if (video.readyState < 2) return;
12089
12195
  video.play().then(() => {
@@ -12109,7 +12215,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
12109
12215
  lastHiddenAtRef.current = null;
12110
12216
  if (!lastHiddenAt) return;
12111
12217
  if (Date.now() - lastHiddenAt < 3e4) return;
12112
- refreshLiveStream("tab visible after idle");
12218
+ void refreshLiveStream("tab visible after idle");
12113
12219
  attemptPlay();
12114
12220
  };
12115
12221
  const startManifestWatchdog = () => {
@@ -12185,7 +12291,38 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
12185
12291
  return `${url}${separator}ts=${Date.now()}`;
12186
12292
  }
12187
12293
  };
12188
- const refreshLiveStream = (reason) => {
12294
+ const ensureManifestFreshness = async (manifestUrl, enforceSegmentAge, reason) => {
12295
+ try {
12296
+ const status = await fetchManifestStatus(manifestUrl);
12297
+ if (status.lastSegmentTimestampMs !== null) {
12298
+ lastSegmentTimestampMsRef.current = status.lastSegmentTimestampMs;
12299
+ }
12300
+ const freshness = evaluateSegmentFreshness({
12301
+ segmentTimestampMs: status.lastSegmentTimestampMs,
12302
+ fallbackTimestampMs: status.lastProgramDateTimeMs,
12303
+ enforceSegmentAge
12304
+ });
12305
+ if (!freshness.isFresh) {
12306
+ markStaleStream(freshness.reason || reason);
12307
+ return false;
12308
+ }
12309
+ return true;
12310
+ } catch (error) {
12311
+ debugLog("[HLS] Manifest freshness check failed", error);
12312
+ {
12313
+ markStaleStream("manifest freshness check failed");
12314
+ return false;
12315
+ }
12316
+ }
12317
+ };
12318
+ const startNativeFreshnessMonitor = (manifestUrl) => {
12319
+ if (nativeFreshnessIntervalRef.current) return;
12320
+ nativeFreshnessIntervalRef.current = setInterval(() => {
12321
+ if (staleManifestTriggeredRef.current) return;
12322
+ void ensureManifestFreshness(manifestUrl, true, "native freshness check");
12323
+ }, 3e4);
12324
+ };
12325
+ const refreshLiveStream = async (reason) => {
12189
12326
  if (!isR2StreamRef.current) return;
12190
12327
  const now4 = Date.now();
12191
12328
  if (now4 - lastLiveReloadRef.current < LIVE_RELOAD_MIN_INTERVAL_MS) {
@@ -12201,6 +12338,10 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
12201
12338
  }
12202
12339
  if (video && nativeStreamUrlRef.current) {
12203
12340
  console.log(`[HLS] Native live reload (${reason})`);
12341
+ const isFresh = await ensureManifestFreshness(nativeStreamUrlRef.current, true, "native live reload");
12342
+ if (!isFresh) {
12343
+ return;
12344
+ }
12204
12345
  const refreshedUrl = buildCacheBustedUrl(nativeStreamUrlRef.current);
12205
12346
  video.src = refreshedUrl;
12206
12347
  video.load();
@@ -12292,7 +12433,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
12292
12433
  };
12293
12434
  const handleEnded = () => {
12294
12435
  if (isNativeHlsRef.current) {
12295
- refreshLiveStream("ended");
12436
+ void refreshLiveStream("ended");
12296
12437
  return;
12297
12438
  }
12298
12439
  if (isR2StreamRef.current) {
@@ -12306,7 +12447,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
12306
12447
  if (isNativeHlsRef.current) {
12307
12448
  if (!isR2StreamRef.current) return;
12308
12449
  waitingTimerRef.current = setTimeout(() => {
12309
- refreshLiveStream("native waiting timeout");
12450
+ void refreshLiveStream("native waiting timeout");
12310
12451
  }, getWaitingTimeoutMs());
12311
12452
  return;
12312
12453
  }
@@ -12429,12 +12570,17 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
12429
12570
  nativeStreamUrlRef.current = resolvedSrc;
12430
12571
  activeStreamUrlRef.current = resolvedSrc;
12431
12572
  console.log("[HLS] Using proxy playlist for Safari R2 stream");
12573
+ const isFresh = await ensureManifestFreshness(resolvedSrc, true, "native proxy start");
12574
+ if (!isFresh) {
12575
+ return;
12576
+ }
12432
12577
  video.src = resolvedSrc;
12433
12578
  video.addEventListener("waiting", handleWaiting);
12434
12579
  video.addEventListener("loadedmetadata", handleLoadedMetadata);
12435
12580
  video.addEventListener("canplay", handleCanPlay);
12436
12581
  video.addEventListener("ended", handleEnded);
12437
12582
  video.addEventListener("error", handleNativeError);
12583
+ startNativeFreshnessMonitor(resolvedSrc);
12438
12584
  attemptPlay();
12439
12585
  return;
12440
12586
  }
@@ -12602,20 +12748,29 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
12602
12748
  }
12603
12749
  }
12604
12750
  }
12605
- if (maxManifestAgeMs > 0 && !details.endList) {
12751
+ if (!details.endList) {
12606
12752
  const now4 = Date.now();
12607
12753
  const fragments = Array.isArray(details.fragments) ? details.fragments : [];
12608
12754
  const lastFragment = fragments.length ? fragments[fragments.length - 1] : void 0;
12609
- const programDateTimeMs = getProgramDateTimeMs(lastFragment?.programDateTime);
12610
- if (programDateTimeMs && now4 - programDateTimeMs > maxManifestAgeMs) {
12611
- markStaleStream(`segment age ${Math.round((now4 - programDateTimeMs) / 1e3)}s`);
12755
+ const segmentTimestampMs = getLatestFragmentTimestampMs(fragments, true);
12756
+ const enforceSegmentAge = isR2StreamRef.current;
12757
+ if (segmentTimestampMs !== null) {
12758
+ lastSegmentTimestampMsRef.current = segmentTimestampMs;
12759
+ }
12760
+ const freshness = evaluateSegmentFreshness({
12761
+ segmentTimestampMs,
12762
+ fallbackTimestampMs: getProgramDateTimeMs(lastFragment?.programDateTime),
12763
+ enforceSegmentAge
12764
+ });
12765
+ if (!freshness.isFresh) {
12766
+ markStaleStream(freshness.reason || "segment stale");
12612
12767
  return;
12613
12768
  }
12614
12769
  const endSn = typeof details.endSN === "number" ? details.endSN : lastFragment?.sn;
12615
12770
  if (typeof endSn === "number") {
12616
12771
  if (lastManifestEndSnRef.current === endSn) {
12617
12772
  const lastUpdatedAt = lastManifestEndSnUpdatedAtRef.current;
12618
- if (lastUpdatedAt && now4 - lastUpdatedAt > maxManifestAgeMs) {
12773
+ if (lastUpdatedAt && now4 - lastUpdatedAt > manifestStaleThresholdMs) {
12619
12774
  markStaleStream(`sequence stalled at ${endSn}`);
12620
12775
  return;
12621
12776
  }
@@ -12640,6 +12795,27 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
12640
12795
  lastManifestLoadRef.current = Date.now();
12641
12796
  resetManifestRetry();
12642
12797
  });
12798
+ hls.on(Hls__default.default.Events.FRAG_LOADING, (_event, data) => {
12799
+ if (staleManifestTriggeredRef.current) return;
12800
+ const frag = data?.frag;
12801
+ if (!frag || frag.sn === "initSegment") return;
12802
+ const enforceSegmentAge = isR2StreamRef.current;
12803
+ const segmentTimestampMs = getFragmentTimestampMs(frag, true);
12804
+ if (segmentTimestampMs !== null) {
12805
+ lastSegmentTimestampMsRef.current = segmentTimestampMs;
12806
+ }
12807
+ const freshness = evaluateSegmentFreshness({
12808
+ segmentTimestampMs,
12809
+ fallbackTimestampMs: getProgramDateTimeMs(frag.programDateTime),
12810
+ enforceSegmentAge
12811
+ });
12812
+ if (!freshness.isFresh) {
12813
+ if (frag.loader?.abort) {
12814
+ frag.loader.abort();
12815
+ }
12816
+ markStaleStream(freshness.reason || "segment stale");
12817
+ }
12818
+ });
12643
12819
  hls.on(Hls__default.default.Events.FRAG_LOADED, (_event, data) => {
12644
12820
  if (!isR2Stream) return;
12645
12821
  lastFragLoadRef.current = Date.now();
@@ -12664,9 +12840,15 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
12664
12840
  if (canUseNative) {
12665
12841
  isNativeHlsRef.current = true;
12666
12842
  console.log("[HLS] Using native HLS");
12667
- video.src = resolvedSrc;
12668
12843
  nativeStreamUrlRef.current = resolvedSrc;
12669
12844
  activeStreamUrlRef.current = resolvedSrc;
12845
+ if (isR2Stream) {
12846
+ const isFresh = await ensureManifestFreshness(resolvedSrc, true, "native start");
12847
+ if (!isFresh) {
12848
+ return;
12849
+ }
12850
+ }
12851
+ video.src = resolvedSrc;
12670
12852
  video.addEventListener("waiting", handleWaiting);
12671
12853
  video.addEventListener("loadedmetadata", handleLoadedMetadata);
12672
12854
  video.addEventListener("canplay", handleCanPlay);
@@ -12674,6 +12856,9 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
12674
12856
  video.addEventListener("error", handleNativeError);
12675
12857
  startPlaybackGovernor();
12676
12858
  startManifestWatchdog();
12859
+ if (isR2Stream) {
12860
+ startNativeFreshnessMonitor(resolvedSrc);
12861
+ }
12677
12862
  attemptPlay();
12678
12863
  } else {
12679
12864
  console.error("[HLS] HLS not supported");
@@ -12687,7 +12872,10 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
12687
12872
  }, [src, shouldPlay, restartKey, isPermanentlyFailed]);
12688
12873
  return {
12689
12874
  restartKey,
12690
- isNativeHls: isNativeHlsRef.current
12875
+ isNativeHls: isNativeHlsRef.current,
12876
+ isStale,
12877
+ staleReason,
12878
+ lastSegmentTimestampMs: lastSegmentTimestampMsRef.current
12691
12879
  };
12692
12880
  }
12693
12881
  function useHlsStreamWithCropping(videoRef, canvasRef, options) {
@@ -14823,7 +15011,77 @@ function getNextUpdateInterval(timestamp) {
14823
15011
  }
14824
15012
  }
14825
15013
 
14826
- // src/lib/hooks/useWorkspaceHealthStatus.ts
15014
+ // src/lib/hooks/useWorkspaceHealthLastSeen.ts
15015
+ var DEFAULT_REFRESH_INTERVAL_MS = 3e4;
15016
+ var useWorkspaceHealthLastSeen = (workspaceIds, options = {}) => {
15017
+ const supabase = useSupabase();
15018
+ const databaseConfig = useDatabaseConfig();
15019
+ const refreshInterval = options.refreshInterval ?? DEFAULT_REFRESH_INTERVAL_MS;
15020
+ const workspaceIdsKey = React25.useMemo(() => {
15021
+ const ids = Array.from(new Set(workspaceIds.filter(Boolean)));
15022
+ return ids.sort().join(",");
15023
+ }, [workspaceIds]);
15024
+ const [lastSeenByWorkspaceId, setLastSeenByWorkspaceId] = React25.useState({});
15025
+ const [isLoading, setIsLoading] = React25.useState(Boolean(workspaceIdsKey));
15026
+ const [error, setError] = React25.useState(null);
15027
+ const isFetchingRef = React25.useRef(false);
15028
+ const refreshIntervalRef = React25.useRef(null);
15029
+ const fetchLastSeen = React25.useCallback(async () => {
15030
+ if (!supabase || !workspaceIdsKey || isFetchingRef.current) return;
15031
+ const healthTable = databaseConfig?.tables?.workspace_health || "workspace_health_status";
15032
+ try {
15033
+ isFetchingRef.current = true;
15034
+ setIsLoading(true);
15035
+ setError(null);
15036
+ const workspaceIdsList = workspaceIdsKey.split(",").filter(Boolean);
15037
+ if (!workspaceIdsList.length) {
15038
+ setLastSeenByWorkspaceId({});
15039
+ return;
15040
+ }
15041
+ const { data, error: fetchError } = await supabase.from(healthTable).select("workspace_id,last_heartbeat,is_healthy").in("workspace_id", workspaceIdsList);
15042
+ if (fetchError) throw fetchError;
15043
+ const nextMap = {};
15044
+ (data || []).forEach((row) => {
15045
+ if (!row?.workspace_id) return;
15046
+ const lastHeartbeat = row.last_heartbeat || null;
15047
+ nextMap[row.workspace_id] = {
15048
+ lastHeartbeat,
15049
+ timeSinceLastUpdate: formatRelativeTime(lastHeartbeat),
15050
+ isHealthy: Boolean(row.is_healthy)
15051
+ };
15052
+ });
15053
+ setLastSeenByWorkspaceId(nextMap);
15054
+ } catch (err) {
15055
+ console.error("[useWorkspaceHealthLastSeen] Error fetching workspace health:", err);
15056
+ setError(err?.message || "Failed to load workspace health");
15057
+ setLastSeenByWorkspaceId({});
15058
+ } finally {
15059
+ setIsLoading(false);
15060
+ isFetchingRef.current = false;
15061
+ }
15062
+ }, [supabase, workspaceIdsKey, databaseConfig?.tables?.workspace_health]);
15063
+ React25.useEffect(() => {
15064
+ fetchLastSeen();
15065
+ }, [fetchLastSeen]);
15066
+ React25.useEffect(() => {
15067
+ if (!refreshInterval || !workspaceIdsKey) return;
15068
+ refreshIntervalRef.current = setInterval(() => {
15069
+ fetchLastSeen();
15070
+ }, refreshInterval);
15071
+ return () => {
15072
+ if (refreshIntervalRef.current) {
15073
+ clearInterval(refreshIntervalRef.current);
15074
+ refreshIntervalRef.current = null;
15075
+ }
15076
+ };
15077
+ }, [fetchLastSeen, refreshInterval, workspaceIdsKey]);
15078
+ return {
15079
+ lastSeenByWorkspaceId,
15080
+ isLoading,
15081
+ error,
15082
+ refetch: fetchLastSeen
15083
+ };
15084
+ };
14827
15085
  var useWorkspaceHealthStatus = (workspaceId) => {
14828
15086
  const supabase = useSupabase();
14829
15087
  const databaseConfig = useDatabaseConfig();
@@ -15504,6 +15762,7 @@ var useSupervisorsByLineIds = (lineIds, options) => {
15504
15762
  const targetLineIdSet = React25.useMemo(() => new Set(lineIds || []), [lineIdsKey]);
15505
15763
  const [supervisorsByLineId, setSupervisorsByLineId] = React25.useState(/* @__PURE__ */ new Map());
15506
15764
  const [supervisorNamesByLineId, setSupervisorNamesByLineId] = React25.useState(/* @__PURE__ */ new Map());
15765
+ const [allSupervisorsMap, setAllSupervisorsMap] = React25.useState(/* @__PURE__ */ new Map());
15507
15766
  const [isLoading, setIsLoading] = React25.useState(true);
15508
15767
  const [error, setError] = React25.useState(null);
15509
15768
  const fetchSupervisors = React25.useCallback(async () => {
@@ -15519,9 +15778,9 @@ var useSupervisorsByLineIds = (lineIds, options) => {
15519
15778
  throw fetchError;
15520
15779
  }
15521
15780
  const nextSupervisorsByLineId = /* @__PURE__ */ new Map();
15781
+ const nextAllSupervisorsMap = /* @__PURE__ */ new Map();
15522
15782
  (data || []).forEach((row) => {
15523
15783
  const assignedLineIds = row?.properties?.line_id || row?.properties?.line_ids || [];
15524
- if (!Array.isArray(assignedLineIds) || assignedLineIds.length === 0) return;
15525
15784
  const email = row.email || "";
15526
15785
  let displayName;
15527
15786
  if (row.first_name) {
@@ -15535,6 +15794,8 @@ var useSupervisorsByLineIds = (lineIds, options) => {
15535
15794
  displayName,
15536
15795
  profilePhotoUrl: row.profile_photo_url
15537
15796
  };
15797
+ nextAllSupervisorsMap.set(supervisor.userId, supervisor);
15798
+ if (!Array.isArray(assignedLineIds) || assignedLineIds.length === 0) return;
15538
15799
  assignedLineIds.forEach((lineId) => {
15539
15800
  if (typeof lineId !== "string") return;
15540
15801
  if (targetLineIdSet.size > 0 && !targetLineIdSet.has(lineId)) return;
@@ -15549,10 +15810,12 @@ var useSupervisorsByLineIds = (lineIds, options) => {
15549
15810
  });
15550
15811
  setSupervisorsByLineId(nextSupervisorsByLineId);
15551
15812
  setSupervisorNamesByLineId(nextSupervisorNamesByLineId);
15813
+ setAllSupervisorsMap(nextAllSupervisorsMap);
15552
15814
  } catch (err) {
15553
15815
  setError(err instanceof Error ? err : new Error("Failed to fetch supervisors"));
15554
15816
  setSupervisorsByLineId(/* @__PURE__ */ new Map());
15555
15817
  setSupervisorNamesByLineId(/* @__PURE__ */ new Map());
15818
+ setAllSupervisorsMap(/* @__PURE__ */ new Map());
15556
15819
  } finally {
15557
15820
  setIsLoading(false);
15558
15821
  }
@@ -15577,6 +15840,7 @@ var useSupervisorsByLineIds = (lineIds, options) => {
15577
15840
  return {
15578
15841
  supervisorNamesByLineId,
15579
15842
  supervisorsByLineId,
15843
+ allSupervisorsMap,
15580
15844
  isLoading,
15581
15845
  error,
15582
15846
  refetch: fetchSupervisors
@@ -29782,13 +30046,14 @@ var VideoCard = React25__namespace.default.memo(({
29782
30046
  className = "",
29783
30047
  compact = false,
29784
30048
  displayName,
30049
+ lastSeenLabel,
29785
30050
  onMouseEnter,
29786
30051
  onMouseLeave
29787
30052
  }) => {
29788
30053
  const videoRef = React25.useRef(null);
29789
30054
  const canvasRef = React25.useRef(null);
29790
30055
  const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
29791
- useHlsStreamWithCropping(videoRef, canvasRef, {
30056
+ const { isStale: isStreamStale } = useHlsStreamWithCropping(videoRef, canvasRef, {
29792
30057
  src: hlsUrl,
29793
30058
  shouldPlay,
29794
30059
  cropping,
@@ -29796,6 +30061,8 @@ var VideoCard = React25__namespace.default.memo(({
29796
30061
  useRAF,
29797
30062
  onFatalError: onFatalError ?? (() => throttledReloadDashboard())
29798
30063
  });
30064
+ const showOffline = Boolean(isStreamStale);
30065
+ const lastSeenText = lastSeenLabel || "Unknown";
29799
30066
  const workspaceDisplayName = displayName || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
29800
30067
  const efficiencyColor = getEfficiencyColor(workspace.efficiency, effectiveLegend);
29801
30068
  const efficiencyOverlayClass = efficiencyColor === "green" ? "bg-[#00D654]/25" : efficiencyColor === "yellow" ? "bg-[#FFD700]/30" : "bg-[#FF2D0A]/30";
@@ -29865,6 +30132,14 @@ var VideoCard = React25__namespace.default.memo(({
29865
30132
  )
29866
30133
  ] }),
29867
30134
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute inset-0 z-20 pointer-events-none ${efficiencyOverlayClass}` }),
30135
+ showOffline && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-40 flex items-center justify-center bg-black/70 px-2 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1", children: [
30136
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: `${compact ? "w-4 h-4" : "w-5 h-5"} text-amber-300` }),
30137
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `font-semibold text-white ${compact ? "text-[11px]" : "text-xs"}`, children: "Not streaming" }),
30138
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `text-gray-200 ${compact ? "text-[10px]" : "text-[11px]"}`, children: [
30139
+ "Last seen: ",
30140
+ lastSeenText
30141
+ ] })
30142
+ ] }) }),
29868
30143
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `absolute ${compact ? "top-1 right-1" : "top-2 right-2"} z-30 bg-black/70 backdrop-blur-sm rounded ${compact ? "px-1.5 py-0.5" : "px-2 py-0.5"} text-white ${compact ? "text-[10px]" : "text-xs"} font-semibold border border-white/10`, children: [
29869
30144
  Math.round(workspace.efficiency),
29870
30145
  "%"
@@ -29891,8 +30166,13 @@ var VideoCard = React25__namespace.default.memo(({
29891
30166
  children: trendInfo.arrow
29892
30167
  }
29893
30168
  ),
29894
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${compact ? "w-1 h-1" : "w-1.5 h-1.5"} rounded-full bg-green-500` }),
29895
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-white text-[11px] sm:${compact ? "text-[10px]" : "text-xs"}`, children: "Live" })
30169
+ /* @__PURE__ */ jsxRuntime.jsx(
30170
+ "div",
30171
+ {
30172
+ className: `${compact ? "w-1 h-1" : "w-1.5 h-1.5"} rounded-full ${showOffline ? "bg-red-500" : "bg-green-500"}`
30173
+ }
30174
+ ),
30175
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-white text-[11px] sm:${compact ? "text-[10px]" : "text-xs"}`, children: showOffline ? "Offline" : "Live" })
29896
30176
  ] })
29897
30177
  ] })
29898
30178
  ]
@@ -29908,6 +30188,9 @@ var VideoCard = React25__namespace.default.memo(({
29908
30188
  if (prevProps.displayName !== nextProps.displayName) {
29909
30189
  return false;
29910
30190
  }
30191
+ if (prevProps.lastSeenLabel !== nextProps.lastSeenLabel) {
30192
+ return false;
30193
+ }
29911
30194
  if (prevProps.legend !== nextProps.legend) {
29912
30195
  return false;
29913
30196
  }
@@ -29965,6 +30248,16 @@ var VideoGridView = React25__namespace.default.memo(({
29965
30248
  const supabase = useSupabase();
29966
30249
  const { cropping, canvasConfig, hlsUrls } = videoConfig;
29967
30250
  const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
30251
+ const workspaceHealthIds = React25.useMemo(() => {
30252
+ const ids = /* @__PURE__ */ new Set();
30253
+ for (const workspace of workspaces) {
30254
+ if (workspace.workspace_uuid) {
30255
+ ids.add(workspace.workspace_uuid);
30256
+ }
30257
+ }
30258
+ return Array.from(ids);
30259
+ }, [workspaces]);
30260
+ const { lastSeenByWorkspaceId } = useWorkspaceHealthLastSeen(workspaceHealthIds);
29968
30261
  React25.useEffect(() => {
29969
30262
  const sample = workspaces.slice(0, 3).map((workspace) => ({
29970
30263
  id: workspace.workspace_uuid || workspace.workspace_name,
@@ -30216,6 +30509,7 @@ var VideoGridView = React25__namespace.default.memo(({
30216
30509
  const isVeryLowEfficiency = workspace.show_exclamation ?? (workspace.efficiency < 50 && workspace.efficiency >= 10);
30217
30510
  const workspaceCropping = getWorkspaceCropping(workspaceId, workspace.workspace_name);
30218
30511
  const workspaceStream = videoStreamsByWorkspaceId?.[workspaceId];
30512
+ const lastSeenLabel = workspace.workspace_uuid ? lastSeenByWorkspaceId[workspace.workspace_uuid]?.timeSinceLastUpdate : void 0;
30219
30513
  const r2Url = workspaceStream?.hls_url;
30220
30514
  const fallbackUrl = getWorkspaceHlsUrl(workspace.workspace_name, workspace.line_id);
30221
30515
  const hasR2Stream = Boolean(r2Url);
@@ -30233,7 +30527,8 @@ var VideoGridView = React25__namespace.default.memo(({
30233
30527
  fallbackUrl,
30234
30528
  hlsUrl,
30235
30529
  isR2Stream,
30236
- shouldPlay
30530
+ shouldPlay,
30531
+ lastSeenLabel
30237
30532
  };
30238
30533
  });
30239
30534
  const croppedActiveCount = workspaceCards.reduce((count, card) => {
@@ -30271,6 +30566,7 @@ var VideoGridView = React25__namespace.default.memo(({
30271
30566
  displayNames[`${card.workspace.line_id}_${card.workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
30272
30567
  getWorkspaceDisplayName(card.workspace.workspace_name, card.workspace.line_id)
30273
30568
  ),
30569
+ lastSeenLabel: card.lastSeenLabel,
30274
30570
  useRAF: effectiveUseRAF,
30275
30571
  compact: !selectedLine,
30276
30572
  onMouseEnter: onWorkspaceHover ? () => onWorkspaceHover(card.workspaceId) : void 0,
@@ -33988,6 +34284,53 @@ var BackButtonMinimal = ({
33988
34284
  }
33989
34285
  );
33990
34286
  };
34287
+ var FittingTitle = ({
34288
+ title,
34289
+ className,
34290
+ as: Component3 = "h3"
34291
+ }) => {
34292
+ const containerRef = React25.useRef(null);
34293
+ const textRef = React25.useRef(null);
34294
+ const [fontSize, setFontSize] = React25.useState(null);
34295
+ React25.useLayoutEffect(() => {
34296
+ const adjustFontSize = () => {
34297
+ if (!containerRef.current || !textRef.current) return;
34298
+ const containerWidth = containerRef.current.offsetWidth;
34299
+ if (containerWidth <= 0) return;
34300
+ textRef.current.style.fontSize = "";
34301
+ textRef.current.style.display = "inline-block";
34302
+ const naturalWidth = textRef.current.offsetWidth;
34303
+ if (naturalWidth > containerWidth) {
34304
+ const computedStyle = window.getComputedStyle(textRef.current);
34305
+ const currentFontSize = parseFloat(computedStyle.fontSize);
34306
+ const ratio = (containerWidth - 2) / naturalWidth;
34307
+ const newFontSize = Math.max(8, currentFontSize * ratio);
34308
+ setFontSize(newFontSize);
34309
+ } else {
34310
+ setFontSize(null);
34311
+ }
34312
+ textRef.current.style.display = "";
34313
+ };
34314
+ adjustFontSize();
34315
+ const observer = new ResizeObserver(() => {
34316
+ window.requestAnimationFrame(adjustFontSize);
34317
+ });
34318
+ if (containerRef.current) {
34319
+ observer.observe(containerRef.current);
34320
+ }
34321
+ return () => observer.disconnect();
34322
+ }, [title]);
34323
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "w-full overflow-hidden min-w-0 flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
34324
+ Component3,
34325
+ {
34326
+ ref: textRef,
34327
+ className: cn("whitespace-nowrap font-bold text-gray-900 tracking-tight", className),
34328
+ style: fontSize ? { fontSize: `${fontSize}px`, lineHeight: 1.2 } : {},
34329
+ title,
34330
+ children: title
34331
+ }
34332
+ ) });
34333
+ };
33991
34334
  var InlineEditableText = ({
33992
34335
  value,
33993
34336
  onSave,
@@ -53349,7 +53692,7 @@ var KPIDetailView = ({
53349
53692
  const configuredTimezone = timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC";
53350
53693
  React25.useMemo(() => getCurrentTimeInZone(configuredTimezone), [configuredTimezone]);
53351
53694
  const supervisorEnabled = dashboardConfig?.supervisorConfig?.enabled || false;
53352
- const { supervisorName } = useLineSupervisor(lineId);
53695
+ const { supervisorName, supervisors } = useLineSupervisor(lineId);
53353
53696
  const { displayNames: workspaceDisplayNames } = useWorkspaceDisplayNames(lineId, companyId);
53354
53697
  React25.useEffect(() => {
53355
53698
  if (urlDate || urlShift !== void 0) {
@@ -53944,10 +54287,20 @@ var KPIDetailView = ({
53944
54287
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-green-500" })
53945
54288
  ] })
53946
54289
  ] }),
53947
- supervisorEnabled && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-gray-500 mt-1 text-center", children: [
54290
+ supervisorEnabled && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 flex justify-center", children: supervisors && supervisors.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5 justify-center", children: supervisors.map((supervisor) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 bg-gray-50 rounded-full pl-0.5 pr-2 py-0.5 border border-gray-100", children: [
54291
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-5 h-5 rounded-full overflow-hidden bg-white border border-gray-100 shadow-sm flex-shrink-0", children: supervisor.profilePhotoUrl ? /* @__PURE__ */ jsxRuntime.jsx(
54292
+ "img",
54293
+ {
54294
+ src: supervisor.profilePhotoUrl,
54295
+ alt: supervisor.displayName,
54296
+ className: "w-full h-full object-cover"
54297
+ }
54298
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 text-[8px] font-bold text-gray-500 uppercase", children: getInitials(supervisor.displayName) }) }),
54299
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium text-gray-700 truncate max-w-[100px]", children: supervisor.displayName })
54300
+ ] }, supervisor.userId)) }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-gray-500 text-center", children: [
53948
54301
  "Supervisor: ",
53949
54302
  supervisorName || "Unassigned"
53950
- ] })
54303
+ ] }) })
53951
54304
  ] }),
53952
54305
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-9" })
53953
54306
  ] }) }),
@@ -53966,10 +54319,17 @@ var KPIDetailView = ({
53966
54319
  /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl md:text-2xl lg:text-3xl font-semibold text-gray-900 text-center truncate", children: resolvedLineInfo?.line_name || "Line" }),
53967
54320
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1 flex-shrink-0" })
53968
54321
  ] }),
53969
- supervisorEnabled && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-gray-600 font-medium", children: [
53970
- "Supervisor: ",
53971
- supervisorName || "Unassigned"
53972
- ] })
54322
+ supervisorEnabled && supervisors && supervisors.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center mt-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center justify-center gap-6", children: supervisors.map((supervisor) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
54323
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 h-8 rounded-full overflow-hidden bg-gray-100 border border-gray-200 shadow-sm flex-shrink-0", children: supervisor.profilePhotoUrl ? /* @__PURE__ */ jsxRuntime.jsx(
54324
+ "img",
54325
+ {
54326
+ src: supervisor.profilePhotoUrl,
54327
+ alt: supervisor.displayName,
54328
+ className: "w-full h-full object-cover"
54329
+ }
54330
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 text-[10px] font-bold text-gray-500 uppercase", children: getInitials(supervisor.displayName) }) }),
54331
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-700", children: supervisor.displayName })
54332
+ ] }, supervisor.userId)) }) })
53973
54333
  ] }) })
53974
54334
  ] }) }),
53975
54335
  (activeTab !== "monthly_history" || urlDate || urlShift) && chartMetrics && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -53984,20 +54344,26 @@ var KPIDetailView = ({
53984
54344
  ] }),
53985
54345
  !urlDate && !urlShift ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) }) }) : urlDate && chartMetrics.date ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference2(chartMetrics.date) }) }) : null
53986
54346
  ] }),
53987
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block mt-3 bg-blue-50 px-3 py-2 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3 md:gap-4", children: [
54347
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block mt-3 bg-blue-50/50 px-4 py-2 rounded-xl border border-blue-100/50 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-6", children: [
53988
54348
  !urlDate && !urlShift && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
53989
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base md:text-lg font-medium text-blue-600", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) }),
53990
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
54349
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-700", children: [
54350
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4 opacity-70", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", 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" }) }),
54351
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-semibold tabular-nums", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) })
54352
+ ] }),
54353
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" })
53991
54354
  ] }),
53992
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: chartMetrics && formatLocalDate(new Date(chartMetrics.date)) }),
53993
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" }),
54355
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
54356
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4 opacity-70", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
54357
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium", children: chartMetrics && formatLocalDate(new Date(chartMetrics.date)) })
54358
+ ] }),
54359
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
53994
54360
  urlDate && chartMetrics.date && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
53995
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs font-medium bg-blue-200 text-blue-800 rounded-md", children: getDaysDifference2(chartMetrics.date) }),
53996
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
54361
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs font-medium bg-blue-100 text-blue-700 border border-blue-200 rounded-md", children: getDaysDifference2(chartMetrics.date) }),
54362
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" })
53997
54363
  ] }),
53998
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
53999
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon(chartMetrics.shift_id ?? 0) }),
54000
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
54364
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
54365
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon(chartMetrics.shift_id ?? 0) }),
54366
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
54001
54367
  getShiftName(chartMetrics.shift_id ?? 0).replace(/ Shift$/i, ""),
54002
54368
  " Shift"
54003
54369
  ] })
@@ -54018,18 +54384,24 @@ var KPIDetailView = ({
54018
54384
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: getShiftName(selectedShiftId) })
54019
54385
  ] })
54020
54386
  ] }),
54021
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block mt-3 bg-blue-50 px-3 py-2 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3 md:gap-4", children: [
54022
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: (() => {
54023
- const monthBounds2 = getMonthKeyBounds(currentYear, currentMonth);
54024
- const normalizedRange = normalizeDateKeyRange(rangeStart, rangeEnd, monthBounds2.startKey, monthBounds2.endKey);
54025
- const startDate = new Date(normalizedRange.startKey);
54026
- const endDate = new Date(normalizedRange.endKey);
54027
- return `${startDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })} - ${endDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`;
54028
- })() }),
54029
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" }),
54030
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
54031
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon(selectedShiftId) }),
54032
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: getShiftName(selectedShiftId) })
54387
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block mt-3 bg-blue-50/50 px-4 py-2 rounded-xl border border-blue-100/50 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-6", children: [
54388
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
54389
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4 opacity-70", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
54390
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium", children: (() => {
54391
+ const monthBounds2 = getMonthKeyBounds(currentYear, currentMonth);
54392
+ const normalizedRange = normalizeDateKeyRange(rangeStart, rangeEnd, monthBounds2.startKey, monthBounds2.endKey);
54393
+ const startDate = new Date(normalizedRange.startKey);
54394
+ const endDate = new Date(normalizedRange.endKey);
54395
+ return `${startDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })} - ${endDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`;
54396
+ })() })
54397
+ ] }),
54398
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
54399
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
54400
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon(selectedShiftId) }),
54401
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
54402
+ getShiftName(selectedShiftId).replace(/ Shift$/i, ""),
54403
+ " Shift"
54404
+ ] })
54033
54405
  ] })
54034
54406
  ] }) })
54035
54407
  ] }),
@@ -54225,21 +54597,65 @@ var LineCard = ({
54225
54597
  children: [
54226
54598
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 sm:mb-5 md:mb-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-start gap-2 sm:gap-3", children: [
54227
54599
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
54228
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg sm:text-xl font-semibold text-gray-900 break-words", children: line.line_name }),
54229
- supervisorEnabled && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1.5", children: supervisors && supervisors.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: supervisors.map((supervisor) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 bg-gray-50 rounded-full pl-0.5 pr-2.5 py-0.5 border border-gray-100 hover:border-gray-200 transition-all duration-300 ease-out group/supervisor hover:scale-150 hover:z-50 hover:shadow-lg relative", children: [
54230
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-6 h-6 rounded-full overflow-hidden bg-white border border-gray-100 shadow-sm flex-shrink-0", children: supervisor.profilePhotoUrl ? /* @__PURE__ */ jsxRuntime.jsx(
54231
- "img",
54232
- {
54233
- src: supervisor.profilePhotoUrl,
54234
- alt: supervisor.displayName,
54235
- className: "w-full h-full object-cover"
54236
- }
54237
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 text-[9px] font-bold text-gray-500 uppercase", children: getInitials(supervisor.displayName) }) }),
54238
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700 truncate max-w-[120px]", children: supervisor.displayName })
54239
- ] }, supervisor.userId)) }) : /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-gray-600", children: [
54240
- "Supervisor: ",
54241
- supervisorName || "Unassigned"
54242
- ] }) })
54600
+ /* @__PURE__ */ jsxRuntime.jsx(
54601
+ FittingTitle,
54602
+ {
54603
+ title: line.line_name,
54604
+ className: "text-[10px] sm:text-xs md:text-sm"
54605
+ }
54606
+ ),
54607
+ supervisorEnabled && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4", children: [
54608
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] font-semibold text-gray-400 uppercase tracking-wider mb-1.5", children: "Assigned To" }),
54609
+ supervisors && supervisors.length > 0 ? supervisors.length === 1 ? (
54610
+ // Single supervisor - just avatar with tooltip
54611
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-12 h-12 rounded-full bg-white border border-gray-100 shadow-sm flex-shrink-0 group/avatar hover:scale-110 transition-transform", children: [
54612
+ supervisors[0].profilePhotoUrl ? /* @__PURE__ */ jsxRuntime.jsx(
54613
+ "img",
54614
+ {
54615
+ src: supervisors[0].profilePhotoUrl,
54616
+ alt: supervisors[0].displayName,
54617
+ className: "w-full h-full object-cover rounded-full"
54618
+ }
54619
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 text-base font-bold text-gray-500 uppercase rounded-full", children: getInitials(supervisors[0].displayName) }),
54620
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-gray-900 text-white text-[10px] font-medium rounded shadow-lg opacity-0 group-hover/avatar:opacity-100 transition-opacity whitespace-nowrap pointer-events-none z-20", children: [
54621
+ supervisors[0].displayName,
54622
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-full left-1/2 -translate-x-1/2 -mt-[1px] border-4 border-transparent border-t-gray-900" })
54623
+ ] })
54624
+ ] })
54625
+ ) : (
54626
+ // Multiple supervisors - overlapping avatars
54627
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex -space-x-4 py-1", children: [
54628
+ supervisors.slice(0, 3).map((supervisor) => /* @__PURE__ */ jsxRuntime.jsxs(
54629
+ "div",
54630
+ {
54631
+ className: "relative inline-block w-12 h-12 rounded-full ring-2 ring-white bg-white shadow-sm z-0 hover:z-10 transition-all hover:scale-110 group/avatar",
54632
+ children: [
54633
+ supervisor.profilePhotoUrl ? /* @__PURE__ */ jsxRuntime.jsx(
54634
+ "img",
54635
+ {
54636
+ src: supervisor.profilePhotoUrl,
54637
+ alt: supervisor.displayName,
54638
+ className: "w-full h-full object-cover rounded-full"
54639
+ }
54640
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-100 text-sm font-bold text-gray-600 uppercase rounded-full", children: getInitials(supervisor.displayName) }),
54641
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-gray-900 text-white text-[10px] font-medium rounded shadow-lg opacity-0 group-hover/avatar:opacity-100 transition-opacity whitespace-nowrap pointer-events-none z-20", children: [
54642
+ supervisor.displayName,
54643
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-full left-1/2 -translate-x-1/2 -mt-[1px] border-4 border-transparent border-t-gray-900" })
54644
+ ] })
54645
+ ]
54646
+ },
54647
+ supervisor.userId
54648
+ )),
54649
+ supervisors.length > 3 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-12 h-12 rounded-full ring-2 ring-white bg-gray-100 items-center justify-center text-sm font-medium text-gray-600 z-0", children: [
54650
+ "+",
54651
+ supervisors.length - 3
54652
+ ] })
54653
+ ] })
54654
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-gray-600", children: [
54655
+ "Supervisor: ",
54656
+ supervisorName || "Unassigned"
54657
+ ] })
54658
+ ] })
54243
54659
  ] }),
54244
54660
  kpis && isOnTrack !== null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1.5 px-2.5 sm:px-3 py-1 sm:py-1.5 rounded-full text-xs font-medium flex-shrink-0 ${isOnTrack ? "bg-emerald-100 text-emerald-700 border border-emerald-200" : "bg-red-100 text-red-700 border border-red-200"}`, style: { minWidth: "fit-content" }, children: [
54245
54661
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-2 h-2 rounded-full ${isOnTrack ? "bg-emerald-500" : "bg-red-500"} animate-pulse` }),
@@ -54261,7 +54677,7 @@ var LineCard = ({
54261
54677
  ] })
54262
54678
  ] }),
54263
54679
  error && !kpis && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Unable to load metrics" }) }),
54264
- kpis && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 sm:space-y-5", children: [
54680
+ kpis && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 sm:space-y-5 pb-8 sm:pb-10", children: [
54265
54681
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
54266
54682
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider mb-1.5 sm:mb-2", children: "Efficiency" }),
54267
54683
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline justify-between", children: [
@@ -54298,16 +54714,6 @@ var LineCard = ({
54298
54714
  }
54299
54715
  }
54300
54716
  ) })
54301
- ] }),
54302
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
54303
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider mb-1.5 sm:mb-2", children: "Underperforming Workspaces" }),
54304
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [
54305
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-xl sm:text-2xl font-semibold ${kpis.underperformingWorkers.current === 0 ? "text-emerald-600" : kpis.underperformingWorkers.current <= 2 ? "text-yellow-600" : "text-red-600"}`, children: kpis.underperformingWorkers.current }),
54306
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs sm:text-sm text-gray-500 font-medium", children: [
54307
- "of ",
54308
- kpis.underperformingWorkers.total
54309
- ] })
54310
- ] })
54311
54717
  ] })
54312
54718
  ] }),
54313
54719
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-3 right-3 sm:bottom-4 sm:right-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 sm:p-2.5 rounded-full bg-gray-50 group-hover:bg-blue-50 transition-colors shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsx(outline.ArrowRightIcon, { className: "w-4 h-4 sm:w-5 sm:h-5 text-gray-400 group-hover:text-blue-600 transition-colors" }) }) })
@@ -54369,7 +54775,7 @@ var KPIsOverviewView = ({
54369
54775
  return map;
54370
54776
  }, [lineMetrics]);
54371
54777
  const visibleLineIds = React25__namespace.default.useMemo(() => lines.map((l) => l.id), [lines]);
54372
- const { supervisorNamesByLineId, supervisorsByLineId } = useSupervisorsByLineIds(visibleLineIds, {
54778
+ const { supervisorNamesByLineId, supervisorsByLineId, allSupervisorsMap } = useSupervisorsByLineIds(visibleLineIds, {
54373
54779
  enabled: supervisorEnabled && visibleLineIds.length > 0
54374
54780
  });
54375
54781
  React25.useEffect(() => {
@@ -54441,17 +54847,34 @@ var KPIsOverviewView = ({
54441
54847
  return `${startLabel} - ${endLabel}`;
54442
54848
  };
54443
54849
  const buildTopPerformerDisplay = (record) => {
54444
- const name = record.recipient_name || "Supervisor";
54850
+ let displayName = record.recipient_name || "Supervisor";
54851
+ if (record.first_name) {
54852
+ displayName = record.last_name ? `${record.first_name} ${record.last_name}` : record.first_name;
54853
+ } else if (record.recipient_user_id && allSupervisorsMap?.has(record.recipient_user_id)) {
54854
+ const supervisor = allSupervisorsMap.get(record.recipient_user_id);
54855
+ if (supervisor) {
54856
+ displayName = supervisor.displayName;
54857
+ }
54858
+ } else if (displayName.includes(".") || displayName.includes("@")) {
54859
+ const parts = displayName.split(/[.@]/);
54860
+ if (parts.length >= 2) {
54861
+ const firstName = parts[0].charAt(0).toUpperCase() + parts[0].slice(1);
54862
+ const lastName = parts[1].charAt(0).toUpperCase() + parts[1].slice(1);
54863
+ displayName = `${firstName} ${lastName}`;
54864
+ } else if (parts.length === 1) {
54865
+ displayName = parts[0].charAt(0).toUpperCase() + parts[0].slice(1);
54866
+ }
54867
+ }
54445
54868
  const efficiencyValue = typeof record.avg_efficiency === "number" ? record.avg_efficiency : Number.parseFloat(String(record.avg_efficiency));
54446
54869
  const efficiency = Number.isFinite(efficiencyValue) ? efficiencyValue : null;
54447
54870
  return {
54448
- name,
54871
+ name: displayName,
54449
54872
  role: "Sup.",
54450
54873
  unit: record.unit || "Line",
54451
54874
  periodLabel: formatTopPerformerWeek(record.period_start, record.period_end),
54452
54875
  efficiency,
54453
54876
  imageUrl: record.profile_photo_url || null,
54454
- initials: getInitials(name)
54877
+ initials: getInitials(displayName)
54455
54878
  };
54456
54879
  };
54457
54880
  const handleLineClick = (line, kpis) => {
@@ -54493,8 +54916,8 @@ var KPIsOverviewView = ({
54493
54916
  const currentShiftDetails = getCurrentShift(configuredTimezone, shiftConfig);
54494
54917
  const shiftName = (currentShiftDetails.shiftName || "Day").replace(/ Shift$/i, "");
54495
54918
  const showTopPerformerImage = Boolean(topPerformer.imageUrl) && !topPerformerImageError;
54496
- const hasTopPerformerEfficiency = typeof topPerformer.efficiency === "number" && Number.isFinite(topPerformer.efficiency);
54497
- const topPerformerEfficiencyLabel = topPerformerLoading ? "--" : typeof topPerformer.efficiency === "number" && Number.isFinite(topPerformer.efficiency) ? `${topPerformer.efficiency.toFixed(1)}%` : "--";
54919
+ typeof topPerformer.efficiency === "number" && Number.isFinite(topPerformer.efficiency);
54920
+ topPerformerLoading ? "--" : typeof topPerformer.efficiency === "number" && Number.isFinite(topPerformer.efficiency) ? `${topPerformer.efficiency.toFixed(1)}%` : "--";
54498
54921
  const getShiftIcon = (shiftId) => {
54499
54922
  const shiftNameLower = shiftName.toLowerCase();
54500
54923
  if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
@@ -54523,7 +54946,7 @@ var KPIsOverviewView = ({
54523
54946
  }
54524
54947
  ),
54525
54948
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
54526
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-gray-900", children: "Shop-floor overview" }),
54949
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-gray-900", children: "Overview" }),
54527
54950
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-emerald-500 animate-pulse ring-2 ring-emerald-500/20" })
54528
54951
  ] }) }),
54529
54952
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-12" })
@@ -54539,7 +54962,7 @@ var KPIsOverviewView = ({
54539
54962
  }
54540
54963
  ) }),
54541
54964
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
54542
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl md:text-2xl lg:text-3xl font-semibold text-gray-900 text-center", children: "Shop-floor overview" }),
54965
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl md:text-2xl lg:text-3xl font-semibold text-gray-900 text-center", children: "Overview" }),
54543
54966
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1 flex-shrink-0" })
54544
54967
  ] }) })
54545
54968
  ] }) })
@@ -54559,7 +54982,7 @@ var KPIsOverviewView = ({
54559
54982
  }
54560
54983
  ),
54561
54984
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
54562
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-gray-900", children: "Shop-floor overview" }),
54985
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-gray-900", children: "Overview" }),
54563
54986
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-emerald-500 animate-pulse ring-2 ring-emerald-500/20" })
54564
54987
  ] }) }),
54565
54988
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-12" })
@@ -54575,7 +54998,7 @@ var KPIsOverviewView = ({
54575
54998
  }
54576
54999
  ) }),
54577
55000
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
54578
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl md:text-2xl lg:text-3xl font-semibold text-gray-900 text-center", children: "Shop-floor overview" }),
55001
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl md:text-2xl lg:text-3xl font-semibold text-gray-900 text-center", children: "Overview" }),
54579
55002
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1 flex-shrink-0" })
54580
55003
  ] }) })
54581
55004
  ] }) })
@@ -54598,7 +55021,7 @@ var KPIsOverviewView = ({
54598
55021
  }
54599
55022
  ),
54600
55023
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
54601
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-gray-900", children: "Shop-floor overview" }),
55024
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-gray-900", children: "Overview" }),
54602
55025
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-emerald-500 animate-pulse ring-2 ring-emerald-500/20" })
54603
55026
  ] }) }),
54604
55027
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-12" })
@@ -54611,43 +55034,46 @@ var KPIsOverviewView = ({
54611
55034
  ] }),
54612
55035
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) }) })
54613
55036
  ] }),
54614
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 bg-white shadow-sm hover:shadow-md transition-all duration-300 ease-out hover:scale-[1.02] relative rounded-full pl-1.5 pr-4 py-1.5 flex items-center justify-between", children: [
54615
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
54616
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
54617
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 rounded-full border border-gray-100 overflow-hidden bg-gray-50", children: showTopPerformerImage ? /* @__PURE__ */ jsxRuntime.jsx(
54618
- "img",
55037
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 bg-white shadow-md hover:shadow-lg transition-all duration-300 ease-out hover:scale-[1.01] relative rounded-2xl border border-amber-100 pl-2 pr-4 py-1.5 flex items-center justify-between group", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 min-w-0", children: [
55038
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 rounded-full border-2 border-amber-100 overflow-hidden bg-amber-50 shadow-sm transition-transform group-hover:scale-105", children: showTopPerformerImage ? /* @__PURE__ */ jsxRuntime.jsx(
55039
+ "img",
55040
+ {
55041
+ src: topPerformer.imageUrl || "",
55042
+ alt: "Top Performer",
55043
+ className: "w-full h-full object-cover",
55044
+ onError: () => setTopPerformerImageError(true)
55045
+ }
55046
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-amber-50 text-sm font-bold text-amber-600", children: topPerformer.initials }) }) }),
55047
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
55048
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 leading-none mb-1", children: [
55049
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-amber-600 uppercase tracking-widest", children: "Performer of the week" }),
55050
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-1 h-1 bg-amber-200 rounded-full" }),
55051
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-semibold text-gray-400", children: topPerformerLoading ? "Loading" : topPerformer.periodLabel })
55052
+ ] }),
55053
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 leading-none", children: [
55054
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[140px]", children: /* @__PURE__ */ jsxRuntime.jsx(
55055
+ FittingTitle,
54619
55056
  {
54620
- src: topPerformer.imageUrl || "",
54621
- alt: "Top Performer",
54622
- className: "w-full h-full object-cover",
54623
- onError: () => setTopPerformerImageError(true)
55057
+ title: topPerformer.name,
55058
+ as: "span",
55059
+ className: "text-sm text-gray-900 font-bold"
54624
55060
  }
54625
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 text-[11px] font-semibold text-gray-600", children: topPerformer.initials }) }),
54626
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-1 -right-1 bg-white rounded-full p-1 shadow-sm border border-gray-100", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trophy, { className: "w-3 h-3 text-amber-500 fill-amber-500" }) })
54627
- ] }),
54628
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
54629
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 leading-none mb-0.5", children: [
54630
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-amber-600 uppercase tracking-wide", children: "Top Performer" }),
54631
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-0.5 h-0.5 bg-gray-300 rounded-full" }),
54632
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium text-gray-500", children: topPerformerLoading ? "Loading" : topPerformer.periodLabel })
54633
- ] }),
54634
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 leading-none", children: [
54635
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-gray-900", children: topPerformer.unit }),
54636
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-px h-2.5 bg-gray-200" }),
54637
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-gray-500", children: [
54638
- topPerformer.role,
54639
- " ",
54640
- topPerformer.name
54641
- ] })
54642
- ] })
55061
+ ) }),
55062
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-px h-3 bg-gray-200 flex-shrink-0" }),
55063
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[120px]", children: /* @__PURE__ */ jsxRuntime.jsx(
55064
+ FittingTitle,
55065
+ {
55066
+ title: topPerformer.unit,
55067
+ className: "text-xs font-medium text-gray-500"
55068
+ }
55069
+ ) })
54643
55070
  ] })
54644
- ] }),
54645
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-gray-700", children: topPerformerEfficiencyLabel })
54646
- ] })
55071
+ ] })
55072
+ ] }) })
54647
55073
  ] }),
54648
55074
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden sm:block", children: [
54649
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center relative mb-1", children: [
54650
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(
55075
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center relative mb-4 h-12", children: [
55076
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0 top-1/2 -translate-y-1/2 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(
54651
55077
  BackButtonMinimal,
54652
55078
  {
54653
55079
  onClick: handleBackClick,
@@ -54656,45 +55082,61 @@ var KPIsOverviewView = ({
54656
55082
  "aria-label": "Navigate back to previous page"
54657
55083
  }
54658
55084
  ) }),
54659
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
54660
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl md:text-2xl lg:text-3xl font-semibold text-gray-900 text-center", children: "Shop-floor overview" }),
54661
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1 flex-shrink-0" })
54662
- ] }) }),
54663
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 z-10 flex items-center gap-1.5 sm:gap-2 lg:gap-3 cursor-default group pr-2 sm:pr-4 xl:pr-6", children: [
54664
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative z-10", children: [
54665
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-7 h-7 sm:w-8 sm:h-8 md:w-9 md:h-9 lg:w-10 lg:h-10 xl:w-12 xl:h-12 rounded-full border border-gray-100 overflow-hidden shadow-sm transition-all duration-300", children: showTopPerformerImage ? /* @__PURE__ */ jsxRuntime.jsx(
54666
- "img",
54667
- {
54668
- src: topPerformer.imageUrl || "",
54669
- alt: "Top Performer",
54670
- className: "w-full h-full object-cover transform transition-transform duration-500 group-hover:scale-105",
54671
- onError: () => setTopPerformerImageError(true)
54672
- }
54673
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 text-[10px] sm:text-xs lg:text-sm font-semibold text-gray-600", children: topPerformer.initials }) }),
54674
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -bottom-0.5 sm:-bottom-1 -right-0.5 sm:-right-1 bg-white rounded-full p-0.5 sm:p-1 shadow-sm border border-gray-100 flex items-center justify-center ring-2 ring-white", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trophy, { className: "w-2 h-2 sm:w-2.5 sm:h-2.5 lg:w-3 lg:h-3 xl:w-3.5 xl:h-3.5 text-amber-500 fill-amber-500 transition-all duration-300" }) })
54675
- ] }),
54676
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center z-10 gap-0.5 min-w-0", children: [
54677
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 sm:gap-1.5 lg:gap-2 leading-none", children: [
54678
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[8px] sm:text-[9px] lg:text-[10px] font-bold text-amber-600 uppercase tracking-wide sm:tracking-widest transition-all duration-300 truncate", children: "Top Performer" }),
54679
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-0.5 h-0.5 bg-gray-300 rounded-full flex-shrink-0" }),
54680
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[8px] sm:text-[9px] lg:text-[10px] font-medium text-gray-500 transition-all duration-300 truncate", children: topPerformerLoading ? "Loading" : topPerformer.periodLabel })
55085
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
55086
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight", children: "Overview" }),
55087
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2.5 w-2.5 rounded-full bg-emerald-500 animate-pulse ring-4 ring-emerald-500/10 flex-shrink-0" })
55088
+ ] }),
55089
+ !topPerformerLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 z-10", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-2xl border border-amber-200 shadow-md pl-1.5 pr-4 py-1.5 flex items-center gap-4 transition-all hover:shadow-lg hover:border-amber-300 group", children: [
55090
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 rounded-full ring-2 ring-amber-100 overflow-hidden bg-amber-50 shadow-inner flex-shrink-0 transition-transform group-hover:scale-105", children: showTopPerformerImage ? /* @__PURE__ */ jsxRuntime.jsx(
55091
+ "img",
55092
+ {
55093
+ src: topPerformer.imageUrl || "",
55094
+ alt: topPerformer.name,
55095
+ className: "w-full h-full object-cover",
55096
+ onError: () => setTopPerformerImageError(true)
55097
+ }
55098
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-sm font-bold text-amber-600 uppercase", children: topPerformer.initials }) }) }),
55099
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-0", children: [
55100
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-[10px] leading-tight mb-1", children: [
55101
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-bold text-amber-600 uppercase tracking-widest", children: "Performer of the week" }),
55102
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-amber-200 opacity-50", children: "\u2022" }),
55103
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-gray-400", children: topPerformer.periodLabel })
54681
55104
  ] }),
54682
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 sm:gap-1.5 lg:gap-2 xl:gap-3 mt-0.5 transition-all duration-300 min-w-0", children: [
54683
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm lg:text-base font-semibold text-gray-900 tracking-tight transition-all duration-300 truncate", children: topPerformer.unit }),
54684
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-px h-2.5 sm:h-3 lg:h-3.5 bg-gray-200 flex-shrink-0" }),
54685
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] sm:text-[10px] lg:text-xs font-bold text-gray-700 transition-all duration-300 truncate whitespace-nowrap", children: hasTopPerformerEfficiency ? `${topPerformer.efficiency?.toFixed(1)}% Eff.` : "TBD" })
55105
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 leading-tight", children: [
55106
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[140px]", children: /* @__PURE__ */ jsxRuntime.jsx(
55107
+ FittingTitle,
55108
+ {
55109
+ title: topPerformer.name,
55110
+ as: "span",
55111
+ className: "text-sm text-gray-900 font-bold"
55112
+ }
55113
+ ) }),
55114
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-px h-3.5 bg-gray-200 flex-shrink-0" }),
55115
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[150px]", children: /* @__PURE__ */ jsxRuntime.jsx(
55116
+ FittingTitle,
55117
+ {
55118
+ title: topPerformer.unit,
55119
+ className: "text-xs font-medium text-gray-500"
55120
+ }
55121
+ ) })
54686
55122
  ] })
54687
55123
  ] })
54688
- ] })
55124
+ ] }) })
54689
55125
  ] }),
54690
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 bg-blue-50 px-3 py-2 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3 md:gap-4", children: [
54691
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base md:text-lg font-medium text-blue-600", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) }),
54692
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" }),
54693
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: formatLocalDate2(/* @__PURE__ */ new Date()) }),
54694
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" }),
54695
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
54696
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon(currentShiftDetails.shiftId) }),
54697
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
55126
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-blue-50/50 px-4 py-2 rounded-xl border border-blue-100/50 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-6", children: [
55127
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-700", children: [
55128
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4 opacity-70", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", 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" }) }),
55129
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-semibold tabular-nums", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) })
55130
+ ] }),
55131
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
55132
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
55133
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4 opacity-70", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
55134
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: formatLocalDate2(/* @__PURE__ */ new Date()) })
55135
+ ] }),
55136
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
55137
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
55138
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon(currentShiftDetails.shiftId) }),
55139
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-semibold uppercase tracking-wider", children: [
54698
55140
  shiftName,
54699
55141
  " Shift"
54700
55142
  ] })
@@ -54742,16 +55184,22 @@ var HeaderRibbon = React25.memo(({
54742
55184
  ] }),
54743
55185
  showTimer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(IsolatedTimer, {}) }) })
54744
55186
  ] }),
54745
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block mt-3 bg-blue-50 px-3 py-2 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3 md:gap-4", children: [
55187
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block mt-3 bg-blue-50/50 px-4 py-2 rounded-xl border border-blue-100/50 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-6", children: [
54746
55188
  showTimer && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
54747
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base md:text-lg font-medium text-blue-600", children: /* @__PURE__ */ jsxRuntime.jsx(IsolatedTimer, {}) }),
54748
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
55189
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-700", children: [
55190
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4 opacity-70", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", 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" }) }),
55191
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-semibold tabular-nums", children: /* @__PURE__ */ jsxRuntime.jsx(IsolatedTimer, {}) })
55192
+ ] }),
55193
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" })
54749
55194
  ] }),
54750
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: currentDate }),
54751
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" }),
54752
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
54753
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: shiftIcon }),
54754
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
55195
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
55196
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4 opacity-70", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
55197
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: currentDate })
55198
+ ] }),
55199
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
55200
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
55201
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: shiftIcon }),
55202
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-semibold uppercase tracking-wider", children: [
54755
55203
  shiftName.replace(/ Shift$/i, ""),
54756
55204
  " Shift"
54757
55205
  ] })
@@ -58650,14 +59098,6 @@ var getInitialTab = (sourceType, defaultTab, fromMonthly, urlDate) => {
58650
59098
  }
58651
59099
  return "overview";
58652
59100
  };
58653
- var getInitials3 = (name) => {
58654
- if (!name) return "??";
58655
- const parts = name.trim().split(" ");
58656
- if (parts.length >= 2) {
58657
- return `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();
58658
- }
58659
- return name.substring(0, 2).toUpperCase();
58660
- };
58661
59101
  var chartCardVariants = {
58662
59102
  initial: { opacity: 0, y: 10 },
58663
59103
  animate: {
@@ -58739,7 +59179,7 @@ var WorkspaceDetailView = ({
58739
59179
  const prewarmedClipsRef = React25.useRef(/* @__PURE__ */ new Set());
58740
59180
  const prewarmInFlightRef = React25.useRef(/* @__PURE__ */ new Set());
58741
59181
  const isClipsEnabled = dashboardConfig?.clipsConfig?.enabled ?? true;
58742
- const supervisorEnabled = dashboardConfig?.supervisorConfig?.enabled || false;
59182
+ dashboardConfig?.supervisorConfig?.enabled || false;
58743
59183
  const effectiveLineId = lineId || selectedLineId;
58744
59184
  const { shiftConfig, isLoading: isShiftConfigLoading, isFromDatabase: isShiftConfigFromDatabase } = useDynamicShiftConfig(effectiveLineId);
58745
59185
  const currentShiftDetails = React25.useMemo(() => {
@@ -59371,29 +59811,16 @@ var WorkspaceDetailView = ({
59371
59811
  "aria-label": "Navigate back to previous page"
59372
59812
  }
59373
59813
  ) }),
59374
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-1/2 transform -translate-x-1/2 max-w-[calc(100%-200px)]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-2", children: [
59375
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
59376
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg md:text-xl lg:text-2xl xl:text-3xl font-semibold text-gray-900 truncate", children: formattedWorkspaceName }),
59377
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex h-2.5 w-2.5", children: [
59378
- isLive && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" }),
59379
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
59380
- "relative inline-flex rounded-full h-2.5 w-2.5",
59381
- isLive ? "bg-green-500" : "bg-red-500"
59382
- ) })
59383
- ] })
59384
- ] }),
59385
- supervisorEnabled && supervisors && supervisors.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2 justify-center", children: supervisors.map((supervisor) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 bg-gray-50 rounded-full pl-0.5 pr-2.5 py-0.5 border border-gray-100 hover:border-gray-200 transition-all duration-300 ease-out group/supervisor hover:scale-150 hover:z-50 hover:shadow-lg relative", children: [
59386
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-6 h-6 rounded-full overflow-hidden bg-white border border-gray-100 shadow-sm flex-shrink-0", children: supervisor.profilePhotoUrl ? /* @__PURE__ */ jsxRuntime.jsx(
59387
- "img",
59388
- {
59389
- src: supervisor.profilePhotoUrl,
59390
- alt: supervisor.displayName,
59391
- className: "w-full h-full object-cover"
59392
- }
59393
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 text-[9px] font-bold text-gray-500 uppercase", children: getInitials3(supervisor.displayName) }) }),
59394
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700 truncate max-w-[120px]", children: supervisor.displayName })
59395
- ] }, supervisor.userId)) })
59396
- ] }) }),
59814
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-1/2 transform -translate-x-1/2 max-w-[calc(100%-200px)]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
59815
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg md:text-xl lg:text-2xl xl:text-3xl font-semibold text-gray-900 truncate", children: formattedWorkspaceName }),
59816
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex h-2.5 w-2.5", children: [
59817
+ isLive && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" }),
59818
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
59819
+ "relative inline-flex rounded-full h-2.5 w-2.5",
59820
+ isLive ? "bg-green-500" : "bg-red-500"
59821
+ ) })
59822
+ ] })
59823
+ ] }) }) }),
59397
59824
  activeTab !== "monthly_history" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-0 top-0 flex flex-col items-end gap-1", children: workspaceHealth && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-500", children: [
59398
59825
  "Last update: ",
59399
59826
  workspaceHealth.timeSinceLastUpdate
@@ -59425,28 +59852,32 @@ var WorkspaceDetailView = ({
59425
59852
  })() })
59426
59853
  ] })
59427
59854
  ] }),
59428
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block mt-3 bg-blue-50 px-3 py-2 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3 md:gap-4", children: [
59429
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: (() => {
59430
- const monthBounds2 = getMonthKeyBounds(selectedYear, selectedMonth);
59431
- const normalizedRange = normalizeDateKeyRange(rangeStart, rangeEnd, monthBounds2.startKey, monthBounds2.endKey);
59432
- const startDate = new Date(normalizedRange.startKey);
59433
- const endDate = new Date(normalizedRange.endKey);
59434
- const isFullMonth = normalizedRange.startKey === monthBounds2.startKey && normalizedRange.endKey === monthBounds2.endKey;
59435
- if (isFullMonth) {
59855
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block mt-3 bg-blue-50/50 px-4 py-2 rounded-xl border border-blue-100/50 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-6", children: [
59856
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
59857
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4 opacity-70", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
59858
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium", children: (() => {
59859
+ const monthBounds2 = getMonthKeyBounds(selectedYear, selectedMonth);
59860
+ const normalizedRange = normalizeDateKeyRange(rangeStart, rangeEnd, monthBounds2.startKey, monthBounds2.endKey);
59861
+ const startDate = new Date(normalizedRange.startKey);
59862
+ const endDate = new Date(normalizedRange.endKey);
59863
+ const isFullMonth = normalizedRange.startKey === monthBounds2.startKey && normalizedRange.endKey === monthBounds2.endKey;
59864
+ if (isFullMonth) {
59865
+ return `${startDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })} - ${endDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`;
59866
+ }
59436
59867
  return `${startDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })} - ${endDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`;
59437
- }
59438
- return `${startDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })} - ${endDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`;
59439
- })() }),
59440
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" }),
59441
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
59442
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: (() => {
59868
+ })() })
59869
+ ] }),
59870
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
59871
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
59872
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: (() => {
59443
59873
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
59444
59874
  const shiftName = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
59445
59875
  return getShiftIcon(shiftName);
59446
59876
  })() }),
59447
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: (() => {
59877
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: (() => {
59448
59878
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
59449
- return shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
59879
+ const name = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
59880
+ return name.replace(/ Shift$/i, "") + " Shift";
59450
59881
  })() })
59451
59882
  ] })
59452
59883
  ] }) })
@@ -59459,28 +59890,37 @@ var WorkspaceDetailView = ({
59459
59890
  ] }),
59460
59891
  !date && !shift && !usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(LiveTimer, {}) }) }) : date ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-amber-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-amber-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : null
59461
59892
  ] }),
59462
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block mt-3 bg-blue-50 px-3 py-2 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3 md:gap-4", children: [
59893
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block mt-3 bg-blue-50/50 px-4 py-2 rounded-xl border border-blue-100/50 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-6", children: [
59463
59894
  !date && !shift && !usingFallbackData && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
59464
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base md:text-lg font-medium text-blue-600", children: /* @__PURE__ */ jsxRuntime.jsx(LiveTimer, {}) }),
59465
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
59895
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-700", children: [
59896
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4 opacity-70", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", 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" }) }),
59897
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-semibold tabular-nums", children: /* @__PURE__ */ jsxRuntime.jsx(LiveTimer, {}) })
59898
+ ] }),
59899
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" })
59900
+ ] }),
59901
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
59902
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4 opacity-70", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
59903
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium", children: formatISTDate2(new Date(workspace.date)) })
59466
59904
  ] }),
59467
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: formatISTDate2(new Date(workspace.date)) }),
59468
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" }),
59905
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
59469
59906
  date && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
59470
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs font-medium bg-blue-200 text-blue-800 rounded-md", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }),
59471
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
59907
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs font-medium bg-blue-100 text-blue-700 border border-blue-200 rounded-md", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }),
59908
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" })
59472
59909
  ] }),
59473
59910
  !date && !shift && usingFallbackData && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
59474
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-2 py-1 text-xs font-medium bg-amber-100 text-amber-700 rounded-md", children: [
59911
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-2 py-1 text-xs font-medium bg-amber-50 text-amber-700 border border-amber-200 rounded-md", children: [
59475
59912
  "Latest available data (",
59476
59913
  getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00"),
59477
59914
  ")"
59478
59915
  ] }),
59479
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
59916
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" })
59480
59917
  ] }),
59481
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
59482
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon(workspace.shift_type) }),
59483
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: workspace.shift_type })
59918
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
59919
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon(workspace.shift_type) }),
59920
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
59921
+ workspace.shift_type.replace(/ Shift$/i, ""),
59922
+ " Shift"
59923
+ ] })
59484
59924
  ] })
59485
59925
  ] }) })
59486
59926
  ] }) }),
@@ -66179,6 +66619,7 @@ exports.FileManagerFilters = FileManagerFilters;
66179
66619
  exports.FilterDialogTrigger = FilterDialogTrigger;
66180
66620
  exports.FirstTimeLoginDebug = FirstTimeLoginDebug;
66181
66621
  exports.FirstTimeLoginHandler = FirstTimeLoginHandler;
66622
+ exports.FittingTitle = FittingTitle;
66182
66623
  exports.GaugeChart = GaugeChart;
66183
66624
  exports.GridComponentsPlaceholder = GridComponentsPlaceholder;
66184
66625
  exports.HamburgerButton = HamburgerButton;
@@ -66567,6 +67008,7 @@ exports.useWorkspaceDisplayName = useWorkspaceDisplayName;
66567
67008
  exports.useWorkspaceDisplayNames = useWorkspaceDisplayNames;
66568
67009
  exports.useWorkspaceDisplayNamesMap = useWorkspaceDisplayNamesMap;
66569
67010
  exports.useWorkspaceHealthById = useWorkspaceHealthById;
67011
+ exports.useWorkspaceHealthLastSeen = useWorkspaceHealthLastSeen;
66570
67012
  exports.useWorkspaceHealthStatus = useWorkspaceHealthStatus;
66571
67013
  exports.useWorkspaceMetrics = useWorkspaceMetrics;
66572
67014
  exports.useWorkspaceNavigation = useWorkspaceNavigation;