@optifye/dashboard-core 6.12.21 → 6.12.23

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
@@ -9933,7 +9933,8 @@ var LinesService = class {
9933
9933
  line.video_grid_metric_mode,
9934
9934
  line.assembly ?? false
9935
9935
  ),
9936
- recentFlowWindowMinutes: line.recent_flow_window_minutes ?? 7
9936
+ recentFlowWindowMinutes: line.recent_flow_window_minutes ?? 7,
9937
+ factoryAreaId: line.factory_area_id ?? null
9937
9938
  }));
9938
9939
  } catch (error) {
9939
9940
  console.error("Error fetching lines:", error);
@@ -9992,7 +9993,8 @@ var LinesService = class {
9992
9993
  line.video_grid_metric_mode,
9993
9994
  line.assembly ?? false
9994
9995
  ),
9995
- recentFlowWindowMinutes: line.recent_flow_window_minutes ?? 7
9996
+ recentFlowWindowMinutes: line.recent_flow_window_minutes ?? 7,
9997
+ factoryAreaId: line.factory_area_id ?? null
9996
9998
  }));
9997
9999
  } catch (error) {
9998
10000
  console.error("Error fetching all lines:", error);
@@ -10059,7 +10061,8 @@ var LinesService = class {
10059
10061
  data.video_grid_metric_mode,
10060
10062
  data.assembly ?? false
10061
10063
  ),
10062
- recentFlowWindowMinutes: data.recent_flow_window_minutes ?? 7
10064
+ recentFlowWindowMinutes: data.recent_flow_window_minutes ?? 7,
10065
+ factoryAreaId: data.factory_area_id ?? null
10063
10066
  };
10064
10067
  } catch (error) {
10065
10068
  console.error("Error fetching line:", error);
@@ -11673,6 +11676,9 @@ var lineLeaderboardService = {
11673
11676
  if (typeof params.limit === "number") {
11674
11677
  searchParams.set("limit", params.limit.toString());
11675
11678
  }
11679
+ if (params.includeBelowThreshold) {
11680
+ searchParams.set("include_below_threshold", "true");
11681
+ }
11676
11682
  const data = await fetchBackendJson(
11677
11683
  supabase,
11678
11684
  `/api/dashboard/line-leaderboard-daily?${searchParams.toString()}`
@@ -14697,11 +14703,22 @@ var transformMonitorWorkspaceMetrics = ({
14697
14703
  actionType: item.action_type,
14698
14704
  actionName: item.action_name
14699
14705
  }),
14706
+ factory_area_id: item.factory_area_id ?? null,
14707
+ factory_area_key: item.factory_area_key ?? null,
14708
+ factory_area_name: item.factory_area_name ?? null,
14709
+ factory_area_enabled: item.factory_area_enabled ?? null,
14710
+ leaderboard_metric_kind: item.leaderboard_metric_kind ?? void 0,
14711
+ leaderboard_value: item.leaderboard_value ?? null,
14712
+ avg_recent_flow: item.avg_recent_flow ?? null,
14700
14713
  recent_flow_percent: item.recent_flow_percent ?? null,
14701
14714
  recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
14702
14715
  recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
14703
14716
  recent_flow_computed_at: item.recent_flow_computed_at ?? null,
14704
14717
  recent_flow_forced_zero_after_shift: item.recent_flow_forced_zero_after_shift ?? null,
14718
+ video_grid_green_streak_active: item.video_grid_green_streak_active ?? null,
14719
+ video_grid_green_streak_minutes: item.video_grid_green_streak_minutes ?? null,
14720
+ video_grid_green_streak_anchor_at: item.video_grid_green_streak_anchor_at ?? null,
14721
+ video_grid_green_streak_started_at: item.video_grid_green_streak_started_at ?? null,
14705
14722
  scheduled_break_active: item.scheduled_break_active ?? false,
14706
14723
  incoming_wip_current: item.incoming_wip_current ?? null,
14707
14724
  incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
@@ -14721,12 +14738,12 @@ var logDebug = (...args) => {
14721
14738
  if (!DEBUG_DASHBOARD_LOGS) return;
14722
14739
  console.log(...args);
14723
14740
  };
14724
- var buildMetricsScopeKey = (lineId, lineIds) => {
14741
+ var buildMetricsScopeKey = (lineId, lineIds, blueComparisonLineIds) => {
14725
14742
  const normalizedLineIds = Array.from(new Set((lineIds || []).filter(Boolean))).sort();
14726
- if (normalizedLineIds.length > 0) {
14727
- return `${lineId}|${normalizedLineIds.join(",")}`;
14728
- }
14729
- return lineId;
14743
+ const normalizedBlueComparisonLineIds = Array.from(new Set((blueComparisonLineIds || []).filter(Boolean))).sort();
14744
+ const lineKey = normalizedLineIds.length > 0 ? normalizedLineIds.join(",") : lineId;
14745
+ const comparisonKey = normalizedBlueComparisonLineIds.length > 0 ? normalizedBlueComparisonLineIds.join(",") : lineKey;
14746
+ return `${lineId}|${lineKey}|blue:${comparisonKey}`;
14730
14747
  };
14731
14748
  var parseEfficiencyLegend = (legend) => {
14732
14749
  if (!legend) return null;
@@ -14748,6 +14765,7 @@ var useDashboardMetrics = ({
14748
14765
  onLineMetricsUpdate,
14749
14766
  lineId,
14750
14767
  lineIds,
14768
+ blueComparisonLineIds,
14751
14769
  userAccessibleLineIds,
14752
14770
  enabled = true
14753
14771
  }) => {
@@ -14770,6 +14788,10 @@ var useDashboardMetrics = ({
14770
14788
  const sourceLineIds = lineIds !== void 0 ? lineIds : userAccessibleLineIds !== void 0 ? userAccessibleLineIds : configuredLineIds;
14771
14789
  return Array.from(new Set((sourceLineIds || []).filter(Boolean)));
14772
14790
  }, [lineIds, userAccessibleLineIds, configuredLineIds]);
14791
+ const normalizedBlueComparisonLineIds = React144.useMemo(
14792
+ () => Array.from(new Set((blueComparisonLineIds || []).filter(Boolean))),
14793
+ [blueComparisonLineIds]
14794
+ );
14773
14795
  const { shiftConfig: staticShiftConfig } = useDashboardConfig();
14774
14796
  const {
14775
14797
  shiftConfigMap: multiLineShiftConfigMap,
@@ -14807,7 +14829,7 @@ var useDashboardMetrics = ({
14807
14829
  const supabase = useSupabase();
14808
14830
  const [metrics2, setMetrics] = React144.useState({ workspaceMetrics: [], lineMetrics: [] });
14809
14831
  const [metricsLineId, setMetricsLineId] = React144.useState(lineId ?? null);
14810
- const [metricsScopeKey, setMetricsScopeKey] = React144.useState(() => buildMetricsScopeKey(lineId, lineIds));
14832
+ const [metricsScopeKey, setMetricsScopeKey] = React144.useState(() => buildMetricsScopeKey(lineId, lineIds, blueComparisonLineIds));
14811
14833
  const [isLoading, setIsLoading] = React144.useState(true);
14812
14834
  const [error, setError] = React144.useState(null);
14813
14835
  const lineIdRef = React144.useRef(lineId);
@@ -14849,8 +14871,12 @@ var useDashboardMetrics = ({
14849
14871
  [entityConfig.companyId]
14850
14872
  );
14851
14873
  const requestedScopeKey = React144.useMemo(
14852
- () => buildMetricsScopeKey(lineId, isFactoryView ? targetFactoryLineIds : void 0),
14853
- [isFactoryView, lineId, targetFactoryLineIds]
14874
+ () => buildMetricsScopeKey(
14875
+ lineId,
14876
+ isFactoryView ? targetFactoryLineIds : void 0,
14877
+ normalizedBlueComparisonLineIds.length ? normalizedBlueComparisonLineIds : void 0
14878
+ ),
14879
+ [isFactoryView, lineId, targetFactoryLineIds, normalizedBlueComparisonLineIds]
14854
14880
  );
14855
14881
  React144.useEffect(() => {
14856
14882
  lineIdRef.current = lineId;
@@ -14880,12 +14906,15 @@ var useDashboardMetrics = ({
14880
14906
  const isFactory = currentLineIdToUse === factoryViewId;
14881
14907
  const targetLineIds = isFactory ? targetFactoryLineIds : [currentLineIdToUse];
14882
14908
  const targetLineIdsKey = targetLineIds.slice().sort().join(",");
14909
+ const effectiveBlueComparisonLineIds = normalizedBlueComparisonLineIds.length ? normalizedBlueComparisonLineIds : targetLineIds;
14910
+ const blueComparisonLineIdsKey = effectiveBlueComparisonLineIds.slice().sort().join(",");
14883
14911
  const usesShiftGroups = isFactory && shiftGroups.length > 0;
14884
14912
  const singleShiftDetails = usesShiftGroups ? null : shiftConfig ? getCurrentShift(defaultTimezone, shiftConfig) : shiftGroups.length === 1 ? { date: shiftGroups[0].date, shiftId: shiftGroups[0].shiftId } : getCurrentShift(defaultTimezone, staticShiftConfig);
14885
- const fetchKey = usesShiftGroups ? `factory|${companyId || "unknown"}|${shiftGroupsKey}` : isFactory ? `factory|${companyId || "unknown"}|${singleShiftDetails?.date}|${singleShiftDetails?.shiftId}|${targetLineIdsKey}` : `${currentLineIdToUse}|${companyId || "unknown"}|${singleShiftDetails?.date}|${singleShiftDetails?.shiftId}`;
14913
+ const fetchKey = usesShiftGroups ? `factory|${companyId || "unknown"}|${shiftGroupsKey}|blue:${blueComparisonLineIdsKey}` : isFactory ? `factory|${companyId || "unknown"}|${singleShiftDetails?.date}|${singleShiftDetails?.shiftId}|${targetLineIdsKey}|blue:${blueComparisonLineIdsKey}` : `${currentLineIdToUse}|${companyId || "unknown"}|${singleShiftDetails?.date}|${singleShiftDetails?.shiftId}|blue:${blueComparisonLineIdsKey}`;
14886
14914
  const responseScopeKey = buildMetricsScopeKey(
14887
14915
  currentLineIdToUse,
14888
- isFactory ? targetLineIds : void 0
14916
+ isFactory ? targetLineIds : void 0,
14917
+ normalizedBlueComparisonLineIds.length ? normalizedBlueComparisonLineIds : void 0
14889
14918
  );
14890
14919
  logDebug("[useDashboardMetrics] Fetch key details:", {
14891
14920
  isFactory,
@@ -14915,6 +14944,7 @@ var useDashboardMetrics = ({
14915
14944
  logDebug("[useDashboardMetrics] Skipping fetch: no target line IDs after scope filtering");
14916
14945
  setMetrics({
14917
14946
  workspaceMetrics: [],
14947
+ blueComparisonWorkspaceMetrics: [],
14918
14948
  lineMetrics: [],
14919
14949
  metadata: void 0,
14920
14950
  efficiencyLegend: DEFAULT_EFFICIENCY_LEGEND
@@ -14925,6 +14955,7 @@ var useDashboardMetrics = ({
14925
14955
  return;
14926
14956
  }
14927
14957
  let allWorkspaceMetrics = [];
14958
+ let allBlueComparisonWorkspaceMetrics = [];
14928
14959
  let allLineMetrics = [];
14929
14960
  let hasFlowBuffers = false;
14930
14961
  let idleTimeVlmByLine = {};
@@ -14932,7 +14963,8 @@ var useDashboardMetrics = ({
14932
14963
  const forceParam = force ? "&force_refresh=true" : "";
14933
14964
  const buildMetricsEndpoint = (params) => {
14934
14965
  const lineIdsParam = isFactory ? `line_ids=${params.groupLineIds.join(",")}` : `line_id=${params.groupLineIds[0]}`;
14935
- return `/api/dashboard/metrics?${lineIdsParam}&date=${params.date}&shift_id=${params.shiftId}&company_id=${companyId}${forceParam}`;
14966
+ const blueComparisonParam = effectiveBlueComparisonLineIds.length ? `&blue_comparison_line_ids=${effectiveBlueComparisonLineIds.join(",")}` : "";
14967
+ return `/api/dashboard/metrics?${lineIdsParam}${blueComparisonParam}&date=${params.date}&shift_id=${params.shiftId}&company_id=${companyId}${forceParam}`;
14936
14968
  };
14937
14969
  if (usesShiftGroups) {
14938
14970
  logDebug("[useDashboardMetrics] Factory view shift groups fetch:", {
@@ -14982,10 +15014,16 @@ var useDashboardMetrics = ({
14982
15014
  if (result.workspace_metrics) {
14983
15015
  allWorkspaceMetrics.push(...result.workspace_metrics);
14984
15016
  }
15017
+ if (result.blue_comparison_workspace_metrics) {
15018
+ allBlueComparisonWorkspaceMetrics.push(...result.blue_comparison_workspace_metrics);
15019
+ }
14985
15020
  if (result.line_metrics) {
14986
15021
  allLineMetrics.push(...result.line_metrics);
14987
15022
  }
14988
15023
  });
15024
+ if (allBlueComparisonWorkspaceMetrics.length === 0) {
15025
+ allBlueComparisonWorkspaceMetrics = allWorkspaceMetrics;
15026
+ }
14989
15027
  logDebug(`[useDashboardMetrics] \u{1F4CA} Merged metrics from ${results.length} shift groups:`, {
14990
15028
  workspaceCount: allWorkspaceMetrics.length,
14991
15029
  lineMetricsCount: allLineMetrics.length
@@ -15023,6 +15061,7 @@ var useDashboardMetrics = ({
15023
15061
  lineCount: backendData.line_metrics?.length || 0
15024
15062
  });
15025
15063
  allWorkspaceMetrics = backendData.workspace_metrics || [];
15064
+ allBlueComparisonWorkspaceMetrics = backendData.blue_comparison_workspace_metrics || allWorkspaceMetrics;
15026
15065
  allLineMetrics = backendData.line_metrics || [];
15027
15066
  hasFlowBuffers = Boolean(backendData?.metadata?.has_flow_buffers);
15028
15067
  if (backendData?.metadata?.idle_time_vlm_by_line && typeof backendData.metadata.idle_time_vlm_by_line === "object") {
@@ -15041,8 +15080,19 @@ var useDashboardMetrics = ({
15041
15080
  shouldOverrideShiftType: (metricLineId) => isFactoryView ? Boolean(multiLineShiftConfigMap.get(metricLineId)) : Boolean(shiftConfig),
15042
15081
  fallbackShiftConfig: staticShiftConfig
15043
15082
  });
15083
+ const transformedBlueComparisonWorkspaceData = allBlueComparisonWorkspaceMetrics === allWorkspaceMetrics ? transformedWorkspaceData : transformMonitorWorkspaceMetrics({
15084
+ rows: allBlueComparisonWorkspaceMetrics,
15085
+ companyId: companyId || "",
15086
+ workspaceConfig: effectiveWorkspaceConfig,
15087
+ appTimezone: detailTimezone,
15088
+ lineMetrics: allLineMetrics,
15089
+ resolveShiftConfig: (metricLineId) => isFactoryView ? multiLineShiftConfigMap.get(metricLineId) || staticShiftConfig : shiftConfig || staticShiftConfig,
15090
+ shouldOverrideShiftType: (metricLineId) => isFactoryView ? Boolean(multiLineShiftConfigMap.get(metricLineId)) : Boolean(shiftConfig),
15091
+ fallbackShiftConfig: staticShiftConfig
15092
+ });
15044
15093
  const newMetricsState = {
15045
15094
  workspaceMetrics: transformedWorkspaceData,
15095
+ blueComparisonWorkspaceMetrics: transformedBlueComparisonWorkspaceData.length ? transformedBlueComparisonWorkspaceData : transformedWorkspaceData,
15046
15096
  lineMetrics: allLineMetrics || [],
15047
15097
  metadata: { hasFlowBuffers, idleTimeVlmByLine },
15048
15098
  efficiencyLegend: efficiencyLegend ?? DEFAULT_EFFICIENCY_LEGEND
@@ -15113,6 +15163,7 @@ var useDashboardMetrics = ({
15113
15163
  shiftGroupsKey,
15114
15164
  configuredLineIds,
15115
15165
  targetFactoryLineIds,
15166
+ normalizedBlueComparisonLineIds,
15116
15167
  isFactoryView,
15117
15168
  multiLineShiftConfigMap,
15118
15169
  staticShiftConfig,
@@ -15553,9 +15604,10 @@ var useDashboardMetrics = ({
15553
15604
  const isCurrentScopeResolved = metricsScopeKey === requestedScopeKey;
15554
15605
  const hasLastGoodMetrics = metrics2.workspaceMetrics.length > 0 || metrics2.lineMetrics.length > 0;
15555
15606
  const canReuseLastGoodMetrics = hasLastGoodMetrics && !isCurrentScopeResolved && (isLoading || !!error);
15556
- const safeMetrics = isCurrentScopeResolved || canReuseLastGoodMetrics ? metrics2 : { workspaceMetrics: [], lineMetrics: [], metadata: void 0, efficiencyLegend: DEFAULT_EFFICIENCY_LEGEND };
15607
+ const safeMetrics = isCurrentScopeResolved || canReuseLastGoodMetrics ? metrics2 : { workspaceMetrics: [], blueComparisonWorkspaceMetrics: [], lineMetrics: [], metadata: void 0, efficiencyLegend: DEFAULT_EFFICIENCY_LEGEND };
15557
15608
  return {
15558
15609
  workspaceMetrics: safeMetrics?.workspaceMetrics || [],
15610
+ blueComparisonWorkspaceMetrics: safeMetrics?.blueComparisonWorkspaceMetrics || safeMetrics?.workspaceMetrics || [],
15559
15611
  lineMetrics: safeMetrics?.lineMetrics || [],
15560
15612
  efficiencyLegend: safeMetrics?.efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND,
15561
15613
  metadata: safeMetrics?.metadata,
@@ -22173,6 +22225,77 @@ var buildKpiLineHierarchy = (lines) => {
22173
22225
  };
22174
22226
  };
22175
22227
 
22228
+ // src/lib/utils/leaderboardGrouping.ts
22229
+ var isFiniteNumber2 = (value) => typeof value === "number" && Number.isFinite(value);
22230
+ var getEnabledFactoryArea = (line) => {
22231
+ if (!line.factory_area_id) return null;
22232
+ if (line.factory_area_enabled !== true) return null;
22233
+ const areaName = line.factory_area_name?.trim();
22234
+ if (!areaName) return null;
22235
+ return { id: line.factory_area_id, name: areaName };
22236
+ };
22237
+ var getLineEfficiency = (lineId, efficiencyByLineId, isLoading) => {
22238
+ if (efficiencyByLineId.has(lineId)) {
22239
+ const value = efficiencyByLineId.get(lineId);
22240
+ return isFiniteNumber2(value) ? value : null;
22241
+ }
22242
+ if (isLoading) return null;
22243
+ return 0;
22244
+ };
22245
+ var buildLineLeaderboardRows = ({
22246
+ lines,
22247
+ efficiencyByLineId,
22248
+ fallbackEfficiencyByLineId,
22249
+ isLoading
22250
+ }) => {
22251
+ const rows = [];
22252
+ const areaGroups = /* @__PURE__ */ new Map();
22253
+ lines.forEach((line) => {
22254
+ const area = getEnabledFactoryArea(line);
22255
+ if (!area) {
22256
+ const efficiency = getLineEfficiency(line.id, efficiencyByLineId, isLoading);
22257
+ rows.push({
22258
+ rowType: "line",
22259
+ id: line.id,
22260
+ displayName: line.line_name,
22261
+ line,
22262
+ lines: [line],
22263
+ efficiency,
22264
+ sortValue: isFiniteNumber2(efficiency) ? efficiency : -1
22265
+ });
22266
+ return;
22267
+ }
22268
+ const group = areaGroups.get(area.id);
22269
+ if (group) {
22270
+ group.lines.push(line);
22271
+ return;
22272
+ }
22273
+ areaGroups.set(area.id, {
22274
+ areaId: area.id,
22275
+ areaName: area.name,
22276
+ lines: [line]
22277
+ });
22278
+ });
22279
+ areaGroups.forEach((group) => {
22280
+ const validEfficiencies = group.lines.map((line) => efficiencyByLineId.get(line.id)).filter(isFiniteNumber2);
22281
+ const fallbackEfficiencies = validEfficiencies.length === 0 ? group.lines.map((line) => fallbackEfficiencyByLineId?.get(line.id)).filter(isFiniteNumber2) : [];
22282
+ const efficiencyValues = validEfficiencies.length > 0 ? validEfficiencies : fallbackEfficiencies;
22283
+ const shouldRenderZeroFallback = efficiencyValues.length === 0 && !!fallbackEfficiencyByLineId && !isLoading;
22284
+ if (efficiencyValues.length === 0 && !shouldRenderZeroFallback) return;
22285
+ const efficiency = shouldRenderZeroFallback ? 0 : efficiencyValues.reduce((sum, value) => sum + value, 0) / efficiencyValues.length;
22286
+ rows.push({
22287
+ rowType: "area",
22288
+ id: `area:${group.areaId}`,
22289
+ displayName: group.areaName,
22290
+ areaId: group.areaId,
22291
+ lines: group.lines,
22292
+ efficiency,
22293
+ sortValue: efficiency
22294
+ });
22295
+ });
22296
+ return rows.sort((left, right) => right.sortValue - left.sortValue).map((row, index) => ({ ...row, rank: index + 1 }));
22297
+ };
22298
+
22176
22299
  // src/lib/utils/awards.ts
22177
22300
  var toNumber2 = (value) => {
22178
22301
  if (typeof value === "number" && Number.isFinite(value)) return value;
@@ -37459,7 +37582,58 @@ HourlyOutputChart.displayName = "HourlyOutputChart";
37459
37582
  // src/components/dashboard/grid/videoGridMetricUtils.ts
37460
37583
  var VIDEO_GRID_LEGEND_LABEL = "Real-Time efficiency";
37461
37584
  var MAP_GRID_LEGEND_LABEL = "Efficiency";
37462
- var isFiniteNumber2 = (value) => typeof value === "number" && Number.isFinite(value);
37585
+ var GREEN_STREAK_FRESHNESS_GRACE_MS = 2 * 60 * 1e3;
37586
+ var CONFIRMED_MINUTE_DURATION_MS = 60 * 1e3;
37587
+ var RECENT_FLOW_COMPUTED_FRESHNESS_MS = 120 * 1e3;
37588
+ var isFiniteNumber3 = (value) => typeof value === "number" && Number.isFinite(value);
37589
+ var padTwoDigits = (value) => String(value).padStart(2, "0");
37590
+ var parseTimestampMs = (value) => {
37591
+ if (!value) {
37592
+ return Number.NaN;
37593
+ }
37594
+ const timestampMs = Date.parse(value);
37595
+ return Number.isFinite(timestampMs) ? timestampMs : Number.NaN;
37596
+ };
37597
+ var isAllGreenStreakFresh = (workspace, anchorAtMs, nowMs2) => {
37598
+ const computedAt = workspace.recent_flow_computed_at;
37599
+ if (typeof computedAt === "string" && computedAt.trim()) {
37600
+ const computedAtMs = parseTimestampMs(computedAt);
37601
+ return Number.isFinite(computedAtMs) && nowMs2 - computedAtMs <= RECENT_FLOW_COMPUTED_FRESHNESS_MS;
37602
+ }
37603
+ return Number.isFinite(anchorAtMs) && nowMs2 <= anchorAtMs + CONFIRMED_MINUTE_DURATION_MS + GREEN_STREAK_FRESHNESS_GRACE_MS;
37604
+ };
37605
+ var formatAllGreenStreakDuration = (elapsedSeconds) => {
37606
+ const safeElapsedSeconds = Math.max(0, Math.floor(elapsedSeconds));
37607
+ const hours = Math.floor(safeElapsedSeconds / 3600);
37608
+ const minutes = Math.floor(safeElapsedSeconds % 3600 / 60);
37609
+ const seconds = safeElapsedSeconds % 60;
37610
+ if (hours > 0) {
37611
+ return `${hours}h ${padTwoDigits(minutes)}m ${padTwoDigits(seconds)}s`;
37612
+ }
37613
+ if (minutes > 0) {
37614
+ return `${minutes}m ${padTwoDigits(seconds)}s`;
37615
+ }
37616
+ return `${seconds}s`;
37617
+ };
37618
+ var getAllGreenStreakMilestone = (elapsedSeconds) => {
37619
+ const safeElapsedSeconds = Math.max(0, Math.floor(elapsedSeconds));
37620
+ const thirtyMinutesSeconds = 30 * 60;
37621
+ const oneHourSeconds = 60 * 60;
37622
+ if (safeElapsedSeconds < thirtyMinutesSeconds) {
37623
+ return null;
37624
+ }
37625
+ if (safeElapsedSeconds < oneHourSeconds) {
37626
+ return {
37627
+ milestoneSeconds: thirtyMinutesSeconds,
37628
+ headline: "30 min"
37629
+ };
37630
+ }
37631
+ const hours = Math.floor(safeElapsedSeconds / oneHourSeconds);
37632
+ return {
37633
+ milestoneSeconds: hours * oneHourSeconds,
37634
+ headline: `${hours * 60} min`
37635
+ };
37636
+ };
37463
37637
  var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
37464
37638
  workspace.video_grid_metric_mode,
37465
37639
  workspace.assembly_enabled === true
@@ -37468,11 +37642,11 @@ var isVideoGridWipGated = (workspace) => isWipGatedVideoGridMetricMode(
37468
37642
  workspace.video_grid_metric_mode,
37469
37643
  workspace.assembly_enabled === true
37470
37644
  );
37471
- var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber2(workspace.recent_flow_percent);
37645
+ var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber3(workspace.recent_flow_percent);
37472
37646
  var isVideoGridRecentFlowUnavailable = (workspace) => isVideoGridRecentFlowEnabled(workspace) && !hasVideoGridRecentFlow(workspace);
37473
37647
  var getRawVideoGridMetricValue = (workspace) => {
37474
37648
  const recentFlowPercent = workspace.recent_flow_percent;
37475
- if (hasVideoGridRecentFlow(workspace) && isFiniteNumber2(recentFlowPercent)) {
37649
+ if (hasVideoGridRecentFlow(workspace) && isFiniteNumber3(recentFlowPercent)) {
37476
37650
  return recentFlowPercent;
37477
37651
  }
37478
37652
  if (isVideoGridRecentFlowUnavailable(workspace)) {
@@ -37481,9 +37655,63 @@ var getRawVideoGridMetricValue = (workspace) => {
37481
37655
  return workspace.efficiency;
37482
37656
  };
37483
37657
  var hasIncomingWipMapping = (workspace) => Boolean(workspace.incoming_wip_buffer_name);
37658
+ var getVideoGridWorkspaceKey = (workspace) => workspace.workspace_uuid || `${workspace.line_id || "unknown"}:${workspace.workspace_name || "unknown"}`;
37659
+ var getVideoGridBlueComparisonGroupKey = (workspace) => {
37660
+ const factoryAreaId = typeof workspace.factory_area_id === "string" ? workspace.factory_area_id.trim() : "";
37661
+ if (factoryAreaId && workspace.factory_area_enabled === true) {
37662
+ return `area:${factoryAreaId}`;
37663
+ }
37664
+ const lineId = typeof workspace.line_id === "string" ? workspace.line_id.trim() : "";
37665
+ return lineId ? `line:${lineId}` : null;
37666
+ };
37667
+ var isVideoGridBlueCandidate = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => hasVideoGridRecentFlow(workspace) && isFiniteNumber3(workspace.recent_flow_percent) && workspace.recent_flow_percent >= legend.green_min;
37668
+ var selectVideoGridBlueWinnerIds = (workspaces, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37669
+ const candidatesByGroup = /* @__PURE__ */ new Map();
37670
+ for (const workspace of workspaces) {
37671
+ if (!isVideoGridBlueCandidate(workspace, legend)) {
37672
+ continue;
37673
+ }
37674
+ const groupKey = getVideoGridBlueComparisonGroupKey(workspace);
37675
+ if (!groupKey) {
37676
+ continue;
37677
+ }
37678
+ const candidates = candidatesByGroup.get(groupKey) || [];
37679
+ candidates.push(workspace);
37680
+ candidatesByGroup.set(groupKey, candidates);
37681
+ }
37682
+ const winners = /* @__PURE__ */ new Set();
37683
+ for (const candidates of candidatesByGroup.values()) {
37684
+ candidates.sort((left, right) => {
37685
+ const leftCurrent = left.recent_flow_percent;
37686
+ const rightCurrent = right.recent_flow_percent;
37687
+ if (rightCurrent !== leftCurrent) {
37688
+ return rightCurrent - leftCurrent;
37689
+ }
37690
+ const leftAverage = isFiniteNumber3(left.avg_recent_flow) ? left.avg_recent_flow : Number.NEGATIVE_INFINITY;
37691
+ const rightAverage = isFiniteNumber3(right.avg_recent_flow) ? right.avg_recent_flow : Number.NEGATIVE_INFINITY;
37692
+ if (rightAverage !== leftAverage) {
37693
+ return rightAverage - leftAverage;
37694
+ }
37695
+ const lineCompare = (left.line_id || "").localeCompare(right.line_id || "");
37696
+ if (lineCompare !== 0) {
37697
+ return lineCompare;
37698
+ }
37699
+ const nameCompare = (left.workspace_name || "").localeCompare(right.workspace_name || "");
37700
+ if (nameCompare !== 0) {
37701
+ return nameCompare;
37702
+ }
37703
+ return getVideoGridWorkspaceKey(left).localeCompare(getVideoGridWorkspaceKey(right));
37704
+ });
37705
+ const winner = candidates[0];
37706
+ if (winner) {
37707
+ winners.add(getVideoGridWorkspaceKey(winner));
37708
+ }
37709
+ }
37710
+ return winners;
37711
+ };
37484
37712
  var getVideoGridBaseColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37485
37713
  const metricValue = getRawVideoGridMetricValue(workspace);
37486
- if (!isFiniteNumber2(metricValue)) {
37714
+ if (!isFiniteNumber3(metricValue)) {
37487
37715
  return "neutral";
37488
37716
  }
37489
37717
  return getEfficiencyColor(metricValue, legend);
@@ -37504,7 +37732,7 @@ var isLowWipGreenOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37504
37732
  if (!hasIncomingWipMapping(workspace)) {
37505
37733
  return false;
37506
37734
  }
37507
- return isFiniteNumber2(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
37735
+ return isFiniteNumber3(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
37508
37736
  };
37509
37737
  var isHighEfficiencyRedFlowOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37510
37738
  if (workspace.scheduled_break_active === true) {
@@ -37522,7 +37750,7 @@ var isHighEfficiencyRedFlowOverride = (workspace, legend = DEFAULT_EFFICIENCY_LE
37522
37750
  if (getVideoGridBaseColorState(workspace, legend) !== "red") {
37523
37751
  return false;
37524
37752
  }
37525
- return isFiniteNumber2(workspace.efficiency) && workspace.efficiency > 100;
37753
+ return isFiniteNumber3(workspace.efficiency) && workspace.efficiency > 100;
37526
37754
  };
37527
37755
  var getVideoGridMetricValue = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => isHighEfficiencyRedFlowOverride(workspace, legend) ? workspace.efficiency : getRawVideoGridMetricValue(workspace);
37528
37756
  var toMinuteBucket = (minuteBucket) => Number.isFinite(minuteBucket) ? Math.floor(minuteBucket) : Math.floor(Date.now() / 6e4);
@@ -37551,7 +37779,10 @@ var getSyntheticLowWipDisplayValue = (workspace, minuteBucket) => {
37551
37779
  return 100 + offset;
37552
37780
  };
37553
37781
  var getVideoGridDisplayValue = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND, minuteBucket) => isLowWipGreenOverride(workspace, legend) ? getSyntheticLowWipDisplayValue(workspace, minuteBucket) : getVideoGridMetricValue(workspace, legend);
37554
- var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37782
+ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND, blueWinnerIds) => {
37783
+ if (blueWinnerIds?.has(getVideoGridWorkspaceKey(workspace)) && isVideoGridBlueCandidate(workspace, legend)) {
37784
+ return "blue";
37785
+ }
37555
37786
  const baseColor = getVideoGridBaseColorState(workspace, legend);
37556
37787
  if (!hasVideoGridRecentFlow(workspace)) {
37557
37788
  return baseColor;
@@ -37571,11 +37802,56 @@ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) =>
37571
37802
  if (!hasIncomingWipMapping(workspace)) {
37572
37803
  return baseColor;
37573
37804
  }
37574
- if (!isFiniteNumber2(workspace.incoming_wip_current)) {
37805
+ if (!isFiniteNumber3(workspace.incoming_wip_current)) {
37575
37806
  return "neutral";
37576
37807
  }
37577
37808
  return baseColor;
37578
37809
  };
37810
+ var hasAllVideoGridWorkspacesGreen = (workspaces, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37811
+ const visibleWorkspaces = workspaces.filter((workspace) => Boolean(workspace.workspace_uuid || workspace.workspace_name));
37812
+ return visibleWorkspaces.length > 0 && visibleWorkspaces.every((workspace) => getVideoGridColorState(workspace, legend) === "green");
37813
+ };
37814
+ var getAllVideoGridGreenStreakDisplay = (workspaces, legend = DEFAULT_EFFICIENCY_LEGEND, nowMs2 = Date.now()) => {
37815
+ const visibleWorkspaces = workspaces.filter((workspace) => Boolean(workspace.workspace_uuid || workspace.workspace_name));
37816
+ if (visibleWorkspaces.length === 0 || !hasAllVideoGridWorkspacesGreen(visibleWorkspaces, legend)) {
37817
+ return null;
37818
+ }
37819
+ const activeStreaks = visibleWorkspaces.map((workspace) => {
37820
+ const startedAt = workspace.video_grid_green_streak_started_at;
37821
+ const anchorAt = workspace.video_grid_green_streak_anchor_at;
37822
+ const streakMinutes = workspace.video_grid_green_streak_minutes;
37823
+ const computedAt = workspace.recent_flow_computed_at;
37824
+ const startedAtMs = parseTimestampMs(startedAt);
37825
+ const anchorAtMs = parseTimestampMs(anchorAt);
37826
+ const computedAtMs = typeof computedAt === "string" && computedAt.trim() ? parseTimestampMs(computedAt) : Number.NaN;
37827
+ const isFresh = isAllGreenStreakFresh(workspace, anchorAtMs, nowMs2);
37828
+ const tickOriginAtMs = Number.isFinite(computedAtMs) ? computedAtMs : anchorAtMs + CONFIRMED_MINUTE_DURATION_MS;
37829
+ if (workspace.video_grid_green_streak_active === true && isFiniteNumber3(streakMinutes) && streakMinutes > 0 && startedAt && anchorAt && Number.isFinite(startedAtMs) && isFresh) {
37830
+ return {
37831
+ startedAt,
37832
+ startedAtMs,
37833
+ anchorAt,
37834
+ streakMinutes,
37835
+ tickOriginAtMs
37836
+ };
37837
+ }
37838
+ return null;
37839
+ });
37840
+ if (activeStreaks.some((streak) => streak === null)) {
37841
+ return null;
37842
+ }
37843
+ const strictestStartedAt = activeStreaks.reduce((latest, current) => current.streakMinutes < latest.streakMinutes || current.streakMinutes === latest.streakMinutes && current.startedAtMs > latest.startedAtMs ? current : latest);
37844
+ const confirmedSeconds = Math.max(0, Math.floor(strictestStartedAt.streakMinutes * 60));
37845
+ return {
37846
+ label: "All green",
37847
+ elapsedSeconds: confirmedSeconds,
37848
+ confirmedSeconds,
37849
+ durationText: formatAllGreenStreakDuration(confirmedSeconds),
37850
+ startedAt: strictestStartedAt.startedAt,
37851
+ anchorAt: strictestStartedAt.anchorAt,
37852
+ tickOriginAtMs: strictestStartedAt.tickOriginAtMs
37853
+ };
37854
+ };
37579
37855
  var getVideoGridLegendLabel = (workspaces) => {
37580
37856
  const visibleWorkspaces = workspaces;
37581
37857
  if (visibleWorkspaces.length === 0) {
@@ -37606,6 +37882,7 @@ var VideoCard = React144__namespace.default.memo(({
37606
37882
  compact = false,
37607
37883
  displayMinuteBucket,
37608
37884
  displayName,
37885
+ isBlueBest = false,
37609
37886
  lastSeenLabel,
37610
37887
  hasRecentHealthSignal: hasRecentHealthSignal2 = false,
37611
37888
  onMouseEnter,
@@ -37627,7 +37904,11 @@ var VideoCard = React144__namespace.default.memo(({
37627
37904
  const workspaceDisplayName = displayName || workspace.displayName || workspace.workspace_name;
37628
37905
  const videoGridMetricValue = getVideoGridMetricValue(workspace, effectiveLegend);
37629
37906
  const videoGridDisplayValue = getVideoGridDisplayValue(workspace, effectiveLegend, displayMinuteBucket);
37630
- const videoGridColorState = getVideoGridColorState(workspace, effectiveLegend);
37907
+ const videoGridColorState = getVideoGridColorState(
37908
+ workspace,
37909
+ effectiveLegend,
37910
+ isBlueBest ? /* @__PURE__ */ new Set([getVideoGridWorkspaceKey(workspace)]) : void 0
37911
+ );
37631
37912
  const isRecentFlowCard = isVideoGridRecentFlowEnabled(workspace);
37632
37913
  const isHighEfficiencyOverride = isHighEfficiencyRedFlowOverride(workspace, effectiveLegend);
37633
37914
  const hasDisplayMetric = typeof videoGridDisplayValue === "number" && Number.isFinite(videoGridDisplayValue);
@@ -37635,9 +37916,9 @@ var VideoCard = React144__namespace.default.memo(({
37635
37916
  const shouldRenderMetricBadge = hasDisplayMetric;
37636
37917
  const badgeTitle = isHighEfficiencyOverride ? `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%` : hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
37637
37918
  const badgeLabel = `${Math.round(videoGridDisplayValue ?? 0)}%`;
37638
- const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
37639
- const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
37640
- const efficiencyStatus = videoGridColorState === "green" ? "High" : videoGridColorState === "yellow" ? "Medium" : videoGridColorState === "red" ? "Low" : "Neutral";
37919
+ const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "blue" ? "bg-[#0EA5E9]/30" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
37920
+ const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "blue" ? "bg-[#0EA5E9]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
37921
+ const efficiencyStatus = videoGridColorState === "green" ? "High" : videoGridColorState === "blue" ? "Best" : videoGridColorState === "yellow" ? "Medium" : videoGridColorState === "red" ? "Low" : "Neutral";
37641
37922
  const trendInfo = workspace.trend !== void 0 ? getTrendArrowAndColor(workspace.trend) : null;
37642
37923
  const handleClick = React144.useCallback(() => {
37643
37924
  trackCoreEvent("Workspace Card Clicked", {
@@ -37758,6 +38039,9 @@ var VideoCard = React144__namespace.default.memo(({
37758
38039
  if (prevProps.displayName !== nextProps.displayName) {
37759
38040
  return false;
37760
38041
  }
38042
+ if (prevProps.isBlueBest !== nextProps.isBlueBest) {
38043
+ return false;
38044
+ }
37761
38045
  if (prevProps.lastSeenLabel !== nextProps.lastSeenLabel) {
37762
38046
  return false;
37763
38047
  }
@@ -37799,6 +38083,7 @@ var hasRecentHealthSignal = (lastHeartbeat) => {
37799
38083
  };
37800
38084
  var VideoGridView = React144__namespace.default.memo(({
37801
38085
  workspaces,
38086
+ blueComparisonWorkspaces,
37802
38087
  selectedLine,
37803
38088
  className = "",
37804
38089
  legend,
@@ -37927,6 +38212,7 @@ var VideoGridView = React144__namespace.default.memo(({
37927
38212
  return a.workspace_name.localeCompare(b.workspace_name);
37928
38213
  });
37929
38214
  }, [filteredWorkspaces]);
38215
+ const blueWinnerIds = React144.useMemo(() => selectVideoGridBlueWinnerIds(blueComparisonWorkspaces || sortedWorkspaces, effectiveLegend), [blueComparisonWorkspaces, sortedWorkspaces, effectiveLegend]);
37930
38216
  const streamsResolvedForWorkspaceSet = resolvedStreamWorkspaceKey === workspaceIdsKey;
37931
38217
  const resolveWorkspaceDisplayName = React144.useCallback((workspace) => {
37932
38218
  return workspace.displayName || displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || workspace.workspace_name;
@@ -38135,11 +38421,13 @@ var VideoGridView = React144__namespace.default.memo(({
38135
38421
  isR2Stream,
38136
38422
  shouldPlay,
38137
38423
  lastSeenLabel,
38138
- hasRecentHealthSignal: hasRecentHealthSignal(workspaceHealth?.lastHeartbeat)
38424
+ hasRecentHealthSignal: hasRecentHealthSignal(workspaceHealth?.lastHeartbeat),
38425
+ isBlueBest: blueWinnerIds.has(getVideoGridWorkspaceKey(workspace))
38139
38426
  };
38140
38427
  });
38141
38428
  }, [
38142
38429
  sortedWorkspaces,
38430
+ blueWinnerIds,
38143
38431
  visibleWorkspaces,
38144
38432
  getWorkspaceCropping,
38145
38433
  videoStreamsByWorkspaceId,
@@ -38186,6 +38474,7 @@ var VideoGridView = React144__namespace.default.memo(({
38186
38474
  useRAF: effectiveUseRAF,
38187
38475
  displayMinuteBucket,
38188
38476
  compact: !selectedLine,
38477
+ isBlueBest: card.isBlueBest,
38189
38478
  onMouseEnter: onWorkspaceHover ? () => onWorkspaceHover(card.workspaceId) : void 0,
38190
38479
  onMouseLeave: onWorkspaceHoverEnd ? () => onWorkspaceHoverEnd(card.workspaceId) : void 0
38191
38480
  }
@@ -39819,7 +40108,7 @@ var BreakNotificationPopup = ({
39819
40108
  return null;
39820
40109
  }
39821
40110
  const currentBreak = visibleBreaks[currentIndex];
39822
- return /* @__PURE__ */ jsxRuntime.jsx(AnimatePresence, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `fixed right-4 top-24 z-50 max-w-xs w-full ${className}`, children: [
40111
+ return /* @__PURE__ */ jsxRuntime.jsx(AnimatePresence, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `fixed right-4 top-24 z-[110] max-w-xs w-full ${className}`, children: [
39823
40112
  visibleBreaks.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
39824
40113
  /* @__PURE__ */ jsxRuntime.jsx(
39825
40114
  "div",
@@ -54743,6 +55032,10 @@ var Legend5 = ({
54743
55032
  ":"
54744
55033
  ] }),
54745
55034
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 sm:gap-4", children: [
55035
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
55036
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 sm:w-2.5 sm:h-2.5 rounded-full bg-[#0EA5E9]" }),
55037
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Best" })
55038
+ ] }),
54746
55039
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
54747
55040
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 sm:w-2.5 sm:h-2.5 rounded-full bg-[#00AB45]" }),
54748
55041
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatPercentRange(effectiveLegend.green_min, effectiveLegend.green_max) })
@@ -54861,6 +55154,7 @@ var WorkspaceGridItem = React144__namespace.default.memo(({
54861
55154
  WorkspaceGridItem.displayName = "WorkspaceGridItem";
54862
55155
  var WorkspaceGrid = React144__namespace.default.memo(({
54863
55156
  workspaces,
55157
+ blueComparisonWorkspaces,
54864
55158
  isPdfMode = false,
54865
55159
  customWorkspacePositions,
54866
55160
  lineNames = {},
@@ -54877,13 +55171,8 @@ var WorkspaceGrid = React144__namespace.default.memo(({
54877
55171
  onWorkspaceHoverEnd,
54878
55172
  toolbarRightContent
54879
55173
  }) => {
54880
- const dashboardConfig = useDashboardConfig();
54881
- const mapViewEnabled = dashboardConfig?.mapViewConfig?.enabled ?? false;
55174
+ const mapViewEnabled = false;
54882
55175
  const [viewMode, setViewMode] = React144.useState(() => {
54883
- if (typeof window !== "undefined" && mapViewEnabled) {
54884
- const saved = localStorage.getItem("home-view-mode");
54885
- return saved === "map" || saved === "video" ? saved : "video";
54886
- }
54887
55176
  return "video";
54888
55177
  });
54889
55178
  React144.useEffect(() => {
@@ -54892,7 +55181,7 @@ var WorkspaceGrid = React144__namespace.default.memo(({
54892
55181
  total_workspaces: workspaces.length
54893
55182
  });
54894
55183
  }, [workspaces.length]);
54895
- const handleViewModeToggle = React144.useCallback(() => {
55184
+ React144.useCallback(() => {
54896
55185
  const newMode = viewMode === "video" ? "map" : "video";
54897
55186
  setViewMode(newMode);
54898
55187
  if (typeof window !== "undefined") {
@@ -54906,8 +55195,8 @@ var WorkspaceGrid = React144__namespace.default.memo(({
54906
55195
  }, [viewMode]);
54907
55196
  const { VideoGridView: VideoGridViewComponent, MapGridView: MapGridViewComponent } = useRegistry();
54908
55197
  const legendMetricLabel = React144.useMemo(
54909
- () => viewMode === "video" ? getVideoGridLegendLabel(workspaces) : MAP_GRID_LEGEND_LABEL,
54910
- [viewMode, workspaces]
55198
+ () => getVideoGridLegendLabel(workspaces),
55199
+ [workspaces]
54911
55200
  );
54912
55201
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col w-full h-full overflow-hidden bg-slate-50/50 ${className}`, children: [
54913
55202
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -54919,21 +55208,7 @@ var WorkspaceGrid = React144__namespace.default.memo(({
54919
55208
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex bg-white/95 rounded-lg shadow-sm px-4 py-2 border border-slate-200/60 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsx(Legend5, { legend, metricLabel: legendMetricLabel }) }) }),
54920
55209
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-3 shrink-0", children: [
54921
55210
  toolbarRightContent,
54922
- mapViewEnabled && /* @__PURE__ */ jsxRuntime.jsx(
54923
- "button",
54924
- {
54925
- onClick: handleViewModeToggle,
54926
- className: "flex items-center gap-2 px-3 py-1.5 bg-white border border-slate-200 rounded-md shadow-sm hover:bg-slate-50 transition-colors duration-200 text-slate-700",
54927
- title: viewMode === "video" ? "Switch to Map View" : "Switch to Video View",
54928
- children: viewMode === "video" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
54929
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Map, { className: "w-4 h-4 text-slate-500" }),
54930
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline text-sm font-medium", children: "Map View" })
54931
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
54932
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { className: "w-4 h-4 text-slate-500" }),
54933
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline text-sm font-medium", children: "Video View" })
54934
- ] })
54935
- }
54936
- )
55211
+ mapViewEnabled
54937
55212
  ] })
54938
55213
  ]
54939
55214
  }
@@ -54951,6 +55226,7 @@ var WorkspaceGrid = React144__namespace.default.memo(({
54951
55226
  VideoGridViewComponent,
54952
55227
  {
54953
55228
  workspaces,
55229
+ blueComparisonWorkspaces,
54954
55230
  lineNames,
54955
55231
  lineOrder,
54956
55232
  videoSources,
@@ -57247,12 +57523,25 @@ var SideNavBar = React144.memo(({
57247
57523
  console.log("\u{1F50D} [SideNavBar] ticketsConfig:", dashboardConfig?.ticketsConfig);
57248
57524
  console.log("\u{1F50D} [SideNavBar] ticketsEnabled:", ticketsEnabled);
57249
57525
  const pathname = propPathname || router$1.pathname;
57526
+ const rawCurrentTabQuery = currentQuery?.tab ?? router$1.query?.tab;
57527
+ const currentTabQuery = Array.isArray(rawCurrentTabQuery) ? rawCurrentTabQuery[0] : rawCurrentTabQuery;
57528
+ const isKpisLeaderboardRoute = pathname === "/kpis" && currentTabQuery === "leaderboard";
57529
+ const isPathActive = React144.useCallback((path) => {
57530
+ if (path === "/") return pathname === "/";
57531
+ if (path === "/leaderboard") {
57532
+ return pathname === "/leaderboard" || pathname.startsWith("/leaderboard/");
57533
+ }
57534
+ if (path === "/kpis") {
57535
+ return pathname === "/kpis" || pathname.startsWith("/kpis/");
57536
+ }
57537
+ return pathname === path || pathname.startsWith(path + "/");
57538
+ }, [pathname]);
57250
57539
  const getButtonClasses = React144.useCallback((path) => {
57251
- const isActive = pathname === path || pathname.startsWith(path + "/");
57540
+ const isActive = isPathActive(path);
57252
57541
  return `w-full flex flex-col items-center justify-center py-4 sm:py-3 px-2 sm:px-1 rounded-lg relative group min-h-[44px] sm:min-h-0
57253
57542
  ${isActive ? "bg-blue-50/80 text-blue-600 font-medium" : "hover:bg-gray-50 text-gray-500 hover:text-gray-700 font-medium active:bg-gray-100"}
57254
57543
  transition-all duration-200 ease-out focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2`;
57255
- }, [pathname]);
57544
+ }, [isPathActive]);
57256
57545
  const buildDashboardSurfaceTrackingEvent = React144.useCallback((source, destinationPath, dashboardSurface) => ({
57257
57546
  name: ROOT_DASHBOARD_EVENT_NAMES[dashboardSurface],
57258
57547
  properties: {
@@ -57285,17 +57574,24 @@ var SideNavBar = React144.memo(({
57285
57574
  onMobileMenuClose?.();
57286
57575
  }, [navigate, onMobileMenuClose, buildDashboardSurfaceTrackingEvent]);
57287
57576
  const handleKPIsClick = React144.useCallback(() => {
57288
- navigate(`/kpis`, {
57289
- trackingEvent: {
57290
- name: "KPI Page Clicked",
57291
- properties: {
57292
- source: "side_nav",
57293
- page_type: "overview"
57294
- }
57577
+ const trackingEvent = {
57578
+ name: "KPI Page Clicked",
57579
+ properties: {
57580
+ source: "side_nav",
57581
+ page_type: "overview"
57295
57582
  }
57583
+ };
57584
+ if (isKpisLeaderboardRoute) {
57585
+ trackCoreEvent(trackingEvent.name, trackingEvent.properties);
57586
+ void router$1.replace("/kpis", void 0, { shallow: false });
57587
+ onMobileMenuClose?.();
57588
+ return;
57589
+ }
57590
+ navigate(`/kpis`, {
57591
+ trackingEvent
57296
57592
  });
57297
57593
  onMobileMenuClose?.();
57298
- }, [navigate, onMobileMenuClose]);
57594
+ }, [isKpisLeaderboardRoute, navigate, onMobileMenuClose, router$1]);
57299
57595
  const handleImprovementClick = React144.useCallback(() => {
57300
57596
  navigate("/improvement-center", {
57301
57597
  trackingEvent: {
@@ -57565,14 +57861,14 @@ var SideNavBar = React144.memo(({
57565
57861
  });
57566
57862
  onMobileMenuClose?.();
57567
57863
  }, [navigate, onMobileMenuClose, buildDashboardSurfaceTrackingEvent, rootDashboardSurface]);
57568
- const homeButtonClasses = React144.useMemo(() => getButtonClasses("/"), [getButtonClasses, pathname]);
57569
- const liveButtonClasses = React144.useMemo(() => getButtonClasses("/live-monitor"), [getButtonClasses, pathname]);
57570
- const leaderboardButtonClasses = React144.useMemo(() => getButtonClasses("/leaderboard"), [getButtonClasses, pathname]);
57571
- const kpisButtonClasses = React144.useMemo(() => getButtonClasses("/kpis"), [getButtonClasses, pathname]);
57572
- const improvementButtonClasses = React144.useMemo(() => getButtonClasses("/improvement-center"), [getButtonClasses, pathname]);
57573
- React144.useMemo(() => getButtonClasses("/supervisor-management"), [getButtonClasses, pathname]);
57574
- const skusButtonClasses = React144.useMemo(() => getButtonClasses("/skus"), [getButtonClasses, pathname]);
57575
- const healthButtonClasses = React144.useMemo(() => getButtonClasses("/health"), [getButtonClasses, pathname]);
57864
+ const homeButtonClasses = React144.useMemo(() => getButtonClasses("/"), [getButtonClasses]);
57865
+ const liveButtonClasses = React144.useMemo(() => getButtonClasses("/live-monitor"), [getButtonClasses]);
57866
+ const leaderboardButtonClasses = React144.useMemo(() => getButtonClasses("/leaderboard"), [getButtonClasses]);
57867
+ const kpisButtonClasses = React144.useMemo(() => getButtonClasses("/kpis"), [getButtonClasses]);
57868
+ const improvementButtonClasses = React144.useMemo(() => getButtonClasses("/improvement-center"), [getButtonClasses]);
57869
+ React144.useMemo(() => getButtonClasses("/supervisor-management"), [getButtonClasses]);
57870
+ const skusButtonClasses = React144.useMemo(() => getButtonClasses("/skus"), [getButtonClasses]);
57871
+ const healthButtonClasses = React144.useMemo(() => getButtonClasses("/health"), [getButtonClasses]);
57576
57872
  const settingsButtonClasses = React144.useMemo(() => {
57577
57873
  const isAnyItemActive = settingsItems.some((item) => item.isActive);
57578
57874
  const isActive = isSettingsOpen || isAnyItemActive;
@@ -57606,7 +57902,7 @@ var SideNavBar = React144.memo(({
57606
57902
  "aria-label": "Home",
57607
57903
  tabIndex: 0,
57608
57904
  role: "tab",
57609
- "aria-selected": pathname === "/" || pathname.startsWith("//"),
57905
+ "aria-selected": isPathActive("/"),
57610
57906
  children: [
57611
57907
  /* @__PURE__ */ jsxRuntime.jsx(outline.HomeIcon, { className: "w-5 h-5 mb-1" }),
57612
57908
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Home" })
@@ -57621,7 +57917,7 @@ var SideNavBar = React144.memo(({
57621
57917
  "aria-label": "Monitor",
57622
57918
  tabIndex: 0,
57623
57919
  role: "tab",
57624
- "aria-selected": pathname === "/live-monitor" || pathname.startsWith("/live-monitor/"),
57920
+ "aria-selected": isPathActive("/live-monitor"),
57625
57921
  children: [
57626
57922
  /* @__PURE__ */ jsxRuntime.jsx(outline.VideoCameraIcon, { className: "w-5 h-5 mb-1" }),
57627
57923
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Monitor" })
@@ -57638,7 +57934,7 @@ var SideNavBar = React144.memo(({
57638
57934
  "aria-label": "Leaderboard",
57639
57935
  tabIndex: 0,
57640
57936
  role: "tab",
57641
- "aria-selected": pathname === "/leaderboard" || pathname.startsWith("/leaderboard/"),
57937
+ "aria-selected": isPathActive("/leaderboard"),
57642
57938
  children: [
57643
57939
  /* @__PURE__ */ jsxRuntime.jsx(outline.TrophyIcon, { className: "w-5 h-5 mb-1" }),
57644
57940
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Leaders" })
@@ -57653,7 +57949,7 @@ var SideNavBar = React144.memo(({
57653
57949
  "aria-label": "Lines",
57654
57950
  tabIndex: 0,
57655
57951
  role: "tab",
57656
- "aria-selected": pathname === "/kpis" || pathname.startsWith("/kpis/"),
57952
+ "aria-selected": isPathActive("/kpis"),
57657
57953
  children: [
57658
57954
  /* @__PURE__ */ jsxRuntime.jsx(outline.ChartBarIcon, { className: "w-5 h-5 mb-1" }),
57659
57955
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Lines" })
@@ -57668,7 +57964,7 @@ var SideNavBar = React144.memo(({
57668
57964
  "aria-label": "Improvement Center",
57669
57965
  tabIndex: 0,
57670
57966
  role: "tab",
57671
- "aria-selected": pathname === "/improvement-center" || pathname.startsWith("/improvement-center/"),
57967
+ "aria-selected": isPathActive("/improvement-center"),
57672
57968
  children: [
57673
57969
  /* @__PURE__ */ jsxRuntime.jsx(outline.LightBulbIcon, { className: "w-5 h-5 mb-1" }),
57674
57970
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight text-center", children: "Improve" })
@@ -57684,7 +57980,7 @@ var SideNavBar = React144.memo(({
57684
57980
  "aria-label": "SKU Management",
57685
57981
  tabIndex: 0,
57686
57982
  role: "tab",
57687
- "aria-selected": pathname === "/skus" || pathname.startsWith("/skus/"),
57983
+ "aria-selected": isPathActive("/skus"),
57688
57984
  children: [
57689
57985
  /* @__PURE__ */ jsxRuntime.jsx(outline.CubeIcon, { className: "w-5 h-5 mb-1" }),
57690
57986
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "SKUs" })
@@ -57699,7 +57995,7 @@ var SideNavBar = React144.memo(({
57699
57995
  "aria-label": "System Health",
57700
57996
  tabIndex: 0,
57701
57997
  role: "tab",
57702
- "aria-selected": pathname === "/health" || pathname.startsWith("/health/"),
57998
+ "aria-selected": isPathActive("/health"),
57703
57999
  children: [
57704
58000
  /* @__PURE__ */ jsxRuntime.jsx(outline.HeartIcon, { className: "w-5 h-5 mb-1" }),
57705
58001
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Health" })
@@ -57729,17 +58025,12 @@ var SideNavBar = React144.memo(({
57729
58025
  ) })
57730
58026
  ] });
57731
58027
  const MobileNavigationContent = () => {
57732
- const isActive = (path) => {
57733
- if (path === "/" && pathname === "/") return true;
57734
- if (path !== "/" && pathname.startsWith(path)) return true;
57735
- return false;
57736
- };
57737
58028
  const getMobileButtonClass = (path) => {
57738
- const active = isActive(path);
58029
+ const active = isPathActive(path);
57739
58030
  return `w-full flex items-center gap-3 px-5 py-3.5 rounded-lg transition-colors active:scale-[0.98] ${active ? "bg-blue-50 text-blue-700" : "text-gray-700 hover:bg-gray-100 active:bg-gray-200"}`;
57740
58031
  };
57741
58032
  const getIconClass = (path) => {
57742
- const active = isActive(path);
58033
+ const active = isPathActive(path);
57743
58034
  return `w-7 h-7 ${active ? "text-blue-600" : "text-gray-600"}`;
57744
58035
  };
57745
58036
  const handleMobileNavClick = (handler) => {
@@ -63696,6 +63987,7 @@ var createEmptyState = () => ({
63696
63987
  scopeKey: null,
63697
63988
  lines: [],
63698
63989
  workspaceMetrics: [],
63990
+ blueComparisonWorkspaceMetrics: [],
63699
63991
  lineMetrics: [],
63700
63992
  kpiTrend: null,
63701
63993
  activeBreaks: [],
@@ -63712,6 +64004,7 @@ var normalizeMetadata = (metadata) => ({
63712
64004
  });
63713
64005
  var useLiveMonitorBootstrap = ({
63714
64006
  lineIds,
64007
+ blueComparisonLineIds,
63715
64008
  companyId,
63716
64009
  enabled = true,
63717
64010
  appTimezone,
@@ -63726,13 +64019,18 @@ var useLiveMonitorBootstrap = ({
63726
64019
  const effectiveWorkspaceConfig = workspaceConfig || DEFAULT_WORKSPACE_CONFIG;
63727
64020
  const effectiveTimezone = appTimezone || "Asia/Kolkata";
63728
64021
  const rawLineIdsKey = (lineIds || []).filter(Boolean).join(",");
64022
+ const rawBlueComparisonLineIdsKey = (blueComparisonLineIds || lineIds || []).filter(Boolean).join(",");
63729
64023
  const normalizedLineIds = React144.useMemo(
63730
64024
  () => Array.from(new Set(rawLineIdsKey ? rawLineIdsKey.split(",") : [])),
63731
64025
  [rawLineIdsKey]
63732
64026
  );
64027
+ const normalizedBlueComparisonLineIds = React144.useMemo(
64028
+ () => Array.from(new Set(rawBlueComparisonLineIdsKey ? rawBlueComparisonLineIdsKey.split(",") : [])),
64029
+ [rawBlueComparisonLineIdsKey]
64030
+ );
63733
64031
  const requestKey = React144.useMemo(
63734
- () => normalizedLineIds.slice().sort().join(","),
63735
- [normalizedLineIds]
64032
+ () => `${normalizedLineIds.slice().sort().join(",")}|blue:${normalizedBlueComparisonLineIds.slice().sort().join(",")}`,
64033
+ [normalizedLineIds, normalizedBlueComparisonLineIds]
63736
64034
  );
63737
64035
  const [state, setState] = React144.useState(() => createEmptyState());
63738
64036
  const [rawState, setRawState] = React144.useState(null);
@@ -63750,6 +64048,9 @@ var useLiveMonitorBootstrap = ({
63750
64048
  const searchParams = new URLSearchParams();
63751
64049
  searchParams.set("company_id", resolvedCompanyId);
63752
64050
  searchParams.set("line_ids", normalizedLineIds.join(","));
64051
+ if (normalizedBlueComparisonLineIds.length) {
64052
+ searchParams.set("blue_comparison_line_ids", normalizedBlueComparisonLineIds.join(","));
64053
+ }
63753
64054
  if (force) {
63754
64055
  searchParams.set("force_refresh", "true");
63755
64056
  }
@@ -63781,6 +64082,7 @@ var useLiveMonitorBootstrap = ({
63781
64082
  extras: {
63782
64083
  company_id: resolvedCompanyId,
63783
64084
  line_ids: normalizedLineIds,
64085
+ blue_comparison_line_ids: normalizedBlueComparisonLineIds,
63784
64086
  force_refresh: force,
63785
64087
  pathname: typeof window !== "undefined" ? window.location.pathname : "unknown"
63786
64088
  }
@@ -63796,6 +64098,7 @@ var useLiveMonitorBootstrap = ({
63796
64098
  supabase,
63797
64099
  resolvedCompanyId,
63798
64100
  normalizedLineIds,
64101
+ normalizedBlueComparisonLineIds,
63799
64102
  requestKey
63800
64103
  ]);
63801
64104
  React144.useEffect(() => {
@@ -63814,6 +64117,16 @@ var useLiveMonitorBootstrap = ({
63814
64117
  fallbackShiftConfig
63815
64118
  });
63816
64119
  const activeBreaks = transformActiveBreaks(rawState.response.active_breaks_by_line);
64120
+ const blueComparisonWorkspaceMetrics = rawState.response.blue_comparison_workspace_metrics ? transformMonitorWorkspaceMetrics({
64121
+ rows: rawState.response.blue_comparison_workspace_metrics,
64122
+ companyId: resolvedCompanyId,
64123
+ workspaceConfig: effectiveWorkspaceConfig,
64124
+ appTimezone: effectiveTimezone,
64125
+ lineMetrics: rawState.response.line_metrics || [],
64126
+ resolveShiftConfig: (lineId) => lineShiftConfigs?.get(lineId) || fallbackShiftConfig,
64127
+ shouldOverrideShiftType: (lineId) => Boolean(lineShiftConfigs?.get(lineId)),
64128
+ fallbackShiftConfig
64129
+ }) : workspaceMetrics;
63817
64130
  const metadata = normalizeMetadata(rawState.response.metadata);
63818
64131
  const workspaceIds = workspaceMetrics.map((metric) => metric.workspace_uuid).filter((workspaceId) => Boolean(workspaceId));
63819
64132
  const videoStreamsByWorkspaceId = rawState.response.video_streams_by_workspace_id || {};
@@ -63831,6 +64144,7 @@ var useLiveMonitorBootstrap = ({
63831
64144
  scopeKey: rawState.response.scope_key || null,
63832
64145
  lines: rawState.response.lines || [],
63833
64146
  workspaceMetrics,
64147
+ blueComparisonWorkspaceMetrics: blueComparisonWorkspaceMetrics.length ? blueComparisonWorkspaceMetrics : workspaceMetrics,
63834
64148
  lineMetrics: rawState.response.line_metrics || [],
63835
64149
  kpiTrend: rawState.response.kpi_trend || null,
63836
64150
  activeBreaks,
@@ -63898,6 +64212,7 @@ var useLiveMonitorBootstrap = ({
63898
64212
  scopeKey: state.scopeKey,
63899
64213
  lines: state.lines,
63900
64214
  workspaceMetrics: state.workspaceMetrics,
64215
+ blueComparisonWorkspaceMetrics: state.blueComparisonWorkspaceMetrics,
63901
64216
  lineMetrics: state.lineMetrics,
63902
64217
  kpiTrend: state.kpiTrend,
63903
64218
  activeBreaks: state.activeBreaks,
@@ -64168,6 +64483,22 @@ var logDebug3 = (...args) => {
64168
64483
  };
64169
64484
  var EMPTY_LINE_IDS = [];
64170
64485
  var EMPTY_WORKSPACES = [];
64486
+ var ALL_GREEN_CELEBRATION_DURATION_MS = 6e3;
64487
+ var ALL_GREEN_MILESTONE_DURATION_MS = 6e3;
64488
+ var ALL_GREEN_STREAK_LOCAL_SECOND_CAP = 59;
64489
+ var formatAllGreenCelebrationTimer = (elapsedSeconds) => {
64490
+ const safeElapsedSeconds = Math.max(1, Math.floor(elapsedSeconds));
64491
+ const minutes = Math.floor(safeElapsedSeconds / 60);
64492
+ const seconds = safeElapsedSeconds % 60;
64493
+ return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}s`;
64494
+ };
64495
+ var getAllGreenBackendVisibleSeconds = (confirmedSeconds, tickOriginAtMs, nowMs2) => {
64496
+ const localSecondOffset = Math.min(
64497
+ ALL_GREEN_STREAK_LOCAL_SECOND_CAP,
64498
+ Math.max(0, Math.floor((nowMs2 - tickOriginAtMs) / 1e3))
64499
+ );
64500
+ return confirmedSeconds + localSecondOffset;
64501
+ };
64171
64502
  var LoadingPageCmp = LoadingPage_default;
64172
64503
  var LoadingOverlayCmp = LoadingOverlay_default;
64173
64504
  function HomeView({
@@ -64309,6 +64640,31 @@ function HomeView({
64309
64640
  () => new Set(selectedLineIds),
64310
64641
  [selectedLineIds]
64311
64642
  );
64643
+ const blueComparisonLineIds = React144.useMemo(() => {
64644
+ const selectedFactoryAreaIds = /* @__PURE__ */ new Set();
64645
+ for (const line of dbLines) {
64646
+ if (!selectedLineIdSet.has(line.id)) {
64647
+ continue;
64648
+ }
64649
+ const factoryAreaId = typeof line.factory_area_id === "string" ? line.factory_area_id.trim() : "";
64650
+ if (factoryAreaId) {
64651
+ selectedFactoryAreaIds.add(factoryAreaId);
64652
+ }
64653
+ }
64654
+ if (selectedFactoryAreaIds.size === 0) {
64655
+ return selectedLineIds;
64656
+ }
64657
+ const dbLinesById = new Map(dbLines.map((line) => [line.id, line]));
64658
+ const selectedIds = new Set(selectedLineIds);
64659
+ return visibleLineIds.filter((lineId) => {
64660
+ if (selectedIds.has(lineId)) {
64661
+ return true;
64662
+ }
64663
+ const line = dbLinesById.get(lineId);
64664
+ const factoryAreaId = typeof line?.factory_area_id === "string" ? line.factory_area_id.trim() : "";
64665
+ return factoryAreaId ? selectedFactoryAreaIds.has(factoryAreaId) : false;
64666
+ });
64667
+ }, [dbLines, selectedLineIdSet, selectedLineIds, visibleLineIds]);
64312
64668
  const metricsScopeLineId = isMultiLineSelection ? factoryViewId : primarySelectedLineId;
64313
64669
  const userCompanyId = React144.useMemo(() => {
64314
64670
  return user?.properties?.company_id || user?.company_id || entityConfig.companyId;
@@ -64349,6 +64705,7 @@ function HomeView({
64349
64705
  }, []);
64350
64706
  const {
64351
64707
  workspaceMetrics: legacyWorkspaceMetrics,
64708
+ blueComparisonWorkspaceMetrics: legacyMetricsBlueComparisonWorkspaceMetrics,
64352
64709
  lineMetrics: legacyLineMetrics,
64353
64710
  efficiencyLegend: legacyEfficiencyLegend,
64354
64711
  metadata: legacyMetricsMetadata,
@@ -64359,6 +64716,7 @@ function HomeView({
64359
64716
  } = useDashboardMetrics({
64360
64717
  lineId: metricsScopeLineId,
64361
64718
  lineIds: selectedLineIds,
64719
+ blueComparisonLineIds,
64362
64720
  onLineMetricsUpdate: handleLineMetricsUpdate,
64363
64721
  userAccessibleLineIds: visibleLineIds,
64364
64722
  enabled: shouldEnableMetricsFetch && !isBootstrapMonitorMode
@@ -64413,6 +64771,7 @@ function HomeView({
64413
64771
  const { trend: legacyKpiTrend } = useKpiTrends(legacyTrendOptions);
64414
64772
  const bootstrapMonitor = useLiveMonitorBootstrap({
64415
64773
  lineIds: selectedLineIds,
64774
+ blueComparisonLineIds,
64416
64775
  companyId: userCompanyId,
64417
64776
  enabled: shouldEnableMetricsFetch && !isLegacyMonitorMode,
64418
64777
  appTimezone: timezone,
@@ -64421,6 +64780,7 @@ function HomeView({
64421
64780
  lineShiftConfigs
64422
64781
  });
64423
64782
  const currentWorkspaceMetrics = isBootstrapMonitorMode ? bootstrapMonitor.workspaceMetrics : legacyWorkspaceMetrics;
64783
+ const currentBlueComparisonWorkspaceMetrics = isBootstrapMonitorMode ? bootstrapMonitor.blueComparisonWorkspaceMetrics : legacyMetricsBlueComparisonWorkspaceMetrics;
64424
64784
  const currentLineMetrics = isBootstrapMonitorMode ? bootstrapMonitor.lineMetrics : legacyLineMetrics;
64425
64785
  const currentEfficiencyLegend = isBootstrapMonitorMode ? bootstrapMonitor.efficiencyLegend : legacyEfficiencyLegend;
64426
64786
  const currentMetricsMetadata = isBootstrapMonitorMode ? bootstrapMonitor.metadata : legacyMetricsMetadata;
@@ -64558,6 +64918,218 @@ function HomeView({
64558
64918
  setBreakNotificationsDismissed(false);
64559
64919
  }
64560
64920
  }, [currentActiveBreaks.length]);
64921
+ const effectiveEfficiencyLegend = currentEfficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
64922
+ React144.useMemo(
64923
+ () => workspaceMetricsWithBreakState.filter((workspace) => Boolean(workspace.workspace_uuid || workspace.workspace_name)).length,
64924
+ [workspaceMetricsWithBreakState]
64925
+ );
64926
+ const allGreenCelebrationSignature = React144.useMemo(() => {
64927
+ const workspaceSignature = workspaceMetricsWithBreakState.map((workspace) => workspace.workspace_uuid || `${workspace.line_id}:${workspace.workspace_name}`).filter(Boolean).sort().join(",");
64928
+ return `${selectedLineIds.join(",")}::${workspaceSignature}`;
64929
+ }, [selectedLineIds, workspaceMetricsWithBreakState]);
64930
+ const allGreenTransitionRef = React144.useRef({ signature: null, previousValidStreakIdentity: null });
64931
+ const allGreenCelebrationTimerRef = React144.useRef(null);
64932
+ const allGreenMilestoneTimerRef = React144.useRef(null);
64933
+ const allGreenMilestoneTrackingRef = React144.useRef({ identity: null, lastMilestoneSeconds: null });
64934
+ const allGreenStreakTimerBaselineRef = React144.useRef(null);
64935
+ const [showAllGreenCelebration, setShowAllGreenCelebration] = React144.useState(false);
64936
+ const [allGreenCelebrationStartedAtMs, setAllGreenCelebrationStartedAtMs] = React144.useState(null);
64937
+ const [greenStreakMilestoneBanner, setGreenStreakMilestoneBanner] = React144.useState(null);
64938
+ const [allGreenStreakNowMs, setAllGreenStreakNowMs] = React144.useState(() => Date.now());
64939
+ const currentAllGreenStreakNowMs = Math.max(allGreenStreakNowMs, Date.now());
64940
+ const allGreenStreakDisplay = React144.useMemo(
64941
+ () => getAllVideoGridGreenStreakDisplay(
64942
+ workspaceMetricsWithBreakState,
64943
+ effectiveEfficiencyLegend,
64944
+ currentAllGreenStreakNowMs
64945
+ ),
64946
+ [currentAllGreenStreakNowMs, effectiveEfficiencyLegend, workspaceMetricsWithBreakState]
64947
+ );
64948
+ const allGreenMilestoneIdentity = React144.useMemo(() => allGreenStreakDisplay ? `${allGreenCelebrationSignature}::${allGreenStreakDisplay.startedAt}` : null, [allGreenCelebrationSignature, allGreenStreakDisplay]);
64949
+ const visibleAllGreenStreakDisplay = React144.useMemo(() => {
64950
+ if (!allGreenStreakDisplay || !allGreenMilestoneIdentity) {
64951
+ allGreenStreakTimerBaselineRef.current = null;
64952
+ return null;
64953
+ }
64954
+ const confirmedSeconds = allGreenStreakDisplay.confirmedSeconds;
64955
+ const backendVisibleSeconds = getAllGreenBackendVisibleSeconds(
64956
+ confirmedSeconds,
64957
+ allGreenStreakDisplay.tickOriginAtMs,
64958
+ currentAllGreenStreakNowMs
64959
+ );
64960
+ const backendMaxVisibleSeconds = confirmedSeconds + ALL_GREEN_STREAK_LOCAL_SECOND_CAP;
64961
+ const currentBaseline = allGreenStreakTimerBaselineRef.current;
64962
+ if (!currentBaseline || currentBaseline.identity !== allGreenMilestoneIdentity) {
64963
+ allGreenStreakTimerBaselineRef.current = {
64964
+ identity: allGreenMilestoneIdentity,
64965
+ baseSeconds: backendVisibleSeconds,
64966
+ baseReceivedAtMs: currentAllGreenStreakNowMs,
64967
+ maxVisibleSeconds: backendMaxVisibleSeconds
64968
+ };
64969
+ } else {
64970
+ currentBaseline.maxVisibleSeconds = Math.max(
64971
+ currentBaseline.maxVisibleSeconds,
64972
+ backendMaxVisibleSeconds
64973
+ );
64974
+ const visibleSeconds = Math.min(
64975
+ currentBaseline.maxVisibleSeconds,
64976
+ currentBaseline.baseSeconds + Math.max(0, Math.floor((currentAllGreenStreakNowMs - currentBaseline.baseReceivedAtMs) / 1e3))
64977
+ );
64978
+ if (backendVisibleSeconds > visibleSeconds) {
64979
+ allGreenStreakTimerBaselineRef.current = {
64980
+ identity: allGreenMilestoneIdentity,
64981
+ baseSeconds: backendVisibleSeconds,
64982
+ baseReceivedAtMs: currentAllGreenStreakNowMs,
64983
+ maxVisibleSeconds: currentBaseline.maxVisibleSeconds
64984
+ };
64985
+ }
64986
+ }
64987
+ const baseline = allGreenStreakTimerBaselineRef.current;
64988
+ const elapsedSeconds = baseline ? Math.min(
64989
+ baseline.maxVisibleSeconds,
64990
+ baseline.baseSeconds + Math.max(0, Math.floor((currentAllGreenStreakNowMs - baseline.baseReceivedAtMs) / 1e3))
64991
+ ) : backendVisibleSeconds;
64992
+ return {
64993
+ ...allGreenStreakDisplay,
64994
+ elapsedSeconds,
64995
+ durationText: formatAllGreenStreakDuration(elapsedSeconds)
64996
+ };
64997
+ }, [allGreenMilestoneIdentity, allGreenStreakDisplay, currentAllGreenStreakNowMs]);
64998
+ const allGreenCelebrationTimerText = React144.useMemo(() => {
64999
+ if (!showAllGreenCelebration || allGreenCelebrationStartedAtMs === null) {
65000
+ return null;
65001
+ }
65002
+ return formatAllGreenCelebrationTimer(
65003
+ Math.max(0, Math.floor((currentAllGreenStreakNowMs - allGreenCelebrationStartedAtMs) / 1e3))
65004
+ );
65005
+ }, [allGreenCelebrationStartedAtMs, currentAllGreenStreakNowMs, showAllGreenCelebration]);
65006
+ React144.useEffect(() => {
65007
+ const hasPossibleStreakTimer = showAllGreenCelebration || Boolean(allGreenStreakDisplay) || workspaceMetricsWithBreakState.some((workspace) => workspace.video_grid_green_streak_active === true);
65008
+ if (!hasPossibleStreakTimer) {
65009
+ return void 0;
65010
+ }
65011
+ const timerId = setInterval(() => {
65012
+ setAllGreenStreakNowMs(Date.now());
65013
+ }, 1e3);
65014
+ return () => {
65015
+ clearInterval(timerId);
65016
+ };
65017
+ }, [allGreenStreakDisplay, showAllGreenCelebration, workspaceMetricsWithBreakState]);
65018
+ const dismissAllGreenCelebration = React144.useCallback(() => {
65019
+ if (allGreenCelebrationTimerRef.current) {
65020
+ clearTimeout(allGreenCelebrationTimerRef.current);
65021
+ allGreenCelebrationTimerRef.current = null;
65022
+ }
65023
+ setShowAllGreenCelebration(false);
65024
+ setAllGreenCelebrationStartedAtMs(null);
65025
+ }, []);
65026
+ const triggerAllGreenCelebration = React144.useCallback(() => {
65027
+ setAllGreenCelebrationStartedAtMs(Date.now());
65028
+ setShowAllGreenCelebration(true);
65029
+ if (allGreenCelebrationTimerRef.current) {
65030
+ clearTimeout(allGreenCelebrationTimerRef.current);
65031
+ }
65032
+ allGreenCelebrationTimerRef.current = setTimeout(() => {
65033
+ setShowAllGreenCelebration(false);
65034
+ setAllGreenCelebrationStartedAtMs(null);
65035
+ allGreenCelebrationTimerRef.current = null;
65036
+ }, ALL_GREEN_CELEBRATION_DURATION_MS);
65037
+ }, []);
65038
+ const dismissGreenStreakMilestoneBanner = React144.useCallback(() => {
65039
+ if (allGreenMilestoneTimerRef.current) {
65040
+ clearTimeout(allGreenMilestoneTimerRef.current);
65041
+ allGreenMilestoneTimerRef.current = null;
65042
+ }
65043
+ setGreenStreakMilestoneBanner(null);
65044
+ }, []);
65045
+ const triggerGreenStreakMilestoneBanner = React144.useCallback((milestone) => {
65046
+ setGreenStreakMilestoneBanner(milestone);
65047
+ if (allGreenMilestoneTimerRef.current) {
65048
+ clearTimeout(allGreenMilestoneTimerRef.current);
65049
+ }
65050
+ allGreenMilestoneTimerRef.current = setTimeout(() => {
65051
+ setGreenStreakMilestoneBanner(null);
65052
+ allGreenMilestoneTimerRef.current = null;
65053
+ }, ALL_GREEN_MILESTONE_DURATION_MS);
65054
+ }, []);
65055
+ React144.useEffect(() => {
65056
+ return () => {
65057
+ if (allGreenCelebrationTimerRef.current) {
65058
+ clearTimeout(allGreenCelebrationTimerRef.current);
65059
+ }
65060
+ if (allGreenMilestoneTimerRef.current) {
65061
+ clearTimeout(allGreenMilestoneTimerRef.current);
65062
+ }
65063
+ };
65064
+ }, []);
65065
+ React144.useEffect(() => {
65066
+ const milestoneTracking = allGreenMilestoneTrackingRef.current;
65067
+ if (currentMetricsLoading) {
65068
+ return;
65069
+ }
65070
+ if (!visibleAllGreenStreakDisplay || !allGreenMilestoneIdentity) {
65071
+ milestoneTracking.identity = null;
65072
+ milestoneTracking.lastMilestoneSeconds = null;
65073
+ dismissGreenStreakMilestoneBanner();
65074
+ return;
65075
+ }
65076
+ const currentMilestone = getAllGreenStreakMilestone(visibleAllGreenStreakDisplay.elapsedSeconds);
65077
+ const currentMilestoneSeconds = currentMilestone?.milestoneSeconds ?? null;
65078
+ if (milestoneTracking.identity !== allGreenMilestoneIdentity) {
65079
+ milestoneTracking.identity = allGreenMilestoneIdentity;
65080
+ milestoneTracking.lastMilestoneSeconds = currentMilestoneSeconds;
65081
+ dismissGreenStreakMilestoneBanner();
65082
+ return;
65083
+ }
65084
+ if (!currentMilestone) {
65085
+ milestoneTracking.lastMilestoneSeconds = null;
65086
+ return;
65087
+ }
65088
+ if ((milestoneTracking.lastMilestoneSeconds ?? 0) < currentMilestone.milestoneSeconds) {
65089
+ milestoneTracking.lastMilestoneSeconds = currentMilestone.milestoneSeconds;
65090
+ triggerGreenStreakMilestoneBanner(currentMilestone);
65091
+ }
65092
+ }, [
65093
+ allGreenMilestoneIdentity,
65094
+ currentMetricsLoading,
65095
+ dismissGreenStreakMilestoneBanner,
65096
+ triggerGreenStreakMilestoneBanner,
65097
+ visibleAllGreenStreakDisplay
65098
+ ]);
65099
+ React144.useEffect(() => {
65100
+ if (currentMetricsLoading) {
65101
+ return;
65102
+ }
65103
+ const currentValidStreakIdentity = visibleAllGreenStreakDisplay && allGreenMilestoneIdentity ? allGreenMilestoneIdentity : null;
65104
+ const transitionState = allGreenTransitionRef.current;
65105
+ if (transitionState.signature !== allGreenCelebrationSignature) {
65106
+ transitionState.signature = allGreenCelebrationSignature;
65107
+ transitionState.previousValidStreakIdentity = currentValidStreakIdentity;
65108
+ dismissAllGreenCelebration();
65109
+ return;
65110
+ }
65111
+ if (!currentValidStreakIdentity) {
65112
+ transitionState.previousValidStreakIdentity = null;
65113
+ dismissAllGreenCelebration();
65114
+ return;
65115
+ }
65116
+ if (transitionState.previousValidStreakIdentity === null) {
65117
+ transitionState.previousValidStreakIdentity = currentValidStreakIdentity;
65118
+ triggerAllGreenCelebration();
65119
+ return;
65120
+ }
65121
+ if (transitionState.previousValidStreakIdentity !== currentValidStreakIdentity) {
65122
+ transitionState.previousValidStreakIdentity = currentValidStreakIdentity;
65123
+ dismissAllGreenCelebration();
65124
+ }
65125
+ }, [
65126
+ allGreenCelebrationSignature,
65127
+ allGreenMilestoneIdentity,
65128
+ currentMetricsLoading,
65129
+ dismissAllGreenCelebration,
65130
+ triggerAllGreenCelebration,
65131
+ visibleAllGreenStreakDisplay
65132
+ ]);
64561
65133
  const {
64562
65134
  streamsByWorkspaceId: legacyVideoStreamsByWorkspaceId,
64563
65135
  isLoading: legacyVideoStreamsLoading
@@ -65124,6 +65696,28 @@ function HomeView({
65124
65696
  updateSelectedLineIds,
65125
65697
  isAllLinesSelection
65126
65698
  ]);
65699
+ const gridToolbarControls = React144.useMemo(() => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-2", children: [
65700
+ /* @__PURE__ */ jsxRuntime.jsx(AnimatePresence, { children: visibleAllGreenStreakDisplay ? /* @__PURE__ */ jsxRuntime.jsxs(
65701
+ motion.div,
65702
+ {
65703
+ initial: { opacity: 0, y: -4 },
65704
+ animate: { opacity: 1, y: 0 },
65705
+ exit: { opacity: 0, y: -4 },
65706
+ transition: { duration: 0.18, ease: "easeOut" },
65707
+ className: "inline-flex items-center gap-1.5 rounded-md border border-[#00AB45]/20 bg-[#00AB45]/10 px-3 py-1.5 text-sm font-semibold text-[#00AB45] shadow-sm",
65708
+ "aria-label": "All green streak",
65709
+ children: [
65710
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-4 w-4" }),
65711
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: `${visibleAllGreenStreakDisplay.label} \xB7 ${visibleAllGreenStreakDisplay.durationText}` })
65712
+ ]
65713
+ },
65714
+ visibleAllGreenStreakDisplay.startedAt
65715
+ ) : null }),
65716
+ lineSelectorComponent
65717
+ ] }), [
65718
+ lineSelectorComponent,
65719
+ visibleAllGreenStreakDisplay
65720
+ ]);
65127
65721
  const useSmoothLoading = (isLoading, minDuration = 400) => {
65128
65722
  const [showLoading, setShowLoading] = React144.useState(isLoading);
65129
65723
  const loadingStartRef2 = React144.useRef(null);
@@ -65296,17 +65890,18 @@ function HomeView({
65296
65890
  className: "h-full",
65297
65891
  children: React144__namespace.default.createElement(WorkspaceGrid, {
65298
65892
  workspaces: workspaceMetricsWithBreakState,
65893
+ blueComparisonWorkspaces: currentBlueComparisonWorkspaceMetrics || workspaceMetricsWithBreakState,
65299
65894
  lineNames: mergedLineNames,
65300
65895
  lineOrder: selectedLineIds,
65301
65896
  factoryView: factoryViewId,
65302
- legend: currentEfficiencyLegend,
65897
+ legend: effectiveEfficiencyLegend,
65303
65898
  videoSources,
65304
65899
  videoStreamsByWorkspaceId: currentVideoStreamsByWorkspaceId,
65305
65900
  videoStreamsLoading: currentVideoStreamsLoading,
65306
65901
  displayNames: metricsDisplayNames,
65307
65902
  hasFlowBuffers,
65308
65903
  className: "h-full",
65309
- toolbarRightContent: lineSelectorComponent,
65904
+ toolbarRightContent: gridToolbarControls,
65310
65905
  onWorkspaceHover: handleWorkspaceHover,
65311
65906
  onWorkspaceHoverEnd: handleWorkspaceHoverEnd
65312
65907
  })
@@ -65329,17 +65924,18 @@ function HomeView({
65329
65924
  children: React144__namespace.default.createElement(WorkspaceGrid, {
65330
65925
  workspaces: [],
65331
65926
  // Show empty grid while loading
65927
+ blueComparisonWorkspaces: [],
65332
65928
  lineNames: mergedLineNames,
65333
65929
  lineOrder: selectedLineIds,
65334
65930
  factoryView: factoryViewId,
65335
- legend: currentEfficiencyLegend,
65931
+ legend: effectiveEfficiencyLegend,
65336
65932
  videoSources,
65337
65933
  videoStreamsByWorkspaceId: currentVideoStreamsByWorkspaceId,
65338
65934
  videoStreamsLoading: currentVideoStreamsLoading,
65339
65935
  displayNames: metricsDisplayNames,
65340
65936
  hasFlowBuffers,
65341
65937
  className: "h-full",
65342
- toolbarRightContent: lineSelectorComponent,
65938
+ toolbarRightContent: gridToolbarControls,
65343
65939
  onWorkspaceHover: handleWorkspaceHover,
65344
65940
  onWorkspaceHoverEnd: handleWorkspaceHoverEnd
65345
65941
  })
@@ -65372,6 +65968,149 @@ function HomeView({
65372
65968
  contentVariant: "plain"
65373
65969
  }
65374
65970
  ),
65971
+ /* @__PURE__ */ jsxRuntime.jsx(AnimatePresence, { children: showAllGreenCelebration ? /* @__PURE__ */ jsxRuntime.jsxs(React144__namespace.default.Fragment, { children: [
65972
+ /* @__PURE__ */ jsxRuntime.jsx(
65973
+ motion.div,
65974
+ {
65975
+ initial: { opacity: 0 },
65976
+ animate: { opacity: 1 },
65977
+ exit: { opacity: 0 },
65978
+ transition: { duration: 0.4 },
65979
+ className: "pointer-events-none fixed inset-0 z-[9998] bg-slate-900/40 backdrop-blur-sm",
65980
+ "aria-hidden": "true"
65981
+ },
65982
+ "all-green-backdrop"
65983
+ ),
65984
+ /* @__PURE__ */ jsxRuntime.jsxs(
65985
+ motion.div,
65986
+ {
65987
+ initial: { opacity: 0 },
65988
+ animate: { opacity: 1 },
65989
+ exit: { opacity: 0, y: -50, scale: 0.9, filter: "blur(10px)" },
65990
+ transition: { duration: 0.4 },
65991
+ className: "pointer-events-none fixed inset-0 z-[10000] flex flex-col items-center justify-center px-4",
65992
+ role: "status",
65993
+ "aria-live": "polite",
65994
+ "aria-label": "All green celebration",
65995
+ children: [
65996
+ /* @__PURE__ */ jsxRuntime.jsxs(
65997
+ motion.div,
65998
+ {
65999
+ initial: { opacity: 0, y: 8, filter: "blur(6px)" },
66000
+ animate: { opacity: 1, y: 0, filter: "blur(0px)" },
66001
+ transition: { duration: 0.28, ease: [0.16, 1, 0.3, 1] },
66002
+ className: "flex flex-wrap items-center justify-center gap-x-4 sm:gap-x-8",
66003
+ children: [
66004
+ /* @__PURE__ */ jsxRuntime.jsx(
66005
+ "span",
66006
+ {
66007
+ className: "text-[100px] font-black uppercase leading-none tracking-tight text-white drop-shadow-2xl sm:text-[140px]",
66008
+ style: { textShadow: "0 18px 36px rgba(0,0,0,0.34)" },
66009
+ children: "ALL"
66010
+ }
66011
+ ),
66012
+ /* @__PURE__ */ jsxRuntime.jsx(
66013
+ "span",
66014
+ {
66015
+ className: "text-[100px] font-black uppercase leading-none tracking-tight text-[#00AB45] drop-shadow-2xl sm:text-[140px]",
66016
+ style: { filter: "drop-shadow(0 18px 36px rgba(0,171,69,0.28))" },
66017
+ children: "GREEN"
66018
+ }
66019
+ )
66020
+ ]
66021
+ }
66022
+ ),
66023
+ /* @__PURE__ */ jsxRuntime.jsx(
66024
+ motion.div,
66025
+ {
66026
+ initial: { opacity: 0, scaleX: 0 },
66027
+ animate: { opacity: 1, scaleX: 1 },
66028
+ transition: { delay: 0.18, duration: 0.45, ease: [0.16, 1, 0.3, 1] },
66029
+ className: "mt-4 h-1 w-44 origin-left rounded-full bg-[#00AB45] shadow-[0_0_16px_rgba(0,171,69,0.44)] sm:w-64"
66030
+ }
66031
+ ),
66032
+ allGreenCelebrationTimerText && /* @__PURE__ */ jsxRuntime.jsxs(
66033
+ motion.div,
66034
+ {
66035
+ initial: { opacity: 0, y: 4 },
66036
+ animate: { opacity: 1, y: 0 },
66037
+ transition: { delay: 0.28, duration: 0.18, ease: "easeOut" },
66038
+ className: "mt-3 flex items-center justify-center gap-2 text-2xl font-semibold tracking-tight text-white drop-shadow-[0_4px_18px_rgba(0,0,0,0.45)] sm:mt-4 sm:text-3xl",
66039
+ children: [
66040
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-2.5 w-2.5 rounded-full bg-[#00AB45] shadow-[0_0_10px_rgba(0,171,69,0.72)]" }),
66041
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: allGreenCelebrationTimerText })
66042
+ ]
66043
+ }
66044
+ )
66045
+ ]
66046
+ },
66047
+ "all-green-center-toast"
66048
+ )
66049
+ ] }, "all-green-celebration") : null }),
66050
+ /* @__PURE__ */ jsxRuntime.jsx(AnimatePresence, { children: greenStreakMilestoneBanner ? /* @__PURE__ */ jsxRuntime.jsxs(React144__namespace.default.Fragment, { children: [
66051
+ /* @__PURE__ */ jsxRuntime.jsx(
66052
+ motion.div,
66053
+ {
66054
+ initial: { opacity: 0 },
66055
+ animate: { opacity: 1 },
66056
+ exit: { opacity: 0 },
66057
+ transition: { duration: 0.4 },
66058
+ className: "pointer-events-none fixed inset-0 z-[9998] bg-slate-900/40 backdrop-blur-sm",
66059
+ "aria-hidden": "true"
66060
+ },
66061
+ `green-streak-backdrop-${greenStreakMilestoneBanner.milestoneSeconds}`
66062
+ ),
66063
+ /* @__PURE__ */ jsxRuntime.jsx(
66064
+ motion.div,
66065
+ {
66066
+ initial: { opacity: 0 },
66067
+ animate: { opacity: 1 },
66068
+ exit: { opacity: 0, y: -50, scale: 0.9, filter: "blur(10px)" },
66069
+ transition: { duration: 0.4 },
66070
+ className: "pointer-events-none fixed inset-0 z-[10000] flex flex-col items-center justify-center px-4",
66071
+ role: "status",
66072
+ "aria-live": "polite",
66073
+ "aria-label": `Green streak milestone: ${greenStreakMilestoneBanner.headline}`,
66074
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center gap-y-4", children: [
66075
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
66076
+ motion.div,
66077
+ {
66078
+ initial: { opacity: 0, y: 8, filter: "blur(6px)" },
66079
+ animate: { opacity: 1, y: 0, filter: "blur(0px)" },
66080
+ transition: { delay: 0.08, duration: 0.28, ease: [0.16, 1, 0.3, 1] },
66081
+ className: "text-[80px] font-black uppercase leading-none tracking-tight text-white drop-shadow-2xl sm:text-[120px]",
66082
+ style: { textShadow: "0 18px 36px rgba(0,0,0,0.34)" },
66083
+ children: greenStreakMilestoneBanner.headline
66084
+ }
66085
+ ) }),
66086
+ /* @__PURE__ */ jsxRuntime.jsx(
66087
+ motion.div,
66088
+ {
66089
+ initial: { opacity: 0, scaleX: 0 },
66090
+ animate: { opacity: 1, scaleX: 1 },
66091
+ transition: { delay: 0.22, duration: 0.45, ease: [0.16, 1, 0.3, 1] },
66092
+ className: "h-1 w-40 origin-left rounded-full bg-[#00AB45] shadow-[0_0_16px_rgba(0,171,69,0.44)] sm:w-56"
66093
+ }
66094
+ ),
66095
+ /* @__PURE__ */ jsxRuntime.jsxs(
66096
+ motion.div,
66097
+ {
66098
+ initial: { opacity: 0, y: 8, filter: "blur(6px)" },
66099
+ animate: { opacity: 1, y: 0, filter: "blur(0px)" },
66100
+ transition: { delay: 0.28, duration: 0.28, ease: [0.16, 1, 0.3, 1] },
66101
+ className: "flex flex-wrap items-center justify-center gap-x-4 text-[60px] font-black uppercase leading-none tracking-tight text-[#00AB45] drop-shadow-2xl sm:gap-x-8 sm:text-[90px]",
66102
+ style: { filter: "drop-shadow(0 18px 36px rgba(0,171,69,0.28))" },
66103
+ children: [
66104
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "ALL" }),
66105
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "GREEN" })
66106
+ ]
66107
+ }
66108
+ )
66109
+ ] })
66110
+ },
66111
+ `green-streak-milestone-${greenStreakMilestoneBanner.milestoneSeconds}`
66112
+ )
66113
+ ] }, `green-streak-milestone-wrapper-${greenStreakMilestoneBanner.milestoneSeconds}`) : null }),
65375
66114
  diagnosisModalOpen && bottleneckModalData?.clipId && /* @__PURE__ */ jsxRuntime.jsx(
65376
66115
  DiagnosisVideoModal,
65377
66116
  {
@@ -68766,6 +69505,7 @@ var LinesLeaderboard = ({
68766
69505
  timeRange,
68767
69506
  setTimeRange,
68768
69507
  todayEfficiencyByLineId,
69508
+ dailyFallbackEfficiencyByLineId,
68769
69509
  monthlyEfficiencyByLineId,
68770
69510
  supervisorsByLineId,
68771
69511
  supervisorNamesByLineId,
@@ -68801,8 +69541,12 @@ var LinesLeaderboard = ({
68801
69541
  });
68802
69542
  setTimeRange(newRange);
68803
69543
  }, [timeRange, lines.length, monthlyEfficiencyByLineId, setTimeRange]);
69544
+ const canClickLeaderboardRow = React144__namespace.default.useCallback(
69545
+ (item) => item.rowType === "line" && !!item.line && canClickLine(item.line.id),
69546
+ [canClickLine]
69547
+ );
68804
69548
  const handleLeaderboardLineClick = React144__namespace.default.useCallback((item, clickSource) => {
68805
- if (!canClickLine(item.line.id)) return;
69549
+ if (!canClickLeaderboardRow(item) || !item.line) return;
68806
69550
  trackCoreEvent("Leaderboard Line Clicked", {
68807
69551
  line_id: item.line.id,
68808
69552
  line_name: item.line.line_name,
@@ -68814,33 +69558,46 @@ var LinesLeaderboard = ({
68814
69558
  supervisor_name: item.supervisorName || "Unassigned"
68815
69559
  });
68816
69560
  onLineClick(item.line);
68817
- }, [canClickLine, onLineClick, timeRange]);
69561
+ }, [canClickLeaderboardRow, onLineClick, timeRange]);
68818
69562
  const viewLoadedTrackedRef = React144__namespace.default.useRef(null);
68819
69563
  const leaderboardData = React144__namespace.default.useMemo(() => {
68820
69564
  const loading = timeRange === "today" ? isLoadingToday : isLoadingMonthly;
68821
69565
  const efficiencyMap = timeRange === "today" ? todayEfficiencyByLineId : monthlyEfficiencyByLineId;
68822
- return lines.map((line) => {
68823
- const supervisors = supervisorsByLineId?.get(line.id) || [];
69566
+ const fallbackEfficiencyMap = timeRange === "today" ? dailyFallbackEfficiencyByLineId : void 0;
69567
+ return buildLineLeaderboardRows({
69568
+ lines,
69569
+ efficiencyByLineId: efficiencyMap,
69570
+ fallbackEfficiencyByLineId: fallbackEfficiencyMap,
69571
+ isLoading: loading
69572
+ }).map((row, index) => {
69573
+ const supervisorByUserId = /* @__PURE__ */ new Map();
69574
+ const fallbackSupervisorNames = [];
69575
+ row.lines.forEach((line) => {
69576
+ (supervisorsByLineId?.get(line.id) || []).forEach((supervisor) => {
69577
+ supervisorByUserId.set(supervisor.userId, supervisor);
69578
+ });
69579
+ const fallbackName = supervisorNamesByLineId.get(line.id);
69580
+ if (fallbackName && !fallbackSupervisorNames.includes(fallbackName)) {
69581
+ fallbackSupervisorNames.push(fallbackName);
69582
+ }
69583
+ });
69584
+ const supervisors = Array.from(supervisorByUserId.values());
68824
69585
  const primarySupervisor = supervisors[0];
68825
- const supervisorName = supervisorNamesByLineId.get(line.id) || primarySupervisor?.displayName || "Unassigned";
69586
+ const supervisorName = supervisors.length > 1 ? `${supervisors.length} supervisors` : primarySupervisor?.displayName || fallbackSupervisorNames[0] || "Unassigned";
68826
69587
  const supervisorImage = primarySupervisor?.profilePhotoUrl || null;
68827
- const hasEfficiency = efficiencyMap.has(line.id);
68828
- const efficiency = hasEfficiency ? efficiencyMap.get(line.id) ?? 0 : loading ? null : timeRange === "monthly" ? 0 : null;
68829
- const sortValue = typeof efficiency === "number" ? efficiency : -1;
68830
69588
  return {
68831
- id: line.id,
68832
- line,
69589
+ ...row,
69590
+ rank: row.rank ?? index + 1,
68833
69591
  supervisorName,
68834
69592
  supervisorImage,
68835
- supervisors,
68836
- efficiency,
68837
- sortValue
69593
+ supervisors
68838
69594
  };
68839
- }).sort((a, b) => b.sortValue - a.sortValue).map((item, index) => ({ ...item, rank: index + 1 }));
69595
+ });
68840
69596
  }, [
68841
69597
  lines,
68842
69598
  timeRange,
68843
69599
  todayEfficiencyByLineId,
69600
+ dailyFallbackEfficiencyByLineId,
68844
69601
  monthlyEfficiencyByLineId,
68845
69602
  supervisorsByLineId,
68846
69603
  supervisorNamesByLineId,
@@ -68857,11 +69614,11 @@ var LinesLeaderboard = ({
68857
69614
  trackCoreEvent("Leaderboard View Loaded", {
68858
69615
  time_range: timeRange,
68859
69616
  lines_count: leaderboardData.length,
68860
- top_line_id: topLine?.line.id,
68861
- top_line_name: topLine?.line.line_name,
69617
+ top_line_id: topLine?.rowType === "line" ? topLine.line?.id : topLine?.areaId,
69618
+ top_line_name: topLine?.displayName,
68862
69619
  top_efficiency: topLine?.efficiency,
68863
- bottom_line_id: bottomLine?.line.id,
68864
- bottom_line_name: bottomLine?.line.line_name,
69620
+ bottom_line_id: bottomLine?.rowType === "line" ? bottomLine.line?.id : bottomLine?.areaId,
69621
+ bottom_line_name: bottomLine?.displayName,
68865
69622
  bottom_efficiency: bottomLine?.efficiency,
68866
69623
  efficiency_spread: topLine && bottomLine && topLine.efficiency !== null && bottomLine.efficiency !== null ? (topLine.efficiency - bottomLine.efficiency).toFixed(1) : null,
68867
69624
  from_page: "kpis_overview"
@@ -68968,7 +69725,7 @@ var LinesLeaderboard = ({
68968
69725
  const isFirst = item.rank === 1;
68969
69726
  const isSecond = item.rank === 2;
68970
69727
  item.rank === 3;
68971
- const isClickable = canClickLine(item.line.id);
69728
+ const isClickable = canClickLeaderboardRow(item);
68972
69729
  return /* @__PURE__ */ jsxRuntime.jsxs(
68973
69730
  "div",
68974
69731
  {
@@ -69011,7 +69768,11 @@ var LinesLeaderboard = ({
69011
69768
  className: `flex flex-col items-center w-32 md:w-40 lg:w-48 xl:w-60 px-2 md:px-3 xl:px-4 pb-3 md:pb-4 pt-8 md:pt-10 rounded-2xl border bg-gradient-to-b shadow-2xl backdrop-blur-sm ${getRankColor(item.rank)} ${isFirst ? "h-44 md:h-52 lg:h-60 xl:h-64" : isSecond ? "h-36 md:h-44 lg:h-52 xl:h-56" : "h-28 md:h-36 lg:h-44 xl:h-48"}`,
69012
69769
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center w-full", children: [
69013
69770
  /* @__PURE__ */ jsxRuntime.jsx("h3", { className: `font-bold text-gray-900 text-center line-clamp-1 mb-1 ${isFirst ? "text-xs md:text-sm lg:text-base xl:text-lg" : "text-[10px] md:text-xs lg:text-sm xl:text-base"}`, children: item.supervisorName }),
69014
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-gray-600 text-center line-clamp-1 font-medium opacity-80 bg-white/50 px-2 md:px-3 py-0.5 rounded-full ${isFirst ? "text-[9px] md:text-[10px] lg:text-xs xl:text-sm mb-2 md:mb-3" : "text-[8px] md:text-[9px] lg:text-[10px] xl:text-xs mb-1 md:mb-2"}`, children: item.line.line_name }),
69771
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-gray-600 text-center line-clamp-1 font-medium opacity-80 bg-white/50 px-2 md:px-3 py-0.5 rounded-full ${isFirst ? "text-[9px] md:text-[10px] lg:text-xs xl:text-sm mb-2 md:mb-3" : "text-[8px] md:text-[9px] lg:text-[10px] xl:text-xs mb-1 md:mb-2"}`, children: item.displayName }),
69772
+ item.rowType === "area" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mb-1 text-[8px] md:text-[9px] lg:text-[10px] xl:text-xs font-semibold uppercase text-gray-500", children: [
69773
+ item.lines.length,
69774
+ " lines"
69775
+ ] }),
69015
69776
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center mt-auto", children: [
69016
69777
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: `font-bold uppercase tracking-widest mb-0.5 ${isFirst ? "text-yellow-700/70 text-[8px] md:text-[9px] lg:text-[10px] xl:text-xs" : isSecond ? "text-gray-600/70 text-[7px] md:text-[8px] lg:text-[9px] xl:text-[10px]" : "text-orange-700/70 text-[7px] md:text-[8px] lg:text-[9px] xl:text-[10px]"}`, children: viewType === "machine" ? "Utilization" : "Efficiency" }),
69017
69778
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: `font-black tracking-tight leading-none ${isFirst ? "text-lg md:text-xl lg:text-2xl xl:text-3xl text-transparent bg-clip-text bg-gradient-to-br from-yellow-600 to-yellow-800 drop-shadow-sm" : isSecond ? "text-base md:text-lg lg:text-xl xl:text-2xl text-transparent bg-clip-text bg-gradient-to-br from-gray-600 to-gray-800 drop-shadow-sm" : "text-sm md:text-base lg:text-lg xl:text-xl text-transparent bg-clip-text bg-gradient-to-br from-orange-600 to-orange-800 drop-shadow-sm"}`, children: formatEfficiency(item.efficiency) })
@@ -69034,7 +69795,7 @@ var LinesLeaderboard = ({
69034
69795
  ] }) }),
69035
69796
  /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-gray-100", children: leaderboardData.map((item) => {
69036
69797
  const isTopThree = item.rank <= 3;
69037
- const isClickable = canClickLine(item.line.id);
69798
+ const isClickable = canClickLeaderboardRow(item);
69038
69799
  return /* @__PURE__ */ jsxRuntime.jsxs(
69039
69800
  "tr",
69040
69801
  {
@@ -69066,7 +69827,13 @@ var LinesLeaderboard = ({
69066
69827
  ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center text-gray-500 overflow-hidden border border-gray-200 flex-shrink-0", children: item.supervisorImage ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: item.supervisorImage, alt: item.supervisorName, className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-bold", children: getInitials(item.supervisorName) }) }),
69067
69828
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-900", children: item.supervisorName })
69068
69829
  ] }) }),
69069
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 whitespace-nowrap text-sm text-gray-500", children: item.line.line_name }),
69830
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 whitespace-nowrap text-sm text-gray-500", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
69831
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-gray-700", children: item.displayName }),
69832
+ item.rowType === "area" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-400", children: [
69833
+ item.lines.length,
69834
+ " lines"
69835
+ ] })
69836
+ ] }) }),
69070
69837
  /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 whitespace-nowrap text-right", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-end", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold text-gray-900", children: formatEfficiency(item.efficiency) }) }) })
69071
69838
  ]
69072
69839
  },
@@ -69344,17 +70111,6 @@ var KPIsOverviewView = ({
69344
70111
  const filterRef = React144.useRef(null);
69345
70112
  const filterButtonRef = React144.useRef(null);
69346
70113
  const [error, setError] = React144.useState(null);
69347
- const [topPerformer, setTopPerformer] = React144.useState({
69348
- name: "Top Performer",
69349
- role: "Sup.",
69350
- unit: "Line",
69351
- periodLabel: (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", { month: "long", year: "numeric" }),
69352
- efficiency: null,
69353
- imageUrl: null,
69354
- initials: "TP"
69355
- });
69356
- const [topPerformerLoading, setTopPerformerLoading] = React144.useState(true);
69357
- const [topPerformerImageError, setTopPerformerImageError] = React144.useState(false);
69358
70114
  const [todayEfficiencyByLineId, setTodayEfficiencyByLineId] = React144.useState(/* @__PURE__ */ new Map());
69359
70115
  const [dailyLoading, setDailyLoading] = React144.useState(false);
69360
70116
  const [dailyError, setDailyError] = React144.useState(null);
@@ -69363,6 +70119,9 @@ var KPIsOverviewView = ({
69363
70119
  const [monthlyError, setMonthlyError] = React144.useState(null);
69364
70120
  const dailyRequestKeyRef = React144.useRef(null);
69365
70121
  const monthlyRequestKeyRef = React144.useRef(null);
70122
+ const dailyFallbackRequestKeyRef = React144.useRef(null);
70123
+ const pendingTabRouteSyncRef = React144.useRef(null);
70124
+ const [scopedDailyFallbackEfficiencyByLineId, setScopedDailyFallbackEfficiencyByLineId] = React144.useState(/* @__PURE__ */ new Map());
69366
70125
  const supabase = useSupabase();
69367
70126
  const { user } = useAuth();
69368
70127
  const dashboardConfig = useDashboardConfig();
@@ -69407,8 +70166,23 @@ var KPIsOverviewView = ({
69407
70166
  const assignedLineIdsForLeaderboard = isSuperAdmin ? void 0 : resolvedAssignedLineIds;
69408
70167
  const leaderboardLinesForView = React144__namespace.default.useMemo(() => {
69409
70168
  const targetMode = viewType === "machine" ? "uptime" : "output";
69410
- return leaderboardLines.filter((line) => (line.monitoring_mode ?? "output") === targetMode);
69411
- }, [leaderboardLines, viewType]);
70169
+ const metadataByLineId = new Map(lines.map((line) => [line.id, line]));
70170
+ return leaderboardLines.map((line) => {
70171
+ const metadata = metadataByLineId.get(line.id);
70172
+ return metadata ? {
70173
+ ...line,
70174
+ factory_id: line.factory_id || metadata.factory_id,
70175
+ factory_name: line.factory_name || metadata.factory_name,
70176
+ company_name: line.company_name || metadata.company_name,
70177
+ monitoring_mode: line.monitoring_mode ?? metadata.monitoring_mode,
70178
+ factory_area_id: line.factory_area_id ?? metadata.factory_area_id ?? null,
70179
+ factory_area_key: line.factory_area_key ?? metadata.factory_area_key ?? null,
70180
+ factory_area_name: line.factory_area_name ?? metadata.factory_area_name ?? null,
70181
+ factory_area_sort_order: line.factory_area_sort_order ?? metadata.factory_area_sort_order ?? null,
70182
+ factory_area_enabled: line.factory_area_enabled ?? metadata.factory_area_enabled ?? null
70183
+ } : line;
70184
+ }).filter((line) => (line.monitoring_mode ?? "output") === targetMode);
70185
+ }, [leaderboardLines, lines, viewType]);
69412
70186
  const linesForView = React144__namespace.default.useMemo(() => {
69413
70187
  const targetMode = viewType === "machine" ? "uptime" : "output";
69414
70188
  return lines.filter((line) => (line.monitoring_mode ?? "output") === targetMode);
@@ -69528,12 +70302,19 @@ var KPIsOverviewView = ({
69528
70302
  React144.useEffect(() => {
69529
70303
  if (!router$1.isReady || !hasHydratedLeaderboardRouteState) return;
69530
70304
  if (activeTab === "today" && loading) return;
70305
+ const currentTab = typeof router$1.query.tab === "string" ? router$1.query.tab : void 0;
70306
+ const currentRouteTab = currentTab === "leaderboard" ? "leaderboard" : "today";
70307
+ if (currentRouteTab !== activeTab) {
70308
+ if (pendingTabRouteSyncRef.current !== activeTab) {
70309
+ return;
70310
+ }
70311
+ pendingTabRouteSyncRef.current = null;
70312
+ }
69531
70313
  const expectedTab = activeTab === "leaderboard" ? "leaderboard" : void 0;
69532
70314
  const expectedDate = activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily ? effectiveLeaderboardDate : void 0;
69533
70315
  const expectedShift = expectedDate !== void 0 ? effectiveLeaderboardShiftId.toString() : void 0;
69534
70316
  const expectedFactory = activeTab === "today" && selectedFactoryNode ? selectedFactoryNode.id : void 0;
69535
70317
  const expectedFactoryArea = activeTab === "today" && selectedFactoryNode && selectedFactoryAreaNode ? selectedFactoryAreaNode.id : void 0;
69536
- const currentTab = typeof router$1.query.tab === "string" ? router$1.query.tab : void 0;
69537
70318
  const currentDateQuery = typeof router$1.query.date === "string" ? router$1.query.date : void 0;
69538
70319
  const currentShiftQuery = typeof router$1.query.shift === "string" ? router$1.query.shift : void 0;
69539
70320
  const currentFactoryQuery = getSingleQueryValue(router$1.query[KPI_FACTORY_QUERY_PARAM]);
@@ -69593,6 +70374,35 @@ var KPIsOverviewView = ({
69593
70374
  });
69594
70375
  return map;
69595
70376
  }, [lineMetrics, lineModeById]);
70377
+ const liveDailyFallbackEfficiencyByLineId = React144__namespace.default.useMemo(() => {
70378
+ const map = /* @__PURE__ */ new Map();
70379
+ lineMetricRowsByLineId.forEach((row, lineId) => {
70380
+ const value = Number(row?.avg_efficiency);
70381
+ if (!Number.isFinite(value)) return;
70382
+ const rowDate = typeof row?.date === "string" ? row.date : typeof row?.operational_date === "string" ? row.operational_date : void 0;
70383
+ const rawShiftId = row?.shift_id ?? row?.shiftId;
70384
+ const parsedShiftId = typeof rawShiftId === "number" ? rawShiftId : Number.parseInt(String(rawShiftId ?? ""), 10);
70385
+ const hasScopedRow = rowDate !== void 0 || rawShiftId !== void 0;
70386
+ const matchesSelectedScope = rowDate === effectiveLeaderboardDate && Number.isFinite(parsedShiftId) && parsedShiftId === effectiveLeaderboardShiftId;
70387
+ const canUseUnscopedLiveFallback = !isHistoricalLeaderboardDaily && !hasScopedRow;
70388
+ if (matchesSelectedScope || canUseUnscopedLiveFallback) {
70389
+ map.set(lineId, value);
70390
+ }
70391
+ });
70392
+ return map;
70393
+ }, [
70394
+ effectiveLeaderboardDate,
70395
+ effectiveLeaderboardShiftId,
70396
+ isHistoricalLeaderboardDaily,
70397
+ lineMetricRowsByLineId
70398
+ ]);
70399
+ const dailyFallbackEfficiencyByLineId = React144__namespace.default.useMemo(() => {
70400
+ const map = new Map(liveDailyFallbackEfficiencyByLineId);
70401
+ scopedDailyFallbackEfficiencyByLineId.forEach((value, lineId) => {
70402
+ map.set(lineId, value);
70403
+ });
70404
+ return map;
70405
+ }, [liveDailyFallbackEfficiencyByLineId, scopedDailyFallbackEfficiencyByLineId]);
69596
70406
  const kpisByLineId = React144__namespace.default.useMemo(() => {
69597
70407
  const map = /* @__PURE__ */ new Map();
69598
70408
  lineMetricRowsByLineId.forEach((row, lineId) => {
@@ -69614,32 +70424,11 @@ var KPIsOverviewView = ({
69614
70424
  () => (leaderboardLines.length > 0 ? leaderboardLines : lines).map((l) => l.id),
69615
70425
  [leaderboardLines, lines]
69616
70426
  );
69617
- const { supervisorNamesByLineId, supervisorsByLineId, allSupervisorsMap } = useSupervisorsByLineIds(supervisorLineIds, {
70427
+ const { supervisorNamesByLineId, supervisorsByLineId } = useSupervisorsByLineIds(supervisorLineIds, {
69618
70428
  enabled: supervisorEnabled && supervisorLineIds.length > 0,
69619
70429
  companyId: resolvedCompanyId,
69620
70430
  useBackend: true
69621
70431
  });
69622
- React144.useEffect(() => {
69623
- let isMounted = true;
69624
- const loadTopPerformer = async () => {
69625
- try {
69626
- const record = await awardsService.getTopPerformer(supabase, resolvedCompanyId);
69627
- if (!isMounted) return;
69628
- if (record) {
69629
- setTopPerformer(buildTopPerformerDisplay(record));
69630
- setTopPerformerImageError(false);
69631
- }
69632
- } catch (err) {
69633
- console.error("[KPIsOverviewView] Failed to load top performer:", err);
69634
- } finally {
69635
- if (isMounted) setTopPerformerLoading(false);
69636
- }
69637
- };
69638
- loadTopPerformer();
69639
- return () => {
69640
- isMounted = false;
69641
- };
69642
- }, [supabase, resolvedCompanyId]);
69643
70432
  React144.useEffect(() => {
69644
70433
  trackCorePageView("KPIs Overview");
69645
70434
  }, []);
@@ -69689,16 +70478,25 @@ var KPIsOverviewView = ({
69689
70478
  `/api/dashboard/leaderboard-lines?company_id=${encodeURIComponent(resolvedCompanyId)}`
69690
70479
  );
69691
70480
  if (!isMounted) return;
69692
- const transformed = (data.lines || []).filter((line) => line.enable !== false).map((line) => ({
69693
- id: line.id,
69694
- line_name: line.line_name,
69695
- factory_id: line.factory_id || "",
69696
- factory_name: "N/A",
69697
- company_id: line.company_id,
69698
- company_name: "",
69699
- enable: line.enable ?? true,
69700
- monitoring_mode: line.monitoring_mode ?? "output"
69701
- }));
70481
+ const metadataByLineId = new Map(lines.map((line) => [line.id, line]));
70482
+ const transformed = (data.lines || []).filter((line) => line.enable !== false).map((line) => {
70483
+ const metadata = metadataByLineId.get(line.id);
70484
+ return {
70485
+ id: line.id,
70486
+ line_name: line.line_name,
70487
+ factory_id: line.factory_id || metadata?.factory_id || "",
70488
+ factory_name: metadata?.factory_name || "N/A",
70489
+ company_id: line.company_id,
70490
+ company_name: metadata?.company_name || "",
70491
+ enable: line.enable ?? true,
70492
+ monitoring_mode: line.monitoring_mode ?? metadata?.monitoring_mode ?? "output",
70493
+ factory_area_id: line.factory_area_id ?? metadata?.factory_area_id ?? null,
70494
+ factory_area_key: line.factory_area_key ?? metadata?.factory_area_key ?? null,
70495
+ factory_area_name: line.factory_area_name ?? metadata?.factory_area_name ?? null,
70496
+ factory_area_sort_order: line.factory_area_sort_order ?? metadata?.factory_area_sort_order ?? null,
70497
+ factory_area_enabled: line.factory_area_enabled ?? metadata?.factory_area_enabled ?? null
70498
+ };
70499
+ });
69702
70500
  setLeaderboardLines(transformed);
69703
70501
  } catch (err) {
69704
70502
  console.error("[KPIsOverviewView] Failed to load leaderboard lines:", err);
@@ -69713,6 +70511,58 @@ var KPIsOverviewView = ({
69713
70511
  isMounted = false;
69714
70512
  };
69715
70513
  }, [supabase, resolvedCompanyId, lines]);
70514
+ React144.useEffect(() => {
70515
+ if (activeTab !== "leaderboard" || timeRange !== "today") return;
70516
+ if (!supabase || !resolvedCompanyId || !effectiveLeaderboardDate || leaderboardLinesForView.length === 0) {
70517
+ setScopedDailyFallbackEfficiencyByLineId(/* @__PURE__ */ new Map());
70518
+ return;
70519
+ }
70520
+ const targetLineIds = leaderboardLinesForView.map((line) => line.id);
70521
+ const lineIdsKey = targetLineIds.slice().sort().join(",");
70522
+ const requestKey = `${effectiveLeaderboardDate}|${effectiveLeaderboardShiftId}|${lineIdsKey}`;
70523
+ if (dailyFallbackRequestKeyRef.current === requestKey) return;
70524
+ dailyFallbackRequestKeyRef.current = requestKey;
70525
+ let isMounted = true;
70526
+ const fetchScopedFallbackEfficiencies = async () => {
70527
+ try {
70528
+ const entries = await lineLeaderboardService.getDailyLineLeaderboard(supabase, {
70529
+ companyId: resolvedCompanyId,
70530
+ date: effectiveLeaderboardDate,
70531
+ shiftId: effectiveLeaderboardShiftId,
70532
+ lineIds: targetLineIds,
70533
+ lineMode: viewType === "machine" ? "uptime" : "output",
70534
+ includeBelowThreshold: true
70535
+ });
70536
+ if (!isMounted) return;
70537
+ const nextMap = /* @__PURE__ */ new Map();
70538
+ entries.forEach((entry) => {
70539
+ const value = Number(entry.avg_efficiency);
70540
+ if (Number.isFinite(value)) {
70541
+ nextMap.set(entry.line_id, value);
70542
+ }
70543
+ });
70544
+ setScopedDailyFallbackEfficiencyByLineId(nextMap);
70545
+ } catch (err) {
70546
+ if (!isMounted) return;
70547
+ console.warn("[KPIsOverviewView] Failed to load daily fallback line efficiencies:", err);
70548
+ setScopedDailyFallbackEfficiencyByLineId(/* @__PURE__ */ new Map());
70549
+ dailyFallbackRequestKeyRef.current = null;
70550
+ }
70551
+ };
70552
+ void fetchScopedFallbackEfficiencies();
70553
+ return () => {
70554
+ isMounted = false;
70555
+ };
70556
+ }, [
70557
+ activeTab,
70558
+ effectiveLeaderboardDate,
70559
+ effectiveLeaderboardShiftId,
70560
+ leaderboardLinesForView,
70561
+ resolvedCompanyId,
70562
+ supabase,
70563
+ timeRange,
70564
+ viewType
70565
+ ]);
69716
70566
  const fetchMonthlyLeaderboard = React144.useCallback(async () => {
69717
70567
  if (!supabase || !resolvedCompanyId || leaderboardLinesForView.length === 0) return;
69718
70568
  const targetLineIds = leaderboardLinesForView.map((line) => line.id);
@@ -69734,10 +70584,11 @@ var KPIsOverviewView = ({
69734
70584
  lineMode: viewType === "machine" ? "uptime" : "output"
69735
70585
  });
69736
70586
  const nextMap = /* @__PURE__ */ new Map();
69737
- targetLineIds.forEach((lineId) => nextMap.set(lineId, 0));
69738
70587
  entries.forEach((entry) => {
69739
70588
  const value = Number(entry.avg_efficiency);
69740
- nextMap.set(entry.line_id, Number.isFinite(value) ? value : 0);
70589
+ if (Number.isFinite(value)) {
70590
+ nextMap.set(entry.line_id, value);
70591
+ }
69741
70592
  });
69742
70593
  setMonthlyEfficiencyByLineId(nextMap);
69743
70594
  trackCoreEvent("Leaderboard Monthly Data Fetched", {
@@ -69784,10 +70635,11 @@ var KPIsOverviewView = ({
69784
70635
  lineMode: viewType === "machine" ? "uptime" : "output"
69785
70636
  });
69786
70637
  const nextMap = /* @__PURE__ */ new Map();
69787
- targetLineIds.forEach((lineId) => nextMap.set(lineId, 0));
69788
70638
  entries.forEach((entry) => {
69789
70639
  const value = Number(entry.avg_efficiency);
69790
- nextMap.set(entry.line_id, Number.isFinite(value) ? value : 0);
70640
+ if (Number.isFinite(value)) {
70641
+ nextMap.set(entry.line_id, value);
70642
+ }
69791
70643
  });
69792
70644
  setTodayEfficiencyByLineId(nextMap);
69793
70645
  } catch (err) {
@@ -69827,69 +70679,6 @@ var KPIsOverviewView = ({
69827
70679
  factoryAreaId: selectedFactoryAreaNode?.id
69828
70680
  });
69829
70681
  }, [activeTab, selectedFactoryNode, selectedFactoryAreaNode]);
69830
- const formatTopPerformerWeek = (periodStart, periodEnd) => {
69831
- const dateToUse = periodStart ? /* @__PURE__ */ new Date(`${periodStart}T00:00:00`) : /* @__PURE__ */ new Date();
69832
- if (Number.isNaN(dateToUse.getTime())) {
69833
- return (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", { month: "long", year: "numeric" });
69834
- }
69835
- return dateToUse.toLocaleDateString("en-US", { month: "long", year: "numeric" });
69836
- };
69837
- const buildTopPerformerDisplay = (record) => {
69838
- const supervisorAvatars = [];
69839
- if (record.supervisors && record.supervisors.length > 0) {
69840
- for (const s of record.supervisors) {
69841
- let supervisorName = "Supervisor";
69842
- if (s.first_name) {
69843
- supervisorName = s.last_name ? `${s.first_name} ${s.last_name}` : s.first_name;
69844
- }
69845
- supervisorAvatars.push({
69846
- userId: s.user_id,
69847
- name: supervisorName,
69848
- imageUrl: s.profile_photo_url || null,
69849
- initials: getInitials(supervisorName)
69850
- });
69851
- }
69852
- }
69853
- let displayName = record.recipient_name || "Supervisor";
69854
- if (record.first_name) {
69855
- displayName = record.last_name ? `${record.first_name} ${record.last_name}` : record.first_name;
69856
- } else if (record.recipient_user_id && allSupervisorsMap?.has(record.recipient_user_id)) {
69857
- const supervisor = allSupervisorsMap.get(record.recipient_user_id);
69858
- if (supervisor) {
69859
- displayName = supervisor.displayName;
69860
- }
69861
- } else if (displayName.includes(".") || displayName.includes("@")) {
69862
- const parts = displayName.split(/[.@]/);
69863
- if (parts.length >= 2) {
69864
- const firstName = parts[0].charAt(0).toUpperCase() + parts[0].slice(1);
69865
- const lastName = parts[1].charAt(0).toUpperCase() + parts[1].slice(1);
69866
- displayName = `${firstName} ${lastName}`;
69867
- } else if (parts.length === 1) {
69868
- displayName = parts[0].charAt(0).toUpperCase() + parts[0].slice(1);
69869
- }
69870
- }
69871
- if (supervisorAvatars.length === 0 && record.recipient_user_id) {
69872
- supervisorAvatars.push({
69873
- userId: record.recipient_user_id,
69874
- name: displayName,
69875
- imageUrl: record.profile_photo_url || null,
69876
- initials: getInitials(displayName)
69877
- });
69878
- }
69879
- const efficiencyValue = typeof record.avg_efficiency === "number" ? record.avg_efficiency : Number.parseFloat(String(record.avg_efficiency));
69880
- const efficiency = Number.isFinite(efficiencyValue) ? efficiencyValue : null;
69881
- const unitLabel = record.winning_line_name || record.unit || "Line";
69882
- return {
69883
- name: displayName,
69884
- role: "Sup.",
69885
- unit: unitLabel,
69886
- periodLabel: formatTopPerformerWeek(record.period_start, record.period_end),
69887
- efficiency,
69888
- imageUrl: record.profile_photo_url || null,
69889
- initials: getInitials(displayName),
69890
- supervisors: supervisorAvatars.length > 0 ? supervisorAvatars : void 0
69891
- };
69892
- };
69893
70682
  const handleLineClick = (line, kpis) => {
69894
70683
  if (!isSuperAdmin && !assignedLineIdSet.has(line.id)) {
69895
70684
  return;
@@ -69937,6 +70726,7 @@ var KPIsOverviewView = ({
69937
70726
  from_page: "kpis_overview",
69938
70727
  lines_count: trackedLineCount
69939
70728
  });
70729
+ pendingTabRouteSyncRef.current = newTab;
69940
70730
  setActiveTab(newTab);
69941
70731
  }, [activeTab, leaderboardLines.length, lines.length]);
69942
70732
  const formatLocalDate2 = React144.useCallback((dateKey) => {
@@ -69961,10 +70751,8 @@ var KPIsOverviewView = ({
69961
70751
  const isMonthlyMode = activeTab === "leaderboard" && timeRange === "monthly";
69962
70752
  const isLeaderboardLoading = timeRange === "today" ? dailyLoading : monthlyLoading;
69963
70753
  const currentEfficiencyMap = timeRange === "today" ? todayEfficiencyByLineId : monthlyEfficiencyByLineId;
69964
- const showLeaderboardLoader = activeTab === "leaderboard" && (leaderboardLinesLoading || isLeaderboardLoading && currentEfficiencyMap.size === 0);
69965
- const showTopPerformerImage = Boolean(topPerformer.imageUrl) && !topPerformerImageError;
69966
- typeof topPerformer.efficiency === "number" && Number.isFinite(topPerformer.efficiency);
69967
- topPerformerLoading ? "--" : typeof topPerformer.efficiency === "number" && Number.isFinite(topPerformer.efficiency) ? `${topPerformer.efficiency.toFixed(1)}%` : "--";
70754
+ const currentFallbackEfficiencyMap = timeRange === "today" ? dailyFallbackEfficiencyByLineId : void 0;
70755
+ const showLeaderboardLoader = activeTab === "leaderboard" && (leaderboardLinesLoading || isLeaderboardLoading && currentEfficiencyMap.size === 0 && (currentFallbackEfficiencyMap?.size ?? 0) === 0);
69968
70756
  const showHistoricalLeaderboardHeader = activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily;
69969
70757
  const headerDateKey = activeTab === "leaderboard" && timeRange === "today" ? effectiveLeaderboardDate : monthEndDateKey;
69970
70758
  const headerShiftId = showHistoricalLeaderboardHeader ? effectiveLeaderboardShiftId : currentShiftDetails.shiftId;
@@ -70169,72 +70957,6 @@ var KPIsOverviewView = ({
70169
70957
  ] }) : /* @__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, {}) }) })
70170
70958
  ] })
70171
70959
  ] }),
70172
- activeTab !== "leaderboard" && /* @__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: [
70173
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-shrink-0", children: [
70174
- (!topPerformer.supervisors || topPerformer.supervisors.length <= 1) && /* @__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(
70175
- "img",
70176
- {
70177
- src: topPerformer.imageUrl || "",
70178
- alt: "Top Performer",
70179
- className: "w-full h-full object-cover",
70180
- onError: () => setTopPerformerImageError(true)
70181
- }
70182
- ) : /* @__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 }) }),
70183
- topPerformer.supervisors && topPerformer.supervisors.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex -space-x-2", children: [
70184
- topPerformer.supervisors.slice(0, 3).map((supervisor, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
70185
- "div",
70186
- {
70187
- className: "relative inline-block w-9 h-9 rounded-full ring-2 ring-white bg-amber-50 shadow-sm z-0 hover:z-10 transition-all hover:scale-110 group/avatar",
70188
- style: { zIndex: 3 - idx },
70189
- children: [
70190
- supervisor.imageUrl ? /* @__PURE__ */ jsxRuntime.jsx(
70191
- "img",
70192
- {
70193
- src: supervisor.imageUrl,
70194
- alt: supervisor.name,
70195
- className: "w-full h-full object-cover rounded-full"
70196
- }
70197
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-xs font-bold text-amber-600 uppercase rounded-full", children: supervisor.initials }),
70198
- /* @__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: [
70199
- supervisor.name,
70200
- /* @__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" })
70201
- ] })
70202
- ]
70203
- },
70204
- supervisor.userId
70205
- )),
70206
- topPerformer.supervisors.length > 3 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-9 h-9 rounded-full ring-2 ring-white bg-amber-100 items-center justify-center text-xs font-medium text-amber-700 z-0", children: [
70207
- "+",
70208
- topPerformer.supervisors.length - 3
70209
- ] })
70210
- ] })
70211
- ] }),
70212
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
70213
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 leading-none mb-1", children: [
70214
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-amber-600 uppercase tracking-widest", children: "Performer of the month" }),
70215
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-1 h-1 bg-amber-200 rounded-full" }),
70216
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-semibold text-gray-400", children: topPerformerLoading ? "Loading" : topPerformer.periodLabel })
70217
- ] }),
70218
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 leading-none", children: [
70219
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[140px]", children: /* @__PURE__ */ jsxRuntime.jsx(
70220
- FittingTitle,
70221
- {
70222
- title: topPerformer.name,
70223
- as: "span",
70224
- className: "text-sm text-gray-900 font-bold"
70225
- }
70226
- ) }),
70227
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-px h-3 bg-gray-200 flex-shrink-0" }),
70228
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[120px]", children: /* @__PURE__ */ jsxRuntime.jsx(
70229
- FittingTitle,
70230
- {
70231
- title: topPerformer.unit,
70232
- className: "text-xs font-medium text-gray-500"
70233
- }
70234
- ) })
70235
- ] })
70236
- ] })
70237
- ] }) }),
70238
70960
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex bg-gray-100/80 p-1 rounded-xl w-full", children: [
70239
70961
  /* @__PURE__ */ jsxRuntime.jsx(
70240
70962
  "button",
@@ -70269,86 +70991,18 @@ var KPIsOverviewView = ({
70269
70991
  /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight", children: activeTab === "leaderboard" ? "Leaderboard" : "Overview" }),
70270
70992
  !showHistoricalLeaderboardHeader && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2.5 w-2.5 rounded-full ring-4 flex-shrink-0 bg-emerald-500 animate-pulse ring-emerald-500/10" })
70271
70993
  ] }),
70272
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 z-10 flex items-center", children: [
70273
- !topPerformerLoading && activeTab !== "leaderboard" && /* @__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: [
70274
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
70275
- (!topPerformer.supervisors || topPerformer.supervisors.length <= 1) && /* @__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(
70276
- "img",
70277
- {
70278
- src: topPerformer.imageUrl || "",
70279
- alt: topPerformer.name,
70280
- className: "w-full h-full object-cover",
70281
- onError: () => setTopPerformerImageError(true)
70282
- }
70283
- ) : /* @__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 }) }),
70284
- topPerformer.supervisors && topPerformer.supervisors.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex -space-x-2", children: [
70285
- topPerformer.supervisors.slice(0, 3).map((supervisor, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
70286
- "div",
70287
- {
70288
- className: "relative inline-block w-10 h-10 rounded-full ring-2 ring-white bg-amber-50 shadow-sm z-0 hover:z-10 transition-all hover:scale-110 group/avatar",
70289
- style: { zIndex: 3 - idx },
70290
- children: [
70291
- supervisor.imageUrl ? /* @__PURE__ */ jsxRuntime.jsx(
70292
- "img",
70293
- {
70294
- src: supervisor.imageUrl,
70295
- alt: supervisor.name,
70296
- className: "w-full h-full object-cover rounded-full"
70297
- }
70298
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-sm font-bold text-amber-600 uppercase rounded-full", children: supervisor.initials }),
70299
- /* @__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: [
70300
- supervisor.name,
70301
- /* @__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" })
70302
- ] })
70303
- ]
70304
- },
70305
- supervisor.userId
70306
- )),
70307
- topPerformer.supervisors.length > 3 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-10 h-10 rounded-full ring-2 ring-white bg-amber-100 items-center justify-center text-sm font-medium text-amber-700 z-0", children: [
70308
- "+",
70309
- topPerformer.supervisors.length - 3
70310
- ] })
70311
- ] })
70312
- ] }),
70313
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-0", children: [
70314
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-[10px] leading-tight mb-1", children: [
70315
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-bold text-amber-600 uppercase tracking-widest", children: "Performer of the month" }),
70316
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-amber-200 opacity-50", children: "\u2022" }),
70317
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-gray-400", children: topPerformer.periodLabel })
70318
- ] }),
70319
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 leading-tight", children: [
70320
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[140px]", children: /* @__PURE__ */ jsxRuntime.jsx(
70321
- FittingTitle,
70322
- {
70323
- title: topPerformer.name,
70324
- as: "span",
70325
- className: "text-sm text-gray-900 font-bold"
70326
- }
70327
- ) }),
70328
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-px h-3.5 bg-gray-200 flex-shrink-0" }),
70329
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[150px]", children: /* @__PURE__ */ jsxRuntime.jsx(
70330
- FittingTitle,
70331
- {
70332
- title: topPerformer.unit,
70333
- className: "text-xs font-medium text-gray-500"
70334
- }
70335
- ) })
70336
- ] })
70337
- ] })
70338
- ] }),
70339
- activeTab === "leaderboard" && isHistoricalLeaderboardDaily && /* @__PURE__ */ jsxRuntime.jsx(
70340
- "button",
70341
- {
70342
- type: "button",
70343
- onClick: () => {
70344
- setSelectedLeaderboardDate(currentShiftDate);
70345
- setSelectedLeaderboardShiftId(currentShiftId);
70346
- },
70347
- className: "text-xs sm:text-sm font-medium text-blue-600 bg-blue-50 border border-blue-100 hover:bg-blue-100 hover:text-blue-700 px-3 py-1.5 rounded-lg transition-colors shadow-sm ml-4 whitespace-nowrap",
70348
- children: "Return to Live"
70349
- }
70350
- )
70351
- ] })
70994
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 z-10 flex items-center", children: activeTab === "leaderboard" && isHistoricalLeaderboardDaily && /* @__PURE__ */ jsxRuntime.jsx(
70995
+ "button",
70996
+ {
70997
+ type: "button",
70998
+ onClick: () => {
70999
+ setSelectedLeaderboardDate(currentShiftDate);
71000
+ setSelectedLeaderboardShiftId(currentShiftId);
71001
+ },
71002
+ className: "text-xs sm:text-sm font-medium text-blue-600 bg-blue-50 border border-blue-100 hover:bg-blue-100 hover:text-blue-700 px-3 py-1.5 rounded-lg transition-colors shadow-sm ml-4 whitespace-nowrap",
71003
+ children: "Return to Live"
71004
+ }
71005
+ ) })
70352
71006
  ] }),
70353
71007
  /* @__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: [
70354
71008
  !isMonthlyMode && !showHistoricalLeaderboardHeader && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -70523,6 +71177,7 @@ var KPIsOverviewView = ({
70523
71177
  timeRange,
70524
71178
  setTimeRange,
70525
71179
  todayEfficiencyByLineId,
71180
+ dailyFallbackEfficiencyByLineId,
70526
71181
  monthlyEfficiencyByLineId,
70527
71182
  supervisorsByLineId,
70528
71183
  supervisorNamesByLineId,
@@ -70555,13 +71210,23 @@ var AnimatedEfficiency = React144.memo(({ value }) => {
70555
71210
  AnimatedEfficiency.displayName = "AnimatedEfficiency";
70556
71211
  var getWorkspaceLeaderboardMetricValue = (workspace) => {
70557
71212
  if (workspace.leaderboard_metric_kind === "recent_flow_shift_average") {
70558
- return toFiniteNumber(workspace.leaderboard_value) ?? toFiniteNumber(workspace.avg_recent_flow);
71213
+ const cycleRatio = getCycleRatio(workspace);
71214
+ return cycleRatio === null ? null : cycleRatio * 100;
70559
71215
  }
70560
71216
  return toFiniteNumber(workspace.leaderboard_value) ?? toFiniteNumber(workspace.efficiency);
70561
71217
  };
70562
71218
  var getWorkspaceDisplayedMetricValue = (workspace) => getWorkspaceLeaderboardMetricValue(workspace);
70563
- var getWorkspaceLeaderboardMetricLabel = (workspace, defaultLabel) => workspace.leaderboard_metric_kind === "recent_flow_shift_average" ? "Avg Flow" : defaultLabel;
71219
+ var getWorkspaceLeaderboardMetricLabel = (workspace, defaultLabel) => workspace.leaderboard_metric_kind === "recent_flow_shift_average" ? "Actual CT / Standard CT" : defaultLabel;
70564
71220
  var renderWorkspaceLeaderboardMetric = (workspace) => {
71221
+ if (workspace.leaderboard_metric_kind === "recent_flow_shift_average") {
71222
+ const actualCT = formatCycleTimeValue(workspace.avg_cycle_time);
71223
+ const standardCT = formatCycleTimeValue(workspace.ideal_cycle_time);
71224
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "tabular-nums", children: [
71225
+ actualCT,
71226
+ " / ",
71227
+ standardCT
71228
+ ] });
71229
+ }
70565
71230
  const displayedMetricValue = getWorkspaceDisplayedMetricValue(workspace);
70566
71231
  if (displayedMetricValue === null) {
70567
71232
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: "--" });
@@ -70839,12 +71504,8 @@ var LeaderboardDetailView = React144.memo(({
70839
71504
  return `Line ${lineId2.substring(0, 8)}`;
70840
71505
  }, [dbLineNames, configuredLineNames, lineNames, line1Id, line2Id]);
70841
71506
  const configuredLineIds = React144.useMemo(() => {
70842
- const allLineIds = getConfiguredLineIds(entityConfig);
70843
- if (userAccessibleLineIds) {
70844
- return allLineIds.filter((id3) => userAccessibleLineIds.includes(id3));
70845
- }
70846
- return allLineIds;
70847
- }, [entityConfig, userAccessibleLineIds]);
71507
+ return getConfiguredLineIds(entityConfig);
71508
+ }, [entityConfig]);
70848
71509
  const accessibleLineIdSet = React144.useMemo(
70849
71510
  () => new Set((userAccessibleLineIds || []).filter(Boolean)),
70850
71511
  [userAccessibleLineIds]
@@ -71532,7 +72193,7 @@ var LeaderboardDetailView = React144.memo(({
71532
72193
  const hasEfficiencyLeaderboardRows = sortedWorkspaces.some(
71533
72194
  (workspace) => workspace.leaderboard_metric_kind !== "recent_flow_shift_average"
71534
72195
  );
71535
- const metricLabel = viewType === "machine" ? "Utilization" : hasRecentFlowLeaderboardRows && !hasEfficiencyLeaderboardRows ? "Avg Flow" : hasRecentFlowLeaderboardRows && hasEfficiencyLeaderboardRows ? "Performance" : "Efficiency";
72196
+ const metricLabel = viewType === "machine" ? "Utilization" : hasRecentFlowLeaderboardRows && !hasEfficiencyLeaderboardRows ? "Actual CT / Standard CT" : hasRecentFlowLeaderboardRows && hasEfficiencyLeaderboardRows ? "Performance" : "Efficiency";
71536
72197
  const descendingSortLabel = "Highest to Lowest";
71537
72198
  const ascendingSortLabel = "Lowest to Highest";
71538
72199
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen bg-slate-50 flex flex-col ${className}`, style: { willChange: "contents" }, children: [
@@ -86453,6 +87114,7 @@ exports.awardsService = awardsService;
86453
87114
  exports.buildDateKey = buildDateKey;
86454
87115
  exports.buildKPIsFromLineMetricsRow = buildKPIsFromLineMetricsRow;
86455
87116
  exports.buildKpiLineHierarchy = buildKpiLineHierarchy;
87117
+ exports.buildLineLeaderboardRows = buildLineLeaderboardRows;
86456
87118
  exports.buildLineSkuBreakdown = buildLineSkuBreakdown;
86457
87119
  exports.buildShiftGroupsKey = buildShiftGroupsKey;
86458
87120
  exports.canRoleAccessDashboardPath = canRoleAccessDashboardPath;