@optifye/dashboard-core 6.12.22 → 6.12.25

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()}`
@@ -14609,6 +14615,32 @@ function getEfficiencyTextColorClasses(efficiency, legend = DEFAULT_EFFICIENCY_L
14609
14615
  }
14610
14616
  }
14611
14617
 
14618
+ // src/lib/utils/qaGreenStreakParams.ts
14619
+ var QA_GREEN_STREAK_QUERY_PARAM_NAMES = [
14620
+ "qa_green_streak_started_at",
14621
+ "qa_green_streak_elapsed_seconds",
14622
+ "qa_green_streak_status"
14623
+ ];
14624
+ var isTruthyEnv = (value) => ["1", "true", "yes", "on"].includes(String(value || "").trim().toLowerCase());
14625
+ var isQaGreenStreakForwardingEnabled = () => isTruthyEnv(process.env.NEXT_PUBLIC_DASHBOARD_QA_GREEN_STREAK_OVERRIDE_ENABLED);
14626
+ var appendQaGreenStreakSearchParams = (targetParams) => {
14627
+ if (!isQaGreenStreakForwardingEnabled() || typeof window === "undefined") {
14628
+ return;
14629
+ }
14630
+ const sourceParams = new URLSearchParams(window.location.search);
14631
+ QA_GREEN_STREAK_QUERY_PARAM_NAMES.forEach((paramName) => {
14632
+ const value = sourceParams.get(paramName);
14633
+ if (value !== null) {
14634
+ targetParams.set(paramName, value);
14635
+ }
14636
+ });
14637
+ };
14638
+ var getQaGreenStreakQueryString = () => {
14639
+ const params = new URLSearchParams();
14640
+ appendQaGreenStreakSearchParams(params);
14641
+ return params.toString();
14642
+ };
14643
+
14612
14644
  // src/lib/utils/monitorWorkspaceMetrics.ts
14613
14645
  var sortWorkspaceMetrics = (left, right) => {
14614
14646
  if (left.line_id !== right.line_id) {
@@ -14697,11 +14729,22 @@ var transformMonitorWorkspaceMetrics = ({
14697
14729
  actionType: item.action_type,
14698
14730
  actionName: item.action_name
14699
14731
  }),
14732
+ factory_area_id: item.factory_area_id ?? null,
14733
+ factory_area_key: item.factory_area_key ?? null,
14734
+ factory_area_name: item.factory_area_name ?? null,
14735
+ factory_area_enabled: item.factory_area_enabled ?? null,
14736
+ leaderboard_metric_kind: item.leaderboard_metric_kind ?? void 0,
14737
+ leaderboard_value: item.leaderboard_value ?? null,
14738
+ avg_recent_flow: item.avg_recent_flow ?? null,
14700
14739
  recent_flow_percent: item.recent_flow_percent ?? null,
14701
14740
  recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
14702
14741
  recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
14703
14742
  recent_flow_computed_at: item.recent_flow_computed_at ?? null,
14704
14743
  recent_flow_forced_zero_after_shift: item.recent_flow_forced_zero_after_shift ?? null,
14744
+ video_grid_green_streak_active: item.video_grid_green_streak_active ?? null,
14745
+ video_grid_green_streak_minutes: item.video_grid_green_streak_minutes ?? null,
14746
+ video_grid_green_streak_anchor_at: item.video_grid_green_streak_anchor_at ?? null,
14747
+ video_grid_green_streak_started_at: item.video_grid_green_streak_started_at ?? null,
14705
14748
  scheduled_break_active: item.scheduled_break_active ?? false,
14706
14749
  incoming_wip_current: item.incoming_wip_current ?? null,
14707
14750
  incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
@@ -14721,12 +14764,12 @@ var logDebug = (...args) => {
14721
14764
  if (!DEBUG_DASHBOARD_LOGS) return;
14722
14765
  console.log(...args);
14723
14766
  };
14724
- var buildMetricsScopeKey = (lineId, lineIds) => {
14767
+ var buildMetricsScopeKey = (lineId, lineIds, blueComparisonLineIds) => {
14725
14768
  const normalizedLineIds = Array.from(new Set((lineIds || []).filter(Boolean))).sort();
14726
- if (normalizedLineIds.length > 0) {
14727
- return `${lineId}|${normalizedLineIds.join(",")}`;
14728
- }
14729
- return lineId;
14769
+ const normalizedBlueComparisonLineIds = Array.from(new Set((blueComparisonLineIds || []).filter(Boolean))).sort();
14770
+ const lineKey = normalizedLineIds.length > 0 ? normalizedLineIds.join(",") : lineId;
14771
+ const comparisonKey = normalizedBlueComparisonLineIds.length > 0 ? normalizedBlueComparisonLineIds.join(",") : lineKey;
14772
+ return `${lineId}|${lineKey}|blue:${comparisonKey}`;
14730
14773
  };
14731
14774
  var parseEfficiencyLegend = (legend) => {
14732
14775
  if (!legend) return null;
@@ -14748,6 +14791,7 @@ var useDashboardMetrics = ({
14748
14791
  onLineMetricsUpdate,
14749
14792
  lineId,
14750
14793
  lineIds,
14794
+ blueComparisonLineIds,
14751
14795
  userAccessibleLineIds,
14752
14796
  enabled = true
14753
14797
  }) => {
@@ -14770,6 +14814,10 @@ var useDashboardMetrics = ({
14770
14814
  const sourceLineIds = lineIds !== void 0 ? lineIds : userAccessibleLineIds !== void 0 ? userAccessibleLineIds : configuredLineIds;
14771
14815
  return Array.from(new Set((sourceLineIds || []).filter(Boolean)));
14772
14816
  }, [lineIds, userAccessibleLineIds, configuredLineIds]);
14817
+ const normalizedBlueComparisonLineIds = React144.useMemo(
14818
+ () => Array.from(new Set((blueComparisonLineIds || []).filter(Boolean))),
14819
+ [blueComparisonLineIds]
14820
+ );
14773
14821
  const { shiftConfig: staticShiftConfig } = useDashboardConfig();
14774
14822
  const {
14775
14823
  shiftConfigMap: multiLineShiftConfigMap,
@@ -14807,7 +14855,7 @@ var useDashboardMetrics = ({
14807
14855
  const supabase = useSupabase();
14808
14856
  const [metrics2, setMetrics] = React144.useState({ workspaceMetrics: [], lineMetrics: [] });
14809
14857
  const [metricsLineId, setMetricsLineId] = React144.useState(lineId ?? null);
14810
- const [metricsScopeKey, setMetricsScopeKey] = React144.useState(() => buildMetricsScopeKey(lineId, lineIds));
14858
+ const [metricsScopeKey, setMetricsScopeKey] = React144.useState(() => buildMetricsScopeKey(lineId, lineIds, blueComparisonLineIds));
14811
14859
  const [isLoading, setIsLoading] = React144.useState(true);
14812
14860
  const [error, setError] = React144.useState(null);
14813
14861
  const lineIdRef = React144.useRef(lineId);
@@ -14849,8 +14897,12 @@ var useDashboardMetrics = ({
14849
14897
  [entityConfig.companyId]
14850
14898
  );
14851
14899
  const requestedScopeKey = React144.useMemo(
14852
- () => buildMetricsScopeKey(lineId, isFactoryView ? targetFactoryLineIds : void 0),
14853
- [isFactoryView, lineId, targetFactoryLineIds]
14900
+ () => buildMetricsScopeKey(
14901
+ lineId,
14902
+ isFactoryView ? targetFactoryLineIds : void 0,
14903
+ normalizedBlueComparisonLineIds.length ? normalizedBlueComparisonLineIds : void 0
14904
+ ),
14905
+ [isFactoryView, lineId, targetFactoryLineIds, normalizedBlueComparisonLineIds]
14854
14906
  );
14855
14907
  React144.useEffect(() => {
14856
14908
  lineIdRef.current = lineId;
@@ -14880,12 +14932,15 @@ var useDashboardMetrics = ({
14880
14932
  const isFactory = currentLineIdToUse === factoryViewId;
14881
14933
  const targetLineIds = isFactory ? targetFactoryLineIds : [currentLineIdToUse];
14882
14934
  const targetLineIdsKey = targetLineIds.slice().sort().join(",");
14935
+ const effectiveBlueComparisonLineIds = normalizedBlueComparisonLineIds.length ? normalizedBlueComparisonLineIds : targetLineIds;
14936
+ const blueComparisonLineIdsKey = effectiveBlueComparisonLineIds.slice().sort().join(",");
14883
14937
  const usesShiftGroups = isFactory && shiftGroups.length > 0;
14884
14938
  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}`;
14939
+ 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
14940
  const responseScopeKey = buildMetricsScopeKey(
14887
14941
  currentLineIdToUse,
14888
- isFactory ? targetLineIds : void 0
14942
+ isFactory ? targetLineIds : void 0,
14943
+ normalizedBlueComparisonLineIds.length ? normalizedBlueComparisonLineIds : void 0
14889
14944
  );
14890
14945
  logDebug("[useDashboardMetrics] Fetch key details:", {
14891
14946
  isFactory,
@@ -14915,6 +14970,7 @@ var useDashboardMetrics = ({
14915
14970
  logDebug("[useDashboardMetrics] Skipping fetch: no target line IDs after scope filtering");
14916
14971
  setMetrics({
14917
14972
  workspaceMetrics: [],
14973
+ blueComparisonWorkspaceMetrics: [],
14918
14974
  lineMetrics: [],
14919
14975
  metadata: void 0,
14920
14976
  efficiencyLegend: DEFAULT_EFFICIENCY_LEGEND
@@ -14925,14 +14981,18 @@ var useDashboardMetrics = ({
14925
14981
  return;
14926
14982
  }
14927
14983
  let allWorkspaceMetrics = [];
14984
+ let allBlueComparisonWorkspaceMetrics = [];
14928
14985
  let allLineMetrics = [];
14929
14986
  let hasFlowBuffers = false;
14930
14987
  let idleTimeVlmByLine = {};
14931
14988
  let efficiencyLegend;
14932
14989
  const forceParam = force ? "&force_refresh=true" : "";
14990
+ const qaGreenStreakParamString = getQaGreenStreakQueryString();
14991
+ const qaGreenStreakParams = qaGreenStreakParamString ? `&${qaGreenStreakParamString}` : "";
14933
14992
  const buildMetricsEndpoint = (params) => {
14934
14993
  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}`;
14994
+ const blueComparisonParam = effectiveBlueComparisonLineIds.length ? `&blue_comparison_line_ids=${effectiveBlueComparisonLineIds.join(",")}` : "";
14995
+ return `/api/dashboard/metrics?${lineIdsParam}${blueComparisonParam}&date=${params.date}&shift_id=${params.shiftId}&company_id=${companyId}${forceParam}${qaGreenStreakParams}`;
14936
14996
  };
14937
14997
  if (usesShiftGroups) {
14938
14998
  logDebug("[useDashboardMetrics] Factory view shift groups fetch:", {
@@ -14982,10 +15042,16 @@ var useDashboardMetrics = ({
14982
15042
  if (result.workspace_metrics) {
14983
15043
  allWorkspaceMetrics.push(...result.workspace_metrics);
14984
15044
  }
15045
+ if (result.blue_comparison_workspace_metrics) {
15046
+ allBlueComparisonWorkspaceMetrics.push(...result.blue_comparison_workspace_metrics);
15047
+ }
14985
15048
  if (result.line_metrics) {
14986
15049
  allLineMetrics.push(...result.line_metrics);
14987
15050
  }
14988
15051
  });
15052
+ if (allBlueComparisonWorkspaceMetrics.length === 0) {
15053
+ allBlueComparisonWorkspaceMetrics = allWorkspaceMetrics;
15054
+ }
14989
15055
  logDebug(`[useDashboardMetrics] \u{1F4CA} Merged metrics from ${results.length} shift groups:`, {
14990
15056
  workspaceCount: allWorkspaceMetrics.length,
14991
15057
  lineMetricsCount: allLineMetrics.length
@@ -15023,6 +15089,7 @@ var useDashboardMetrics = ({
15023
15089
  lineCount: backendData.line_metrics?.length || 0
15024
15090
  });
15025
15091
  allWorkspaceMetrics = backendData.workspace_metrics || [];
15092
+ allBlueComparisonWorkspaceMetrics = backendData.blue_comparison_workspace_metrics || allWorkspaceMetrics;
15026
15093
  allLineMetrics = backendData.line_metrics || [];
15027
15094
  hasFlowBuffers = Boolean(backendData?.metadata?.has_flow_buffers);
15028
15095
  if (backendData?.metadata?.idle_time_vlm_by_line && typeof backendData.metadata.idle_time_vlm_by_line === "object") {
@@ -15041,8 +15108,19 @@ var useDashboardMetrics = ({
15041
15108
  shouldOverrideShiftType: (metricLineId) => isFactoryView ? Boolean(multiLineShiftConfigMap.get(metricLineId)) : Boolean(shiftConfig),
15042
15109
  fallbackShiftConfig: staticShiftConfig
15043
15110
  });
15111
+ const transformedBlueComparisonWorkspaceData = allBlueComparisonWorkspaceMetrics === allWorkspaceMetrics ? transformedWorkspaceData : transformMonitorWorkspaceMetrics({
15112
+ rows: allBlueComparisonWorkspaceMetrics,
15113
+ companyId: companyId || "",
15114
+ workspaceConfig: effectiveWorkspaceConfig,
15115
+ appTimezone: detailTimezone,
15116
+ lineMetrics: allLineMetrics,
15117
+ resolveShiftConfig: (metricLineId) => isFactoryView ? multiLineShiftConfigMap.get(metricLineId) || staticShiftConfig : shiftConfig || staticShiftConfig,
15118
+ shouldOverrideShiftType: (metricLineId) => isFactoryView ? Boolean(multiLineShiftConfigMap.get(metricLineId)) : Boolean(shiftConfig),
15119
+ fallbackShiftConfig: staticShiftConfig
15120
+ });
15044
15121
  const newMetricsState = {
15045
15122
  workspaceMetrics: transformedWorkspaceData,
15123
+ blueComparisonWorkspaceMetrics: transformedBlueComparisonWorkspaceData.length ? transformedBlueComparisonWorkspaceData : transformedWorkspaceData,
15046
15124
  lineMetrics: allLineMetrics || [],
15047
15125
  metadata: { hasFlowBuffers, idleTimeVlmByLine },
15048
15126
  efficiencyLegend: efficiencyLegend ?? DEFAULT_EFFICIENCY_LEGEND
@@ -15113,6 +15191,7 @@ var useDashboardMetrics = ({
15113
15191
  shiftGroupsKey,
15114
15192
  configuredLineIds,
15115
15193
  targetFactoryLineIds,
15194
+ normalizedBlueComparisonLineIds,
15116
15195
  isFactoryView,
15117
15196
  multiLineShiftConfigMap,
15118
15197
  staticShiftConfig,
@@ -15553,9 +15632,10 @@ var useDashboardMetrics = ({
15553
15632
  const isCurrentScopeResolved = metricsScopeKey === requestedScopeKey;
15554
15633
  const hasLastGoodMetrics = metrics2.workspaceMetrics.length > 0 || metrics2.lineMetrics.length > 0;
15555
15634
  const canReuseLastGoodMetrics = hasLastGoodMetrics && !isCurrentScopeResolved && (isLoading || !!error);
15556
- const safeMetrics = isCurrentScopeResolved || canReuseLastGoodMetrics ? metrics2 : { workspaceMetrics: [], lineMetrics: [], metadata: void 0, efficiencyLegend: DEFAULT_EFFICIENCY_LEGEND };
15635
+ const safeMetrics = isCurrentScopeResolved || canReuseLastGoodMetrics ? metrics2 : { workspaceMetrics: [], blueComparisonWorkspaceMetrics: [], lineMetrics: [], metadata: void 0, efficiencyLegend: DEFAULT_EFFICIENCY_LEGEND };
15557
15636
  return {
15558
15637
  workspaceMetrics: safeMetrics?.workspaceMetrics || [],
15638
+ blueComparisonWorkspaceMetrics: safeMetrics?.blueComparisonWorkspaceMetrics || safeMetrics?.workspaceMetrics || [],
15559
15639
  lineMetrics: safeMetrics?.lineMetrics || [],
15560
15640
  efficiencyLegend: safeMetrics?.efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND,
15561
15641
  metadata: safeMetrics?.metadata,
@@ -22173,6 +22253,77 @@ var buildKpiLineHierarchy = (lines) => {
22173
22253
  };
22174
22254
  };
22175
22255
 
22256
+ // src/lib/utils/leaderboardGrouping.ts
22257
+ var isFiniteNumber2 = (value) => typeof value === "number" && Number.isFinite(value);
22258
+ var getEnabledFactoryArea = (line) => {
22259
+ if (!line.factory_area_id) return null;
22260
+ if (line.factory_area_enabled !== true) return null;
22261
+ const areaName = line.factory_area_name?.trim();
22262
+ if (!areaName) return null;
22263
+ return { id: line.factory_area_id, name: areaName };
22264
+ };
22265
+ var getLineEfficiency = (lineId, efficiencyByLineId, isLoading) => {
22266
+ if (efficiencyByLineId.has(lineId)) {
22267
+ const value = efficiencyByLineId.get(lineId);
22268
+ return isFiniteNumber2(value) ? value : null;
22269
+ }
22270
+ if (isLoading) return null;
22271
+ return 0;
22272
+ };
22273
+ var buildLineLeaderboardRows = ({
22274
+ lines,
22275
+ efficiencyByLineId,
22276
+ fallbackEfficiencyByLineId,
22277
+ isLoading
22278
+ }) => {
22279
+ const rows = [];
22280
+ const areaGroups = /* @__PURE__ */ new Map();
22281
+ lines.forEach((line) => {
22282
+ const area = getEnabledFactoryArea(line);
22283
+ if (!area) {
22284
+ const efficiency = getLineEfficiency(line.id, efficiencyByLineId, isLoading);
22285
+ rows.push({
22286
+ rowType: "line",
22287
+ id: line.id,
22288
+ displayName: line.line_name,
22289
+ line,
22290
+ lines: [line],
22291
+ efficiency,
22292
+ sortValue: isFiniteNumber2(efficiency) ? efficiency : -1
22293
+ });
22294
+ return;
22295
+ }
22296
+ const group = areaGroups.get(area.id);
22297
+ if (group) {
22298
+ group.lines.push(line);
22299
+ return;
22300
+ }
22301
+ areaGroups.set(area.id, {
22302
+ areaId: area.id,
22303
+ areaName: area.name,
22304
+ lines: [line]
22305
+ });
22306
+ });
22307
+ areaGroups.forEach((group) => {
22308
+ const validEfficiencies = group.lines.map((line) => efficiencyByLineId.get(line.id)).filter(isFiniteNumber2);
22309
+ const fallbackEfficiencies = validEfficiencies.length === 0 ? group.lines.map((line) => fallbackEfficiencyByLineId?.get(line.id)).filter(isFiniteNumber2) : [];
22310
+ const efficiencyValues = validEfficiencies.length > 0 ? validEfficiencies : fallbackEfficiencies;
22311
+ const shouldRenderZeroFallback = efficiencyValues.length === 0 && !!fallbackEfficiencyByLineId && !isLoading;
22312
+ if (efficiencyValues.length === 0 && !shouldRenderZeroFallback) return;
22313
+ const efficiency = shouldRenderZeroFallback ? 0 : efficiencyValues.reduce((sum, value) => sum + value, 0) / efficiencyValues.length;
22314
+ rows.push({
22315
+ rowType: "area",
22316
+ id: `area:${group.areaId}`,
22317
+ displayName: group.areaName,
22318
+ areaId: group.areaId,
22319
+ lines: group.lines,
22320
+ efficiency,
22321
+ sortValue: efficiency
22322
+ });
22323
+ });
22324
+ return rows.sort((left, right) => right.sortValue - left.sortValue).map((row, index) => ({ ...row, rank: index + 1 }));
22325
+ };
22326
+
22176
22327
  // src/lib/utils/awards.ts
22177
22328
  var toNumber2 = (value) => {
22178
22329
  if (typeof value === "number" && Number.isFinite(value)) return value;
@@ -37459,7 +37610,58 @@ HourlyOutputChart.displayName = "HourlyOutputChart";
37459
37610
  // src/components/dashboard/grid/videoGridMetricUtils.ts
37460
37611
  var VIDEO_GRID_LEGEND_LABEL = "Real-Time efficiency";
37461
37612
  var MAP_GRID_LEGEND_LABEL = "Efficiency";
37462
- var isFiniteNumber2 = (value) => typeof value === "number" && Number.isFinite(value);
37613
+ var GREEN_STREAK_FRESHNESS_GRACE_MS = 2 * 60 * 1e3;
37614
+ var CONFIRMED_MINUTE_DURATION_MS = 60 * 1e3;
37615
+ var RECENT_FLOW_COMPUTED_FRESHNESS_MS = 120 * 1e3;
37616
+ var isFiniteNumber3 = (value) => typeof value === "number" && Number.isFinite(value);
37617
+ var padTwoDigits = (value) => String(value).padStart(2, "0");
37618
+ var parseTimestampMs = (value) => {
37619
+ if (!value) {
37620
+ return Number.NaN;
37621
+ }
37622
+ const timestampMs = Date.parse(value);
37623
+ return Number.isFinite(timestampMs) ? timestampMs : Number.NaN;
37624
+ };
37625
+ var isAllGreenStreakFresh = (workspace, anchorAtMs, nowMs2) => {
37626
+ const computedAt = workspace.recent_flow_computed_at;
37627
+ if (typeof computedAt === "string" && computedAt.trim()) {
37628
+ const computedAtMs = parseTimestampMs(computedAt);
37629
+ return Number.isFinite(computedAtMs) && nowMs2 - computedAtMs <= RECENT_FLOW_COMPUTED_FRESHNESS_MS;
37630
+ }
37631
+ return Number.isFinite(anchorAtMs) && nowMs2 <= anchorAtMs + CONFIRMED_MINUTE_DURATION_MS + GREEN_STREAK_FRESHNESS_GRACE_MS;
37632
+ };
37633
+ var formatAllGreenStreakDuration = (elapsedSeconds) => {
37634
+ const safeElapsedSeconds = Math.max(0, Math.floor(elapsedSeconds));
37635
+ const hours = Math.floor(safeElapsedSeconds / 3600);
37636
+ const minutes = Math.floor(safeElapsedSeconds % 3600 / 60);
37637
+ const seconds = safeElapsedSeconds % 60;
37638
+ if (hours > 0) {
37639
+ return `${hours}h ${padTwoDigits(minutes)}m ${padTwoDigits(seconds)}s`;
37640
+ }
37641
+ if (minutes > 0) {
37642
+ return `${minutes}m ${padTwoDigits(seconds)}s`;
37643
+ }
37644
+ return `${seconds}s`;
37645
+ };
37646
+ var getAllGreenStreakMilestone = (elapsedSeconds) => {
37647
+ const safeElapsedSeconds = Math.max(0, Math.floor(elapsedSeconds));
37648
+ const thirtyMinutesSeconds = 30 * 60;
37649
+ const oneHourSeconds = 60 * 60;
37650
+ if (safeElapsedSeconds < thirtyMinutesSeconds) {
37651
+ return null;
37652
+ }
37653
+ if (safeElapsedSeconds < oneHourSeconds) {
37654
+ return {
37655
+ milestoneSeconds: thirtyMinutesSeconds,
37656
+ headline: "30 min"
37657
+ };
37658
+ }
37659
+ const hours = Math.floor(safeElapsedSeconds / oneHourSeconds);
37660
+ return {
37661
+ milestoneSeconds: hours * oneHourSeconds,
37662
+ headline: `${hours * 60} min`
37663
+ };
37664
+ };
37463
37665
  var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
37464
37666
  workspace.video_grid_metric_mode,
37465
37667
  workspace.assembly_enabled === true
@@ -37468,11 +37670,11 @@ var isVideoGridWipGated = (workspace) => isWipGatedVideoGridMetricMode(
37468
37670
  workspace.video_grid_metric_mode,
37469
37671
  workspace.assembly_enabled === true
37470
37672
  );
37471
- var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber2(workspace.recent_flow_percent);
37673
+ var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber3(workspace.recent_flow_percent);
37472
37674
  var isVideoGridRecentFlowUnavailable = (workspace) => isVideoGridRecentFlowEnabled(workspace) && !hasVideoGridRecentFlow(workspace);
37473
37675
  var getRawVideoGridMetricValue = (workspace) => {
37474
37676
  const recentFlowPercent = workspace.recent_flow_percent;
37475
- if (hasVideoGridRecentFlow(workspace) && isFiniteNumber2(recentFlowPercent)) {
37677
+ if (hasVideoGridRecentFlow(workspace) && isFiniteNumber3(recentFlowPercent)) {
37476
37678
  return recentFlowPercent;
37477
37679
  }
37478
37680
  if (isVideoGridRecentFlowUnavailable(workspace)) {
@@ -37481,9 +37683,63 @@ var getRawVideoGridMetricValue = (workspace) => {
37481
37683
  return workspace.efficiency;
37482
37684
  };
37483
37685
  var hasIncomingWipMapping = (workspace) => Boolean(workspace.incoming_wip_buffer_name);
37686
+ var getVideoGridWorkspaceKey = (workspace) => workspace.workspace_uuid || `${workspace.line_id || "unknown"}:${workspace.workspace_name || "unknown"}`;
37687
+ var getVideoGridBlueComparisonGroupKey = (workspace) => {
37688
+ const factoryAreaId = typeof workspace.factory_area_id === "string" ? workspace.factory_area_id.trim() : "";
37689
+ if (factoryAreaId && workspace.factory_area_enabled === true) {
37690
+ return `area:${factoryAreaId}`;
37691
+ }
37692
+ const lineId = typeof workspace.line_id === "string" ? workspace.line_id.trim() : "";
37693
+ return lineId ? `line:${lineId}` : null;
37694
+ };
37695
+ var isVideoGridBlueCandidate = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => hasVideoGridRecentFlow(workspace) && isFiniteNumber3(workspace.recent_flow_percent) && workspace.recent_flow_percent >= legend.green_min;
37696
+ var selectVideoGridBlueWinnerIds = (workspaces, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37697
+ const candidatesByGroup = /* @__PURE__ */ new Map();
37698
+ for (const workspace of workspaces) {
37699
+ if (!isVideoGridBlueCandidate(workspace, legend)) {
37700
+ continue;
37701
+ }
37702
+ const groupKey = getVideoGridBlueComparisonGroupKey(workspace);
37703
+ if (!groupKey) {
37704
+ continue;
37705
+ }
37706
+ const candidates = candidatesByGroup.get(groupKey) || [];
37707
+ candidates.push(workspace);
37708
+ candidatesByGroup.set(groupKey, candidates);
37709
+ }
37710
+ const winners = /* @__PURE__ */ new Set();
37711
+ for (const candidates of candidatesByGroup.values()) {
37712
+ candidates.sort((left, right) => {
37713
+ const leftCurrent = left.recent_flow_percent;
37714
+ const rightCurrent = right.recent_flow_percent;
37715
+ if (rightCurrent !== leftCurrent) {
37716
+ return rightCurrent - leftCurrent;
37717
+ }
37718
+ const leftAverage = isFiniteNumber3(left.avg_recent_flow) ? left.avg_recent_flow : Number.NEGATIVE_INFINITY;
37719
+ const rightAverage = isFiniteNumber3(right.avg_recent_flow) ? right.avg_recent_flow : Number.NEGATIVE_INFINITY;
37720
+ if (rightAverage !== leftAverage) {
37721
+ return rightAverage - leftAverage;
37722
+ }
37723
+ const lineCompare = (left.line_id || "").localeCompare(right.line_id || "");
37724
+ if (lineCompare !== 0) {
37725
+ return lineCompare;
37726
+ }
37727
+ const nameCompare = (left.workspace_name || "").localeCompare(right.workspace_name || "");
37728
+ if (nameCompare !== 0) {
37729
+ return nameCompare;
37730
+ }
37731
+ return getVideoGridWorkspaceKey(left).localeCompare(getVideoGridWorkspaceKey(right));
37732
+ });
37733
+ const winner = candidates[0];
37734
+ if (winner) {
37735
+ winners.add(getVideoGridWorkspaceKey(winner));
37736
+ }
37737
+ }
37738
+ return winners;
37739
+ };
37484
37740
  var getVideoGridBaseColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37485
37741
  const metricValue = getRawVideoGridMetricValue(workspace);
37486
- if (!isFiniteNumber2(metricValue)) {
37742
+ if (!isFiniteNumber3(metricValue)) {
37487
37743
  return "neutral";
37488
37744
  }
37489
37745
  return getEfficiencyColor(metricValue, legend);
@@ -37504,7 +37760,7 @@ var isLowWipGreenOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37504
37760
  if (!hasIncomingWipMapping(workspace)) {
37505
37761
  return false;
37506
37762
  }
37507
- return isFiniteNumber2(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
37763
+ return isFiniteNumber3(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
37508
37764
  };
37509
37765
  var isHighEfficiencyRedFlowOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37510
37766
  if (workspace.scheduled_break_active === true) {
@@ -37522,7 +37778,7 @@ var isHighEfficiencyRedFlowOverride = (workspace, legend = DEFAULT_EFFICIENCY_LE
37522
37778
  if (getVideoGridBaseColorState(workspace, legend) !== "red") {
37523
37779
  return false;
37524
37780
  }
37525
- return isFiniteNumber2(workspace.efficiency) && workspace.efficiency > 100;
37781
+ return isFiniteNumber3(workspace.efficiency) && workspace.efficiency > 100;
37526
37782
  };
37527
37783
  var getVideoGridMetricValue = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => isHighEfficiencyRedFlowOverride(workspace, legend) ? workspace.efficiency : getRawVideoGridMetricValue(workspace);
37528
37784
  var toMinuteBucket = (minuteBucket) => Number.isFinite(minuteBucket) ? Math.floor(minuteBucket) : Math.floor(Date.now() / 6e4);
@@ -37551,7 +37807,10 @@ var getSyntheticLowWipDisplayValue = (workspace, minuteBucket) => {
37551
37807
  return 100 + offset;
37552
37808
  };
37553
37809
  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) => {
37810
+ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND, blueWinnerIds) => {
37811
+ if (blueWinnerIds?.has(getVideoGridWorkspaceKey(workspace)) && isVideoGridBlueCandidate(workspace, legend)) {
37812
+ return "blue";
37813
+ }
37555
37814
  const baseColor = getVideoGridBaseColorState(workspace, legend);
37556
37815
  if (!hasVideoGridRecentFlow(workspace)) {
37557
37816
  return baseColor;
@@ -37571,11 +37830,54 @@ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) =>
37571
37830
  if (!hasIncomingWipMapping(workspace)) {
37572
37831
  return baseColor;
37573
37832
  }
37574
- if (!isFiniteNumber2(workspace.incoming_wip_current)) {
37833
+ if (!isFiniteNumber3(workspace.incoming_wip_current)) {
37575
37834
  return "neutral";
37576
37835
  }
37577
37836
  return baseColor;
37578
37837
  };
37838
+ var hasAllVideoGridWorkspacesGreen = (workspaces, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37839
+ const visibleWorkspaces = workspaces.filter((workspace) => Boolean(workspace.workspace_uuid || workspace.workspace_name));
37840
+ return visibleWorkspaces.length > 0 && visibleWorkspaces.every((workspace) => getVideoGridColorState(workspace, legend) === "green");
37841
+ };
37842
+ var getAllVideoGridGreenStreakDisplay = (workspaces, legend = DEFAULT_EFFICIENCY_LEGEND, nowMs2 = Date.now()) => {
37843
+ const visibleWorkspaces = workspaces.filter((workspace) => Boolean(workspace.workspace_uuid || workspace.workspace_name));
37844
+ if (visibleWorkspaces.length === 0 || !hasAllVideoGridWorkspacesGreen(visibleWorkspaces, legend)) {
37845
+ return null;
37846
+ }
37847
+ const activeStreaks = visibleWorkspaces.map((workspace) => {
37848
+ const startedAt = workspace.video_grid_green_streak_started_at;
37849
+ const anchorAt = workspace.video_grid_green_streak_anchor_at;
37850
+ const streakMinutes = workspace.video_grid_green_streak_minutes;
37851
+ const startedAtMs = parseTimestampMs(startedAt);
37852
+ const anchorAtMs = parseTimestampMs(anchorAt);
37853
+ const isFresh = isAllGreenStreakFresh(workspace, anchorAtMs, nowMs2);
37854
+ const tickOriginAtMs = anchorAtMs + CONFIRMED_MINUTE_DURATION_MS;
37855
+ if (workspace.video_grid_green_streak_active === true && isFiniteNumber3(streakMinutes) && streakMinutes > 0 && startedAt && anchorAt && Number.isFinite(startedAtMs) && isFresh) {
37856
+ return {
37857
+ startedAt,
37858
+ startedAtMs,
37859
+ anchorAt,
37860
+ streakMinutes,
37861
+ tickOriginAtMs
37862
+ };
37863
+ }
37864
+ return null;
37865
+ });
37866
+ if (activeStreaks.some((streak) => streak === null)) {
37867
+ return null;
37868
+ }
37869
+ const strictestStartedAt = activeStreaks.reduce((latest, current) => current.streakMinutes < latest.streakMinutes || current.streakMinutes === latest.streakMinutes && current.startedAtMs > latest.startedAtMs ? current : latest);
37870
+ const confirmedSeconds = Math.max(0, Math.floor(strictestStartedAt.streakMinutes * 60));
37871
+ return {
37872
+ label: "All green",
37873
+ elapsedSeconds: confirmedSeconds,
37874
+ confirmedSeconds,
37875
+ durationText: formatAllGreenStreakDuration(confirmedSeconds),
37876
+ startedAt: strictestStartedAt.startedAt,
37877
+ anchorAt: strictestStartedAt.anchorAt,
37878
+ tickOriginAtMs: strictestStartedAt.tickOriginAtMs
37879
+ };
37880
+ };
37579
37881
  var getVideoGridLegendLabel = (workspaces) => {
37580
37882
  const visibleWorkspaces = workspaces;
37581
37883
  if (visibleWorkspaces.length === 0) {
@@ -37606,6 +37908,7 @@ var VideoCard = React144__namespace.default.memo(({
37606
37908
  compact = false,
37607
37909
  displayMinuteBucket,
37608
37910
  displayName,
37911
+ isBlueBest = false,
37609
37912
  lastSeenLabel,
37610
37913
  hasRecentHealthSignal: hasRecentHealthSignal2 = false,
37611
37914
  onMouseEnter,
@@ -37627,7 +37930,11 @@ var VideoCard = React144__namespace.default.memo(({
37627
37930
  const workspaceDisplayName = displayName || workspace.displayName || workspace.workspace_name;
37628
37931
  const videoGridMetricValue = getVideoGridMetricValue(workspace, effectiveLegend);
37629
37932
  const videoGridDisplayValue = getVideoGridDisplayValue(workspace, effectiveLegend, displayMinuteBucket);
37630
- const videoGridColorState = getVideoGridColorState(workspace, effectiveLegend);
37933
+ const videoGridColorState = getVideoGridColorState(
37934
+ workspace,
37935
+ effectiveLegend,
37936
+ isBlueBest ? /* @__PURE__ */ new Set([getVideoGridWorkspaceKey(workspace)]) : void 0
37937
+ );
37631
37938
  const isRecentFlowCard = isVideoGridRecentFlowEnabled(workspace);
37632
37939
  const isHighEfficiencyOverride = isHighEfficiencyRedFlowOverride(workspace, effectiveLegend);
37633
37940
  const hasDisplayMetric = typeof videoGridDisplayValue === "number" && Number.isFinite(videoGridDisplayValue);
@@ -37635,9 +37942,9 @@ var VideoCard = React144__namespace.default.memo(({
37635
37942
  const shouldRenderMetricBadge = hasDisplayMetric;
37636
37943
  const badgeTitle = isHighEfficiencyOverride ? `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%` : hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
37637
37944
  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";
37945
+ const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "blue" ? "bg-[#0EA5E9]/30" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
37946
+ const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "blue" ? "bg-[#0EA5E9]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
37947
+ const efficiencyStatus = videoGridColorState === "green" ? "High" : videoGridColorState === "blue" ? "Best" : videoGridColorState === "yellow" ? "Medium" : videoGridColorState === "red" ? "Low" : "Neutral";
37641
37948
  const trendInfo = workspace.trend !== void 0 ? getTrendArrowAndColor(workspace.trend) : null;
37642
37949
  const handleClick = React144.useCallback(() => {
37643
37950
  trackCoreEvent("Workspace Card Clicked", {
@@ -37758,6 +38065,9 @@ var VideoCard = React144__namespace.default.memo(({
37758
38065
  if (prevProps.displayName !== nextProps.displayName) {
37759
38066
  return false;
37760
38067
  }
38068
+ if (prevProps.isBlueBest !== nextProps.isBlueBest) {
38069
+ return false;
38070
+ }
37761
38071
  if (prevProps.lastSeenLabel !== nextProps.lastSeenLabel) {
37762
38072
  return false;
37763
38073
  }
@@ -37799,6 +38109,7 @@ var hasRecentHealthSignal = (lastHeartbeat) => {
37799
38109
  };
37800
38110
  var VideoGridView = React144__namespace.default.memo(({
37801
38111
  workspaces,
38112
+ blueComparisonWorkspaces,
37802
38113
  selectedLine,
37803
38114
  className = "",
37804
38115
  legend,
@@ -37927,6 +38238,7 @@ var VideoGridView = React144__namespace.default.memo(({
37927
38238
  return a.workspace_name.localeCompare(b.workspace_name);
37928
38239
  });
37929
38240
  }, [filteredWorkspaces]);
38241
+ const blueWinnerIds = React144.useMemo(() => selectVideoGridBlueWinnerIds(blueComparisonWorkspaces || sortedWorkspaces, effectiveLegend), [blueComparisonWorkspaces, sortedWorkspaces, effectiveLegend]);
37930
38242
  const streamsResolvedForWorkspaceSet = resolvedStreamWorkspaceKey === workspaceIdsKey;
37931
38243
  const resolveWorkspaceDisplayName = React144.useCallback((workspace) => {
37932
38244
  return workspace.displayName || displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || workspace.workspace_name;
@@ -38135,11 +38447,13 @@ var VideoGridView = React144__namespace.default.memo(({
38135
38447
  isR2Stream,
38136
38448
  shouldPlay,
38137
38449
  lastSeenLabel,
38138
- hasRecentHealthSignal: hasRecentHealthSignal(workspaceHealth?.lastHeartbeat)
38450
+ hasRecentHealthSignal: hasRecentHealthSignal(workspaceHealth?.lastHeartbeat),
38451
+ isBlueBest: blueWinnerIds.has(getVideoGridWorkspaceKey(workspace))
38139
38452
  };
38140
38453
  });
38141
38454
  }, [
38142
38455
  sortedWorkspaces,
38456
+ blueWinnerIds,
38143
38457
  visibleWorkspaces,
38144
38458
  getWorkspaceCropping,
38145
38459
  videoStreamsByWorkspaceId,
@@ -38186,6 +38500,7 @@ var VideoGridView = React144__namespace.default.memo(({
38186
38500
  useRAF: effectiveUseRAF,
38187
38501
  displayMinuteBucket,
38188
38502
  compact: !selectedLine,
38503
+ isBlueBest: card.isBlueBest,
38189
38504
  onMouseEnter: onWorkspaceHover ? () => onWorkspaceHover(card.workspaceId) : void 0,
38190
38505
  onMouseLeave: onWorkspaceHoverEnd ? () => onWorkspaceHoverEnd(card.workspaceId) : void 0
38191
38506
  }
@@ -54743,6 +55058,10 @@ var Legend5 = ({
54743
55058
  ":"
54744
55059
  ] }),
54745
55060
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 sm:gap-4", children: [
55061
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
55062
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 sm:w-2.5 sm:h-2.5 rounded-full bg-[#0EA5E9]" }),
55063
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Best" })
55064
+ ] }),
54746
55065
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
54747
55066
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 sm:w-2.5 sm:h-2.5 rounded-full bg-[#00AB45]" }),
54748
55067
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatPercentRange(effectiveLegend.green_min, effectiveLegend.green_max) })
@@ -54861,6 +55180,7 @@ var WorkspaceGridItem = React144__namespace.default.memo(({
54861
55180
  WorkspaceGridItem.displayName = "WorkspaceGridItem";
54862
55181
  var WorkspaceGrid = React144__namespace.default.memo(({
54863
55182
  workspaces,
55183
+ blueComparisonWorkspaces,
54864
55184
  isPdfMode = false,
54865
55185
  customWorkspacePositions,
54866
55186
  lineNames = {},
@@ -54877,13 +55197,8 @@ var WorkspaceGrid = React144__namespace.default.memo(({
54877
55197
  onWorkspaceHoverEnd,
54878
55198
  toolbarRightContent
54879
55199
  }) => {
54880
- const dashboardConfig = useDashboardConfig();
54881
- const mapViewEnabled = dashboardConfig?.mapViewConfig?.enabled ?? false;
55200
+ const mapViewEnabled = false;
54882
55201
  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
55202
  return "video";
54888
55203
  });
54889
55204
  React144.useEffect(() => {
@@ -54892,7 +55207,7 @@ var WorkspaceGrid = React144__namespace.default.memo(({
54892
55207
  total_workspaces: workspaces.length
54893
55208
  });
54894
55209
  }, [workspaces.length]);
54895
- const handleViewModeToggle = React144.useCallback(() => {
55210
+ React144.useCallback(() => {
54896
55211
  const newMode = viewMode === "video" ? "map" : "video";
54897
55212
  setViewMode(newMode);
54898
55213
  if (typeof window !== "undefined") {
@@ -54906,8 +55221,8 @@ var WorkspaceGrid = React144__namespace.default.memo(({
54906
55221
  }, [viewMode]);
54907
55222
  const { VideoGridView: VideoGridViewComponent, MapGridView: MapGridViewComponent } = useRegistry();
54908
55223
  const legendMetricLabel = React144.useMemo(
54909
- () => viewMode === "video" ? getVideoGridLegendLabel(workspaces) : MAP_GRID_LEGEND_LABEL,
54910
- [viewMode, workspaces]
55224
+ () => getVideoGridLegendLabel(workspaces),
55225
+ [workspaces]
54911
55226
  );
54912
55227
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col w-full h-full overflow-hidden bg-slate-50/50 ${className}`, children: [
54913
55228
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -54919,21 +55234,7 @@ var WorkspaceGrid = React144__namespace.default.memo(({
54919
55234
  /* @__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
55235
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-3 shrink-0", children: [
54921
55236
  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
- )
55237
+ mapViewEnabled
54937
55238
  ] })
54938
55239
  ]
54939
55240
  }
@@ -54951,6 +55252,7 @@ var WorkspaceGrid = React144__namespace.default.memo(({
54951
55252
  VideoGridViewComponent,
54952
55253
  {
54953
55254
  workspaces,
55255
+ blueComparisonWorkspaces,
54954
55256
  lineNames,
54955
55257
  lineOrder,
54956
55258
  videoSources,
@@ -57247,12 +57549,25 @@ var SideNavBar = React144.memo(({
57247
57549
  console.log("\u{1F50D} [SideNavBar] ticketsConfig:", dashboardConfig?.ticketsConfig);
57248
57550
  console.log("\u{1F50D} [SideNavBar] ticketsEnabled:", ticketsEnabled);
57249
57551
  const pathname = propPathname || router$1.pathname;
57552
+ const rawCurrentTabQuery = currentQuery?.tab ?? router$1.query?.tab;
57553
+ const currentTabQuery = Array.isArray(rawCurrentTabQuery) ? rawCurrentTabQuery[0] : rawCurrentTabQuery;
57554
+ const isKpisLeaderboardRoute = pathname === "/kpis" && currentTabQuery === "leaderboard";
57555
+ const isPathActive = React144.useCallback((path) => {
57556
+ if (path === "/") return pathname === "/";
57557
+ if (path === "/leaderboard") {
57558
+ return pathname === "/leaderboard" || pathname.startsWith("/leaderboard/");
57559
+ }
57560
+ if (path === "/kpis") {
57561
+ return pathname === "/kpis" || pathname.startsWith("/kpis/");
57562
+ }
57563
+ return pathname === path || pathname.startsWith(path + "/");
57564
+ }, [pathname]);
57250
57565
  const getButtonClasses = React144.useCallback((path) => {
57251
- const isActive = pathname === path || pathname.startsWith(path + "/");
57566
+ const isActive = isPathActive(path);
57252
57567
  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
57568
  ${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
57569
  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]);
57570
+ }, [isPathActive]);
57256
57571
  const buildDashboardSurfaceTrackingEvent = React144.useCallback((source, destinationPath, dashboardSurface) => ({
57257
57572
  name: ROOT_DASHBOARD_EVENT_NAMES[dashboardSurface],
57258
57573
  properties: {
@@ -57285,17 +57600,24 @@ var SideNavBar = React144.memo(({
57285
57600
  onMobileMenuClose?.();
57286
57601
  }, [navigate, onMobileMenuClose, buildDashboardSurfaceTrackingEvent]);
57287
57602
  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
- }
57603
+ const trackingEvent = {
57604
+ name: "KPI Page Clicked",
57605
+ properties: {
57606
+ source: "side_nav",
57607
+ page_type: "overview"
57295
57608
  }
57609
+ };
57610
+ if (isKpisLeaderboardRoute) {
57611
+ trackCoreEvent(trackingEvent.name, trackingEvent.properties);
57612
+ void router$1.replace("/kpis", void 0, { shallow: false });
57613
+ onMobileMenuClose?.();
57614
+ return;
57615
+ }
57616
+ navigate(`/kpis`, {
57617
+ trackingEvent
57296
57618
  });
57297
57619
  onMobileMenuClose?.();
57298
- }, [navigate, onMobileMenuClose]);
57620
+ }, [isKpisLeaderboardRoute, navigate, onMobileMenuClose, router$1]);
57299
57621
  const handleImprovementClick = React144.useCallback(() => {
57300
57622
  navigate("/improvement-center", {
57301
57623
  trackingEvent: {
@@ -57565,14 +57887,14 @@ var SideNavBar = React144.memo(({
57565
57887
  });
57566
57888
  onMobileMenuClose?.();
57567
57889
  }, [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]);
57890
+ const homeButtonClasses = React144.useMemo(() => getButtonClasses("/"), [getButtonClasses]);
57891
+ const liveButtonClasses = React144.useMemo(() => getButtonClasses("/live-monitor"), [getButtonClasses]);
57892
+ const leaderboardButtonClasses = React144.useMemo(() => getButtonClasses("/leaderboard"), [getButtonClasses]);
57893
+ const kpisButtonClasses = React144.useMemo(() => getButtonClasses("/kpis"), [getButtonClasses]);
57894
+ const improvementButtonClasses = React144.useMemo(() => getButtonClasses("/improvement-center"), [getButtonClasses]);
57895
+ React144.useMemo(() => getButtonClasses("/supervisor-management"), [getButtonClasses]);
57896
+ const skusButtonClasses = React144.useMemo(() => getButtonClasses("/skus"), [getButtonClasses]);
57897
+ const healthButtonClasses = React144.useMemo(() => getButtonClasses("/health"), [getButtonClasses]);
57576
57898
  const settingsButtonClasses = React144.useMemo(() => {
57577
57899
  const isAnyItemActive = settingsItems.some((item) => item.isActive);
57578
57900
  const isActive = isSettingsOpen || isAnyItemActive;
@@ -57606,7 +57928,7 @@ var SideNavBar = React144.memo(({
57606
57928
  "aria-label": "Home",
57607
57929
  tabIndex: 0,
57608
57930
  role: "tab",
57609
- "aria-selected": pathname === "/" || pathname.startsWith("//"),
57931
+ "aria-selected": isPathActive("/"),
57610
57932
  children: [
57611
57933
  /* @__PURE__ */ jsxRuntime.jsx(outline.HomeIcon, { className: "w-5 h-5 mb-1" }),
57612
57934
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Home" })
@@ -57621,7 +57943,7 @@ var SideNavBar = React144.memo(({
57621
57943
  "aria-label": "Monitor",
57622
57944
  tabIndex: 0,
57623
57945
  role: "tab",
57624
- "aria-selected": pathname === "/live-monitor" || pathname.startsWith("/live-monitor/"),
57946
+ "aria-selected": isPathActive("/live-monitor"),
57625
57947
  children: [
57626
57948
  /* @__PURE__ */ jsxRuntime.jsx(outline.VideoCameraIcon, { className: "w-5 h-5 mb-1" }),
57627
57949
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Monitor" })
@@ -57638,7 +57960,7 @@ var SideNavBar = React144.memo(({
57638
57960
  "aria-label": "Leaderboard",
57639
57961
  tabIndex: 0,
57640
57962
  role: "tab",
57641
- "aria-selected": pathname === "/leaderboard" || pathname.startsWith("/leaderboard/"),
57963
+ "aria-selected": isPathActive("/leaderboard"),
57642
57964
  children: [
57643
57965
  /* @__PURE__ */ jsxRuntime.jsx(outline.TrophyIcon, { className: "w-5 h-5 mb-1" }),
57644
57966
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Leaders" })
@@ -57653,7 +57975,7 @@ var SideNavBar = React144.memo(({
57653
57975
  "aria-label": "Lines",
57654
57976
  tabIndex: 0,
57655
57977
  role: "tab",
57656
- "aria-selected": pathname === "/kpis" || pathname.startsWith("/kpis/"),
57978
+ "aria-selected": isPathActive("/kpis"),
57657
57979
  children: [
57658
57980
  /* @__PURE__ */ jsxRuntime.jsx(outline.ChartBarIcon, { className: "w-5 h-5 mb-1" }),
57659
57981
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Lines" })
@@ -57668,7 +57990,7 @@ var SideNavBar = React144.memo(({
57668
57990
  "aria-label": "Improvement Center",
57669
57991
  tabIndex: 0,
57670
57992
  role: "tab",
57671
- "aria-selected": pathname === "/improvement-center" || pathname.startsWith("/improvement-center/"),
57993
+ "aria-selected": isPathActive("/improvement-center"),
57672
57994
  children: [
57673
57995
  /* @__PURE__ */ jsxRuntime.jsx(outline.LightBulbIcon, { className: "w-5 h-5 mb-1" }),
57674
57996
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight text-center", children: "Improve" })
@@ -57684,7 +58006,7 @@ var SideNavBar = React144.memo(({
57684
58006
  "aria-label": "SKU Management",
57685
58007
  tabIndex: 0,
57686
58008
  role: "tab",
57687
- "aria-selected": pathname === "/skus" || pathname.startsWith("/skus/"),
58009
+ "aria-selected": isPathActive("/skus"),
57688
58010
  children: [
57689
58011
  /* @__PURE__ */ jsxRuntime.jsx(outline.CubeIcon, { className: "w-5 h-5 mb-1" }),
57690
58012
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "SKUs" })
@@ -57699,7 +58021,7 @@ var SideNavBar = React144.memo(({
57699
58021
  "aria-label": "System Health",
57700
58022
  tabIndex: 0,
57701
58023
  role: "tab",
57702
- "aria-selected": pathname === "/health" || pathname.startsWith("/health/"),
58024
+ "aria-selected": isPathActive("/health"),
57703
58025
  children: [
57704
58026
  /* @__PURE__ */ jsxRuntime.jsx(outline.HeartIcon, { className: "w-5 h-5 mb-1" }),
57705
58027
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Health" })
@@ -57729,17 +58051,12 @@ var SideNavBar = React144.memo(({
57729
58051
  ) })
57730
58052
  ] });
57731
58053
  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
58054
  const getMobileButtonClass = (path) => {
57738
- const active = isActive(path);
58055
+ const active = isPathActive(path);
57739
58056
  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
58057
  };
57741
58058
  const getIconClass = (path) => {
57742
- const active = isActive(path);
58059
+ const active = isPathActive(path);
57743
58060
  return `w-7 h-7 ${active ? "text-blue-600" : "text-gray-600"}`;
57744
58061
  };
57745
58062
  const handleMobileNavClick = (handler) => {
@@ -63673,6 +63990,8 @@ var HelpView = ({
63673
63990
  };
63674
63991
  var AuthenticatedHelpView = withAuth(HelpView);
63675
63992
  var HelpView_default = HelpView;
63993
+ var REALTIME_REFRESH_DEBOUNCE_MS2 = 1500;
63994
+ var REALTIME_REFRESH_MIN_INTERVAL_MS2 = 5e3;
63676
63995
  var transformActiveBreaks = (activeBreaksByLine) => {
63677
63996
  if (!activeBreaksByLine) return [];
63678
63997
  return Object.values(activeBreaksByLine).flat().map((item) => ({
@@ -63696,6 +64015,7 @@ var createEmptyState = () => ({
63696
64015
  scopeKey: null,
63697
64016
  lines: [],
63698
64017
  workspaceMetrics: [],
64018
+ blueComparisonWorkspaceMetrics: [],
63699
64019
  lineMetrics: [],
63700
64020
  kpiTrend: null,
63701
64021
  activeBreaks: [],
@@ -63710,8 +64030,20 @@ var normalizeMetadata = (metadata) => ({
63710
64030
  cacheStatus: metadata?.cache_status,
63711
64031
  warnings: metadata?.warnings ?? []
63712
64032
  });
64033
+ var createResolvedScopeLookup = (resolvedScope, workspaces, blueComparisonWorkspaces) => {
64034
+ const lookup = /* @__PURE__ */ new Set();
64035
+ const addEntry = (lineId, date, shiftId) => {
64036
+ if (!lineId || !date || shiftId === void 0 || shiftId === null) return;
64037
+ lookup.add(`${lineId}|${date}|${shiftId}`);
64038
+ };
64039
+ resolvedScope.forEach((entry) => addEntry(entry.line_id, entry.date, entry.shift_id));
64040
+ workspaces.forEach((workspace) => addEntry(workspace.line_id, workspace.date, workspace.shift_id));
64041
+ blueComparisonWorkspaces.forEach((workspace) => addEntry(workspace.line_id, workspace.date, workspace.shift_id));
64042
+ return lookup;
64043
+ };
63713
64044
  var useLiveMonitorBootstrap = ({
63714
64045
  lineIds,
64046
+ blueComparisonLineIds,
63715
64047
  companyId,
63716
64048
  enabled = true,
63717
64049
  appTimezone,
@@ -63726,33 +64058,56 @@ var useLiveMonitorBootstrap = ({
63726
64058
  const effectiveWorkspaceConfig = workspaceConfig || DEFAULT_WORKSPACE_CONFIG;
63727
64059
  const effectiveTimezone = appTimezone || "Asia/Kolkata";
63728
64060
  const rawLineIdsKey = (lineIds || []).filter(Boolean).join(",");
64061
+ const rawBlueComparisonLineIdsKey = (blueComparisonLineIds || lineIds || []).filter(Boolean).join(",");
63729
64062
  const normalizedLineIds = React144.useMemo(
63730
64063
  () => Array.from(new Set(rawLineIdsKey ? rawLineIdsKey.split(",") : [])),
63731
64064
  [rawLineIdsKey]
63732
64065
  );
64066
+ const normalizedBlueComparisonLineIds = React144.useMemo(
64067
+ () => Array.from(new Set(rawBlueComparisonLineIdsKey ? rawBlueComparisonLineIdsKey.split(",") : [])),
64068
+ [rawBlueComparisonLineIdsKey]
64069
+ );
64070
+ const realtimeLineIds = React144.useMemo(
64071
+ () => Array.from(new Set([...normalizedLineIds, ...normalizedBlueComparisonLineIds].filter(Boolean))).sort(),
64072
+ [normalizedLineIds, normalizedBlueComparisonLineIds]
64073
+ );
63733
64074
  const requestKey = React144.useMemo(
63734
- () => normalizedLineIds.slice().sort().join(","),
63735
- [normalizedLineIds]
64075
+ () => `${normalizedLineIds.slice().sort().join(",")}|blue:${normalizedBlueComparisonLineIds.slice().sort().join(",")}`,
64076
+ [normalizedLineIds, normalizedBlueComparisonLineIds]
64077
+ );
64078
+ const realtimeLineIdsKey = React144.useMemo(() => realtimeLineIds.join(","), [realtimeLineIds]);
64079
+ const companySpecificMetricsTable = React144.useMemo(
64080
+ () => getCompanyMetricsTableName(resolvedCompanyId, "performance_metrics"),
64081
+ [resolvedCompanyId]
63736
64082
  );
63737
64083
  const [state, setState] = React144.useState(() => createEmptyState());
63738
64084
  const [rawState, setRawState] = React144.useState(null);
63739
64085
  const [isLoading, setIsLoading] = React144.useState(false);
63740
64086
  const [error, setError] = React144.useState(null);
63741
64087
  const activeRequestIdRef = React144.useRef(0);
64088
+ const isFetchingRef = React144.useRef(false);
64089
+ const pendingRealtimeRefreshRef = React144.useRef(false);
64090
+ const realtimeRefreshTimerRef = React144.useRef(null);
64091
+ const lastRealtimeRefreshStartedAtRef = React144.useRef(0);
63742
64092
  const fetchBootstrap = React144.useCallback(async (force = false) => {
63743
64093
  if (!enabled || !supabase || !resolvedCompanyId || normalizedLineIds.length === 0) {
63744
64094
  return;
63745
64095
  }
63746
64096
  const requestId = ++activeRequestIdRef.current;
64097
+ isFetchingRef.current = true;
63747
64098
  setIsLoading(true);
63748
64099
  setError(null);
63749
64100
  try {
63750
64101
  const searchParams = new URLSearchParams();
63751
64102
  searchParams.set("company_id", resolvedCompanyId);
63752
64103
  searchParams.set("line_ids", normalizedLineIds.join(","));
64104
+ if (normalizedBlueComparisonLineIds.length) {
64105
+ searchParams.set("blue_comparison_line_ids", normalizedBlueComparisonLineIds.join(","));
64106
+ }
63753
64107
  if (force) {
63754
64108
  searchParams.set("force_refresh", "true");
63755
64109
  }
64110
+ appendQaGreenStreakSearchParams(searchParams);
63756
64111
  const response = await fetchBackendJson(
63757
64112
  supabase,
63758
64113
  `/api/dashboard/monitor-bootstrap?${searchParams.toString()}`,
@@ -63781,6 +64136,7 @@ var useLiveMonitorBootstrap = ({
63781
64136
  extras: {
63782
64137
  company_id: resolvedCompanyId,
63783
64138
  line_ids: normalizedLineIds,
64139
+ blue_comparison_line_ids: normalizedBlueComparisonLineIds,
63784
64140
  force_refresh: force,
63785
64141
  pathname: typeof window !== "undefined" ? window.location.pathname : "unknown"
63786
64142
  }
@@ -63789,6 +64145,7 @@ var useLiveMonitorBootstrap = ({
63789
64145
  } finally {
63790
64146
  if (requestId === activeRequestIdRef.current) {
63791
64147
  setIsLoading(false);
64148
+ isFetchingRef.current = false;
63792
64149
  }
63793
64150
  }
63794
64151
  }, [
@@ -63796,8 +64153,55 @@ var useLiveMonitorBootstrap = ({
63796
64153
  supabase,
63797
64154
  resolvedCompanyId,
63798
64155
  normalizedLineIds,
64156
+ normalizedBlueComparisonLineIds,
63799
64157
  requestKey
63800
64158
  ]);
64159
+ const fetchBootstrapRef = React144.useRef(fetchBootstrap);
64160
+ React144.useEffect(() => {
64161
+ fetchBootstrapRef.current = fetchBootstrap;
64162
+ }, [fetchBootstrap]);
64163
+ const clearRealtimeRefreshTimer = React144.useCallback(() => {
64164
+ if (realtimeRefreshTimerRef.current !== null) {
64165
+ window.clearTimeout(realtimeRefreshTimerRef.current);
64166
+ realtimeRefreshTimerRef.current = null;
64167
+ }
64168
+ }, []);
64169
+ const scheduleRealtimeRefresh = React144.useCallback(() => {
64170
+ if (!enabled || !supabase || realtimeRefreshTimerRef.current !== null) {
64171
+ return;
64172
+ }
64173
+ const elapsedSinceLastRealtimeRefresh = Date.now() - lastRealtimeRefreshStartedAtRef.current;
64174
+ const minIntervalRemaining = Math.max(0, REALTIME_REFRESH_MIN_INTERVAL_MS2 - elapsedSinceLastRealtimeRefresh);
64175
+ const nextDelay = Math.max(REALTIME_REFRESH_DEBOUNCE_MS2, minIntervalRemaining);
64176
+ realtimeRefreshTimerRef.current = window.setTimeout(() => {
64177
+ realtimeRefreshTimerRef.current = null;
64178
+ if (!pendingRealtimeRefreshRef.current) {
64179
+ return;
64180
+ }
64181
+ if (isFetchingRef.current) {
64182
+ scheduleRealtimeRefresh();
64183
+ return;
64184
+ }
64185
+ pendingRealtimeRefreshRef.current = false;
64186
+ lastRealtimeRefreshStartedAtRef.current = Date.now();
64187
+ void fetchBootstrapRef.current(true);
64188
+ }, nextDelay);
64189
+ }, [enabled, supabase]);
64190
+ const queueRealtimeRefresh = React144.useCallback(() => {
64191
+ if (!enabled || !supabase) {
64192
+ pendingRealtimeRefreshRef.current = false;
64193
+ clearRealtimeRefreshTimer();
64194
+ return;
64195
+ }
64196
+ pendingRealtimeRefreshRef.current = true;
64197
+ scheduleRealtimeRefresh();
64198
+ }, [clearRealtimeRefreshTimer, enabled, scheduleRealtimeRefresh, supabase]);
64199
+ React144.useEffect(() => {
64200
+ return () => {
64201
+ pendingRealtimeRefreshRef.current = false;
64202
+ clearRealtimeRefreshTimer();
64203
+ };
64204
+ }, [clearRealtimeRefreshTimer]);
63801
64205
  React144.useEffect(() => {
63802
64206
  if (!enabled || !rawState || !resolvedCompanyId) {
63803
64207
  return;
@@ -63814,6 +64218,16 @@ var useLiveMonitorBootstrap = ({
63814
64218
  fallbackShiftConfig
63815
64219
  });
63816
64220
  const activeBreaks = transformActiveBreaks(rawState.response.active_breaks_by_line);
64221
+ const blueComparisonWorkspaceMetrics = rawState.response.blue_comparison_workspace_metrics ? transformMonitorWorkspaceMetrics({
64222
+ rows: rawState.response.blue_comparison_workspace_metrics,
64223
+ companyId: resolvedCompanyId,
64224
+ workspaceConfig: effectiveWorkspaceConfig,
64225
+ appTimezone: effectiveTimezone,
64226
+ lineMetrics: rawState.response.line_metrics || [],
64227
+ resolveShiftConfig: (lineId) => lineShiftConfigs?.get(lineId) || fallbackShiftConfig,
64228
+ shouldOverrideShiftType: (lineId) => Boolean(lineShiftConfigs?.get(lineId)),
64229
+ fallbackShiftConfig
64230
+ }) : workspaceMetrics;
63817
64231
  const metadata = normalizeMetadata(rawState.response.metadata);
63818
64232
  const workspaceIds = workspaceMetrics.map((metric) => metric.workspace_uuid).filter((workspaceId) => Boolean(workspaceId));
63819
64233
  const videoStreamsByWorkspaceId = rawState.response.video_streams_by_workspace_id || {};
@@ -63831,6 +64245,7 @@ var useLiveMonitorBootstrap = ({
63831
64245
  scopeKey: rawState.response.scope_key || null,
63832
64246
  lines: rawState.response.lines || [],
63833
64247
  workspaceMetrics,
64248
+ blueComparisonWorkspaceMetrics: blueComparisonWorkspaceMetrics.length ? blueComparisonWorkspaceMetrics : workspaceMetrics,
63834
64249
  lineMetrics: rawState.response.line_metrics || [],
63835
64250
  kpiTrend: rawState.response.kpi_trend || null,
63836
64251
  activeBreaks,
@@ -63865,6 +64280,83 @@ var useLiveMonitorBootstrap = ({
63865
64280
  }
63866
64281
  void fetchBootstrap(false);
63867
64282
  }, [enabled, resolvedCompanyId, normalizedLineIds, supabase, fetchBootstrap]);
64283
+ const realtimeScopeKey = React144.useMemo(() => Array.from(createResolvedScopeLookup(
64284
+ state.resolvedScope,
64285
+ state.workspaceMetrics,
64286
+ state.blueComparisonWorkspaceMetrics
64287
+ )).sort().join("||"), [state.resolvedScope, state.workspaceMetrics, state.blueComparisonWorkspaceMetrics]);
64288
+ React144.useEffect(() => {
64289
+ if (!enabled || !resolvedCompanyId || !realtimeLineIdsKey || !supabase) {
64290
+ return void 0;
64291
+ }
64292
+ const scopeLookup = new Set(realtimeScopeKey ? realtimeScopeKey.split("||") : []);
64293
+ if (scopeLookup.size === 0) {
64294
+ return void 0;
64295
+ }
64296
+ const realtimeLineIdsForFilter = realtimeLineIdsKey.split(",").filter(Boolean);
64297
+ if (realtimeLineIdsForFilter.length === 0) {
64298
+ return void 0;
64299
+ }
64300
+ const lineIdFilter = `line_id=in.(${realtimeLineIdsForFilter.join(",")})`;
64301
+ const channels = [];
64302
+ const shouldRefreshForPayload = (payload) => {
64303
+ const payloadData = payload.new || payload.old;
64304
+ return scopeLookup.has(`${payloadData?.line_id}|${payloadData?.date}|${payloadData?.shift_id}`);
64305
+ };
64306
+ const createSubscription = (table, channelNameBase) => {
64307
+ const channelName = `${channelNameBase}-${state.scopeKey || requestKey}`.replace(/[^a-zA-Z0-9_-]/g, "");
64308
+ const channel = supabase.channel(channelName).on(
64309
+ "postgres_changes",
64310
+ { event: "*", schema: "public", table, filter: lineIdFilter },
64311
+ (payload) => {
64312
+ if (shouldRefreshForPayload(payload)) {
64313
+ queueRealtimeRefresh();
64314
+ }
64315
+ }
64316
+ ).subscribe();
64317
+ channels.push(channel);
64318
+ };
64319
+ createSubscription(companySpecificMetricsTable, "monitor-bootstrap-ws");
64320
+ createSubscription("line_metrics", "monitor-bootstrap-lm");
64321
+ createSubscription("wip_buffer_metrics", "monitor-bootstrap-wip-metrics");
64322
+ createSubscription("wip_buffer_alerts", "monitor-bootstrap-wip-alerts");
64323
+ return () => {
64324
+ channels.forEach((channel) => {
64325
+ supabase.removeChannel(channel);
64326
+ });
64327
+ };
64328
+ }, [
64329
+ enabled,
64330
+ resolvedCompanyId,
64331
+ realtimeLineIdsKey,
64332
+ supabase,
64333
+ realtimeScopeKey,
64334
+ state.scopeKey,
64335
+ requestKey,
64336
+ companySpecificMetricsTable,
64337
+ queueRealtimeRefresh
64338
+ ]);
64339
+ React144.useEffect(() => {
64340
+ if (!enabled || !resolvedCompanyId || normalizedLineIds.length === 0 || !supabase) {
64341
+ return void 0;
64342
+ }
64343
+ const forceRefreshOnResume = () => {
64344
+ void fetchBootstrapRef.current(true);
64345
+ };
64346
+ const handleVisibilityChange = () => {
64347
+ if (document.visibilityState === "visible") {
64348
+ forceRefreshOnResume();
64349
+ }
64350
+ };
64351
+ document.addEventListener("visibilitychange", handleVisibilityChange);
64352
+ window.addEventListener("focus", forceRefreshOnResume);
64353
+ window.addEventListener("online", forceRefreshOnResume);
64354
+ return () => {
64355
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
64356
+ window.removeEventListener("focus", forceRefreshOnResume);
64357
+ window.removeEventListener("online", forceRefreshOnResume);
64358
+ };
64359
+ }, [enabled, normalizedLineIds.length, resolvedCompanyId, supabase]);
63868
64360
  React144.useEffect(() => {
63869
64361
  if (!enabled || !resolvedCompanyId || normalizedLineIds.length === 0 || !supabase) {
63870
64362
  return void 0;
@@ -63898,6 +64390,7 @@ var useLiveMonitorBootstrap = ({
63898
64390
  scopeKey: state.scopeKey,
63899
64391
  lines: state.lines,
63900
64392
  workspaceMetrics: state.workspaceMetrics,
64393
+ blueComparisonWorkspaceMetrics: state.blueComparisonWorkspaceMetrics,
63901
64394
  lineMetrics: state.lineMetrics,
63902
64395
  kpiTrend: state.kpiTrend,
63903
64396
  activeBreaks: state.activeBreaks,
@@ -64168,6 +64661,22 @@ var logDebug3 = (...args) => {
64168
64661
  };
64169
64662
  var EMPTY_LINE_IDS = [];
64170
64663
  var EMPTY_WORKSPACES = [];
64664
+ var ALL_GREEN_CELEBRATION_DURATION_MS = 6e3;
64665
+ var ALL_GREEN_MILESTONE_DURATION_MS = 6e3;
64666
+ var ALL_GREEN_STREAK_LOCAL_SECOND_CAP = 59;
64667
+ var formatAllGreenCelebrationTimer = (elapsedSeconds) => {
64668
+ const safeElapsedSeconds = Math.max(1, Math.floor(elapsedSeconds));
64669
+ const minutes = Math.floor(safeElapsedSeconds / 60);
64670
+ const seconds = safeElapsedSeconds % 60;
64671
+ return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}s`;
64672
+ };
64673
+ var getAllGreenBackendVisibleSeconds = (confirmedSeconds, tickOriginAtMs, nowMs2) => {
64674
+ const localSecondOffset = Math.min(
64675
+ ALL_GREEN_STREAK_LOCAL_SECOND_CAP,
64676
+ Math.max(0, Math.floor((nowMs2 - tickOriginAtMs) / 1e3))
64677
+ );
64678
+ return confirmedSeconds + localSecondOffset;
64679
+ };
64171
64680
  var LoadingPageCmp = LoadingPage_default;
64172
64681
  var LoadingOverlayCmp = LoadingOverlay_default;
64173
64682
  function HomeView({
@@ -64309,6 +64818,31 @@ function HomeView({
64309
64818
  () => new Set(selectedLineIds),
64310
64819
  [selectedLineIds]
64311
64820
  );
64821
+ const blueComparisonLineIds = React144.useMemo(() => {
64822
+ const selectedFactoryAreaIds = /* @__PURE__ */ new Set();
64823
+ for (const line of dbLines) {
64824
+ if (!selectedLineIdSet.has(line.id)) {
64825
+ continue;
64826
+ }
64827
+ const factoryAreaId = typeof line.factory_area_id === "string" ? line.factory_area_id.trim() : "";
64828
+ if (factoryAreaId) {
64829
+ selectedFactoryAreaIds.add(factoryAreaId);
64830
+ }
64831
+ }
64832
+ if (selectedFactoryAreaIds.size === 0) {
64833
+ return selectedLineIds;
64834
+ }
64835
+ const dbLinesById = new Map(dbLines.map((line) => [line.id, line]));
64836
+ const selectedIds = new Set(selectedLineIds);
64837
+ return visibleLineIds.filter((lineId) => {
64838
+ if (selectedIds.has(lineId)) {
64839
+ return true;
64840
+ }
64841
+ const line = dbLinesById.get(lineId);
64842
+ const factoryAreaId = typeof line?.factory_area_id === "string" ? line.factory_area_id.trim() : "";
64843
+ return factoryAreaId ? selectedFactoryAreaIds.has(factoryAreaId) : false;
64844
+ });
64845
+ }, [dbLines, selectedLineIdSet, selectedLineIds, visibleLineIds]);
64312
64846
  const metricsScopeLineId = isMultiLineSelection ? factoryViewId : primarySelectedLineId;
64313
64847
  const userCompanyId = React144.useMemo(() => {
64314
64848
  return user?.properties?.company_id || user?.company_id || entityConfig.companyId;
@@ -64349,6 +64883,7 @@ function HomeView({
64349
64883
  }, []);
64350
64884
  const {
64351
64885
  workspaceMetrics: legacyWorkspaceMetrics,
64886
+ blueComparisonWorkspaceMetrics: legacyMetricsBlueComparisonWorkspaceMetrics,
64352
64887
  lineMetrics: legacyLineMetrics,
64353
64888
  efficiencyLegend: legacyEfficiencyLegend,
64354
64889
  metadata: legacyMetricsMetadata,
@@ -64359,6 +64894,7 @@ function HomeView({
64359
64894
  } = useDashboardMetrics({
64360
64895
  lineId: metricsScopeLineId,
64361
64896
  lineIds: selectedLineIds,
64897
+ blueComparisonLineIds,
64362
64898
  onLineMetricsUpdate: handleLineMetricsUpdate,
64363
64899
  userAccessibleLineIds: visibleLineIds,
64364
64900
  enabled: shouldEnableMetricsFetch && !isBootstrapMonitorMode
@@ -64413,6 +64949,7 @@ function HomeView({
64413
64949
  const { trend: legacyKpiTrend } = useKpiTrends(legacyTrendOptions);
64414
64950
  const bootstrapMonitor = useLiveMonitorBootstrap({
64415
64951
  lineIds: selectedLineIds,
64952
+ blueComparisonLineIds,
64416
64953
  companyId: userCompanyId,
64417
64954
  enabled: shouldEnableMetricsFetch && !isLegacyMonitorMode,
64418
64955
  appTimezone: timezone,
@@ -64421,6 +64958,7 @@ function HomeView({
64421
64958
  lineShiftConfigs
64422
64959
  });
64423
64960
  const currentWorkspaceMetrics = isBootstrapMonitorMode ? bootstrapMonitor.workspaceMetrics : legacyWorkspaceMetrics;
64961
+ const currentBlueComparisonWorkspaceMetrics = isBootstrapMonitorMode ? bootstrapMonitor.blueComparisonWorkspaceMetrics : legacyMetricsBlueComparisonWorkspaceMetrics;
64424
64962
  const currentLineMetrics = isBootstrapMonitorMode ? bootstrapMonitor.lineMetrics : legacyLineMetrics;
64425
64963
  const currentEfficiencyLegend = isBootstrapMonitorMode ? bootstrapMonitor.efficiencyLegend : legacyEfficiencyLegend;
64426
64964
  const currentMetricsMetadata = isBootstrapMonitorMode ? bootstrapMonitor.metadata : legacyMetricsMetadata;
@@ -64558,6 +65096,212 @@ function HomeView({
64558
65096
  setBreakNotificationsDismissed(false);
64559
65097
  }
64560
65098
  }, [currentActiveBreaks.length]);
65099
+ const effectiveEfficiencyLegend = currentEfficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
65100
+ React144.useMemo(
65101
+ () => workspaceMetricsWithBreakState.filter((workspace) => Boolean(workspace.workspace_uuid || workspace.workspace_name)).length,
65102
+ [workspaceMetricsWithBreakState]
65103
+ );
65104
+ const allGreenCelebrationSignature = React144.useMemo(() => {
65105
+ const workspaceSignature = workspaceMetricsWithBreakState.map((workspace) => workspace.workspace_uuid || `${workspace.line_id}:${workspace.workspace_name}`).filter(Boolean).sort().join(",");
65106
+ return `${selectedLineIds.join(",")}::${workspaceSignature}`;
65107
+ }, [selectedLineIds, workspaceMetricsWithBreakState]);
65108
+ const allGreenTransitionRef = React144.useRef({ signature: null, previousValidStreakIdentity: null });
65109
+ const allGreenCelebrationTimerRef = React144.useRef(null);
65110
+ const allGreenMilestoneTimerRef = React144.useRef(null);
65111
+ const allGreenMilestoneTrackingRef = React144.useRef({ identity: null, lastMilestoneSeconds: null });
65112
+ const allGreenStreakTimerBaselineRef = React144.useRef(null);
65113
+ const [showAllGreenCelebration, setShowAllGreenCelebration] = React144.useState(false);
65114
+ const [greenStreakMilestoneBanner, setGreenStreakMilestoneBanner] = React144.useState(null);
65115
+ const [allGreenStreakNowMs, setAllGreenStreakNowMs] = React144.useState(() => Date.now());
65116
+ const currentAllGreenStreakNowMs = Math.max(allGreenStreakNowMs, Date.now());
65117
+ const allGreenStreakDisplay = React144.useMemo(
65118
+ () => getAllVideoGridGreenStreakDisplay(
65119
+ workspaceMetricsWithBreakState,
65120
+ effectiveEfficiencyLegend,
65121
+ currentAllGreenStreakNowMs
65122
+ ),
65123
+ [currentAllGreenStreakNowMs, effectiveEfficiencyLegend, workspaceMetricsWithBreakState]
65124
+ );
65125
+ const allGreenMilestoneIdentity = React144.useMemo(() => allGreenStreakDisplay ? `${allGreenCelebrationSignature}::${allGreenStreakDisplay.startedAt}` : null, [allGreenCelebrationSignature, allGreenStreakDisplay]);
65126
+ const visibleAllGreenStreakDisplay = React144.useMemo(() => {
65127
+ if (!allGreenStreakDisplay || !allGreenMilestoneIdentity) {
65128
+ allGreenStreakTimerBaselineRef.current = null;
65129
+ return null;
65130
+ }
65131
+ const confirmedSeconds = allGreenStreakDisplay.confirmedSeconds;
65132
+ const backendVisibleSeconds = getAllGreenBackendVisibleSeconds(
65133
+ confirmedSeconds,
65134
+ allGreenStreakDisplay.tickOriginAtMs,
65135
+ currentAllGreenStreakNowMs
65136
+ );
65137
+ const backendMaxVisibleSeconds = confirmedSeconds + ALL_GREEN_STREAK_LOCAL_SECOND_CAP;
65138
+ const currentBaseline = allGreenStreakTimerBaselineRef.current;
65139
+ if (!currentBaseline || currentBaseline.identity !== allGreenMilestoneIdentity) {
65140
+ allGreenStreakTimerBaselineRef.current = {
65141
+ identity: allGreenMilestoneIdentity,
65142
+ baseSeconds: backendVisibleSeconds,
65143
+ baseReceivedAtMs: currentAllGreenStreakNowMs,
65144
+ maxVisibleSeconds: backendMaxVisibleSeconds
65145
+ };
65146
+ } else {
65147
+ currentBaseline.maxVisibleSeconds = Math.max(
65148
+ currentBaseline.maxVisibleSeconds,
65149
+ backendMaxVisibleSeconds
65150
+ );
65151
+ const visibleSeconds = Math.min(
65152
+ currentBaseline.maxVisibleSeconds,
65153
+ currentBaseline.baseSeconds + Math.max(0, Math.floor((currentAllGreenStreakNowMs - currentBaseline.baseReceivedAtMs) / 1e3))
65154
+ );
65155
+ if (backendVisibleSeconds > visibleSeconds) {
65156
+ allGreenStreakTimerBaselineRef.current = {
65157
+ identity: allGreenMilestoneIdentity,
65158
+ baseSeconds: backendVisibleSeconds,
65159
+ baseReceivedAtMs: currentAllGreenStreakNowMs,
65160
+ maxVisibleSeconds: currentBaseline.maxVisibleSeconds
65161
+ };
65162
+ }
65163
+ }
65164
+ const baseline = allGreenStreakTimerBaselineRef.current;
65165
+ const elapsedSeconds = baseline ? Math.min(
65166
+ baseline.maxVisibleSeconds,
65167
+ baseline.baseSeconds + Math.max(0, Math.floor((currentAllGreenStreakNowMs - baseline.baseReceivedAtMs) / 1e3))
65168
+ ) : backendVisibleSeconds;
65169
+ return {
65170
+ ...allGreenStreakDisplay,
65171
+ elapsedSeconds,
65172
+ durationText: formatAllGreenStreakDuration(elapsedSeconds)
65173
+ };
65174
+ }, [allGreenMilestoneIdentity, allGreenStreakDisplay, currentAllGreenStreakNowMs]);
65175
+ const allGreenCelebrationTimerText = React144.useMemo(() => {
65176
+ if (!showAllGreenCelebration || !visibleAllGreenStreakDisplay) {
65177
+ return null;
65178
+ }
65179
+ return formatAllGreenCelebrationTimer(visibleAllGreenStreakDisplay.elapsedSeconds);
65180
+ }, [showAllGreenCelebration, visibleAllGreenStreakDisplay]);
65181
+ React144.useEffect(() => {
65182
+ const hasPossibleStreakTimer = showAllGreenCelebration || Boolean(allGreenStreakDisplay) || workspaceMetricsWithBreakState.some((workspace) => workspace.video_grid_green_streak_active === true);
65183
+ if (!hasPossibleStreakTimer) {
65184
+ return void 0;
65185
+ }
65186
+ const timerId = setInterval(() => {
65187
+ setAllGreenStreakNowMs(Date.now());
65188
+ }, 1e3);
65189
+ return () => {
65190
+ clearInterval(timerId);
65191
+ };
65192
+ }, [allGreenStreakDisplay, showAllGreenCelebration, workspaceMetricsWithBreakState]);
65193
+ const dismissAllGreenCelebration = React144.useCallback(() => {
65194
+ if (allGreenCelebrationTimerRef.current) {
65195
+ clearTimeout(allGreenCelebrationTimerRef.current);
65196
+ allGreenCelebrationTimerRef.current = null;
65197
+ }
65198
+ setShowAllGreenCelebration(false);
65199
+ }, []);
65200
+ const triggerAllGreenCelebration = React144.useCallback(() => {
65201
+ setShowAllGreenCelebration(true);
65202
+ if (allGreenCelebrationTimerRef.current) {
65203
+ clearTimeout(allGreenCelebrationTimerRef.current);
65204
+ }
65205
+ allGreenCelebrationTimerRef.current = setTimeout(() => {
65206
+ setShowAllGreenCelebration(false);
65207
+ allGreenCelebrationTimerRef.current = null;
65208
+ }, ALL_GREEN_CELEBRATION_DURATION_MS);
65209
+ }, []);
65210
+ const dismissGreenStreakMilestoneBanner = React144.useCallback(() => {
65211
+ if (allGreenMilestoneTimerRef.current) {
65212
+ clearTimeout(allGreenMilestoneTimerRef.current);
65213
+ allGreenMilestoneTimerRef.current = null;
65214
+ }
65215
+ setGreenStreakMilestoneBanner(null);
65216
+ }, []);
65217
+ const triggerGreenStreakMilestoneBanner = React144.useCallback((milestone) => {
65218
+ setGreenStreakMilestoneBanner(milestone);
65219
+ if (allGreenMilestoneTimerRef.current) {
65220
+ clearTimeout(allGreenMilestoneTimerRef.current);
65221
+ }
65222
+ allGreenMilestoneTimerRef.current = setTimeout(() => {
65223
+ setGreenStreakMilestoneBanner(null);
65224
+ allGreenMilestoneTimerRef.current = null;
65225
+ }, ALL_GREEN_MILESTONE_DURATION_MS);
65226
+ }, []);
65227
+ React144.useEffect(() => {
65228
+ return () => {
65229
+ if (allGreenCelebrationTimerRef.current) {
65230
+ clearTimeout(allGreenCelebrationTimerRef.current);
65231
+ }
65232
+ if (allGreenMilestoneTimerRef.current) {
65233
+ clearTimeout(allGreenMilestoneTimerRef.current);
65234
+ }
65235
+ };
65236
+ }, []);
65237
+ React144.useEffect(() => {
65238
+ const milestoneTracking = allGreenMilestoneTrackingRef.current;
65239
+ if (currentMetricsLoading) {
65240
+ return;
65241
+ }
65242
+ if (!visibleAllGreenStreakDisplay || !allGreenMilestoneIdentity) {
65243
+ milestoneTracking.identity = null;
65244
+ milestoneTracking.lastMilestoneSeconds = null;
65245
+ dismissGreenStreakMilestoneBanner();
65246
+ return;
65247
+ }
65248
+ const currentMilestone = getAllGreenStreakMilestone(visibleAllGreenStreakDisplay.elapsedSeconds);
65249
+ const currentMilestoneSeconds = currentMilestone?.milestoneSeconds ?? null;
65250
+ if (milestoneTracking.identity !== allGreenMilestoneIdentity) {
65251
+ milestoneTracking.identity = allGreenMilestoneIdentity;
65252
+ milestoneTracking.lastMilestoneSeconds = currentMilestoneSeconds;
65253
+ dismissGreenStreakMilestoneBanner();
65254
+ return;
65255
+ }
65256
+ if (!currentMilestone) {
65257
+ milestoneTracking.lastMilestoneSeconds = null;
65258
+ return;
65259
+ }
65260
+ if ((milestoneTracking.lastMilestoneSeconds ?? 0) < currentMilestone.milestoneSeconds) {
65261
+ milestoneTracking.lastMilestoneSeconds = currentMilestone.milestoneSeconds;
65262
+ triggerGreenStreakMilestoneBanner(currentMilestone);
65263
+ }
65264
+ }, [
65265
+ allGreenMilestoneIdentity,
65266
+ currentMetricsLoading,
65267
+ dismissGreenStreakMilestoneBanner,
65268
+ triggerGreenStreakMilestoneBanner,
65269
+ visibleAllGreenStreakDisplay
65270
+ ]);
65271
+ React144.useEffect(() => {
65272
+ if (currentMetricsLoading) {
65273
+ return;
65274
+ }
65275
+ const currentValidStreakIdentity = visibleAllGreenStreakDisplay && allGreenMilestoneIdentity ? allGreenMilestoneIdentity : null;
65276
+ const transitionState = allGreenTransitionRef.current;
65277
+ if (transitionState.signature !== allGreenCelebrationSignature) {
65278
+ transitionState.signature = allGreenCelebrationSignature;
65279
+ transitionState.previousValidStreakIdentity = currentValidStreakIdentity;
65280
+ dismissAllGreenCelebration();
65281
+ return;
65282
+ }
65283
+ if (!currentValidStreakIdentity) {
65284
+ transitionState.previousValidStreakIdentity = null;
65285
+ dismissAllGreenCelebration();
65286
+ return;
65287
+ }
65288
+ if (transitionState.previousValidStreakIdentity === null) {
65289
+ transitionState.previousValidStreakIdentity = currentValidStreakIdentity;
65290
+ triggerAllGreenCelebration();
65291
+ return;
65292
+ }
65293
+ if (transitionState.previousValidStreakIdentity !== currentValidStreakIdentity) {
65294
+ transitionState.previousValidStreakIdentity = currentValidStreakIdentity;
65295
+ dismissAllGreenCelebration();
65296
+ }
65297
+ }, [
65298
+ allGreenCelebrationSignature,
65299
+ allGreenMilestoneIdentity,
65300
+ currentMetricsLoading,
65301
+ dismissAllGreenCelebration,
65302
+ triggerAllGreenCelebration,
65303
+ visibleAllGreenStreakDisplay
65304
+ ]);
64561
65305
  const {
64562
65306
  streamsByWorkspaceId: legacyVideoStreamsByWorkspaceId,
64563
65307
  isLoading: legacyVideoStreamsLoading
@@ -65124,6 +65868,28 @@ function HomeView({
65124
65868
  updateSelectedLineIds,
65125
65869
  isAllLinesSelection
65126
65870
  ]);
65871
+ const gridToolbarControls = React144.useMemo(() => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-2", children: [
65872
+ /* @__PURE__ */ jsxRuntime.jsx(AnimatePresence, { children: visibleAllGreenStreakDisplay ? /* @__PURE__ */ jsxRuntime.jsxs(
65873
+ motion.div,
65874
+ {
65875
+ initial: { opacity: 0, y: -4 },
65876
+ animate: { opacity: 1, y: 0 },
65877
+ exit: { opacity: 0, y: -4 },
65878
+ transition: { duration: 0.18, ease: "easeOut" },
65879
+ 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",
65880
+ "aria-label": "All green streak",
65881
+ children: [
65882
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-4 w-4" }),
65883
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: `${visibleAllGreenStreakDisplay.label} \xB7 ${visibleAllGreenStreakDisplay.durationText}` })
65884
+ ]
65885
+ },
65886
+ visibleAllGreenStreakDisplay.startedAt
65887
+ ) : null }),
65888
+ lineSelectorComponent
65889
+ ] }), [
65890
+ lineSelectorComponent,
65891
+ visibleAllGreenStreakDisplay
65892
+ ]);
65127
65893
  const useSmoothLoading = (isLoading, minDuration = 400) => {
65128
65894
  const [showLoading, setShowLoading] = React144.useState(isLoading);
65129
65895
  const loadingStartRef2 = React144.useRef(null);
@@ -65296,17 +66062,18 @@ function HomeView({
65296
66062
  className: "h-full",
65297
66063
  children: React144__namespace.default.createElement(WorkspaceGrid, {
65298
66064
  workspaces: workspaceMetricsWithBreakState,
66065
+ blueComparisonWorkspaces: currentBlueComparisonWorkspaceMetrics || workspaceMetricsWithBreakState,
65299
66066
  lineNames: mergedLineNames,
65300
66067
  lineOrder: selectedLineIds,
65301
66068
  factoryView: factoryViewId,
65302
- legend: currentEfficiencyLegend,
66069
+ legend: effectiveEfficiencyLegend,
65303
66070
  videoSources,
65304
66071
  videoStreamsByWorkspaceId: currentVideoStreamsByWorkspaceId,
65305
66072
  videoStreamsLoading: currentVideoStreamsLoading,
65306
66073
  displayNames: metricsDisplayNames,
65307
66074
  hasFlowBuffers,
65308
66075
  className: "h-full",
65309
- toolbarRightContent: lineSelectorComponent,
66076
+ toolbarRightContent: gridToolbarControls,
65310
66077
  onWorkspaceHover: handleWorkspaceHover,
65311
66078
  onWorkspaceHoverEnd: handleWorkspaceHoverEnd
65312
66079
  })
@@ -65329,17 +66096,18 @@ function HomeView({
65329
66096
  children: React144__namespace.default.createElement(WorkspaceGrid, {
65330
66097
  workspaces: [],
65331
66098
  // Show empty grid while loading
66099
+ blueComparisonWorkspaces: [],
65332
66100
  lineNames: mergedLineNames,
65333
66101
  lineOrder: selectedLineIds,
65334
66102
  factoryView: factoryViewId,
65335
- legend: currentEfficiencyLegend,
66103
+ legend: effectiveEfficiencyLegend,
65336
66104
  videoSources,
65337
66105
  videoStreamsByWorkspaceId: currentVideoStreamsByWorkspaceId,
65338
66106
  videoStreamsLoading: currentVideoStreamsLoading,
65339
66107
  displayNames: metricsDisplayNames,
65340
66108
  hasFlowBuffers,
65341
66109
  className: "h-full",
65342
- toolbarRightContent: lineSelectorComponent,
66110
+ toolbarRightContent: gridToolbarControls,
65343
66111
  onWorkspaceHover: handleWorkspaceHover,
65344
66112
  onWorkspaceHoverEnd: handleWorkspaceHoverEnd
65345
66113
  })
@@ -65372,6 +66140,149 @@ function HomeView({
65372
66140
  contentVariant: "plain"
65373
66141
  }
65374
66142
  ),
66143
+ /* @__PURE__ */ jsxRuntime.jsx(AnimatePresence, { children: showAllGreenCelebration ? /* @__PURE__ */ jsxRuntime.jsxs(React144__namespace.default.Fragment, { children: [
66144
+ /* @__PURE__ */ jsxRuntime.jsx(
66145
+ motion.div,
66146
+ {
66147
+ initial: { opacity: 0 },
66148
+ animate: { opacity: 1 },
66149
+ exit: { opacity: 0 },
66150
+ transition: { duration: 0.4 },
66151
+ className: "pointer-events-none fixed inset-0 z-[9998] bg-slate-900/40 backdrop-blur-sm",
66152
+ "aria-hidden": "true"
66153
+ },
66154
+ "all-green-backdrop"
66155
+ ),
66156
+ /* @__PURE__ */ jsxRuntime.jsxs(
66157
+ motion.div,
66158
+ {
66159
+ initial: { opacity: 0 },
66160
+ animate: { opacity: 1 },
66161
+ exit: { opacity: 0, y: -50, scale: 0.9, filter: "blur(10px)" },
66162
+ transition: { duration: 0.4 },
66163
+ className: "pointer-events-none fixed inset-0 z-[10000] flex flex-col items-center justify-center px-4",
66164
+ role: "status",
66165
+ "aria-live": "polite",
66166
+ "aria-label": "All green celebration",
66167
+ children: [
66168
+ /* @__PURE__ */ jsxRuntime.jsxs(
66169
+ motion.div,
66170
+ {
66171
+ initial: { opacity: 0, y: 8, filter: "blur(6px)" },
66172
+ animate: { opacity: 1, y: 0, filter: "blur(0px)" },
66173
+ transition: { duration: 0.28, ease: [0.16, 1, 0.3, 1] },
66174
+ className: "flex flex-wrap items-center justify-center gap-x-4 sm:gap-x-8",
66175
+ children: [
66176
+ /* @__PURE__ */ jsxRuntime.jsx(
66177
+ "span",
66178
+ {
66179
+ className: "text-[100px] font-black uppercase leading-none tracking-tight text-white drop-shadow-2xl sm:text-[140px]",
66180
+ style: { textShadow: "0 18px 36px rgba(0,0,0,0.34)" },
66181
+ children: "ALL"
66182
+ }
66183
+ ),
66184
+ /* @__PURE__ */ jsxRuntime.jsx(
66185
+ "span",
66186
+ {
66187
+ className: "text-[100px] font-black uppercase leading-none tracking-tight text-[#00AB45] drop-shadow-2xl sm:text-[140px]",
66188
+ style: { filter: "drop-shadow(0 18px 36px rgba(0,171,69,0.28))" },
66189
+ children: "GREEN"
66190
+ }
66191
+ )
66192
+ ]
66193
+ }
66194
+ ),
66195
+ /* @__PURE__ */ jsxRuntime.jsx(
66196
+ motion.div,
66197
+ {
66198
+ initial: { opacity: 0, scaleX: 0 },
66199
+ animate: { opacity: 1, scaleX: 1 },
66200
+ transition: { delay: 0.18, duration: 0.45, ease: [0.16, 1, 0.3, 1] },
66201
+ 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"
66202
+ }
66203
+ ),
66204
+ allGreenCelebrationTimerText && /* @__PURE__ */ jsxRuntime.jsxs(
66205
+ motion.div,
66206
+ {
66207
+ initial: { opacity: 0, y: 4 },
66208
+ animate: { opacity: 1, y: 0 },
66209
+ transition: { delay: 0.28, duration: 0.18, ease: "easeOut" },
66210
+ 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",
66211
+ children: [
66212
+ /* @__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)]" }),
66213
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: allGreenCelebrationTimerText })
66214
+ ]
66215
+ }
66216
+ )
66217
+ ]
66218
+ },
66219
+ "all-green-center-toast"
66220
+ )
66221
+ ] }, "all-green-celebration") : null }),
66222
+ /* @__PURE__ */ jsxRuntime.jsx(AnimatePresence, { children: greenStreakMilestoneBanner ? /* @__PURE__ */ jsxRuntime.jsxs(React144__namespace.default.Fragment, { children: [
66223
+ /* @__PURE__ */ jsxRuntime.jsx(
66224
+ motion.div,
66225
+ {
66226
+ initial: { opacity: 0 },
66227
+ animate: { opacity: 1 },
66228
+ exit: { opacity: 0 },
66229
+ transition: { duration: 0.4 },
66230
+ className: "pointer-events-none fixed inset-0 z-[9998] bg-slate-900/40 backdrop-blur-sm",
66231
+ "aria-hidden": "true"
66232
+ },
66233
+ `green-streak-backdrop-${greenStreakMilestoneBanner.milestoneSeconds}`
66234
+ ),
66235
+ /* @__PURE__ */ jsxRuntime.jsx(
66236
+ motion.div,
66237
+ {
66238
+ initial: { opacity: 0 },
66239
+ animate: { opacity: 1 },
66240
+ exit: { opacity: 0, y: -50, scale: 0.9, filter: "blur(10px)" },
66241
+ transition: { duration: 0.4 },
66242
+ className: "pointer-events-none fixed inset-0 z-[10000] flex flex-col items-center justify-center px-4",
66243
+ role: "status",
66244
+ "aria-live": "polite",
66245
+ "aria-label": `Green streak milestone: ${greenStreakMilestoneBanner.headline}`,
66246
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center gap-y-4", children: [
66247
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
66248
+ motion.div,
66249
+ {
66250
+ initial: { opacity: 0, y: 8, filter: "blur(6px)" },
66251
+ animate: { opacity: 1, y: 0, filter: "blur(0px)" },
66252
+ transition: { delay: 0.08, duration: 0.28, ease: [0.16, 1, 0.3, 1] },
66253
+ className: "text-[80px] font-black uppercase leading-none tracking-tight text-white drop-shadow-2xl sm:text-[120px]",
66254
+ style: { textShadow: "0 18px 36px rgba(0,0,0,0.34)" },
66255
+ children: greenStreakMilestoneBanner.headline
66256
+ }
66257
+ ) }),
66258
+ /* @__PURE__ */ jsxRuntime.jsx(
66259
+ motion.div,
66260
+ {
66261
+ initial: { opacity: 0, scaleX: 0 },
66262
+ animate: { opacity: 1, scaleX: 1 },
66263
+ transition: { delay: 0.22, duration: 0.45, ease: [0.16, 1, 0.3, 1] },
66264
+ className: "h-1 w-40 origin-left rounded-full bg-[#00AB45] shadow-[0_0_16px_rgba(0,171,69,0.44)] sm:w-56"
66265
+ }
66266
+ ),
66267
+ /* @__PURE__ */ jsxRuntime.jsxs(
66268
+ motion.div,
66269
+ {
66270
+ initial: { opacity: 0, y: 8, filter: "blur(6px)" },
66271
+ animate: { opacity: 1, y: 0, filter: "blur(0px)" },
66272
+ transition: { delay: 0.28, duration: 0.28, ease: [0.16, 1, 0.3, 1] },
66273
+ 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]",
66274
+ style: { filter: "drop-shadow(0 18px 36px rgba(0,171,69,0.28))" },
66275
+ children: [
66276
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "ALL" }),
66277
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "GREEN" })
66278
+ ]
66279
+ }
66280
+ )
66281
+ ] })
66282
+ },
66283
+ `green-streak-milestone-${greenStreakMilestoneBanner.milestoneSeconds}`
66284
+ )
66285
+ ] }, `green-streak-milestone-wrapper-${greenStreakMilestoneBanner.milestoneSeconds}`) : null }),
65375
66286
  diagnosisModalOpen && bottleneckModalData?.clipId && /* @__PURE__ */ jsxRuntime.jsx(
65376
66287
  DiagnosisVideoModal,
65377
66288
  {
@@ -68766,6 +69677,7 @@ var LinesLeaderboard = ({
68766
69677
  timeRange,
68767
69678
  setTimeRange,
68768
69679
  todayEfficiencyByLineId,
69680
+ dailyFallbackEfficiencyByLineId,
68769
69681
  monthlyEfficiencyByLineId,
68770
69682
  supervisorsByLineId,
68771
69683
  supervisorNamesByLineId,
@@ -68801,8 +69713,12 @@ var LinesLeaderboard = ({
68801
69713
  });
68802
69714
  setTimeRange(newRange);
68803
69715
  }, [timeRange, lines.length, monthlyEfficiencyByLineId, setTimeRange]);
69716
+ const canClickLeaderboardRow = React144__namespace.default.useCallback(
69717
+ (item) => item.rowType === "line" && !!item.line && canClickLine(item.line.id),
69718
+ [canClickLine]
69719
+ );
68804
69720
  const handleLeaderboardLineClick = React144__namespace.default.useCallback((item, clickSource) => {
68805
- if (!canClickLine(item.line.id)) return;
69721
+ if (!canClickLeaderboardRow(item) || !item.line) return;
68806
69722
  trackCoreEvent("Leaderboard Line Clicked", {
68807
69723
  line_id: item.line.id,
68808
69724
  line_name: item.line.line_name,
@@ -68814,33 +69730,46 @@ var LinesLeaderboard = ({
68814
69730
  supervisor_name: item.supervisorName || "Unassigned"
68815
69731
  });
68816
69732
  onLineClick(item.line);
68817
- }, [canClickLine, onLineClick, timeRange]);
69733
+ }, [canClickLeaderboardRow, onLineClick, timeRange]);
68818
69734
  const viewLoadedTrackedRef = React144__namespace.default.useRef(null);
68819
69735
  const leaderboardData = React144__namespace.default.useMemo(() => {
68820
69736
  const loading = timeRange === "today" ? isLoadingToday : isLoadingMonthly;
68821
69737
  const efficiencyMap = timeRange === "today" ? todayEfficiencyByLineId : monthlyEfficiencyByLineId;
68822
- return lines.map((line) => {
68823
- const supervisors = supervisorsByLineId?.get(line.id) || [];
69738
+ const fallbackEfficiencyMap = timeRange === "today" ? dailyFallbackEfficiencyByLineId : void 0;
69739
+ return buildLineLeaderboardRows({
69740
+ lines,
69741
+ efficiencyByLineId: efficiencyMap,
69742
+ fallbackEfficiencyByLineId: fallbackEfficiencyMap,
69743
+ isLoading: loading
69744
+ }).map((row, index) => {
69745
+ const supervisorByUserId = /* @__PURE__ */ new Map();
69746
+ const fallbackSupervisorNames = [];
69747
+ row.lines.forEach((line) => {
69748
+ (supervisorsByLineId?.get(line.id) || []).forEach((supervisor) => {
69749
+ supervisorByUserId.set(supervisor.userId, supervisor);
69750
+ });
69751
+ const fallbackName = supervisorNamesByLineId.get(line.id);
69752
+ if (fallbackName && !fallbackSupervisorNames.includes(fallbackName)) {
69753
+ fallbackSupervisorNames.push(fallbackName);
69754
+ }
69755
+ });
69756
+ const supervisors = Array.from(supervisorByUserId.values());
68824
69757
  const primarySupervisor = supervisors[0];
68825
- const supervisorName = supervisorNamesByLineId.get(line.id) || primarySupervisor?.displayName || "Unassigned";
69758
+ const supervisorName = supervisors.length > 1 ? `${supervisors.length} supervisors` : primarySupervisor?.displayName || fallbackSupervisorNames[0] || "Unassigned";
68826
69759
  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
69760
  return {
68831
- id: line.id,
68832
- line,
69761
+ ...row,
69762
+ rank: row.rank ?? index + 1,
68833
69763
  supervisorName,
68834
69764
  supervisorImage,
68835
- supervisors,
68836
- efficiency,
68837
- sortValue
69765
+ supervisors
68838
69766
  };
68839
- }).sort((a, b) => b.sortValue - a.sortValue).map((item, index) => ({ ...item, rank: index + 1 }));
69767
+ });
68840
69768
  }, [
68841
69769
  lines,
68842
69770
  timeRange,
68843
69771
  todayEfficiencyByLineId,
69772
+ dailyFallbackEfficiencyByLineId,
68844
69773
  monthlyEfficiencyByLineId,
68845
69774
  supervisorsByLineId,
68846
69775
  supervisorNamesByLineId,
@@ -68857,11 +69786,11 @@ var LinesLeaderboard = ({
68857
69786
  trackCoreEvent("Leaderboard View Loaded", {
68858
69787
  time_range: timeRange,
68859
69788
  lines_count: leaderboardData.length,
68860
- top_line_id: topLine?.line.id,
68861
- top_line_name: topLine?.line.line_name,
69789
+ top_line_id: topLine?.rowType === "line" ? topLine.line?.id : topLine?.areaId,
69790
+ top_line_name: topLine?.displayName,
68862
69791
  top_efficiency: topLine?.efficiency,
68863
- bottom_line_id: bottomLine?.line.id,
68864
- bottom_line_name: bottomLine?.line.line_name,
69792
+ bottom_line_id: bottomLine?.rowType === "line" ? bottomLine.line?.id : bottomLine?.areaId,
69793
+ bottom_line_name: bottomLine?.displayName,
68865
69794
  bottom_efficiency: bottomLine?.efficiency,
68866
69795
  efficiency_spread: topLine && bottomLine && topLine.efficiency !== null && bottomLine.efficiency !== null ? (topLine.efficiency - bottomLine.efficiency).toFixed(1) : null,
68867
69796
  from_page: "kpis_overview"
@@ -68968,7 +69897,7 @@ var LinesLeaderboard = ({
68968
69897
  const isFirst = item.rank === 1;
68969
69898
  const isSecond = item.rank === 2;
68970
69899
  item.rank === 3;
68971
- const isClickable = canClickLine(item.line.id);
69900
+ const isClickable = canClickLeaderboardRow(item);
68972
69901
  return /* @__PURE__ */ jsxRuntime.jsxs(
68973
69902
  "div",
68974
69903
  {
@@ -69011,7 +69940,11 @@ var LinesLeaderboard = ({
69011
69940
  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
69941
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center w-full", children: [
69013
69942
  /* @__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 }),
69943
+ /* @__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 }),
69944
+ 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: [
69945
+ item.lines.length,
69946
+ " lines"
69947
+ ] }),
69015
69948
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center mt-auto", children: [
69016
69949
  /* @__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
69950
  /* @__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 +69967,7 @@ var LinesLeaderboard = ({
69034
69967
  ] }) }),
69035
69968
  /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-gray-100", children: leaderboardData.map((item) => {
69036
69969
  const isTopThree = item.rank <= 3;
69037
- const isClickable = canClickLine(item.line.id);
69970
+ const isClickable = canClickLeaderboardRow(item);
69038
69971
  return /* @__PURE__ */ jsxRuntime.jsxs(
69039
69972
  "tr",
69040
69973
  {
@@ -69066,7 +69999,13 @@ var LinesLeaderboard = ({
69066
69999
  ] }) : /* @__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
70000
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-900", children: item.supervisorName })
69068
70001
  ] }) }),
69069
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 whitespace-nowrap text-sm text-gray-500", children: item.line.line_name }),
70002
+ /* @__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: [
70003
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-gray-700", children: item.displayName }),
70004
+ item.rowType === "area" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-400", children: [
70005
+ item.lines.length,
70006
+ " lines"
70007
+ ] })
70008
+ ] }) }),
69070
70009
  /* @__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
70010
  ]
69072
70011
  },
@@ -69344,17 +70283,6 @@ var KPIsOverviewView = ({
69344
70283
  const filterRef = React144.useRef(null);
69345
70284
  const filterButtonRef = React144.useRef(null);
69346
70285
  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
70286
  const [todayEfficiencyByLineId, setTodayEfficiencyByLineId] = React144.useState(/* @__PURE__ */ new Map());
69359
70287
  const [dailyLoading, setDailyLoading] = React144.useState(false);
69360
70288
  const [dailyError, setDailyError] = React144.useState(null);
@@ -69363,6 +70291,9 @@ var KPIsOverviewView = ({
69363
70291
  const [monthlyError, setMonthlyError] = React144.useState(null);
69364
70292
  const dailyRequestKeyRef = React144.useRef(null);
69365
70293
  const monthlyRequestKeyRef = React144.useRef(null);
70294
+ const dailyFallbackRequestKeyRef = React144.useRef(null);
70295
+ const pendingTabRouteSyncRef = React144.useRef(null);
70296
+ const [scopedDailyFallbackEfficiencyByLineId, setScopedDailyFallbackEfficiencyByLineId] = React144.useState(/* @__PURE__ */ new Map());
69366
70297
  const supabase = useSupabase();
69367
70298
  const { user } = useAuth();
69368
70299
  const dashboardConfig = useDashboardConfig();
@@ -69407,8 +70338,23 @@ var KPIsOverviewView = ({
69407
70338
  const assignedLineIdsForLeaderboard = isSuperAdmin ? void 0 : resolvedAssignedLineIds;
69408
70339
  const leaderboardLinesForView = React144__namespace.default.useMemo(() => {
69409
70340
  const targetMode = viewType === "machine" ? "uptime" : "output";
69410
- return leaderboardLines.filter((line) => (line.monitoring_mode ?? "output") === targetMode);
69411
- }, [leaderboardLines, viewType]);
70341
+ const metadataByLineId = new Map(lines.map((line) => [line.id, line]));
70342
+ return leaderboardLines.map((line) => {
70343
+ const metadata = metadataByLineId.get(line.id);
70344
+ return metadata ? {
70345
+ ...line,
70346
+ factory_id: line.factory_id || metadata.factory_id,
70347
+ factory_name: line.factory_name || metadata.factory_name,
70348
+ company_name: line.company_name || metadata.company_name,
70349
+ monitoring_mode: line.monitoring_mode ?? metadata.monitoring_mode,
70350
+ factory_area_id: line.factory_area_id ?? metadata.factory_area_id ?? null,
70351
+ factory_area_key: line.factory_area_key ?? metadata.factory_area_key ?? null,
70352
+ factory_area_name: line.factory_area_name ?? metadata.factory_area_name ?? null,
70353
+ factory_area_sort_order: line.factory_area_sort_order ?? metadata.factory_area_sort_order ?? null,
70354
+ factory_area_enabled: line.factory_area_enabled ?? metadata.factory_area_enabled ?? null
70355
+ } : line;
70356
+ }).filter((line) => (line.monitoring_mode ?? "output") === targetMode);
70357
+ }, [leaderboardLines, lines, viewType]);
69412
70358
  const linesForView = React144__namespace.default.useMemo(() => {
69413
70359
  const targetMode = viewType === "machine" ? "uptime" : "output";
69414
70360
  return lines.filter((line) => (line.monitoring_mode ?? "output") === targetMode);
@@ -69528,12 +70474,19 @@ var KPIsOverviewView = ({
69528
70474
  React144.useEffect(() => {
69529
70475
  if (!router$1.isReady || !hasHydratedLeaderboardRouteState) return;
69530
70476
  if (activeTab === "today" && loading) return;
70477
+ const currentTab = typeof router$1.query.tab === "string" ? router$1.query.tab : void 0;
70478
+ const currentRouteTab = currentTab === "leaderboard" ? "leaderboard" : "today";
70479
+ if (currentRouteTab !== activeTab) {
70480
+ if (pendingTabRouteSyncRef.current !== activeTab) {
70481
+ return;
70482
+ }
70483
+ pendingTabRouteSyncRef.current = null;
70484
+ }
69531
70485
  const expectedTab = activeTab === "leaderboard" ? "leaderboard" : void 0;
69532
70486
  const expectedDate = activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily ? effectiveLeaderboardDate : void 0;
69533
70487
  const expectedShift = expectedDate !== void 0 ? effectiveLeaderboardShiftId.toString() : void 0;
69534
70488
  const expectedFactory = activeTab === "today" && selectedFactoryNode ? selectedFactoryNode.id : void 0;
69535
70489
  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
70490
  const currentDateQuery = typeof router$1.query.date === "string" ? router$1.query.date : void 0;
69538
70491
  const currentShiftQuery = typeof router$1.query.shift === "string" ? router$1.query.shift : void 0;
69539
70492
  const currentFactoryQuery = getSingleQueryValue(router$1.query[KPI_FACTORY_QUERY_PARAM]);
@@ -69593,6 +70546,35 @@ var KPIsOverviewView = ({
69593
70546
  });
69594
70547
  return map;
69595
70548
  }, [lineMetrics, lineModeById]);
70549
+ const liveDailyFallbackEfficiencyByLineId = React144__namespace.default.useMemo(() => {
70550
+ const map = /* @__PURE__ */ new Map();
70551
+ lineMetricRowsByLineId.forEach((row, lineId) => {
70552
+ const value = Number(row?.avg_efficiency);
70553
+ if (!Number.isFinite(value)) return;
70554
+ const rowDate = typeof row?.date === "string" ? row.date : typeof row?.operational_date === "string" ? row.operational_date : void 0;
70555
+ const rawShiftId = row?.shift_id ?? row?.shiftId;
70556
+ const parsedShiftId = typeof rawShiftId === "number" ? rawShiftId : Number.parseInt(String(rawShiftId ?? ""), 10);
70557
+ const hasScopedRow = rowDate !== void 0 || rawShiftId !== void 0;
70558
+ const matchesSelectedScope = rowDate === effectiveLeaderboardDate && Number.isFinite(parsedShiftId) && parsedShiftId === effectiveLeaderboardShiftId;
70559
+ const canUseUnscopedLiveFallback = !isHistoricalLeaderboardDaily && !hasScopedRow;
70560
+ if (matchesSelectedScope || canUseUnscopedLiveFallback) {
70561
+ map.set(lineId, value);
70562
+ }
70563
+ });
70564
+ return map;
70565
+ }, [
70566
+ effectiveLeaderboardDate,
70567
+ effectiveLeaderboardShiftId,
70568
+ isHistoricalLeaderboardDaily,
70569
+ lineMetricRowsByLineId
70570
+ ]);
70571
+ const dailyFallbackEfficiencyByLineId = React144__namespace.default.useMemo(() => {
70572
+ const map = new Map(liveDailyFallbackEfficiencyByLineId);
70573
+ scopedDailyFallbackEfficiencyByLineId.forEach((value, lineId) => {
70574
+ map.set(lineId, value);
70575
+ });
70576
+ return map;
70577
+ }, [liveDailyFallbackEfficiencyByLineId, scopedDailyFallbackEfficiencyByLineId]);
69596
70578
  const kpisByLineId = React144__namespace.default.useMemo(() => {
69597
70579
  const map = /* @__PURE__ */ new Map();
69598
70580
  lineMetricRowsByLineId.forEach((row, lineId) => {
@@ -69614,32 +70596,11 @@ var KPIsOverviewView = ({
69614
70596
  () => (leaderboardLines.length > 0 ? leaderboardLines : lines).map((l) => l.id),
69615
70597
  [leaderboardLines, lines]
69616
70598
  );
69617
- const { supervisorNamesByLineId, supervisorsByLineId, allSupervisorsMap } = useSupervisorsByLineIds(supervisorLineIds, {
70599
+ const { supervisorNamesByLineId, supervisorsByLineId } = useSupervisorsByLineIds(supervisorLineIds, {
69618
70600
  enabled: supervisorEnabled && supervisorLineIds.length > 0,
69619
70601
  companyId: resolvedCompanyId,
69620
70602
  useBackend: true
69621
70603
  });
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
70604
  React144.useEffect(() => {
69644
70605
  trackCorePageView("KPIs Overview");
69645
70606
  }, []);
@@ -69689,16 +70650,25 @@ var KPIsOverviewView = ({
69689
70650
  `/api/dashboard/leaderboard-lines?company_id=${encodeURIComponent(resolvedCompanyId)}`
69690
70651
  );
69691
70652
  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
- }));
70653
+ const metadataByLineId = new Map(lines.map((line) => [line.id, line]));
70654
+ const transformed = (data.lines || []).filter((line) => line.enable !== false).map((line) => {
70655
+ const metadata = metadataByLineId.get(line.id);
70656
+ return {
70657
+ id: line.id,
70658
+ line_name: line.line_name,
70659
+ factory_id: line.factory_id || metadata?.factory_id || "",
70660
+ factory_name: metadata?.factory_name || "N/A",
70661
+ company_id: line.company_id,
70662
+ company_name: metadata?.company_name || "",
70663
+ enable: line.enable ?? true,
70664
+ monitoring_mode: line.monitoring_mode ?? metadata?.monitoring_mode ?? "output",
70665
+ factory_area_id: line.factory_area_id ?? metadata?.factory_area_id ?? null,
70666
+ factory_area_key: line.factory_area_key ?? metadata?.factory_area_key ?? null,
70667
+ factory_area_name: line.factory_area_name ?? metadata?.factory_area_name ?? null,
70668
+ factory_area_sort_order: line.factory_area_sort_order ?? metadata?.factory_area_sort_order ?? null,
70669
+ factory_area_enabled: line.factory_area_enabled ?? metadata?.factory_area_enabled ?? null
70670
+ };
70671
+ });
69702
70672
  setLeaderboardLines(transformed);
69703
70673
  } catch (err) {
69704
70674
  console.error("[KPIsOverviewView] Failed to load leaderboard lines:", err);
@@ -69713,6 +70683,58 @@ var KPIsOverviewView = ({
69713
70683
  isMounted = false;
69714
70684
  };
69715
70685
  }, [supabase, resolvedCompanyId, lines]);
70686
+ React144.useEffect(() => {
70687
+ if (activeTab !== "leaderboard" || timeRange !== "today") return;
70688
+ if (!supabase || !resolvedCompanyId || !effectiveLeaderboardDate || leaderboardLinesForView.length === 0) {
70689
+ setScopedDailyFallbackEfficiencyByLineId(/* @__PURE__ */ new Map());
70690
+ return;
70691
+ }
70692
+ const targetLineIds = leaderboardLinesForView.map((line) => line.id);
70693
+ const lineIdsKey = targetLineIds.slice().sort().join(",");
70694
+ const requestKey = `${effectiveLeaderboardDate}|${effectiveLeaderboardShiftId}|${lineIdsKey}`;
70695
+ if (dailyFallbackRequestKeyRef.current === requestKey) return;
70696
+ dailyFallbackRequestKeyRef.current = requestKey;
70697
+ let isMounted = true;
70698
+ const fetchScopedFallbackEfficiencies = async () => {
70699
+ try {
70700
+ const entries = await lineLeaderboardService.getDailyLineLeaderboard(supabase, {
70701
+ companyId: resolvedCompanyId,
70702
+ date: effectiveLeaderboardDate,
70703
+ shiftId: effectiveLeaderboardShiftId,
70704
+ lineIds: targetLineIds,
70705
+ lineMode: viewType === "machine" ? "uptime" : "output",
70706
+ includeBelowThreshold: true
70707
+ });
70708
+ if (!isMounted) return;
70709
+ const nextMap = /* @__PURE__ */ new Map();
70710
+ entries.forEach((entry) => {
70711
+ const value = Number(entry.avg_efficiency);
70712
+ if (Number.isFinite(value)) {
70713
+ nextMap.set(entry.line_id, value);
70714
+ }
70715
+ });
70716
+ setScopedDailyFallbackEfficiencyByLineId(nextMap);
70717
+ } catch (err) {
70718
+ if (!isMounted) return;
70719
+ console.warn("[KPIsOverviewView] Failed to load daily fallback line efficiencies:", err);
70720
+ setScopedDailyFallbackEfficiencyByLineId(/* @__PURE__ */ new Map());
70721
+ dailyFallbackRequestKeyRef.current = null;
70722
+ }
70723
+ };
70724
+ void fetchScopedFallbackEfficiencies();
70725
+ return () => {
70726
+ isMounted = false;
70727
+ };
70728
+ }, [
70729
+ activeTab,
70730
+ effectiveLeaderboardDate,
70731
+ effectiveLeaderboardShiftId,
70732
+ leaderboardLinesForView,
70733
+ resolvedCompanyId,
70734
+ supabase,
70735
+ timeRange,
70736
+ viewType
70737
+ ]);
69716
70738
  const fetchMonthlyLeaderboard = React144.useCallback(async () => {
69717
70739
  if (!supabase || !resolvedCompanyId || leaderboardLinesForView.length === 0) return;
69718
70740
  const targetLineIds = leaderboardLinesForView.map((line) => line.id);
@@ -69734,10 +70756,11 @@ var KPIsOverviewView = ({
69734
70756
  lineMode: viewType === "machine" ? "uptime" : "output"
69735
70757
  });
69736
70758
  const nextMap = /* @__PURE__ */ new Map();
69737
- targetLineIds.forEach((lineId) => nextMap.set(lineId, 0));
69738
70759
  entries.forEach((entry) => {
69739
70760
  const value = Number(entry.avg_efficiency);
69740
- nextMap.set(entry.line_id, Number.isFinite(value) ? value : 0);
70761
+ if (Number.isFinite(value)) {
70762
+ nextMap.set(entry.line_id, value);
70763
+ }
69741
70764
  });
69742
70765
  setMonthlyEfficiencyByLineId(nextMap);
69743
70766
  trackCoreEvent("Leaderboard Monthly Data Fetched", {
@@ -69784,10 +70807,11 @@ var KPIsOverviewView = ({
69784
70807
  lineMode: viewType === "machine" ? "uptime" : "output"
69785
70808
  });
69786
70809
  const nextMap = /* @__PURE__ */ new Map();
69787
- targetLineIds.forEach((lineId) => nextMap.set(lineId, 0));
69788
70810
  entries.forEach((entry) => {
69789
70811
  const value = Number(entry.avg_efficiency);
69790
- nextMap.set(entry.line_id, Number.isFinite(value) ? value : 0);
70812
+ if (Number.isFinite(value)) {
70813
+ nextMap.set(entry.line_id, value);
70814
+ }
69791
70815
  });
69792
70816
  setTodayEfficiencyByLineId(nextMap);
69793
70817
  } catch (err) {
@@ -69827,69 +70851,6 @@ var KPIsOverviewView = ({
69827
70851
  factoryAreaId: selectedFactoryAreaNode?.id
69828
70852
  });
69829
70853
  }, [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
70854
  const handleLineClick = (line, kpis) => {
69894
70855
  if (!isSuperAdmin && !assignedLineIdSet.has(line.id)) {
69895
70856
  return;
@@ -69937,6 +70898,7 @@ var KPIsOverviewView = ({
69937
70898
  from_page: "kpis_overview",
69938
70899
  lines_count: trackedLineCount
69939
70900
  });
70901
+ pendingTabRouteSyncRef.current = newTab;
69940
70902
  setActiveTab(newTab);
69941
70903
  }, [activeTab, leaderboardLines.length, lines.length]);
69942
70904
  const formatLocalDate2 = React144.useCallback((dateKey) => {
@@ -69961,10 +70923,8 @@ var KPIsOverviewView = ({
69961
70923
  const isMonthlyMode = activeTab === "leaderboard" && timeRange === "monthly";
69962
70924
  const isLeaderboardLoading = timeRange === "today" ? dailyLoading : monthlyLoading;
69963
70925
  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)}%` : "--";
70926
+ const currentFallbackEfficiencyMap = timeRange === "today" ? dailyFallbackEfficiencyByLineId : void 0;
70927
+ const showLeaderboardLoader = activeTab === "leaderboard" && (leaderboardLinesLoading || isLeaderboardLoading && currentEfficiencyMap.size === 0 && (currentFallbackEfficiencyMap?.size ?? 0) === 0);
69968
70928
  const showHistoricalLeaderboardHeader = activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily;
69969
70929
  const headerDateKey = activeTab === "leaderboard" && timeRange === "today" ? effectiveLeaderboardDate : monthEndDateKey;
69970
70930
  const headerShiftId = showHistoricalLeaderboardHeader ? effectiveLeaderboardShiftId : currentShiftDetails.shiftId;
@@ -70169,72 +71129,6 @@ var KPIsOverviewView = ({
70169
71129
  ] }) : /* @__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
71130
  ] })
70171
71131
  ] }),
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
71132
  /* @__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
71133
  /* @__PURE__ */ jsxRuntime.jsx(
70240
71134
  "button",
@@ -70269,86 +71163,18 @@ var KPIsOverviewView = ({
70269
71163
  /* @__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
71164
  !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
71165
  ] }),
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
- ] })
71166
+ /* @__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(
71167
+ "button",
71168
+ {
71169
+ type: "button",
71170
+ onClick: () => {
71171
+ setSelectedLeaderboardDate(currentShiftDate);
71172
+ setSelectedLeaderboardShiftId(currentShiftId);
71173
+ },
71174
+ 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",
71175
+ children: "Return to Live"
71176
+ }
71177
+ ) })
70352
71178
  ] }),
70353
71179
  /* @__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
71180
  !isMonthlyMode && !showHistoricalLeaderboardHeader && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -70523,6 +71349,7 @@ var KPIsOverviewView = ({
70523
71349
  timeRange,
70524
71350
  setTimeRange,
70525
71351
  todayEfficiencyByLineId,
71352
+ dailyFallbackEfficiencyByLineId,
70526
71353
  monthlyEfficiencyByLineId,
70527
71354
  supervisorsByLineId,
70528
71355
  supervisorNamesByLineId,
@@ -70555,13 +71382,23 @@ var AnimatedEfficiency = React144.memo(({ value }) => {
70555
71382
  AnimatedEfficiency.displayName = "AnimatedEfficiency";
70556
71383
  var getWorkspaceLeaderboardMetricValue = (workspace) => {
70557
71384
  if (workspace.leaderboard_metric_kind === "recent_flow_shift_average") {
70558
- return toFiniteNumber(workspace.leaderboard_value) ?? toFiniteNumber(workspace.avg_recent_flow);
71385
+ const cycleRatio = getCycleRatio(workspace);
71386
+ return cycleRatio === null ? null : cycleRatio * 100;
70559
71387
  }
70560
71388
  return toFiniteNumber(workspace.leaderboard_value) ?? toFiniteNumber(workspace.efficiency);
70561
71389
  };
70562
71390
  var getWorkspaceDisplayedMetricValue = (workspace) => getWorkspaceLeaderboardMetricValue(workspace);
70563
- var getWorkspaceLeaderboardMetricLabel = (workspace, defaultLabel) => workspace.leaderboard_metric_kind === "recent_flow_shift_average" ? "Avg Flow" : defaultLabel;
71391
+ var getWorkspaceLeaderboardMetricLabel = (workspace, defaultLabel) => workspace.leaderboard_metric_kind === "recent_flow_shift_average" ? "Actual CT / Standard CT" : defaultLabel;
70564
71392
  var renderWorkspaceLeaderboardMetric = (workspace) => {
71393
+ if (workspace.leaderboard_metric_kind === "recent_flow_shift_average") {
71394
+ const actualCT = formatCycleTimeValue(workspace.avg_cycle_time);
71395
+ const standardCT = formatCycleTimeValue(workspace.ideal_cycle_time);
71396
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "tabular-nums", children: [
71397
+ actualCT,
71398
+ " / ",
71399
+ standardCT
71400
+ ] });
71401
+ }
70565
71402
  const displayedMetricValue = getWorkspaceDisplayedMetricValue(workspace);
70566
71403
  if (displayedMetricValue === null) {
70567
71404
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: "--" });
@@ -70839,12 +71676,8 @@ var LeaderboardDetailView = React144.memo(({
70839
71676
  return `Line ${lineId2.substring(0, 8)}`;
70840
71677
  }, [dbLineNames, configuredLineNames, lineNames, line1Id, line2Id]);
70841
71678
  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]);
71679
+ return getConfiguredLineIds(entityConfig);
71680
+ }, [entityConfig]);
70848
71681
  const accessibleLineIdSet = React144.useMemo(
70849
71682
  () => new Set((userAccessibleLineIds || []).filter(Boolean)),
70850
71683
  [userAccessibleLineIds]
@@ -71532,7 +72365,7 @@ var LeaderboardDetailView = React144.memo(({
71532
72365
  const hasEfficiencyLeaderboardRows = sortedWorkspaces.some(
71533
72366
  (workspace) => workspace.leaderboard_metric_kind !== "recent_flow_shift_average"
71534
72367
  );
71535
- const metricLabel = viewType === "machine" ? "Utilization" : hasRecentFlowLeaderboardRows && !hasEfficiencyLeaderboardRows ? "Avg Flow" : hasRecentFlowLeaderboardRows && hasEfficiencyLeaderboardRows ? "Performance" : "Efficiency";
72368
+ const metricLabel = viewType === "machine" ? "Utilization" : hasRecentFlowLeaderboardRows && !hasEfficiencyLeaderboardRows ? "Actual CT / Standard CT" : hasRecentFlowLeaderboardRows && hasEfficiencyLeaderboardRows ? "Performance" : "Efficiency";
71536
72369
  const descendingSortLabel = "Highest to Lowest";
71537
72370
  const ascendingSortLabel = "Lowest to Highest";
71538
72371
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen bg-slate-50 flex flex-col ${className}`, style: { willChange: "contents" }, children: [
@@ -86453,6 +87286,7 @@ exports.awardsService = awardsService;
86453
87286
  exports.buildDateKey = buildDateKey;
86454
87287
  exports.buildKPIsFromLineMetricsRow = buildKPIsFromLineMetricsRow;
86455
87288
  exports.buildKpiLineHierarchy = buildKpiLineHierarchy;
87289
+ exports.buildLineLeaderboardRows = buildLineLeaderboardRows;
86456
87290
  exports.buildLineSkuBreakdown = buildLineSkuBreakdown;
86457
87291
  exports.buildShiftGroupsKey = buildShiftGroupsKey;
86458
87292
  exports.canRoleAccessDashboardPath = canRoleAccessDashboardPath;