@optifye/dashboard-core 6.11.15 → 6.11.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -12,7 +12,7 @@ import Hls, { Events, ErrorTypes } from 'hls.js';
12
12
  import useSWR from 'swr';
13
13
  import { Camera, AlertTriangle, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, Filter, X, Coffee, Plus, ArrowUp, ArrowDown, ArrowRight, ArrowLeft, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ChevronLeft, ChevronRight, TrendingUp, Sparkles, Pause, Play, XCircle, HelpCircle, Activity, Wrench, UserX, Package, RefreshCw, Palette, CheckCircle2, TrendingDown, FolderOpen, Folder, Tag, Sliders, Layers, Search, Edit2, CheckCircle, User, Users, Shield, Building2, Mail, Lock, Info, Share2, Trophy, Target, Download, Sun, Moon, MousePointer, UserPlus, UserCog, Trash2, Eye, MoreVertical, BarChart3, Pencil, UserCheck, LogOut, Film, MessageSquare, Menu, Send, Copy, Settings, LifeBuoy, EyeOff, Zap, Flame, Crown, Medal } from 'lucide-react';
14
14
  import { memo, noop, warning, invariant, progress, secondsToMilliseconds, millisecondsToSeconds } from 'motion-utils';
15
- import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, ReferenceLine, Tooltip, Legend, Bar, LabelList, ResponsiveContainer, LineChart as LineChart$1, Line, PieChart, Pie, Cell, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
15
+ import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, ReferenceLine, Tooltip, Legend, Bar, LabelList, ResponsiveContainer, PieChart, Pie, Cell, LineChart as LineChart$1, Line, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
16
16
  import { Slot } from '@radix-ui/react-slot';
17
17
  import * as SelectPrimitive from '@radix-ui/react-select';
18
18
  import { DayPicker, useNavigation as useNavigation$1 } from 'react-day-picker';
@@ -3266,11 +3266,9 @@ var normalizeShiftDefinitions = (timezone, shiftConfig) => {
3266
3266
  }
3267
3267
  return { shifts: legacyShifts, timezone: fallbackTimezone };
3268
3268
  };
3269
- var determineShiftFromDefinitions = (timezone, shifts, now4 = /* @__PURE__ */ new Date()) => {
3269
+ var determineActiveShiftFromDefinitions = (timezone, shifts, now4 = /* @__PURE__ */ new Date()) => {
3270
3270
  const zonedNow = toZonedTime(now4, timezone);
3271
3271
  const currentMinutes = zonedNow.getHours() * 60 + zonedNow.getMinutes();
3272
- let chosen;
3273
- let operationalDate = getOperationalDate(timezone, now4, shifts[0].startTime);
3274
3272
  for (const shift of shifts) {
3275
3273
  const start = parseTimeToMinutes(shift.startTime);
3276
3274
  const endRaw = parseTimeToMinutes(shift.endTime);
@@ -3278,32 +3276,47 @@ var determineShiftFromDefinitions = (timezone, shifts, now4 = /* @__PURE__ */ ne
3278
3276
  const wraps = end <= start;
3279
3277
  if (wraps) end += 1440;
3280
3278
  if (start <= currentMinutes && currentMinutes < end) {
3281
- chosen = shift;
3282
- operationalDate = getOperationalDate(timezone, now4, shift.startTime);
3283
- break;
3279
+ return {
3280
+ shiftId: shift.shiftId,
3281
+ shiftName: shift.shiftName,
3282
+ startTime: shift.startTime,
3283
+ endTime: shift.endTime,
3284
+ timezone,
3285
+ date: getOperationalDate(timezone, now4, shift.startTime)
3286
+ };
3284
3287
  }
3285
3288
  if (start <= currentMinutes + 1440 && currentMinutes + 1440 < end) {
3286
- chosen = shift;
3287
- operationalDate = getOperationalDate(timezone, now4, shift.startTime);
3288
- break;
3289
+ return {
3290
+ shiftId: shift.shiftId,
3291
+ shiftName: shift.shiftName,
3292
+ startTime: shift.startTime,
3293
+ endTime: shift.endTime,
3294
+ timezone,
3295
+ date: getOperationalDate(timezone, now4, shift.startTime)
3296
+ };
3289
3297
  }
3290
3298
  }
3291
- if (!chosen) {
3292
- chosen = shifts[0];
3293
- operationalDate = getOperationalDate(timezone, now4, chosen.startTime);
3299
+ return null;
3300
+ };
3301
+ var getCurrentShift = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
3302
+ const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
3303
+ const activeShift = determineActiveShiftFromDefinitions(effectiveTz, shifts, now4);
3304
+ if (activeShift) {
3305
+ return activeShift;
3294
3306
  }
3307
+ const fallbackShift = shifts[0];
3295
3308
  return {
3296
- shiftId: chosen.shiftId,
3297
- shiftName: chosen.shiftName,
3298
- startTime: chosen.startTime,
3299
- endTime: chosen.endTime,
3300
- timezone,
3301
- date: operationalDate
3309
+ shiftId: fallbackShift.shiftId,
3310
+ shiftName: fallbackShift.shiftName,
3311
+ startTime: fallbackShift.startTime,
3312
+ endTime: fallbackShift.endTime,
3313
+ timezone: effectiveTz,
3314
+ date: getOperationalDate(effectiveTz, now4, fallbackShift.startTime)
3302
3315
  };
3303
3316
  };
3304
- var getCurrentShift = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
3317
+ var getActiveShift = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
3305
3318
  const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
3306
- return determineShiftFromDefinitions(effectiveTz, shifts, now4);
3319
+ return determineActiveShiftFromDefinitions(effectiveTz, shifts, now4);
3307
3320
  };
3308
3321
  var isTransitionPeriod = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
3309
3322
  const transitionMinutes = shiftConfig?.transitionPeriodMinutes ?? DEFAULT_TRANSITION_MINUTES;
@@ -12835,6 +12848,7 @@ var useShiftGroups = ({
12835
12848
  }) => {
12836
12849
  const [shiftGroups, setShiftGroups] = useState([]);
12837
12850
  const [shiftGroupsKey, setShiftGroupsKey] = useState("");
12851
+ const [hasComputed, setHasComputed] = useState(false);
12838
12852
  const lastKeyRef = useRef("");
12839
12853
  const mapRef = useRef(shiftConfigMap);
12840
12854
  useEffect(() => {
@@ -12845,6 +12859,7 @@ var useShiftGroups = ({
12845
12859
  lastKeyRef.current = "";
12846
12860
  setShiftGroups([]);
12847
12861
  setShiftGroupsKey("");
12862
+ setHasComputed(false);
12848
12863
  return;
12849
12864
  }
12850
12865
  let isMounted = true;
@@ -12857,6 +12872,7 @@ var useShiftGroups = ({
12857
12872
  setShiftGroups(groups);
12858
12873
  setShiftGroupsKey(key);
12859
12874
  }
12875
+ setHasComputed(true);
12860
12876
  };
12861
12877
  compute();
12862
12878
  const intervalId = setInterval(compute, pollIntervalMs);
@@ -12865,7 +12881,7 @@ var useShiftGroups = ({
12865
12881
  clearInterval(intervalId);
12866
12882
  };
12867
12883
  }, [enabled, shiftConfigMap.size, timezone, pollIntervalMs]);
12868
- return { shiftGroups, shiftGroupsKey };
12884
+ return { shiftGroups, shiftGroupsKey, hasComputed };
12869
12885
  };
12870
12886
 
12871
12887
  // src/lib/types/efficiencyLegend.ts
@@ -12927,52 +12943,6 @@ function getEfficiencyTextColorClasses(efficiency, legend = DEFAULT_EFFICIENCY_L
12927
12943
  }
12928
12944
  }
12929
12945
 
12930
- // src/lib/hooks/useDashboardMetrics.recentFlow.ts
12931
- var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
12932
- var getWorkspaceRecentFlowCacheKey = (workspace) => {
12933
- const workspaceKey = workspace.workspace_uuid || workspace.workspace_name || "unknown";
12934
- return `${workspaceKey}|${workspace.date}|${workspace.shift_id}`;
12935
- };
12936
- var toRecentFlowSnapshot = (workspace) => {
12937
- if (!isFiniteNumber(workspace.recent_flow_percent)) {
12938
- return null;
12939
- }
12940
- return {
12941
- recent_flow_percent: workspace.recent_flow_percent,
12942
- recent_flow_actual_rate_pph: workspace.recent_flow_actual_rate_pph ?? null,
12943
- recent_flow_healthy_rate_pph: workspace.recent_flow_healthy_rate_pph ?? null,
12944
- recent_flow_window_minutes: workspace.recent_flow_window_minutes ?? null,
12945
- recent_flow_effective_end_at: workspace.recent_flow_effective_end_at ?? null
12946
- };
12947
- };
12948
- var mergeWorkspaceRecentFlowMetrics = (workspaces, previousCache) => {
12949
- const nextCache = /* @__PURE__ */ new Map();
12950
- const mergedWorkspaces = workspaces.map((workspace) => {
12951
- const cacheKey = getWorkspaceRecentFlowCacheKey(workspace);
12952
- const currentSnapshot = toRecentFlowSnapshot(workspace);
12953
- if (workspace.recent_flow_mode === "computed" && currentSnapshot) {
12954
- nextCache.set(cacheKey, currentSnapshot);
12955
- return workspace;
12956
- }
12957
- if (workspace.recent_flow_mode === "hold") {
12958
- const cachedSnapshot = previousCache.get(cacheKey);
12959
- if (cachedSnapshot) {
12960
- nextCache.set(cacheKey, cachedSnapshot);
12961
- return {
12962
- ...workspace,
12963
- ...cachedSnapshot,
12964
- recent_flow_mode: "hold"
12965
- };
12966
- }
12967
- }
12968
- return workspace;
12969
- });
12970
- return {
12971
- workspaces: mergedWorkspaces,
12972
- cache: nextCache
12973
- };
12974
- };
12975
-
12976
12946
  // src/lib/hooks/useDashboardMetrics.ts
12977
12947
  var DEBUG_DASHBOARD_LOGS = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
12978
12948
  var logDebug = (...args) => {
@@ -13061,7 +13031,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13061
13031
  const abortControllerRef = useRef(null);
13062
13032
  const lastFetchKeyRef = useRef(null);
13063
13033
  const inFlightFetchKeyRef = useRef(null);
13064
- const recentFlowCacheRef = useRef(/* @__PURE__ */ new Map());
13065
13034
  const updateQueueRef = useRef(false);
13066
13035
  const onLineMetricsUpdateRef = useRef(onLineMetricsUpdate);
13067
13036
  const shiftGroupsRef = useRef(shiftGroups);
@@ -13095,7 +13064,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13095
13064
  setError(null);
13096
13065
  lastFetchKeyRef.current = null;
13097
13066
  inFlightFetchKeyRef.current = null;
13098
- recentFlowCacheRef.current = /* @__PURE__ */ new Map();
13099
13067
  }, [lineId]);
13100
13068
  const fetchAllMetrics = useCallback(async (options = {}) => {
13101
13069
  const { force = false } = options;
@@ -13370,12 +13338,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13370
13338
  actionType: item.action_type,
13371
13339
  actionName: item.action_name
13372
13340
  }),
13373
- recent_flow_mode: item.recent_flow_mode ?? void 0,
13374
13341
  recent_flow_percent: item.recent_flow_percent ?? null,
13375
- recent_flow_actual_rate_pph: item.recent_flow_actual_rate_pph ?? null,
13376
- recent_flow_healthy_rate_pph: item.recent_flow_healthy_rate_pph ?? null,
13377
- recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
13378
13342
  recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
13343
+ recent_flow_computed_at: item.recent_flow_computed_at ?? null,
13379
13344
  incoming_wip_current: item.incoming_wip_current ?? null,
13380
13345
  incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
13381
13346
  incoming_wip_buffer_name: item.incoming_wip_buffer_name ?? null
@@ -13386,16 +13351,11 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13386
13351
  const wsNumB = parseInt(b.workspace_name?.replace(/[^0-9]/g, "") || "0");
13387
13352
  return wsNumA - wsNumB;
13388
13353
  });
13389
- const {
13390
- workspaces: mergedWorkspaceData,
13391
- cache: nextRecentFlowCache
13392
- } = mergeWorkspaceRecentFlowMetrics(transformedWorkspaceData, recentFlowCacheRef.current);
13393
- recentFlowCacheRef.current = nextRecentFlowCache;
13394
- mergedWorkspaceData.forEach((metric) => {
13354
+ transformedWorkspaceData.forEach((metric) => {
13395
13355
  workspaceMetricsStore.setOverview(metric);
13396
13356
  });
13397
13357
  const newMetricsState = {
13398
- workspaceMetrics: mergedWorkspaceData,
13358
+ workspaceMetrics: transformedWorkspaceData,
13399
13359
  lineMetrics: allLineMetrics || [],
13400
13360
  metadata: { hasFlowBuffers, idleTimeVlmByLine },
13401
13361
  efficiencyLegend: efficiencyLegend ?? DEFAULT_EFFICIENCY_LEGEND
@@ -16820,7 +16780,7 @@ var useActiveBreaks = (lineIds) => {
16820
16780
  const [isLoading, setIsLoading] = useState(true);
16821
16781
  const [error, setError] = useState(null);
16822
16782
  const supabase = useSupabase();
16823
- const parseTimeToMinutes3 = (timeStr) => {
16783
+ const parseTimeToMinutes4 = (timeStr) => {
16824
16784
  const [hours, minutes] = timeStr.split(":").map(Number);
16825
16785
  return hours * 60 + minutes;
16826
16786
  };
@@ -16829,8 +16789,8 @@ var useActiveBreaks = (lineIds) => {
16829
16789
  return now4.getHours() * 60 + now4.getMinutes();
16830
16790
  };
16831
16791
  const isTimeInBreak = (breakStart, breakEnd, currentMinutes) => {
16832
- const startMinutes = parseTimeToMinutes3(breakStart);
16833
- const endMinutes = parseTimeToMinutes3(breakEnd);
16792
+ const startMinutes = parseTimeToMinutes4(breakStart);
16793
+ const endMinutes = parseTimeToMinutes4(breakEnd);
16834
16794
  if (endMinutes < startMinutes) {
16835
16795
  return currentMinutes >= startMinutes || currentMinutes < endMinutes;
16836
16796
  } else {
@@ -16838,8 +16798,8 @@ var useActiveBreaks = (lineIds) => {
16838
16798
  }
16839
16799
  };
16840
16800
  const calculateBreakProgress = (breakStart, breakEnd, currentMinutes) => {
16841
- const startMinutes = parseTimeToMinutes3(breakStart);
16842
- const endMinutes = parseTimeToMinutes3(breakEnd);
16801
+ const startMinutes = parseTimeToMinutes4(breakStart);
16802
+ const endMinutes = parseTimeToMinutes4(breakEnd);
16843
16803
  let elapsedMinutes = 0;
16844
16804
  let remainingMinutes = 0;
16845
16805
  if (endMinutes < startMinutes) {
@@ -16857,8 +16817,8 @@ var useActiveBreaks = (lineIds) => {
16857
16817
  return { elapsedMinutes, remainingMinutes };
16858
16818
  };
16859
16819
  const isTimeInShift = (startTime, endTime, currentMinutes) => {
16860
- const startMinutes = parseTimeToMinutes3(startTime);
16861
- const endMinutes = parseTimeToMinutes3(endTime);
16820
+ const startMinutes = parseTimeToMinutes4(startTime);
16821
+ const endMinutes = parseTimeToMinutes4(endTime);
16862
16822
  if (endMinutes < startMinutes) {
16863
16823
  return currentMinutes >= startMinutes || currentMinutes < endMinutes;
16864
16824
  } else {
@@ -16918,8 +16878,8 @@ var useActiveBreaks = (lineIds) => {
16918
16878
  const endTime = breakItem.end || breakItem.endTime || "00:00";
16919
16879
  let duration = breakItem.duration || 0;
16920
16880
  if (!duration || duration === 0) {
16921
- const startMinutes = parseTimeToMinutes3(startTime);
16922
- const endMinutes = parseTimeToMinutes3(endTime);
16881
+ const startMinutes = parseTimeToMinutes4(startTime);
16882
+ const endMinutes = parseTimeToMinutes4(endTime);
16923
16883
  duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
16924
16884
  }
16925
16885
  return {
@@ -16935,8 +16895,8 @@ var useActiveBreaks = (lineIds) => {
16935
16895
  const endTime = breakItem.end || breakItem.endTime || "00:00";
16936
16896
  let duration = breakItem.duration || 0;
16937
16897
  if (!duration || duration === 0) {
16938
- const startMinutes = parseTimeToMinutes3(startTime);
16939
- const endMinutes = parseTimeToMinutes3(endTime);
16898
+ const startMinutes = parseTimeToMinutes4(startTime);
16899
+ const endMinutes = parseTimeToMinutes4(endTime);
16940
16900
  duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
16941
16901
  }
16942
16902
  return {
@@ -23017,6 +22977,16 @@ var createThrottledReload = (interval = 5e3, maxReloads = 3) => {
23017
22977
  };
23018
22978
  var throttledReloadDashboard = createThrottledReload(5e3, 3);
23019
22979
 
22980
+ // src/lib/utils/dev/localDevTestLogin.ts
22981
+ var isLoopbackHostname = (hostname) => {
22982
+ const normalized = String(hostname || "").trim().toLowerCase();
22983
+ return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1";
22984
+ };
22985
+ var shouldEnableLocalDevTestLogin = ({
22986
+ enabledFlag,
22987
+ hostname
22988
+ }) => enabledFlag && isLoopbackHostname(hostname);
22989
+
23020
22990
  // src/lib/utils/index.ts
23021
22991
  var formatIdleTime = (idleTimeInSeconds) => {
23022
22992
  if (!idleTimeInSeconds || idleTimeInSeconds <= 0) {
@@ -31201,12 +31171,16 @@ var LoginPage = ({
31201
31171
  onRateLimitCheck,
31202
31172
  logoSrc = optifye_logo_default,
31203
31173
  logoAlt = "Optifye",
31204
- brandName = "Optifye"
31174
+ brandName = "Optifye",
31175
+ showDevTestLogin = false,
31176
+ devTestLoginLabel = "Sign in as Test User",
31177
+ onDevTestLogin
31205
31178
  }) => {
31206
31179
  const [email, setEmail] = useState("");
31207
31180
  const [otp, setOtp] = useState("");
31208
31181
  const [step, setStep] = useState("email");
31209
31182
  const [loading, setLoading] = useState(false);
31183
+ const [devLoginLoading, setDevLoginLoading] = useState(false);
31210
31184
  const [error, setError] = useState(null);
31211
31185
  const [countdown, setCountdown] = useState(0);
31212
31186
  const supabase = useSupabase();
@@ -31270,6 +31244,25 @@ var LoginPage = ({
31270
31244
  startCountdown();
31271
31245
  }
31272
31246
  };
31247
+ const handleDevTestLogin = async () => {
31248
+ if (!onDevTestLogin) {
31249
+ return;
31250
+ }
31251
+ setDevLoginLoading(true);
31252
+ setError(null);
31253
+ try {
31254
+ const result = await onDevTestLogin();
31255
+ const nextError = typeof result === "object" && result !== null && "error" in result ? result.error : null;
31256
+ if (typeof nextError === "string" && nextError.trim()) {
31257
+ setError(nextError);
31258
+ }
31259
+ } catch (err) {
31260
+ console.error("Dev test login failed:", err);
31261
+ setError("Dev test login unavailable.");
31262
+ } finally {
31263
+ setDevLoginLoading(false);
31264
+ }
31265
+ };
31273
31266
  return /* @__PURE__ */ jsx("div", { className: "min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100", children: /* @__PURE__ */ jsxs("div", { className: "max-w-md w-full mx-4", children: [
31274
31267
  /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-2xl shadow-xl border border-slate-200 p-8", children: [
31275
31268
  /* @__PURE__ */ jsxs("div", { className: "text-center mb-8", children: [
@@ -31310,7 +31303,7 @@ var LoginPage = ({
31310
31303
  "button",
31311
31304
  {
31312
31305
  type: "submit",
31313
- disabled: loading,
31306
+ disabled: loading || devLoginLoading,
31314
31307
  className: "w-full py-3 px-4 bg-slate-900 hover:bg-slate-800 focus:ring-2 focus:ring-slate-600 focus:ring-offset-2 text-white font-medium rounded-xl transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
31315
31308
  children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
31316
31309
  /* @__PURE__ */ jsxs("svg", { className: "animate-spin -ml-1 mr-3 h-4 w-4 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
@@ -31320,7 +31313,31 @@ var LoginPage = ({
31320
31313
  "Sending..."
31321
31314
  ] }) : "Continue with Email"
31322
31315
  }
31323
- )
31316
+ ),
31317
+ showDevTestLogin && onDevTestLogin ? /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
31318
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
31319
+ /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-slate-200" }),
31320
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium uppercase tracking-[0.2em] text-slate-400", children: "Local Dev" }),
31321
+ /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-slate-200" })
31322
+ ] }),
31323
+ /* @__PURE__ */ jsx(
31324
+ "button",
31325
+ {
31326
+ type: "button",
31327
+ disabled: loading || devLoginLoading,
31328
+ onClick: () => void handleDevTestLogin(),
31329
+ className: "w-full py-3 px-4 bg-white hover:bg-slate-50 focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 text-slate-700 font-medium rounded-xl border border-slate-200 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
31330
+ children: devLoginLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
31331
+ /* @__PURE__ */ jsxs("svg", { className: "animate-spin -ml-1 mr-3 h-4 w-4 text-slate-700", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
31332
+ /* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
31333
+ /* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
31334
+ ] }),
31335
+ "Signing In..."
31336
+ ] }) : devTestLoginLabel
31337
+ }
31338
+ ),
31339
+ /* @__PURE__ */ jsx("p", { className: "text-center text-xs text-slate-500", children: "Localhost-only convenience login for the shared test account." })
31340
+ ] }) : null
31324
31341
  ] }) : /* @__PURE__ */ jsxs("form", { className: "space-y-6", onSubmit: handleVerifyOTP, children: [
31325
31342
  /* @__PURE__ */ jsxs("div", { children: [
31326
31343
  /* @__PURE__ */ jsx("label", { htmlFor: "otp", className: "block text-sm font-medium text-slate-700 mb-2 text-center", children: "Enter the 6-digit code sent to" }),
@@ -31345,7 +31362,7 @@ var LoginPage = ({
31345
31362
  "button",
31346
31363
  {
31347
31364
  type: "submit",
31348
- disabled: loading || otp.length !== 6,
31365
+ disabled: loading || devLoginLoading || otp.length !== 6,
31349
31366
  className: "w-full py-3 px-4 bg-slate-900 hover:bg-slate-800 focus:ring-2 focus:ring-slate-600 focus:ring-offset-2 text-white font-medium rounded-xl transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
31350
31367
  children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
31351
31368
  /* @__PURE__ */ jsxs("svg", { className: "animate-spin -ml-1 mr-3 h-4 w-4 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
@@ -32170,6 +32187,7 @@ var LineChartComponent = ({
32170
32187
  xAxisLabel,
32171
32188
  xAxisTickFormatter,
32172
32189
  // Pass through for X-axis tick formatting
32190
+ xAxisInterval,
32173
32191
  yAxisLabel,
32174
32192
  yAxisUnit,
32175
32193
  yAxisDomain,
@@ -32186,31 +32204,35 @@ var LineChartComponent = ({
32186
32204
  ...restOfChartProps
32187
32205
  }) => {
32188
32206
  const containerRef = React141__default.useRef(null);
32189
- const [containerReady, setContainerReady] = React141__default.useState(false);
32190
- const themeConfig = useThemeConfig();
32191
- const { formatNumber } = useFormatNumber();
32207
+ const [dimensions, setDimensions] = React141__default.useState({ width: 0, height: 0 });
32208
+ const [hasValidData, setHasValidData] = React141__default.useState(false);
32192
32209
  React141__default.useEffect(() => {
32193
- const checkContainerDimensions = () => {
32194
- if (containerRef.current) {
32195
- const rect = containerRef.current.getBoundingClientRect();
32196
- if (rect.width > 0 && rect.height > 0) {
32197
- setContainerReady(true);
32198
- }
32199
- }
32200
- };
32201
- checkContainerDimensions();
32202
- const resizeObserver = new ResizeObserver(checkContainerDimensions);
32203
- if (containerRef.current) {
32204
- resizeObserver.observe(containerRef.current);
32210
+ const currentHasValidData = data && lines && lines.length > 0 && data.some(
32211
+ (item) => lines.some((line) => {
32212
+ const val = item[line.dataKey];
32213
+ return typeof val === "number" && val > 0;
32214
+ })
32215
+ );
32216
+ if (currentHasValidData && !hasValidData) {
32217
+ setHasValidData(true);
32205
32218
  }
32206
- const fallbackTimeout = setTimeout(() => {
32207
- setContainerReady(true);
32208
- }, 100);
32209
- return () => {
32210
- resizeObserver.disconnect();
32211
- clearTimeout(fallbackTimeout);
32212
- };
32219
+ }, [data, lines, hasValidData]);
32220
+ React141__default.useEffect(() => {
32221
+ if (!containerRef.current) return;
32222
+ const observer = new ResizeObserver((entries) => {
32223
+ const entry = entries[0];
32224
+ if (entry) {
32225
+ setDimensions({
32226
+ width: entry.contentRect.width,
32227
+ height: entry.contentRect.height
32228
+ });
32229
+ }
32230
+ });
32231
+ observer.observe(containerRef.current);
32232
+ return () => observer.disconnect();
32213
32233
  }, []);
32234
+ const themeConfig = useThemeConfig();
32235
+ const { formatNumber } = useFormatNumber();
32214
32236
  const yAxisTickFormatter = (value) => {
32215
32237
  return `${formatNumber(value)}${yAxisUnit || ""}`;
32216
32238
  };
@@ -32232,57 +32254,72 @@ var LineChartComponent = ({
32232
32254
  const gridStrokeColor = themeConfig?.gray?.["300"] || "#ccc";
32233
32255
  const axisTickFillColor = themeConfig?.gray?.["600"] || "#666";
32234
32256
  const axisStrokeColor = themeConfig?.gray?.["400"] || "#999";
32235
- const chartContent = /* @__PURE__ */ jsxs(LineChart$1, { data, margin: { top: 5, right: 30, left: 20, bottom: 20 }, ...restOfChartProps, children: [
32236
- showGrid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: gridStrokeColor }),
32237
- /* @__PURE__ */ jsx(
32238
- XAxis,
32239
- {
32240
- dataKey: xAxisDataKey,
32241
- label: xAxisLabel ? { value: xAxisLabel, position: "insideBottom", offset: -10 } : void 0,
32242
- tickFormatter: xAxisTickFormatter,
32243
- tick: { fontSize: 12, fill: axisTickFillColor },
32244
- stroke: axisStrokeColor
32245
- }
32246
- ),
32247
- /* @__PURE__ */ jsx(
32248
- YAxis,
32249
- {
32250
- label: yAxisLabel ? { value: yAxisLabel, angle: -90, position: "insideLeft" } : void 0,
32251
- tickFormatter: yAxisTickFormatter,
32252
- domain: yAxisDomain,
32253
- tick: { fontSize: 12, fill: axisTickFillColor },
32254
- stroke: axisStrokeColor
32255
- }
32256
- ),
32257
- showTooltip && /* @__PURE__ */ jsx(
32258
- Tooltip,
32259
- {
32260
- formatter: tooltipFormatter || defaultTooltipFormatter,
32261
- labelFormatter: tooltipLabelFormatter,
32262
- itemStyle: { color: "#111827" },
32263
- cursor: { strokeDasharray: "3 3" }
32264
- }
32265
- ),
32266
- showLegend && /* @__PURE__ */ jsx(Legend, { payload: legendPayload }),
32267
- lines.map((lineConfig, index) => {
32268
- const lineProps = {
32269
- ...lineConfig,
32270
- key: lineConfig.dataKey,
32271
- type: lineConfig.type || "monotone",
32272
- stroke: lineConfig.stroke || defaultColors[index % defaultColors.length],
32273
- activeDot: lineConfig.activeDot !== void 0 ? lineConfig.activeDot : { r: 6 }
32274
- };
32275
- return /* @__PURE__ */ jsx(Line, { ...lineProps, children: lineConfig.labelList && /* @__PURE__ */ jsx(
32276
- LabelList,
32277
- {
32278
- dataKey: lineConfig.dataKey,
32279
- position: "top",
32280
- formatter: (value) => formatNumber(value),
32281
- ...typeof lineConfig.labelList === "object" ? lineConfig.labelList : {}
32282
- }
32283
- ) });
32284
- })
32285
- ] });
32257
+ const renderChartContent = (chartWidth, chartHeight) => /* @__PURE__ */ jsxs(
32258
+ LineChart$1,
32259
+ {
32260
+ width: chartWidth,
32261
+ height: chartHeight,
32262
+ data,
32263
+ margin: { top: 5, right: 30, left: 20, bottom: 20 },
32264
+ ...restOfChartProps,
32265
+ children: [
32266
+ showGrid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: gridStrokeColor }),
32267
+ /* @__PURE__ */ jsx(
32268
+ XAxis,
32269
+ {
32270
+ dataKey: xAxisDataKey,
32271
+ label: xAxisLabel ? { value: xAxisLabel, position: "insideBottom", offset: -10 } : void 0,
32272
+ tickFormatter: xAxisTickFormatter,
32273
+ interval: xAxisInterval,
32274
+ tick: { fontSize: 12, fill: axisTickFillColor },
32275
+ stroke: axisStrokeColor
32276
+ }
32277
+ ),
32278
+ /* @__PURE__ */ jsx(
32279
+ YAxis,
32280
+ {
32281
+ label: yAxisLabel ? { value: yAxisLabel, angle: -90, position: "insideLeft" } : void 0,
32282
+ tickFormatter: yAxisTickFormatter,
32283
+ domain: yAxisDomain,
32284
+ tick: { fontSize: 12, fill: axisTickFillColor },
32285
+ stroke: axisStrokeColor
32286
+ }
32287
+ ),
32288
+ showTooltip && /* @__PURE__ */ jsx(
32289
+ Tooltip,
32290
+ {
32291
+ formatter: tooltipFormatter || defaultTooltipFormatter,
32292
+ labelFormatter: tooltipLabelFormatter,
32293
+ itemStyle: { color: "#111827" },
32294
+ cursor: { strokeDasharray: "3 3" }
32295
+ }
32296
+ ),
32297
+ showLegend && /* @__PURE__ */ jsx(Legend, { payload: legendPayload }),
32298
+ lines.map((lineConfig, index) => {
32299
+ const lineProps = {
32300
+ ...lineConfig,
32301
+ key: lineConfig.dataKey,
32302
+ type: lineConfig.type || "monotone",
32303
+ stroke: lineConfig.stroke || defaultColors[index % defaultColors.length],
32304
+ activeDot: lineConfig.activeDot !== void 0 ? lineConfig.activeDot : { r: 6 },
32305
+ isAnimationActive: true,
32306
+ animationDuration: 1500,
32307
+ animationBegin: 300
32308
+ };
32309
+ return /* @__PURE__ */ jsx(Line, { ...lineProps, children: lineConfig.labelList && /* @__PURE__ */ jsx(
32310
+ LabelList,
32311
+ {
32312
+ dataKey: lineConfig.dataKey,
32313
+ position: "top",
32314
+ formatter: (value) => formatNumber(value),
32315
+ ...typeof lineConfig.labelList === "object" ? lineConfig.labelList : {}
32316
+ }
32317
+ ) });
32318
+ })
32319
+ ]
32320
+ },
32321
+ hasValidData ? "valid" : "empty"
32322
+ );
32286
32323
  if (responsive) {
32287
32324
  return /* @__PURE__ */ jsx(
32288
32325
  "div",
@@ -32290,11 +32327,20 @@ var LineChartComponent = ({
32290
32327
  ref: containerRef,
32291
32328
  className: clsx(fillContainer ? "w-full h-full" : "w-full h-auto", className),
32292
32329
  style: fillContainer ? { height: "100%", minHeight: "50px", minWidth: "100px" } : { aspectRatio: `${aspect}/1`, minHeight: "50px", minWidth: "100px" },
32293
- children: containerReady ? /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: chartContent }) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 rounded-lg", children: /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-sm", children: "Loading chart..." }) })
32330
+ children: /* @__PURE__ */ jsx(
32331
+ motion.div,
32332
+ {
32333
+ initial: { opacity: 0 },
32334
+ animate: { opacity: 1 },
32335
+ transition: { duration: 0.5 },
32336
+ className: "w-full h-full",
32337
+ children: dimensions.width > 0 && dimensions.height > 0 && renderChartContent(dimensions.width, dimensions.height)
32338
+ }
32339
+ )
32294
32340
  }
32295
32341
  );
32296
32342
  }
32297
- return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: chartContent });
32343
+ return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: renderChartContent(restOfChartProps.width, restOfChartProps.height) });
32298
32344
  };
32299
32345
  var LineChart = React141__default.memo(LineChartComponent, (prevProps, nextProps) => {
32300
32346
  if (prevProps.xAxisDataKey !== nextProps.xAxisDataKey || prevProps.xAxisLabel !== nextProps.xAxisLabel || prevProps.yAxisLabel !== nextProps.yAxisLabel || prevProps.yAxisUnit !== nextProps.yAxisUnit || prevProps.className !== nextProps.className || prevProps.showGrid !== nextProps.showGrid || prevProps.showLegend !== nextProps.showLegend || prevProps.showTooltip !== nextProps.showTooltip || prevProps.responsive !== nextProps.responsive || prevProps.aspect !== nextProps.aspect || JSON.stringify(prevProps.yAxisDomain) !== JSON.stringify(nextProps.yAxisDomain)) {
@@ -32562,14 +32608,35 @@ var CycleTimeOverTimeChart = ({
32562
32608
  }) => {
32563
32609
  const MAX_DATA_POINTS = 40;
32564
32610
  const containerRef = React141__default.useRef(null);
32565
- const [containerReady, setContainerReady] = React141__default.useState(false);
32566
- const parseTimeToMinutes3 = (value) => {
32611
+ const [dimensions, setDimensions] = React141__default.useState({ width: 0, height: 0 });
32612
+ const [hasValidData, setHasValidData] = React141__default.useState(false);
32613
+ React141__default.useEffect(() => {
32614
+ const currentHasValidData = data && data.some((val) => val !== null && val > 0);
32615
+ if (currentHasValidData && !hasValidData) {
32616
+ setHasValidData(true);
32617
+ }
32618
+ }, [data, hasValidData]);
32619
+ React141__default.useEffect(() => {
32620
+ if (!containerRef.current) return;
32621
+ const observer = new ResizeObserver((entries) => {
32622
+ const entry = entries[0];
32623
+ if (entry) {
32624
+ setDimensions({
32625
+ width: entry.contentRect.width,
32626
+ height: entry.contentRect.height
32627
+ });
32628
+ }
32629
+ });
32630
+ observer.observe(containerRef.current);
32631
+ return () => observer.disconnect();
32632
+ }, []);
32633
+ const parseTimeToMinutes4 = (value) => {
32567
32634
  const [hours, minutes] = value.split(":").map(Number);
32568
32635
  if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return 0;
32569
32636
  return hours * 60 + minutes;
32570
32637
  };
32571
32638
  const formatHourLabel = (slotIndex) => {
32572
- const baseMinutes = parseTimeToMinutes3(shiftStart);
32639
+ const baseMinutes = parseTimeToMinutes4(shiftStart);
32573
32640
  const absoluteMinutes = baseMinutes + slotIndex * 60;
32574
32641
  const hour24 = Math.floor(absoluteMinutes % (24 * 60) / 60);
32575
32642
  const ampm = hour24 >= 12 ? "PM" : "AM";
@@ -32588,52 +32655,7 @@ var CycleTimeOverTimeChart = ({
32588
32655
  const displayData = getDisplayData(data);
32589
32656
  const DURATION = displayData.length;
32590
32657
  const effectiveDatasetKey = datasetKey || `cycle-time:${xAxisMode}`;
32591
- const [animatedDatasetKey, setAnimatedDatasetKey] = React141__default.useState(null);
32592
- const shouldAnimate = animatedDatasetKey !== effectiveDatasetKey;
32593
- const handleAnimationEnd = React141__default.useCallback(() => {
32594
- setAnimatedDatasetKey((currentValue) => currentValue === effectiveDatasetKey ? currentValue : effectiveDatasetKey);
32595
- }, [effectiveDatasetKey]);
32596
32658
  const finalData = displayData;
32597
- React141__default.useEffect(() => {
32598
- const containerNode = containerRef.current;
32599
- if (!containerNode) {
32600
- setContainerReady(true);
32601
- return void 0;
32602
- }
32603
- let frameId = null;
32604
- let resizeObserver = null;
32605
- const checkContainerDimensions = () => {
32606
- const rect = containerNode.getBoundingClientRect();
32607
- const isReady = rect.width > 0 && rect.height > 0;
32608
- if (isReady) {
32609
- setContainerReady(true);
32610
- }
32611
- return isReady;
32612
- };
32613
- if (checkContainerDimensions()) {
32614
- return void 0;
32615
- }
32616
- frameId = window.requestAnimationFrame(() => {
32617
- checkContainerDimensions();
32618
- });
32619
- if (typeof ResizeObserver !== "undefined") {
32620
- resizeObserver = new ResizeObserver(() => {
32621
- if (checkContainerDimensions() && resizeObserver) {
32622
- resizeObserver.disconnect();
32623
- resizeObserver = null;
32624
- }
32625
- });
32626
- resizeObserver.observe(containerNode);
32627
- } else {
32628
- setContainerReady(true);
32629
- }
32630
- return () => {
32631
- if (frameId !== null) {
32632
- window.cancelAnimationFrame(frameId);
32633
- }
32634
- resizeObserver?.disconnect();
32635
- };
32636
- }, []);
32637
32659
  const labelInterval = React141__default.useMemo(() => {
32638
32660
  if (xAxisMode === "hourly") {
32639
32661
  return Math.max(1, Math.ceil(DURATION / 8));
@@ -32841,144 +32863,154 @@ var CycleTimeOverTimeChart = ({
32841
32863
  return /* @__PURE__ */ jsxs(
32842
32864
  "div",
32843
32865
  {
32844
- ref: containerRef,
32845
32866
  className: `w-full h-full min-w-0 flex flex-col relative pb-2 ${className}`,
32846
32867
  style: { minHeight: "200px", minWidth: 0 },
32847
32868
  children: [
32848
32869
  renderLegend(),
32849
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 w-full", children: containerReady ? /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
32850
- LineChart$1,
32870
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 w-full", ref: containerRef, children: /* @__PURE__ */ jsx(
32871
+ motion.div,
32851
32872
  {
32852
- data: chartData,
32853
- margin: {
32854
- top: 5,
32855
- right: 30,
32856
- bottom: 25,
32857
- left: 10
32858
- },
32859
- children: [
32860
- /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
32861
- /* @__PURE__ */ jsx(
32862
- XAxis,
32863
- {
32864
- dataKey: "label",
32865
- tick: { fontSize: 11 },
32866
- interval: 0,
32867
- angle: xAxisMode === "hourly" ? 0 : -30,
32868
- textAnchor: xAxisMode === "hourly" ? "middle" : "end",
32869
- tickMargin: xAxisMode === "hourly" ? 8 : 15,
32870
- height: xAxisMode === "hourly" ? 40 : 60
32871
- }
32872
- ),
32873
- /* @__PURE__ */ jsx(
32874
- YAxis,
32875
- {
32876
- tickMargin: 8,
32877
- width: 45,
32878
- yAxisId: "cycle",
32879
- domain: ["auto", "auto"],
32880
- ticks: [0, idealCycleTime, ...Array.from({ length: 4 }, (_, i) => (i + 1) * Math.ceil(idealCycleTime / 2))].sort((a, b) => a - b),
32881
- tickFormatter: (value) => String(value),
32882
- tick: (props) => {
32883
- const { x, y, payload } = props;
32884
- const displayValue = typeof payload.value === "number" ? payload.value.toFixed(1) : String(payload.value);
32885
- return /* @__PURE__ */ jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsx(
32886
- "text",
32887
- {
32888
- x: 0,
32889
- y: 0,
32890
- dy: 4,
32891
- textAnchor: "end",
32892
- fill: payload.value === idealCycleTime ? "#E34329" : "#666",
32893
- fontSize: 12,
32894
- fontWeight: payload.value === idealCycleTime ? "bold" : "normal",
32895
- children: displayValue
32896
- },
32897
- `tick-${payload.value}-${x}-${y}`
32898
- ) });
32899
- }
32900
- }
32901
- ),
32902
- showIdleTime && /* @__PURE__ */ jsx(
32903
- YAxis,
32904
- {
32905
- yAxisId: "idle",
32906
- orientation: "right",
32907
- tickMargin: 8,
32908
- width: 35,
32909
- domain: [0, 60],
32910
- tickFormatter: (value) => `${value}m`,
32911
- tick: { fontSize: 11, fill: "#f59e0b" },
32912
- axisLine: false,
32913
- tickLine: false
32914
- }
32915
- ),
32916
- /* @__PURE__ */ jsx(
32917
- Tooltip,
32918
- {
32919
- cursor: { stroke: "#E5E7EB", strokeWidth: 1 },
32920
- content: renderChartTooltip,
32921
- animationDuration: 200
32922
- }
32923
- ),
32924
- /* @__PURE__ */ jsx(
32925
- ReferenceLine,
32926
- {
32927
- y: idealCycleTime,
32928
- yAxisId: "cycle",
32929
- stroke: "#E34329",
32930
- strokeDasharray: "3 3",
32931
- strokeWidth: 2,
32932
- label: {
32933
- position: "right",
32934
- value: `${idealCycleTime.toFixed(1)}s`,
32935
- fill: "#E34329",
32936
- fontSize: 12,
32937
- fontWeight: 500
32938
- }
32939
- }
32940
- ),
32941
- /* @__PURE__ */ jsx(
32942
- Line,
32943
- {
32944
- type: "monotone",
32945
- yAxisId: "cycle",
32946
- dataKey: "cycleTime",
32947
- stroke: "#3B82F6",
32948
- strokeWidth: 2,
32949
- connectNulls: false,
32950
- dot: renderCycleDot,
32951
- activeDot: renderCycleActiveDot,
32952
- isAnimationActive: shouldAnimate,
32953
- animationBegin: 0,
32954
- animationDuration: 1200,
32955
- animationEasing: "ease-out",
32956
- onAnimationEnd: handleAnimationEnd
32957
- },
32958
- `${effectiveDatasetKey}:cycle`
32959
- ),
32960
- showIdleTime && /* @__PURE__ */ jsx(
32961
- Line,
32962
- {
32963
- type: "monotone",
32964
- yAxisId: "idle",
32965
- dataKey: "idleMinutes",
32966
- stroke: "#f59e0b",
32967
- strokeWidth: 2,
32968
- strokeDasharray: "4 4",
32969
- connectNulls: false,
32970
- dot: renderIdleDot,
32971
- activeDot: renderIdleActiveDot,
32972
- isAnimationActive: shouldAnimate,
32973
- animationBegin: 0,
32974
- animationDuration: 1200,
32975
- animationEasing: "ease-out"
32873
+ initial: { opacity: 0 },
32874
+ animate: { opacity: 1 },
32875
+ transition: { duration: 0.5 },
32876
+ className: "w-full h-full",
32877
+ children: dimensions.width > 0 && dimensions.height > 0 && /* @__PURE__ */ jsxs(
32878
+ LineChart$1,
32879
+ {
32880
+ width: dimensions.width,
32881
+ height: dimensions.height,
32882
+ data: chartData,
32883
+ margin: {
32884
+ top: 5,
32885
+ right: 30,
32886
+ bottom: 25,
32887
+ left: 10
32976
32888
  },
32977
- `${effectiveDatasetKey}:idle`
32978
- )
32979
- ]
32889
+ children: [
32890
+ /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
32891
+ /* @__PURE__ */ jsx(
32892
+ XAxis,
32893
+ {
32894
+ dataKey: "label",
32895
+ tick: { fontSize: 11 },
32896
+ interval: 0,
32897
+ angle: xAxisMode === "hourly" ? 0 : -30,
32898
+ textAnchor: xAxisMode === "hourly" ? "middle" : "end",
32899
+ tickMargin: xAxisMode === "hourly" ? 8 : 15,
32900
+ height: xAxisMode === "hourly" ? 40 : 60
32901
+ }
32902
+ ),
32903
+ /* @__PURE__ */ jsx(
32904
+ YAxis,
32905
+ {
32906
+ tickMargin: 8,
32907
+ width: 45,
32908
+ yAxisId: "cycle",
32909
+ domain: ["auto", "auto"],
32910
+ ticks: [0, idealCycleTime, ...Array.from({ length: 4 }, (_, i) => (i + 1) * Math.ceil(idealCycleTime / 2))].sort((a, b) => a - b),
32911
+ tickFormatter: (value) => String(value),
32912
+ tick: (props) => {
32913
+ const { x, y, payload } = props;
32914
+ const displayValue = typeof payload.value === "number" ? payload.value.toFixed(1) : String(payload.value);
32915
+ return /* @__PURE__ */ jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsx(
32916
+ "text",
32917
+ {
32918
+ x: 0,
32919
+ y: 0,
32920
+ dy: 4,
32921
+ textAnchor: "end",
32922
+ fill: payload.value === idealCycleTime ? "#E34329" : "#666",
32923
+ fontSize: 12,
32924
+ fontWeight: payload.value === idealCycleTime ? "bold" : "normal",
32925
+ children: displayValue
32926
+ },
32927
+ `tick-${payload.value}-${x}-${y}`
32928
+ ) });
32929
+ }
32930
+ }
32931
+ ),
32932
+ showIdleTime && /* @__PURE__ */ jsx(
32933
+ YAxis,
32934
+ {
32935
+ yAxisId: "idle",
32936
+ orientation: "right",
32937
+ tickMargin: 8,
32938
+ width: 35,
32939
+ domain: [0, 60],
32940
+ tickFormatter: (value) => `${value}m`,
32941
+ tick: { fontSize: 11, fill: "#f59e0b" },
32942
+ axisLine: false,
32943
+ tickLine: false
32944
+ }
32945
+ ),
32946
+ /* @__PURE__ */ jsx(
32947
+ Tooltip,
32948
+ {
32949
+ cursor: { stroke: "#E5E7EB", strokeWidth: 1 },
32950
+ content: renderChartTooltip,
32951
+ animationDuration: 200
32952
+ }
32953
+ ),
32954
+ /* @__PURE__ */ jsx(
32955
+ ReferenceLine,
32956
+ {
32957
+ y: idealCycleTime,
32958
+ yAxisId: "cycle",
32959
+ stroke: "#E34329",
32960
+ strokeDasharray: "3 3",
32961
+ strokeWidth: 2,
32962
+ label: {
32963
+ position: "right",
32964
+ value: `${idealCycleTime.toFixed(1)}s`,
32965
+ fill: "#E34329",
32966
+ fontSize: 12,
32967
+ fontWeight: 500
32968
+ }
32969
+ }
32970
+ ),
32971
+ /* @__PURE__ */ jsx(
32972
+ Line,
32973
+ {
32974
+ type: "monotone",
32975
+ yAxisId: "cycle",
32976
+ dataKey: "cycleTime",
32977
+ stroke: "#3B82F6",
32978
+ strokeWidth: 2,
32979
+ connectNulls: false,
32980
+ dot: renderCycleDot,
32981
+ activeDot: renderCycleActiveDot,
32982
+ isAnimationActive: true,
32983
+ animationBegin: 300,
32984
+ animationDuration: 1500,
32985
+ animationEasing: "ease-out"
32986
+ },
32987
+ `${effectiveDatasetKey}:cycle`
32988
+ ),
32989
+ showIdleTime && /* @__PURE__ */ jsx(
32990
+ Line,
32991
+ {
32992
+ type: "monotone",
32993
+ yAxisId: "idle",
32994
+ dataKey: "idleMinutes",
32995
+ stroke: "#f59e0b",
32996
+ strokeWidth: 2,
32997
+ strokeDasharray: "4 4",
32998
+ connectNulls: false,
32999
+ dot: renderIdleDot,
33000
+ activeDot: renderIdleActiveDot,
33001
+ isAnimationActive: true,
33002
+ animationBegin: 300,
33003
+ animationDuration: 1500,
33004
+ animationEasing: "ease-out"
33005
+ },
33006
+ `${effectiveDatasetKey}:idle`
33007
+ )
33008
+ ]
33009
+ },
33010
+ hasValidData ? "valid" : "empty"
33011
+ )
32980
33012
  }
32981
- ) }) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 rounded-lg", children: /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-sm", children: "Loading chart..." }) }) })
33013
+ ) })
32982
33014
  ]
32983
33015
  }
32984
33016
  );
@@ -33828,10 +33860,10 @@ var HourlyOutputChart = React141__default.memo(HourlyOutputChartComponent, (prev
33828
33860
  HourlyOutputChart.displayName = "HourlyOutputChart";
33829
33861
 
33830
33862
  // src/components/dashboard/grid/videoGridMetricUtils.ts
33831
- var VIDEO_GRID_LEGEND_LABEL = "Flow";
33863
+ var VIDEO_GRID_LEGEND_LABEL = "7 Minute Efficiency";
33832
33864
  var MAP_GRID_LEGEND_LABEL = "Efficiency";
33833
- var MIXED_VIDEO_GRID_LEGEND_LABEL = "Flow / Efficiency";
33834
- var isFiniteNumber2 = (value) => typeof value === "number" && Number.isFinite(value);
33865
+ var MIXED_VIDEO_GRID_LEGEND_LABEL = "Efficiency";
33866
+ var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
33835
33867
  var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
33836
33868
  workspace.video_grid_metric_mode,
33837
33869
  workspace.assembly_enabled === true
@@ -33840,11 +33872,11 @@ var isVideoGridWipGated = (workspace) => isWipGatedVideoGridMetricMode(
33840
33872
  workspace.video_grid_metric_mode,
33841
33873
  workspace.assembly_enabled === true
33842
33874
  );
33843
- var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber2(workspace.recent_flow_percent);
33875
+ var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber(workspace.recent_flow_percent);
33844
33876
  var isVideoGridRecentFlowUnavailable = (workspace) => isVideoGridRecentFlowEnabled(workspace) && !hasVideoGridRecentFlow(workspace);
33845
33877
  var getVideoGridMetricValue = (workspace) => {
33846
33878
  const recentFlowPercent = workspace.recent_flow_percent;
33847
- if (hasVideoGridRecentFlow(workspace) && isFiniteNumber2(recentFlowPercent)) {
33879
+ if (hasVideoGridRecentFlow(workspace) && isFiniteNumber(recentFlowPercent)) {
33848
33880
  return recentFlowPercent;
33849
33881
  }
33850
33882
  if (isVideoGridRecentFlowUnavailable(workspace)) {
@@ -33855,7 +33887,7 @@ var getVideoGridMetricValue = (workspace) => {
33855
33887
  var hasIncomingWipMapping = (workspace) => Boolean(workspace.incoming_wip_buffer_name);
33856
33888
  var getVideoGridBaseColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
33857
33889
  const metricValue = getVideoGridMetricValue(workspace);
33858
- if (!isFiniteNumber2(metricValue)) {
33890
+ if (!isFiniteNumber(metricValue)) {
33859
33891
  return "neutral";
33860
33892
  }
33861
33893
  return getEfficiencyColor(metricValue, legend);
@@ -33870,7 +33902,7 @@ var isLowWipGreenOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
33870
33902
  if (!hasIncomingWipMapping(workspace)) {
33871
33903
  return false;
33872
33904
  }
33873
- return isFiniteNumber2(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
33905
+ return isFiniteNumber(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
33874
33906
  };
33875
33907
  var toMinuteBucket = (minuteBucket) => Number.isFinite(minuteBucket) ? Math.floor(minuteBucket) : Math.floor(Date.now() / 6e4);
33876
33908
  var getEffectiveFlowMinuteBucket = (workspace) => {
@@ -33912,7 +33944,7 @@ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) =>
33912
33944
  if (!hasIncomingWipMapping(workspace)) {
33913
33945
  return baseColor;
33914
33946
  }
33915
- if (!isFiniteNumber2(workspace.incoming_wip_current)) {
33947
+ if (!isFiniteNumber(workspace.incoming_wip_current)) {
33916
33948
  return "neutral";
33917
33949
  }
33918
33950
  if (isLowWipGreenOverride(workspace, legend)) {
@@ -33982,8 +34014,9 @@ var VideoCard = React141__default.memo(({
33982
34014
  const isRecentFlowCard = isVideoGridRecentFlowEnabled(workspace);
33983
34015
  const hasDisplayMetric = typeof videoGridDisplayValue === "number" && Number.isFinite(videoGridDisplayValue);
33984
34016
  const hasBarMetric = typeof videoGridMetricValue === "number" && Number.isFinite(videoGridMetricValue);
34017
+ const shouldRenderMetricBadge = hasDisplayMetric;
33985
34018
  const badgeTitle = hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
33986
- const badgeLabel = hasDisplayMetric ? `${Math.round(videoGridDisplayValue)}%` : "X";
34019
+ const badgeLabel = `${Math.round(videoGridDisplayValue ?? 0)}%`;
33987
34020
  const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
33988
34021
  const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
33989
34022
  const efficiencyStatus = videoGridColorState === "green" ? "High" : videoGridColorState === "yellow" ? "Medium" : videoGridColorState === "red" ? "Low" : "Neutral";
@@ -34059,7 +34092,7 @@ var VideoCard = React141__default.memo(({
34059
34092
  lastSeenText
34060
34093
  ] })
34061
34094
  ] }) }),
34062
- /* @__PURE__ */ jsx("div", { className: `absolute ${compact ? "top-1 right-1" : "top-2 right-2"} z-30`, children: /* @__PURE__ */ jsx(
34095
+ shouldRenderMetricBadge && /* @__PURE__ */ jsx("div", { className: `absolute ${compact ? "top-1 right-1" : "top-2 right-2"} z-30`, children: /* @__PURE__ */ jsx(
34063
34096
  "div",
34064
34097
  {
34065
34098
  "data-testid": "video-card-metric-badge",
@@ -34104,7 +34137,7 @@ var VideoCard = React141__default.memo(({
34104
34137
  }
34105
34138
  );
34106
34139
  }, (prevProps, nextProps) => {
34107
- if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_mode !== nextProps.workspace.recent_flow_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
34140
+ if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
34108
34141
  return false;
34109
34142
  }
34110
34143
  if (prevProps.workspace.workspace_uuid !== nextProps.workspace.workspace_uuid || prevProps.workspace.workspace_name !== nextProps.workspace.workspace_name || prevProps.workspace.line_id !== nextProps.workspace.line_id) {
@@ -44572,7 +44605,7 @@ var ShiftDisplay = memo$1(({ className, variant = "default", lineId }) => {
44572
44605
  return null;
44573
44606
  }
44574
44607
  };
44575
- const getShiftIcon = (shift) => {
44608
+ const getShiftIcon2 = (shift) => {
44576
44609
  if (shift === "Day") {
44577
44610
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z", clipRule: "evenodd" }) });
44578
44611
  } else {
@@ -44598,7 +44631,7 @@ var ShiftDisplay = memo$1(({ className, variant = "default", lineId }) => {
44598
44631
  }
44599
44632
  if (variant === "enhanced") {
44600
44633
  return /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
44601
- /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon(currentShiftText) }),
44634
+ /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
44602
44635
  /* @__PURE__ */ jsxs("span", { className: "text-base font-medium text-blue-800", children: [
44603
44636
  currentShiftText,
44604
44637
  " Shift"
@@ -44606,7 +44639,7 @@ var ShiftDisplay = memo$1(({ className, variant = "default", lineId }) => {
44606
44639
  ] });
44607
44640
  }
44608
44641
  return /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
44609
- /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon(currentShiftText) }),
44642
+ /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
44610
44643
  /* @__PURE__ */ jsxs("span", { className: "text-base font-medium text-blue-800", children: [
44611
44644
  currentShiftText,
44612
44645
  " Shift"
@@ -47243,7 +47276,7 @@ var LinePdfGenerator = ({
47243
47276
  doc.setLineWidth(0.8);
47244
47277
  doc.line(20, 123, 190, 123);
47245
47278
  const hourlyOverviewStartY = 128;
47246
- const parseTimeToMinutes3 = (timeStr) => {
47279
+ const parseTimeToMinutes4 = (timeStr) => {
47247
47280
  const [hours, minutes] = timeStr.split(":");
47248
47281
  const hour = parseInt(hours, 10);
47249
47282
  const minute = parseInt(minutes || "0", 10);
@@ -47276,7 +47309,7 @@ var LinePdfGenerator = ({
47276
47309
  };
47277
47310
  };
47278
47311
  const getHourlyTimeRanges = (startTimeStr, endTimeStr) => {
47279
- const startMinutes = parseTimeToMinutes3(startTimeStr);
47312
+ const startMinutes = parseTimeToMinutes4(startTimeStr);
47280
47313
  if (Number.isNaN(startMinutes)) {
47281
47314
  return [];
47282
47315
  }
@@ -47284,7 +47317,7 @@ var LinePdfGenerator = ({
47284
47317
  const defaultHours = 11;
47285
47318
  return Array.from({ length: defaultHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
47286
47319
  }
47287
- const endMinutes = parseTimeToMinutes3(endTimeStr);
47320
+ const endMinutes = parseTimeToMinutes4(endTimeStr);
47288
47321
  if (Number.isNaN(endMinutes)) {
47289
47322
  const fallbackHours = 11;
47290
47323
  return Array.from({ length: fallbackHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
@@ -49053,7 +49086,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
49053
49086
  minute: "2-digit",
49054
49087
  hour12: true
49055
49088
  });
49056
- const parseTimeToMinutes3 = (timeValue) => {
49089
+ const parseTimeToMinutes4 = (timeValue) => {
49057
49090
  const [hourPart, minutePart] = timeValue.split(":").map(Number);
49058
49091
  const hour = Number.isFinite(hourPart) ? hourPart : 0;
49059
49092
  const minute = Number.isFinite(minutePart) ? minutePart : 0;
@@ -49070,8 +49103,8 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
49070
49103
  const IST_OFFSET_MINUTES = 330;
49071
49104
  return Date.UTC(year, month - 1, day, hour, minute) - IST_OFFSET_MINUTES * 60 * 1e3;
49072
49105
  };
49073
- const shiftStartMinutes = parseTimeToMinutes3(workspace.shift_start);
49074
- const shiftEndMinutes = parseTimeToMinutes3(workspace.shift_end);
49106
+ const shiftStartMinutes = parseTimeToMinutes4(workspace.shift_start);
49107
+ const shiftEndMinutes = parseTimeToMinutes4(workspace.shift_end);
49075
49108
  const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
49076
49109
  const shiftStartUtcMs = toShiftUtcMs(workspace.date, workspace.shift_start);
49077
49110
  const shiftEndUtcMs = toShiftUtcMs(workspace.date, workspace.shift_end) + (wrapsMidnight ? 24 * 60 * 60 * 1e3 : 0);
@@ -49786,8 +49819,7 @@ var WorkspaceCycleTimeMetricCards = ({
49786
49819
  {
49787
49820
  data: idleTimeData.chartData,
49788
49821
  isLoading: idleTimeData.isLoading,
49789
- error: idleTimeData.error,
49790
- variant: "bar"
49822
+ error: idleTimeData.error
49791
49823
  }
49792
49824
  ) })
49793
49825
  ] })
@@ -51378,7 +51410,7 @@ var DashboardHeader = memo$1(({ lineTitle, className = "", headerControls, lineI
51378
51410
  const rawName = currentShift.shiftName || "Day";
51379
51411
  return rawName.toLowerCase().includes("shift") ? rawName : `${rawName} Shift`;
51380
51412
  };
51381
- const getShiftIcon = () => {
51413
+ const getShiftIcon2 = () => {
51382
51414
  const currentShift = getCurrentShift(timezone, shiftConfig);
51383
51415
  const shiftName = (currentShift.shiftName || "").toLowerCase();
51384
51416
  if (shiftName.includes("day") || shiftName.includes("morning") || currentShift.shiftId === 0) {
@@ -51412,7 +51444,7 @@ var DashboardHeader = memo$1(({ lineTitle, className = "", headerControls, lineI
51412
51444
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: /* @__PURE__ */ jsx(Timer2, {}) }),
51413
51445
  /* @__PURE__ */ jsx("span", { className: "text-gray-300", children: "|" }),
51414
51446
  isShiftConfigLoading ? /* @__PURE__ */ jsx("div", { className: "h-3.5 w-16 bg-gray-200 rounded animate-pulse" }) : /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 font-medium", children: [
51415
- /* @__PURE__ */ jsx("span", { className: "opacity-75", children: getShiftIcon() }),
51447
+ /* @__PURE__ */ jsx("span", { className: "opacity-75", children: getShiftIcon2() }),
51416
51448
  getShiftName()
51417
51449
  ] })
51418
51450
  ] })
@@ -51429,7 +51461,7 @@ var DashboardHeader = memo$1(({ lineTitle, className = "", headerControls, lineI
51429
51461
  /* @__PURE__ */ jsxs("div", { className: "mt-2 inline-flex flex-wrap items-center gap-3", children: [
51430
51462
  /* @__PURE__ */ jsx("div", { className: "text-xs md:text-sm font-medium text-gray-600 whitespace-nowrap", children: /* @__PURE__ */ jsx(Timer2, {}) }),
51431
51463
  /* @__PURE__ */ jsx("div", { className: "inline-flex items-center gap-1", children: isShiftConfigLoading ? /* @__PURE__ */ jsx("div", { className: "h-4 w-20 bg-gray-200 rounded animate-pulse" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
51432
- /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
51464
+ /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
51433
51465
  /* @__PURE__ */ jsx("span", { className: "text-xs md:text-sm font-medium text-gray-600 whitespace-nowrap", children: getShiftName() })
51434
51466
  ] }) })
51435
51467
  ] })
@@ -58400,7 +58432,7 @@ var FactoryView = ({
58400
58432
  const currentShift = getCurrentShiftInfo();
58401
58433
  return (currentShift.shiftName || "Day").replace(/ Shift$/i, "");
58402
58434
  };
58403
- const getShiftIcon = () => {
58435
+ const getShiftIcon2 = () => {
58404
58436
  const currentShift = getCurrentShiftInfo();
58405
58437
  const shiftNameLower = (currentShift.shiftName || "").toLowerCase();
58406
58438
  if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || currentShift.shiftId === 0) {
@@ -58446,7 +58478,7 @@ var FactoryView = ({
58446
58478
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center justify-center gap-2", children: [
58447
58479
  /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: /* @__PURE__ */ jsx(ISTTimer_default, {}) }) }),
58448
58480
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
58449
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon() }),
58481
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2() }),
58450
58482
  /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
58451
58483
  getShiftName(),
58452
58484
  " Shift"
@@ -58465,7 +58497,7 @@ var FactoryView = ({
58465
58497
  " IST"
58466
58498
  ] }),
58467
58499
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1", children: [
58468
- /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
58500
+ /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
58469
58501
  /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
58470
58502
  getShiftName(),
58471
58503
  " Shift"
@@ -61177,7 +61209,7 @@ var KPIDetailView = ({
61177
61209
  const getShiftName = useCallback((shiftId) => {
61178
61210
  return getShiftNameById(shiftId, configuredTimezone, shiftConfig);
61179
61211
  }, [configuredTimezone, shiftConfig]);
61180
- const getShiftIcon = useCallback((shiftId) => {
61212
+ const getShiftIcon2 = useCallback((shiftId) => {
61181
61213
  if (shiftId === 0) {
61182
61214
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
61183
61215
  }
@@ -62057,7 +62089,7 @@ var KPIDetailView = ({
62057
62089
  /* @__PURE__ */ jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
62058
62090
  /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: chartMetrics && formatLocalDate(new Date(chartMetrics.date)) }) }),
62059
62091
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
62060
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(chartMetrics.shift_id ?? 0) }),
62092
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(chartMetrics.shift_id ?? 0) }),
62061
62093
  /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
62062
62094
  getShiftName(chartMetrics.shift_id ?? 0).replace(/ Shift$/i, ""),
62063
62095
  " Shift"
@@ -62083,7 +62115,7 @@ var KPIDetailView = ({
62083
62115
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" })
62084
62116
  ] }),
62085
62117
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
62086
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(chartMetrics.shift_id ?? 0) }),
62118
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon2(chartMetrics.shift_id ?? 0) }),
62087
62119
  /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
62088
62120
  getShiftName(chartMetrics.shift_id ?? 0).replace(/ Shift$/i, ""),
62089
62121
  " Shift"
@@ -62101,7 +62133,7 @@ var KPIDetailView = ({
62101
62133
  return `${startDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })} - ${endDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`;
62102
62134
  })() }) }),
62103
62135
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
62104
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(selectedShiftId) }),
62136
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(selectedShiftId) }),
62105
62137
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: getShiftName(selectedShiftId) })
62106
62138
  ] })
62107
62139
  ] }),
@@ -62118,7 +62150,7 @@ var KPIDetailView = ({
62118
62150
  ] }),
62119
62151
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" }),
62120
62152
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
62121
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(selectedShiftId) }),
62153
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon2(selectedShiftId) }),
62122
62154
  /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
62123
62155
  getShiftName(selectedShiftId).replace(/ Shift$/i, ""),
62124
62156
  " Shift"
@@ -63494,7 +63526,7 @@ var KPIsOverviewView = ({
63494
63526
  const headerShiftId = showHistoricalLeaderboardHeader ? effectiveLeaderboardShiftId : currentShiftDetails.shiftId;
63495
63527
  const headerShiftName = getShiftNameById(headerShiftId, configuredTimezone, shiftConfig).replace(/ Shift$/i, "");
63496
63528
  const headerDateLabel = isMonthlyMode ? getMonthRange() : formatLocalDate2(headerDateKey);
63497
- const getShiftIcon = (shiftId) => {
63529
+ const getShiftIcon2 = (shiftId) => {
63498
63530
  const shiftNameLower = getShiftNameById(shiftId, configuredTimezone, shiftConfig).toLowerCase();
63499
63531
  if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
63500
63532
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
@@ -63611,7 +63643,7 @@ var KPIsOverviewView = ({
63611
63643
  /* @__PURE__ */ jsx("div", { className: `inline-flex items-center bg-gray-100 rounded-full ${isMonthlyMode ? "px-4 py-1.5 ring-1 ring-gray-200 shadow-sm" : "px-2.5 py-1"}`, children: /* @__PURE__ */ jsx("span", { className: `font-medium text-gray-700 ${isMonthlyMode ? "text-sm" : "text-xs"}`, children: headerDateLabel }) }),
63612
63644
  !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
63613
63645
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
63614
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(headerShiftId) }),
63646
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(headerShiftId) }),
63615
63647
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: headerShiftName })
63616
63648
  ] }),
63617
63649
  showHistoricalLeaderboardHeader ? /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-amber-50 text-amber-700 rounded-full", children: [
@@ -63807,7 +63839,7 @@ var KPIsOverviewView = ({
63807
63839
  !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
63808
63840
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" }),
63809
63841
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
63810
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(headerShiftId) }),
63842
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon2(headerShiftId) }),
63811
63843
  /* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold uppercase tracking-wider", children: [
63812
63844
  headerShiftName,
63813
63845
  " Shift"
@@ -63951,6 +63983,52 @@ var KPIsOverviewView = ({
63951
63983
  ] });
63952
63984
  };
63953
63985
  var KPIsOverviewView_default = KPIsOverviewView;
63986
+ var toFiniteNumber = (value) => {
63987
+ if (typeof value === "number" && Number.isFinite(value)) return value;
63988
+ if (typeof value === "string" && value.trim() !== "") {
63989
+ const parsed = Number(value);
63990
+ return Number.isFinite(parsed) ? parsed : null;
63991
+ }
63992
+ return null;
63993
+ };
63994
+ var getCycleRatio = (workspace) => {
63995
+ const idealCycleTime = toFiniteNumber(workspace.ideal_cycle_time);
63996
+ const avgCycleTime = toFiniteNumber(workspace.avg_cycle_time);
63997
+ if (idealCycleTime === null || avgCycleTime === null || idealCycleTime <= 0 || avgCycleTime <= 0) {
63998
+ return null;
63999
+ }
64000
+ return idealCycleTime / avgCycleTime;
64001
+ };
64002
+ var formatCycleTimeValue = (value) => {
64003
+ const numericValue = toFiniteNumber(value);
64004
+ if (numericValue === null || numericValue <= 0) return "--";
64005
+ return `${numericValue.toFixed(1)}s`;
64006
+ };
64007
+ var CycleTimeComparison = memo$1(({
64008
+ workspace,
64009
+ variant = "table"
64010
+ }) => {
64011
+ const averageValue = formatCycleTimeValue(workspace.avg_cycle_time);
64012
+ const standardValue = formatCycleTimeValue(workspace.ideal_cycle_time);
64013
+ if (variant === "mobile") {
64014
+ return /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center justify-between py-2 border-t border-gray-100", children: [
64015
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider", children: "Standard Cycle Time" }),
64016
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium tabular-nums text-gray-500", children: standardValue })
64017
+ ] });
64018
+ }
64019
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
64020
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
64021
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wider text-gray-500", children: "Average" }),
64022
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold tabular-nums text-gray-900", children: averageValue })
64023
+ ] }),
64024
+ /* @__PURE__ */ jsx("div", { className: "h-6 w-px bg-gray-200" }),
64025
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
64026
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wider text-gray-500", children: "Standard" }),
64027
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium tabular-nums text-gray-500", children: standardValue })
64028
+ ] })
64029
+ ] });
64030
+ }, (prevProps, nextProps) => prevProps.variant === nextProps.variant && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time);
64031
+ CycleTimeComparison.displayName = "CycleTimeComparison";
63954
64032
  var IsolatedTimer = memo$1(() => {
63955
64033
  return /* @__PURE__ */ jsx(ISTTimer_default, {});
63956
64034
  });
@@ -63968,11 +64046,11 @@ var HeaderRibbon = memo$1(({
63968
64046
  currentDate,
63969
64047
  currentMobileDate,
63970
64048
  shiftId,
63971
- getShiftIcon,
64049
+ getShiftIcon: getShiftIcon2,
63972
64050
  getShiftName,
63973
64051
  showTimer = true
63974
64052
  }) => {
63975
- const shiftIcon = useMemo(() => getShiftIcon(shiftId), [getShiftIcon, shiftId]);
64053
+ const shiftIcon = useMemo(() => getShiftIcon2(shiftId), [getShiftIcon2, shiftId]);
63976
64054
  const shiftName = useMemo(() => getShiftName(shiftId), [getShiftName, shiftId]);
63977
64055
  return /* @__PURE__ */ jsxs(Fragment, { children: [
63978
64056
  /* @__PURE__ */ jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
@@ -64014,8 +64092,9 @@ var MobileWorkspaceCard = memo$1(({
64014
64092
  isClickable,
64015
64093
  onWorkspaceClick,
64016
64094
  getMedalIcon,
64017
- efficiencyLabel
64018
- }) => /* @__PURE__ */ jsx(
64095
+ metricLabel,
64096
+ isAssemblyMode
64097
+ }) => /* @__PURE__ */ jsxs(
64019
64098
  motion.div,
64020
64099
  {
64021
64100
  layout: true,
@@ -64026,28 +64105,31 @@ var MobileWorkspaceCard = memo$1(({
64026
64105
  },
64027
64106
  onClick: isClickable ? () => onWorkspaceClick(workspace, rank) : void 0,
64028
64107
  className: `${cardClass} p-3 rounded-lg border shadow-sm active:scale-[0.98] ${isClickable ? "cursor-pointer" : "cursor-not-allowed opacity-75"}`,
64029
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
64030
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
64031
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
64032
- /* @__PURE__ */ jsxs("div", { className: "text-2xl font-bold text-gray-700", children: [
64033
- "#",
64034
- rank
64108
+ children: [
64109
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2 gap-3", children: [
64110
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
64111
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
64112
+ /* @__PURE__ */ jsxs("div", { className: "text-2xl font-bold text-gray-700", children: [
64113
+ "#",
64114
+ rank
64115
+ ] }),
64116
+ getMedalIcon(rank)
64035
64117
  ] }),
64036
- getMedalIcon(rank)
64118
+ /* @__PURE__ */ jsxs("div", { children: [
64119
+ /* @__PURE__ */ jsx("div", { className: "font-semibold text-gray-900", children: workspace.displayName }),
64120
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: workspace.lineName })
64121
+ ] })
64037
64122
  ] }),
64038
- /* @__PURE__ */ jsxs("div", { children: [
64039
- /* @__PURE__ */ jsx("div", { className: "font-semibold text-gray-900", children: workspace.displayName }),
64040
- /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: workspace.lineName })
64123
+ /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
64124
+ /* @__PURE__ */ jsx("div", { className: "font-bold text-gray-900 text-lg", children: isAssemblyMode ? /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: formatCycleTimeValue(workspace.avg_cycle_time) }) : /* @__PURE__ */ jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) }),
64125
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: metricLabel })
64041
64126
  ] })
64042
64127
  ] }),
64043
- /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
64044
- /* @__PURE__ */ jsx("div", { className: "text-lg font-bold text-gray-900", children: /* @__PURE__ */ jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) }),
64045
- /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: efficiencyLabel })
64046
- ] })
64047
- ] })
64128
+ isAssemblyMode && /* @__PURE__ */ jsx(CycleTimeComparison, { workspace, variant: "mobile" })
64129
+ ]
64048
64130
  }
64049
64131
  ), (prevProps, nextProps) => {
64050
- return prevProps.efficiencyLabel === nextProps.efficiencyLabel && prevProps.rank === nextProps.rank && prevProps.cardClass === nextProps.cardClass && prevProps.isClickable === nextProps.isClickable && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.action_count === nextProps.workspace.action_count && prevProps.workspace.action_threshold === nextProps.workspace.action_threshold && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
64132
+ return prevProps.metricLabel === nextProps.metricLabel && prevProps.isAssemblyMode === nextProps.isAssemblyMode && prevProps.rank === nextProps.rank && prevProps.cardClass === nextProps.cardClass && prevProps.isClickable === nextProps.isClickable && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time && prevProps.workspace.action_count === nextProps.workspace.action_count && prevProps.workspace.action_threshold === nextProps.workspace.action_threshold && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
64051
64133
  });
64052
64134
  MobileWorkspaceCard.displayName = "MobileWorkspaceCard";
64053
64135
  var DesktopWorkspaceRow = memo$1(({
@@ -64056,7 +64138,8 @@ var DesktopWorkspaceRow = memo$1(({
64056
64138
  rowClass,
64057
64139
  isClickable,
64058
64140
  onWorkspaceClick,
64059
- getMedalIcon
64141
+ getMedalIcon,
64142
+ isAssemblyMode
64060
64143
  }) => /* @__PURE__ */ jsxs(
64061
64144
  motion.tr,
64062
64145
  {
@@ -64073,11 +64156,11 @@ var DesktopWorkspaceRow = memo$1(({
64073
64156
  ] }) }),
64074
64157
  /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsx("div", { className: "font-medium", children: workspace.displayName }) }),
64075
64158
  /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsx("div", { className: "font-medium", children: workspace.lineName }) }),
64076
- /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base font-medium whitespace-nowrap", children: /* @__PURE__ */ jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) })
64159
+ /* @__PURE__ */ jsx("td", { className: `px-3 py-2.5 sm:p-4 text-sm sm:text-base font-medium ${isAssemblyMode ? "" : "whitespace-nowrap"}`, children: isAssemblyMode ? /* @__PURE__ */ jsx(CycleTimeComparison, { workspace, variant: "table" }) : /* @__PURE__ */ jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) })
64077
64160
  ]
64078
64161
  }
64079
64162
  ), (prevProps, nextProps) => {
64080
- return prevProps.index === nextProps.index && prevProps.rowClass === nextProps.rowClass && prevProps.isClickable === nextProps.isClickable && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
64163
+ return prevProps.index === nextProps.index && prevProps.rowClass === nextProps.rowClass && prevProps.isClickable === nextProps.isClickable && prevProps.isAssemblyMode === nextProps.isAssemblyMode && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
64081
64164
  });
64082
64165
  DesktopWorkspaceRow.displayName = "DesktopWorkspaceRow";
64083
64166
  var LeaderboardDetailView = memo$1(({
@@ -64099,6 +64182,7 @@ var LeaderboardDetailView = memo$1(({
64099
64182
  const supabase = useSupabase();
64100
64183
  const [sortAscending, setSortAscending] = useState(false);
64101
64184
  const [viewType, setViewType] = useState("operator");
64185
+ const [outputCategory, setOutputCategory] = useState("standard");
64102
64186
  const [activeTab, setActiveTab] = useState("today");
64103
64187
  const timezone = useAppTimezone();
64104
64188
  const staticShiftConfig = useShiftConfig();
@@ -64177,6 +64261,7 @@ var LeaderboardDetailView = memo$1(({
64177
64261
  const monthlyRequestKeyRef = useRef(null);
64178
64262
  const leaderboardUpdateQueuedRef = useRef(false);
64179
64263
  const leaderboardUpdateTimerRef = useRef(null);
64264
+ const leaderboardViewTrackedRef = useRef(null);
64180
64265
  const filterRef = useRef(null);
64181
64266
  const filterButtonRef = useRef(null);
64182
64267
  const mobileFilterButtonRef = useRef(null);
@@ -64309,6 +64394,17 @@ var LeaderboardDetailView = memo$1(({
64309
64394
  }
64310
64395
  return Array.from(uniqueLines.entries()).map(([id3, name]) => ({ id: id3, label: name }));
64311
64396
  }, [configuredLineIds, lines, getLineName]);
64397
+ const scopedLines = useMemo(() => {
64398
+ const configuredLineIdSet = new Set(configuredLineIds);
64399
+ return lines.filter((line) => configuredLineIds.length === 0 || configuredLineIdSet.has(line.id));
64400
+ }, [configuredLineIds, lines]);
64401
+ const scopedLineAssemblyMap = useMemo(() => {
64402
+ const map = /* @__PURE__ */ new Map();
64403
+ scopedLines.forEach((line) => {
64404
+ map.set(line.id, line.assembly === true);
64405
+ });
64406
+ return map;
64407
+ }, [scopedLines]);
64312
64408
  const shiftOptions = useMemo(() => {
64313
64409
  if (activeShiftConfig?.shifts && activeShiftConfig.shifts.length > 0) {
64314
64410
  return activeShiftConfig.shifts.map((shift2) => ({
@@ -64332,6 +64428,33 @@ var LeaderboardDetailView = memo$1(({
64332
64428
  const parsed = Number(selectedShiftFilter);
64333
64429
  return Number.isFinite(parsed) ? parsed : void 0;
64334
64430
  }, [selectedShiftFilter]);
64431
+ const outputScopeLines = useMemo(() => {
64432
+ const outputLines = scopedLines.filter((line) => (line.monitoring_mode ?? "output") !== "uptime");
64433
+ if (selectedLineFilter === "all") {
64434
+ return outputLines;
64435
+ }
64436
+ return outputLines.filter((line) => line.id === selectedLineFilter);
64437
+ }, [scopedLines, selectedLineFilter]);
64438
+ const hasAssemblyOutputScope = useMemo(
64439
+ () => outputScopeLines.some((line) => line.assembly === true),
64440
+ [outputScopeLines]
64441
+ );
64442
+ const hasStandardOutputScope = useMemo(
64443
+ () => outputScopeLines.some((line) => line.assembly !== true),
64444
+ [outputScopeLines]
64445
+ );
64446
+ const showOutputCategoryDropdown = viewType === "operator" && hasAssemblyOutputScope && hasStandardOutputScope;
64447
+ const isAssemblyMode = viewType === "operator" && outputCategory === "assembly";
64448
+ useEffect(() => {
64449
+ if (viewType !== "operator") return;
64450
+ if (hasAssemblyOutputScope && !hasStandardOutputScope && outputCategory !== "assembly") {
64451
+ setOutputCategory("assembly");
64452
+ return;
64453
+ }
64454
+ if (hasStandardOutputScope && !hasAssemblyOutputScope && outputCategory !== "standard") {
64455
+ setOutputCategory("standard");
64456
+ }
64457
+ }, [viewType, hasAssemblyOutputScope, hasStandardOutputScope, outputCategory]);
64335
64458
  const handleLineFilterChange = useCallback((value) => {
64336
64459
  setSelectedLineFilter(value);
64337
64460
  }, []);
@@ -64341,17 +64464,19 @@ var LeaderboardDetailView = memo$1(({
64341
64464
  const clearFilters = useCallback(() => {
64342
64465
  setSortAscending(false);
64343
64466
  setSelectedLineFilter("all");
64467
+ setOutputCategory("standard");
64344
64468
  setSelectedShiftFilter(currentShiftInfo.shiftId.toString());
64345
64469
  }, [currentShiftInfo.shiftId]);
64346
64470
  const activeFiltersCount = useMemo(() => {
64347
64471
  let count = 0;
64348
64472
  if (sortAscending) count++;
64349
64473
  if (selectedLineFilter !== "all") count++;
64474
+ if (showOutputCategoryDropdown && outputCategory !== "standard") count++;
64350
64475
  if (selectedShiftFilter !== currentShiftInfo.shiftId.toString()) {
64351
64476
  count++;
64352
64477
  }
64353
64478
  return count;
64354
- }, [sortAscending, selectedLineFilter, selectedShiftFilter, currentShiftInfo.shiftId]);
64479
+ }, [sortAscending, selectedLineFilter, outputCategory, showOutputCategoryDropdown, selectedShiftFilter, currentShiftInfo.shiftId]);
64355
64480
  const shouldFetchShiftConfigs = !date && shiftId === void 0;
64356
64481
  const {
64357
64482
  shiftConfigMap: multiLineShiftConfigMap,
@@ -64403,7 +64528,8 @@ var LeaderboardDetailView = memo$1(({
64403
64528
  action_count: entry.total_output || 0,
64404
64529
  pph: entry.avg_pph || 0,
64405
64530
  performance_score: entry.performance_score ?? 0,
64406
- avg_cycle_time: entry.avg_cycle_time || 0,
64531
+ avg_cycle_time: toFiniteNumber(entry.avg_cycle_time) ?? 0,
64532
+ ideal_cycle_time: toFiniteNumber(entry.ideal_cycle_time) ?? void 0,
64407
64533
  trend: 0,
64408
64534
  predicted_output: 0,
64409
64535
  efficiency: entry.efficiency || 0,
@@ -64581,7 +64707,7 @@ var LeaderboardDetailView = memo$1(({
64581
64707
  const currentShift = getCurrentShift(timezone || "Asia/Kolkata", activeShiftConfig);
64582
64708
  return currentShift.shiftName || getShiftNameById(currentShift.shiftId, timezone || "Asia/Kolkata", activeShiftConfig);
64583
64709
  }, [timezone, activeShiftConfig, shiftGroups]);
64584
- const getShiftIcon = useCallback((shiftId2) => {
64710
+ const getShiftIcon2 = useCallback((shiftId2) => {
64585
64711
  if (shiftId2 === void 0 && shiftGroups.length > 1) {
64586
64712
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
64587
64713
  }
@@ -64647,15 +64773,20 @@ var LeaderboardDetailView = memo$1(({
64647
64773
  if (!canOpenWorkspace(workspace.line_id)) {
64648
64774
  return;
64649
64775
  }
64776
+ const cycleRatio = getCycleRatio(workspace);
64650
64777
  trackCoreEvent("Workspace from Leaderboard Clicked", {
64651
64778
  workspace_name: workspace.workspace_name,
64652
64779
  workspace_id: workspace.workspace_uuid,
64653
64780
  rank,
64654
64781
  total_workspaces: workspacesLengthRef.current,
64655
64782
  // Use ref instead of state to avoid dependency
64783
+ metric_context: viewType === "machine" ? "machine" : outputCategory,
64656
64784
  efficiency: workspace.efficiency,
64657
64785
  action_count: workspace.action_count,
64658
- action_threshold: workspace.action_threshold
64786
+ action_threshold: workspace.action_threshold,
64787
+ avg_cycle_time: workspace.avg_cycle_time,
64788
+ ideal_cycle_time: workspace.ideal_cycle_time ?? null,
64789
+ cycle_ratio: cycleRatio
64659
64790
  });
64660
64791
  const displayName = workspace.displayName || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
64661
64792
  const navParams = workspace.workspace_uuid ? getWorkspaceNavigationParams(workspace.workspace_uuid, displayName, workspace.line_id) : "";
@@ -64679,7 +64810,7 @@ var LeaderboardDetailView = memo$1(({
64679
64810
  const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
64680
64811
  navigation.navigate(`/workspace/${workspace.workspace_uuid}${combinedParams}`);
64681
64812
  }
64682
- }, [canOpenWorkspace, onWorkspaceClick, navigation, date, shiftId]);
64813
+ }, [canOpenWorkspace, onWorkspaceClick, navigation, date, shiftId, outputCategory, viewType]);
64683
64814
  useEffect(() => {
64684
64815
  workspacesLengthRef.current = activeEntries.length || 0;
64685
64816
  }, [activeEntries.length]);
@@ -64700,16 +64831,20 @@ var LeaderboardDetailView = memo$1(({
64700
64831
  return activeEntries.map((ws) => ({
64701
64832
  ...ws,
64702
64833
  displayName: ws.displayName || getWorkspaceDisplayName(ws.workspace_name, ws.line_id),
64703
- lineName: getLineName(ws.line_id)
64834
+ lineName: getLineName(ws.line_id),
64835
+ isAssemblyLine: scopedLineAssemblyMap.get(ws.line_id) === true
64704
64836
  }));
64705
- }, [activeEntries, getLineName]);
64837
+ }, [activeEntries, getLineName, scopedLineAssemblyMap]);
64706
64838
  const sortedWorkspaces = useMemo(() => {
64707
64839
  let filtered = [...workspaceDisplayData];
64708
64840
  filtered = filtered.filter((ws) => {
64709
64841
  if (viewType === "machine") {
64710
64842
  return ws.monitoring_mode === "uptime";
64711
64843
  }
64712
- return ws.monitoring_mode !== "uptime";
64844
+ if (ws.monitoring_mode === "uptime") {
64845
+ return false;
64846
+ }
64847
+ return isAssemblyMode ? ws.isAssemblyLine : !ws.isAssemblyLine;
64713
64848
  });
64714
64849
  if (selectedLineFilter !== "all") {
64715
64850
  filtered = filtered.filter((ws) => ws.line_id === selectedLineFilter);
@@ -64718,13 +64853,61 @@ var LeaderboardDetailView = memo$1(({
64718
64853
  filtered = filtered.filter((ws) => ws.shift_id?.toString() === selectedShiftFilter);
64719
64854
  }
64720
64855
  return filtered.sort((a, b) => {
64856
+ if (isAssemblyMode) {
64857
+ const ratioA = getCycleRatio(a);
64858
+ const ratioB = getCycleRatio(b);
64859
+ if (ratioA === null && ratioB === null) return 0;
64860
+ if (ratioA === null) return 1;
64861
+ if (ratioB === null) return -1;
64862
+ return sortAscending ? ratioA - ratioB : ratioB - ratioA;
64863
+ }
64721
64864
  const effA = a.efficiency || 0;
64722
64865
  const effB = b.efficiency || 0;
64723
64866
  return sortAscending ? effA - effB : effB - effA;
64724
64867
  });
64725
- }, [workspaceDisplayData, sortAscending, selectedLineFilter, selectedShiftFilter, activeTab, viewType]);
64868
+ }, [workspaceDisplayData, sortAscending, selectedLineFilter, selectedShiftFilter, activeTab, viewType, isAssemblyMode]);
64726
64869
  const loading = activeTab === "today" ? todayLoading : monthlyLoading;
64727
64870
  const error = activeTab === "today" ? todayError : monthlyError;
64871
+ useEffect(() => {
64872
+ if (loading || error || sortedWorkspaces.length === 0) return;
64873
+ const trackingKey = [
64874
+ activeTab,
64875
+ viewType,
64876
+ outputCategory,
64877
+ selectedLineFilter,
64878
+ selectedShiftFilter,
64879
+ sortAscending ? "asc" : "desc",
64880
+ sortedWorkspaces.length
64881
+ ].join("|");
64882
+ if (leaderboardViewTrackedRef.current === trackingKey) return;
64883
+ leaderboardViewTrackedRef.current = trackingKey;
64884
+ const topWorkspace = sortedWorkspaces[0];
64885
+ trackCoreEvent("Workspace Leaderboard View Loaded", {
64886
+ time_range: activeTab,
64887
+ view_type: viewType,
64888
+ metric_context: viewType === "machine" ? "machine" : outputCategory,
64889
+ line_filter: selectedLineFilter,
64890
+ shift_filter: selectedShiftFilter,
64891
+ sort_direction: sortAscending ? "asc" : "desc",
64892
+ workspace_count: sortedWorkspaces.length,
64893
+ top_workspace_id: topWorkspace?.workspace_uuid ?? null,
64894
+ top_workspace_name: topWorkspace?.workspace_name ?? null,
64895
+ top_efficiency: topWorkspace?.efficiency ?? null,
64896
+ top_avg_cycle_time: topWorkspace?.avg_cycle_time ?? null,
64897
+ top_ideal_cycle_time: topWorkspace?.ideal_cycle_time ?? null,
64898
+ top_cycle_ratio: topWorkspace ? getCycleRatio(topWorkspace) : null
64899
+ });
64900
+ }, [
64901
+ loading,
64902
+ error,
64903
+ sortedWorkspaces,
64904
+ activeTab,
64905
+ viewType,
64906
+ outputCategory,
64907
+ selectedLineFilter,
64908
+ selectedShiftFilter,
64909
+ sortAscending
64910
+ ]);
64728
64911
  const currentDateFormatted = useMemo(() => {
64729
64912
  const dateStr = (/* @__PURE__ */ new Date()).toDateString();
64730
64913
  return formatDate2(new Date(dateStr));
@@ -64742,7 +64925,9 @@ var LeaderboardDetailView = memo$1(({
64742
64925
  error.message
64743
64926
  ] }) });
64744
64927
  }
64745
- const efficiencyLabel = viewType === "machine" ? "Utilization" : "Efficiency";
64928
+ const metricLabel = viewType === "machine" ? "Utilization" : isAssemblyMode ? "Cycle Time" : "Efficiency";
64929
+ const descendingSortLabel = "Highest to Lowest";
64930
+ const ascendingSortLabel = "Lowest to Highest";
64746
64931
  return /* @__PURE__ */ jsxs("div", { className: `min-h-screen bg-slate-50 flex flex-col ${className}`, style: { willChange: "contents" }, children: [
64747
64932
  /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-20 bg-white shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ jsxs("div", { className: "px-3 sm:px-6 md:px-8 py-2 sm:py-2.5", children: [
64748
64933
  /* @__PURE__ */ jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
@@ -64792,7 +64977,7 @@ var LeaderboardDetailView = memo$1(({
64792
64977
  ] }),
64793
64978
  /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
64794
64979
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
64795
- /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: efficiencyLabel }),
64980
+ /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: metricLabel }),
64796
64981
  /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
64797
64982
  "select",
64798
64983
  {
@@ -64801,8 +64986,25 @@ var LeaderboardDetailView = memo$1(({
64801
64986
  className: "w-full appearance-none pl-3 pr-8 py-2 text-sm bg-gray-50 border border-gray-200 hover:border-gray-300 rounded-lg text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-white transition-all cursor-pointer",
64802
64987
  style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.75rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
64803
64988
  children: [
64804
- /* @__PURE__ */ jsx("option", { value: "desc", children: "Highest to Lowest" }),
64805
- /* @__PURE__ */ jsx("option", { value: "asc", children: "Lowest to Highest" })
64989
+ /* @__PURE__ */ jsx("option", { value: "desc", children: descendingSortLabel }),
64990
+ /* @__PURE__ */ jsx("option", { value: "asc", children: ascendingSortLabel })
64991
+ ]
64992
+ }
64993
+ ) })
64994
+ ] }),
64995
+ showOutputCategoryDropdown && /* @__PURE__ */ jsxs("div", { className: "space-y-1 sm:hidden", children: [
64996
+ /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: "Output Type" }),
64997
+ /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
64998
+ "select",
64999
+ {
65000
+ "aria-label": "Output leaderboard category",
65001
+ value: outputCategory,
65002
+ onChange: (e) => setOutputCategory(e.target.value),
65003
+ className: "w-full appearance-none pl-3 pr-8 py-2 text-sm bg-gray-50 border border-gray-200 hover:border-gray-300 rounded-lg text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-white transition-all cursor-pointer",
65004
+ style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.75rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
65005
+ children: [
65006
+ /* @__PURE__ */ jsx("option", { value: "standard", children: "Standard" }),
65007
+ /* @__PURE__ */ jsx("option", { value: "assembly", children: "Assembly" })
64806
65008
  ]
64807
65009
  }
64808
65010
  ) })
@@ -64844,7 +65046,7 @@ var LeaderboardDetailView = memo$1(({
64844
65046
  currentDate: activeTab === "monthly" ? monthlyRangeText : currentDateFormatted,
64845
65047
  currentMobileDate: activeTab === "monthly" ? monthlyRangeText : currentMobileDateFormatted,
64846
65048
  shiftId: activeTab === "monthly" ? monthlyShiftId : todayShiftId,
64847
- getShiftIcon,
65049
+ getShiftIcon: getShiftIcon2,
64848
65050
  getShiftName,
64849
65051
  showTimer: activeTab === "today"
64850
65052
  }
@@ -64942,6 +65144,20 @@ var LeaderboardDetailView = memo$1(({
64942
65144
  ]
64943
65145
  }
64944
65146
  ) }),
65147
+ showOutputCategoryDropdown && /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
65148
+ "select",
65149
+ {
65150
+ "aria-label": "Output leaderboard category",
65151
+ value: outputCategory,
65152
+ onChange: (e) => setOutputCategory(e.target.value),
65153
+ className: "appearance-none pl-3 pr-8 py-1.5 text-sm font-medium bg-white border border-gray-200 hover:border-gray-300 rounded-lg text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all cursor-pointer shadow-sm",
65154
+ style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.5rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
65155
+ children: [
65156
+ /* @__PURE__ */ jsx("option", { value: "standard", children: "Standard" }),
65157
+ /* @__PURE__ */ jsx("option", { value: "assembly", children: "Assembly" })
65158
+ ]
65159
+ }
65160
+ ) }),
64945
65161
  /* @__PURE__ */ jsxs(
64946
65162
  "button",
64947
65163
  {
@@ -64973,7 +65189,8 @@ var LeaderboardDetailView = memo$1(({
64973
65189
  isClickable: canOpenWorkspace(ws.line_id),
64974
65190
  onWorkspaceClick: stableHandleWorkspaceClick,
64975
65191
  getMedalIcon: stableGetMedalIcon,
64976
- efficiencyLabel
65192
+ metricLabel,
65193
+ isAssemblyMode
64977
65194
  },
64978
65195
  ws.workspace_uuid
64979
65196
  );
@@ -64984,7 +65201,7 @@ var LeaderboardDetailView = memo$1(({
64984
65201
  /* @__PURE__ */ jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Rank" }),
64985
65202
  /* @__PURE__ */ jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Workspace" }),
64986
65203
  /* @__PURE__ */ jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Line" }),
64987
- /* @__PURE__ */ jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: efficiencyLabel })
65204
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: metricLabel })
64988
65205
  ] }) }),
64989
65206
  /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-gray-100", children: sortedWorkspaces.map((ws, index) => {
64990
65207
  const isTopThree = index < 3;
@@ -64997,7 +65214,8 @@ var LeaderboardDetailView = memo$1(({
64997
65214
  rowClass,
64998
65215
  isClickable: canOpenWorkspace(ws.line_id),
64999
65216
  onWorkspaceClick: stableHandleWorkspaceClick,
65000
- getMedalIcon: stableGetMedalIcon
65217
+ getMedalIcon: stableGetMedalIcon,
65218
+ isAssemblyMode
65001
65219
  },
65002
65220
  ws.workspace_uuid
65003
65221
  );
@@ -65015,7 +65233,10 @@ function LoginView({
65015
65233
  logoSrc = optifye_logo_default,
65016
65234
  logoAlt = "Optifye",
65017
65235
  brandName = "Optifye",
65018
- onRateLimitCheck
65236
+ onRateLimitCheck,
65237
+ showDevTestLogin = false,
65238
+ devTestLoginLabel,
65239
+ onDevTestLogin
65019
65240
  }) {
65020
65241
  return /* @__PURE__ */ jsx(
65021
65242
  LoginPage,
@@ -65023,7 +65244,10 @@ function LoginView({
65023
65244
  logoSrc,
65024
65245
  logoAlt,
65025
65246
  brandName,
65026
- onRateLimitCheck
65247
+ onRateLimitCheck,
65248
+ showDevTestLogin,
65249
+ devTestLoginLabel,
65250
+ onDevTestLogin
65027
65251
  }
65028
65252
  );
65029
65253
  }
@@ -68211,20 +68435,30 @@ function useTimezone(options = {}) {
68211
68435
  }
68212
68436
 
68213
68437
  // src/views/workspace-detail-view.utils.ts
68214
- var getWorkspaceCycleTimePresentation = ({
68438
+ var getWorkspaceDetailLayoutMode = ({
68215
68439
  workspace,
68216
68440
  showCycleTimeChart
68217
68441
  }) => {
68218
68442
  if (workspace?.monitoring_mode === "uptime") {
68219
- return "output";
68443
+ return "uptime";
68220
68444
  }
68221
68445
  if (showCycleTimeChart === false) {
68222
68446
  return "output";
68223
68447
  }
68224
- if (!shouldUseAssemblyCycleTimeLayout(workspace)) {
68448
+ return shouldUseAssemblyCycleTimeLayout(workspace) ? "assembly_cycle" : "output";
68449
+ };
68450
+ var getCycleTimeRenderState = ({
68451
+ workspace,
68452
+ authoritativeMetrics,
68453
+ showCycleTimeChart
68454
+ }) => {
68455
+ if (getWorkspaceDetailLayoutMode({ workspace, showCycleTimeChart }) !== "assembly_cycle") {
68225
68456
  return "output";
68226
68457
  }
68227
- return workspace?.cycle_time_data_status === "missing_clips" ? "cycle_unavailable" : "cycle_chart";
68458
+ if (!authoritativeMetrics) {
68459
+ return "chart_loading";
68460
+ }
68461
+ return authoritativeMetrics.cycle_time_data_status === "missing_clips" ? "cycle_unavailable" : "cycle_chart";
68228
68462
  };
68229
68463
  var formatDateInTimezone = (date = /* @__PURE__ */ new Date(), timezone, options) => {
68230
68464
  const defaultOptions = {
@@ -68632,33 +68866,34 @@ var WorkspaceDetailView = ({
68632
68866
  idle_time_hourly: void 0
68633
68867
  };
68634
68868
  }, [cachedOverviewMetrics, shiftConfig?.shifts]);
68635
- const workspace = (isHistoricView ? historicMetrics : liveMetrics) || cachedDetailedMetrics || overviewFallback;
68869
+ const authoritativeCycleMetrics = isHistoricView ? historicMetrics : liveMetrics;
68870
+ const workspace = authoritativeCycleMetrics || cachedDetailedMetrics || overviewFallback;
68636
68871
  const { timezone: cycleTimeTimezone } = useTimezone({
68637
68872
  lineId: effectiveLineId || workspace?.line_id || void 0,
68638
68873
  workspaceId: workspaceId || void 0
68639
68874
  });
68640
68875
  const effectiveCycleTimeTimezone = cycleTimeTimezone || timezone;
68641
- const detailedWorkspaceMetrics = (isHistoricView ? historicMetrics : liveMetrics) || cachedDetailedMetrics;
68876
+ const detailedWorkspaceMetrics = authoritativeCycleMetrics || cachedDetailedMetrics;
68642
68877
  const cycleTimeChartData = useMemo(
68643
- () => Array.isArray(workspace?.hourly_cycle_times) ? workspace.hourly_cycle_times.map((value) => {
68878
+ () => Array.isArray(authoritativeCycleMetrics?.hourly_cycle_times) ? authoritativeCycleMetrics.hourly_cycle_times.map((value) => {
68644
68879
  const numericValue = Number(value);
68645
68880
  return Number.isFinite(numericValue) ? numericValue : 0;
68646
68881
  }) : [],
68647
- [workspace?.hourly_cycle_times]
68882
+ [authoritativeCycleMetrics?.hourly_cycle_times]
68648
68883
  );
68649
68884
  const maskedCycleTimeChartData = useMemo(
68650
68885
  () => maskFutureHourlySeries({
68651
68886
  data: cycleTimeChartData,
68652
- shiftStart: workspace?.shift_start,
68653
- shiftEnd: workspace?.shift_end,
68654
- shiftDate: workspace?.date || date || calculatedOperationalDate || null,
68887
+ shiftStart: authoritativeCycleMetrics?.shift_start,
68888
+ shiftEnd: authoritativeCycleMetrics?.shift_end,
68889
+ shiftDate: authoritativeCycleMetrics?.date || date || calculatedOperationalDate || null,
68655
68890
  timezone: effectiveCycleTimeTimezone
68656
68891
  }),
68657
68892
  [
68658
68893
  cycleTimeChartData,
68659
- workspace?.shift_start,
68660
- workspace?.shift_end,
68661
- workspace?.date,
68894
+ authoritativeCycleMetrics?.shift_start,
68895
+ authoritativeCycleMetrics?.shift_end,
68896
+ authoritativeCycleMetrics?.date,
68662
68897
  date,
68663
68898
  calculatedOperationalDate,
68664
68899
  effectiveCycleTimeTimezone
@@ -68666,13 +68901,13 @@ var WorkspaceDetailView = ({
68666
68901
  );
68667
68902
  const cycleTimeDatasetKey = useMemo(
68668
68903
  () => [
68669
- workspace?.workspace_id || workspaceId || "workspace",
68670
- date || workspace?.date || "live",
68671
- parsedShiftId ?? workspace?.shift_id ?? "current",
68904
+ authoritativeCycleMetrics?.workspace_id || workspaceId || "workspace",
68905
+ date || authoritativeCycleMetrics?.date || "live",
68906
+ parsedShiftId ?? authoritativeCycleMetrics?.shift_id ?? "current",
68672
68907
  "hourly",
68673
68908
  "backend"
68674
68909
  ].join(":"),
68675
- [workspace?.workspace_id, workspaceId, date, workspace?.date, parsedShiftId, workspace?.shift_id]
68910
+ [authoritativeCycleMetrics?.workspace_id, workspaceId, date, authoritativeCycleMetrics?.date, parsedShiftId, authoritativeCycleMetrics?.shift_id]
68676
68911
  );
68677
68912
  const hasWorkspaceSnapshot = Boolean(workspace);
68678
68913
  const loading = ((isHistoricView ? historicLoading : liveLoading) || isShiftConfigLoading) && !hasWorkspaceSnapshot;
@@ -68921,30 +69156,46 @@ var WorkspaceDetailView = ({
68921
69156
  action_type: workspace.action_type
68922
69157
  } : null;
68923
69158
  const isAssemblyWorkspace = shouldUseAssemblyCycleTimeLayout(workspaceCycleTimeEligibility);
68924
- const cycleTimePresentation = getWorkspaceCycleTimePresentation({
69159
+ const layoutMode = getWorkspaceDetailLayoutMode({
68925
69160
  workspace: workspace ? {
68926
69161
  monitoring_mode: workspace.monitoring_mode,
68927
69162
  line_assembly_enabled: workspace.line_assembly_enabled,
68928
69163
  action_family: workspace.action_family,
68929
- action_type: workspace.action_type,
68930
- cycle_time_data_status: workspace.cycle_time_data_status
69164
+ action_type: workspace.action_type
68931
69165
  } : null,
68932
69166
  showCycleTimeChart
68933
69167
  });
68934
- const shouldShowCycleTimeChart = cycleTimePresentation !== "output";
69168
+ const isAssemblyCycleLayout = layoutMode === "assembly_cycle";
69169
+ const isOutputLayout = layoutMode === "output";
69170
+ const cycleTimePresentation = getCycleTimeRenderState({
69171
+ workspace: workspace ? {
69172
+ monitoring_mode: workspace.monitoring_mode,
69173
+ line_assembly_enabled: workspace.line_assembly_enabled,
69174
+ action_family: workspace.action_family,
69175
+ action_type: workspace.action_type
69176
+ } : null,
69177
+ authoritativeMetrics: authoritativeCycleMetrics ? {
69178
+ cycle_time_data_status: authoritativeCycleMetrics.cycle_time_data_status
69179
+ } : null,
69180
+ showCycleTimeChart
69181
+ });
69182
+ const shouldShowCycleTimeChart = cycleTimePresentation === "cycle_chart";
68935
69183
  const shouldShowCycleTimeUnavailableState = cycleTimePresentation === "cycle_unavailable";
68936
- const showIdleBreakdownChart = !shouldShowCycleTimeChart && idleTimeVlmEnabled;
69184
+ const shouldShowCycleTimeLoadingState = cycleTimePresentation === "chart_loading";
69185
+ const shouldShowAssemblyOverviewLoadingState = isAssemblyCycleLayout && shouldShowCycleTimeLoadingState && hasWorkspaceSnapshot;
69186
+ const showIdleBreakdownChart = !isAssemblyCycleLayout && idleTimeVlmEnabled;
69187
+ const canToggleChartIdleTime = !isUptimeMode && !shouldShowCycleTimeLoadingState && !shouldShowCycleTimeUnavailableState;
68937
69188
  const idleClipDate = date || workspace?.date || calculatedOperationalDate || getOperationalDate(timezone);
68938
69189
  const idleClipShiftId = parsedShiftId ?? workspace?.shift_id;
68939
69190
  const rawHourlyIdleMinutes = useMemo(() => {
68940
69191
  if (!shouldShowCycleTimeChart || !workspace?.idle_time_hourly || !workspace?.shift_start) return [];
68941
- const parseTimeToMinutes3 = (time2) => {
69192
+ const parseTimeToMinutes4 = (time2) => {
68942
69193
  const [h, m] = time2.split(":").map(Number);
68943
69194
  if (!Number.isFinite(h) || !Number.isFinite(m)) return 0;
68944
69195
  return h * 60 + m;
68945
69196
  };
68946
- const startTotal = parseTimeToMinutes3(workspace.shift_start);
68947
- const endTotalRaw = workspace.shift_end ? parseTimeToMinutes3(workspace.shift_end) : startTotal + 11 * 60;
69197
+ const startTotal = parseTimeToMinutes4(workspace.shift_start);
69198
+ const endTotalRaw = workspace.shift_end ? parseTimeToMinutes4(workspace.shift_end) : startTotal + 11 * 60;
68948
69199
  const endTotal = endTotalRaw <= startTotal ? endTotalRaw + 24 * 60 : endTotalRaw;
68949
69200
  const shiftDuration = Math.max(60, endTotal - startTotal);
68950
69201
  const totalHourSlots = Math.max(1, Math.ceil(shiftDuration / 60));
@@ -68994,6 +69245,18 @@ var WorkspaceDetailView = ({
68994
69245
  workspace.cycle_completion_clip_count
68995
69246
  ] })
68996
69247
  ] }), [workspace?.cycle_completion_clip_count]);
69248
+ const assemblyOverviewLoadingView = useMemo(() => /* @__PURE__ */ jsxs("div", { className: "space-y-4 pb-4", "data-testid": "assembly-overview-loading-state", children: [
69249
+ /* @__PURE__ */ jsx("div", { className: "bg-white rounded-lg shadow-sm p-6 lg:p-8", children: /* @__PURE__ */ jsx("div", { className: "min-h-[280px] lg:min-h-[340px] flex flex-col justify-center", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-xl mx-auto animate-pulse space-y-3", children: [
69250
+ /* @__PURE__ */ jsx("div", { className: "h-3 bg-gray-200 rounded-full w-3/4 mx-auto" }),
69251
+ /* @__PURE__ */ jsx("div", { className: "h-3 bg-gray-100 rounded-full w-full" }),
69252
+ /* @__PURE__ */ jsx("div", { className: "h-3 bg-gray-100 rounded-full w-5/6 mx-auto" })
69253
+ ] }) }) }),
69254
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: [0, 1, 2].map((index) => /* @__PURE__ */ jsx("div", { className: "bg-white rounded-lg shadow-sm p-5", children: /* @__PURE__ */ jsxs("div", { className: "animate-pulse space-y-3", children: [
69255
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-24 bg-gray-200 rounded" }),
69256
+ /* @__PURE__ */ jsx("div", { className: "h-10 w-20 bg-gray-100 rounded" }),
69257
+ /* @__PURE__ */ jsx("div", { className: "h-3 w-28 bg-gray-100 rounded" })
69258
+ ] }) }, index)) })
69259
+ ] }), []);
68997
69260
  const shiftDurationMinutes = useMemo(
68998
69261
  () => getShiftDurationMinutes(workspace?.shift_start, workspace?.shift_end),
68999
69262
  [workspace?.shift_start, workspace?.shift_end]
@@ -69048,7 +69311,7 @@ var WorkspaceDetailView = ({
69048
69311
  }, [isUptimeMode, uptimeSeries, shiftDurationMinutes, elapsedShiftMinutes, workspace?.idle_time]);
69049
69312
  const overviewTabLabel = isUptimeMode ? "Utilization" : "Efficiency";
69050
69313
  const idleClipFetchEnabled = Boolean(
69051
- workspaceId && idleClipDate && idleClipShiftId !== void 0 && activeTab === "overview" && idleTimeVlmEnabled && !shouldShowCycleTimeChart && !isUptimeMode
69314
+ workspaceId && idleClipDate && idleClipShiftId !== void 0 && activeTab === "overview" && idleTimeVlmEnabled && isOutputLayout
69052
69315
  );
69053
69316
  const {
69054
69317
  idleClips: idleTimeClips,
@@ -69119,7 +69382,7 @@ var WorkspaceDetailView = ({
69119
69382
  }
69120
69383
  }
69121
69384
  };
69122
- const getShiftIcon = (shiftType) => {
69385
+ const getShiftIcon2 = (shiftType) => {
69123
69386
  const shiftTypeLower = shiftType?.toLowerCase() || "";
69124
69387
  if (shiftTypeLower.includes("day") || shiftTypeLower.includes("morning")) {
69125
69388
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
@@ -69268,7 +69531,7 @@ var WorkspaceDetailView = ({
69268
69531
  /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: (() => {
69269
69532
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
69270
69533
  const shiftName = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
69271
- return getShiftIcon(shiftName);
69534
+ return getShiftIcon2(shiftName);
69272
69535
  })() }),
69273
69536
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: (() => {
69274
69537
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
@@ -69296,7 +69559,7 @@ var WorkspaceDetailView = ({
69296
69559
  /* @__PURE__ */ jsx("div", { className: "opacity-70", children: (() => {
69297
69560
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
69298
69561
  const shiftName = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
69299
- return getShiftIcon(shiftName);
69562
+ return getShiftIcon2(shiftName);
69300
69563
  })() }),
69301
69564
  /* @__PURE__ */ jsx("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: (() => {
69302
69565
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
@@ -69309,7 +69572,7 @@ var WorkspaceDetailView = ({
69309
69572
  /* @__PURE__ */ jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
69310
69573
  /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: formatISTDate2(new Date(workspace.date)) }) }),
69311
69574
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
69312
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(workspace.shift_type) }),
69575
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(workspace.shift_type) }),
69313
69576
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: workspace.shift_type })
69314
69577
  ] }),
69315
69578
  !date && !shift && !usingFallbackData ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsx(LiveTimer, {}) }) }) : date ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : usingFallbackData ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-amber-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-amber-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : null
@@ -69340,7 +69603,7 @@ var WorkspaceDetailView = ({
69340
69603
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" })
69341
69604
  ] }),
69342
69605
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
69343
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(workspace.shift_type) }),
69606
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon2(workspace.shift_type) }),
69344
69607
  /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
69345
69608
  workspace.shift_type.replace(/ Shift$/i, ""),
69346
69609
  " Shift"
@@ -69459,9 +69722,9 @@ var WorkspaceDetailView = ({
69459
69722
  ] })
69460
69723
  ] }),
69461
69724
  /* @__PURE__ */ jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4", children: [
69462
- activeTab === "overview" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full lg:h-[calc(100vh-12rem)] overflow-y-auto lg:min-h-0 pb-4", children: [
69725
+ activeTab === "overview" && /* @__PURE__ */ jsx("div", { className: "flex flex-col h-full lg:h-[calc(100vh-12rem)] overflow-y-auto lg:min-h-0 pb-4", children: shouldShowAssemblyOverviewLoadingState ? assemblyOverviewLoadingView : /* @__PURE__ */ jsxs(Fragment, { children: [
69463
69726
  /* @__PURE__ */ jsxs("div", { className: "block lg:hidden space-y-6 pb-6", children: [
69464
- !shouldShowCycleTimeChart && !isUptimeMode && /* @__PURE__ */ jsxs(
69727
+ isOutputLayout && !isUptimeMode && /* @__PURE__ */ jsxs(
69465
69728
  motion.div,
69466
69729
  {
69467
69730
  className: "bg-white rounded-lg shadow-sm p-6 h-[300px]",
@@ -69489,8 +69752,8 @@ var WorkspaceDetailView = ({
69489
69752
  animate: "animate",
69490
69753
  children: [
69491
69754
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-4", children: [
69492
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle time trend" : "Hourly Output" }),
69493
- !isUptimeMode && !shouldShowCycleTimeUnavailableState && /* @__PURE__ */ jsx(
69755
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : isAssemblyCycleLayout ? "Cycle time trend" : "Hourly Output" }),
69756
+ canToggleChartIdleTime && /* @__PURE__ */ jsx(
69494
69757
  "button",
69495
69758
  {
69496
69759
  onClick: () => setShowChartIdleTime(!showChartIdleTime),
@@ -69519,19 +69782,19 @@ var WorkspaceDetailView = ({
69519
69782
  timezone,
69520
69783
  elapsedMinutes: elapsedShiftMinutes
69521
69784
  }
69522
- ) : shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69785
+ ) : isAssemblyCycleLayout ? shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69523
69786
  CycleTimeOverTimeChart,
69524
69787
  {
69525
69788
  data: maskedCycleTimeChartData,
69526
- idealCycleTime: workspace.ideal_cycle_time || 0,
69527
- shiftStart: workspace.shift_start || "",
69528
- shiftEnd: workspace.shift_end || "",
69789
+ idealCycleTime: authoritativeCycleMetrics?.ideal_cycle_time || 0,
69790
+ shiftStart: authoritativeCycleMetrics?.shift_start || "",
69791
+ shiftEnd: authoritativeCycleMetrics?.shift_end || "",
69529
69792
  xAxisMode: "hourly",
69530
69793
  datasetKey: cycleTimeDatasetKey,
69531
69794
  showIdleTime: showChartIdleTime,
69532
69795
  idleTimeData: hourlyIdleMinutes
69533
69796
  }
69534
- ) : /* @__PURE__ */ jsx(
69797
+ ) : null : /* @__PURE__ */ jsx(
69535
69798
  HourlyOutputChart2,
69536
69799
  {
69537
69800
  data: workspace.hourly_action_counts || [],
@@ -69551,7 +69814,7 @@ var WorkspaceDetailView = ({
69551
69814
  ]
69552
69815
  }
69553
69816
  ),
69554
- !shouldShowCycleTimeChart && idleTimeVlmEnabled && /* @__PURE__ */ jsxs(
69817
+ showIdleBreakdownChart && /* @__PURE__ */ jsxs(
69555
69818
  motion.div,
69556
69819
  {
69557
69820
  className: "bg-white rounded-lg shadow-sm p-4 h-[300px]",
@@ -69571,7 +69834,7 @@ var WorkspaceDetailView = ({
69571
69834
  ]
69572
69835
  }
69573
69836
  ),
69574
- isUptimeMode ? /* @__PURE__ */ jsx(UptimeMetricCards, { workspace, uptimePieData }) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69837
+ isUptimeMode ? /* @__PURE__ */ jsx(UptimeMetricCards, { workspace, uptimePieData }) : isAssemblyCycleLayout ? /* @__PURE__ */ jsx(
69575
69838
  WorkspaceCycleTimeMetricCards,
69576
69839
  {
69577
69840
  workspace,
@@ -69591,7 +69854,7 @@ var WorkspaceDetailView = ({
69591
69854
  desktopTopSectionClass
69592
69855
  ),
69593
69856
  children: [
69594
- !shouldShowCycleTimeChart && !isUptimeMode && /* @__PURE__ */ jsxs(
69857
+ isOutputLayout && !isUptimeMode && /* @__PURE__ */ jsxs(
69595
69858
  motion.div,
69596
69859
  {
69597
69860
  className: "bg-white rounded-lg shadow-sm p-4 lg:col-span-2 flex flex-col min-h-0",
@@ -69615,15 +69878,15 @@ var WorkspaceDetailView = ({
69615
69878
  {
69616
69879
  className: clsx(
69617
69880
  "bg-white rounded-lg shadow-sm p-4 flex flex-col min-h-0",
69618
- isUptimeMode && showIdleBreakdownChart ? "lg:col-span-2" : shouldShowCycleTimeChart || isUptimeMode ? "lg:col-span-10" : idleTimeVlmEnabled ? "lg:col-span-6" : "lg:col-span-8"
69881
+ isUptimeMode && showIdleBreakdownChart ? "lg:col-span-2" : isAssemblyCycleLayout || isUptimeMode ? "lg:col-span-10" : idleTimeVlmEnabled ? "lg:col-span-6" : "lg:col-span-8"
69619
69882
  ),
69620
69883
  variants: chartCardVariants,
69621
69884
  initial: "initial",
69622
69885
  animate: "animate",
69623
69886
  children: [
69624
69887
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 mb-4 flex-none", children: [
69625
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle time trend" : "Hourly Output" }),
69626
- !isUptimeMode && !shouldShowCycleTimeUnavailableState && /* @__PURE__ */ jsx(
69888
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : isAssemblyCycleLayout ? "Cycle time trend" : "Hourly Output" }),
69889
+ canToggleChartIdleTime && /* @__PURE__ */ jsx(
69627
69890
  "button",
69628
69891
  {
69629
69892
  onClick: () => setShowChartIdleTime(!showChartIdleTime),
@@ -69648,19 +69911,19 @@ var WorkspaceDetailView = ({
69648
69911
  timezone,
69649
69912
  elapsedMinutes: elapsedShiftMinutes
69650
69913
  }
69651
- ) : shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69914
+ ) : isAssemblyCycleLayout ? shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69652
69915
  CycleTimeOverTimeChart,
69653
69916
  {
69654
69917
  data: maskedCycleTimeChartData,
69655
- idealCycleTime: workspace.ideal_cycle_time || 0,
69656
- shiftStart: workspace.shift_start || "",
69657
- shiftEnd: workspace.shift_end || "",
69918
+ idealCycleTime: authoritativeCycleMetrics?.ideal_cycle_time || 0,
69919
+ shiftStart: authoritativeCycleMetrics?.shift_start || "",
69920
+ shiftEnd: authoritativeCycleMetrics?.shift_end || "",
69658
69921
  xAxisMode: "hourly",
69659
69922
  datasetKey: cycleTimeDatasetKey,
69660
69923
  showIdleTime: showChartIdleTime,
69661
69924
  idleTimeData: hourlyIdleMinutes
69662
69925
  }
69663
- ) : /* @__PURE__ */ jsx(
69926
+ ) : null : /* @__PURE__ */ jsx(
69664
69927
  HourlyOutputChart2,
69665
69928
  {
69666
69929
  data: workspace.hourly_action_counts || [],
@@ -69678,7 +69941,7 @@ var WorkspaceDetailView = ({
69678
69941
  ]
69679
69942
  }
69680
69943
  ),
69681
- !shouldShowCycleTimeChart && idleTimeVlmEnabled && /* @__PURE__ */ jsxs(
69944
+ showIdleBreakdownChart && /* @__PURE__ */ jsxs(
69682
69945
  motion.div,
69683
69946
  {
69684
69947
  className: clsx(
@@ -69704,7 +69967,7 @@ var WorkspaceDetailView = ({
69704
69967
  ]
69705
69968
  }
69706
69969
  ),
69707
- isUptimeMode ? /* @__PURE__ */ jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsx(UptimeMetricCards, { workspace, uptimePieData, className: "flex-1" }) }) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69970
+ isUptimeMode ? /* @__PURE__ */ jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsx(UptimeMetricCards, { workspace, uptimePieData, className: "flex-1" }) }) : isAssemblyCycleLayout ? /* @__PURE__ */ jsx(
69708
69971
  WorkspaceCycleTimeMetricCards,
69709
69972
  {
69710
69973
  workspace,
@@ -69715,7 +69978,7 @@ var WorkspaceDetailView = ({
69715
69978
  }
69716
69979
  ) : /* @__PURE__ */ jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsx(WorkspaceMetricCards, { workspace, legend: efficiencyLegend, className: "flex-1" }) })
69717
69980
  ] })
69718
- ] }),
69981
+ ] }) }),
69719
69982
  activeTab === "monthly_history" && /* @__PURE__ */ jsxs("div", { className: "h-[calc(100vh-10rem)] overflow-y-auto px-2 sm:px-4 lg:px-0", children: [
69720
69983
  usingFallbackData && !date && !shift && /* @__PURE__ */ jsx("div", { className: "mb-3 sm:mb-4 bg-amber-50 border border-amber-200 rounded-lg px-3 sm:px-4 py-2 sm:py-3 text-amber-800", children: /* @__PURE__ */ jsxs("p", { className: "text-xs sm:text-sm font-medium flex items-center", children: [
69721
69984
  /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-4 w-4 sm:h-5 sm:w-5 mr-2", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) }),
@@ -72347,7 +72610,7 @@ var normalizeLabel = (value) => {
72347
72610
  const trimmed = value.trim();
72348
72611
  return trimmed.length > 0 ? trimmed : void 0;
72349
72612
  };
72350
- var toFiniteNumber = (value) => {
72613
+ var toFiniteNumber2 = (value) => {
72351
72614
  if (typeof value === "number" && Number.isFinite(value)) return value;
72352
72615
  if (typeof value === "string" && value.trim().length > 0) {
72353
72616
  const parsed = Number(value);
@@ -72381,7 +72644,7 @@ var formatImprovementPieceGain = (pcsGain) => {
72381
72644
  var getPositiveImprovementGain = ({
72382
72645
  estimated_gain_pieces
72383
72646
  }) => {
72384
- const issueGain = toFiniteNumber(estimated_gain_pieces);
72647
+ const issueGain = toFiniteNumber2(estimated_gain_pieces);
72385
72648
  return {
72386
72649
  pcsGain: issueGain !== null && issueGain > 0 ? issueGain : null
72387
72650
  };
@@ -72389,7 +72652,7 @@ var getPositiveImprovementGain = ({
72389
72652
  var getImprovementPcsGainSortValue = (input) => {
72390
72653
  const { pcsGain } = getPositiveImprovementGain(input);
72391
72654
  if (pcsGain !== null) return pcsGain;
72392
- const raw = toFiniteNumber(input.estimated_gain_pieces);
72655
+ const raw = toFiniteNumber2(input.estimated_gain_pieces);
72393
72656
  return raw ?? null;
72394
72657
  };
72395
72658
  var getImprovementDisplayMetadata = ({
@@ -72409,7 +72672,7 @@ var getImprovementDisplayMetadata = ({
72409
72672
  metadataLabel: [workstationLabel, lineLabel, supervisorLabel].join(" \xB7 ")
72410
72673
  };
72411
72674
  };
72412
- var toFiniteNumber2 = (value) => {
72675
+ var toFiniteNumber3 = (value) => {
72413
72676
  if (typeof value === "number" && Number.isFinite(value)) return value;
72414
72677
  if (typeof value === "string" && value.trim().length > 0) {
72415
72678
  const parsed = Number(value);
@@ -72437,15 +72700,15 @@ var compareImprovementRecommendationPriority = (left, right) => {
72437
72700
  if (leftIndustrial !== rightIndustrial) {
72438
72701
  return rightIndustrial - leftIndustrial;
72439
72702
  }
72440
- const leftGain = toFiniteNumber2(left.estimated_gain_pieces);
72441
- const rightGain = toFiniteNumber2(right.estimated_gain_pieces);
72703
+ const leftGain = toFiniteNumber3(left.estimated_gain_pieces);
72704
+ const rightGain = toFiniteNumber3(right.estimated_gain_pieces);
72442
72705
  if (leftGain !== rightGain) {
72443
72706
  if (leftGain === null) return 1;
72444
72707
  if (rightGain === null) return -1;
72445
72708
  return rightGain - leftGain;
72446
72709
  }
72447
- const leftRatio = toFiniteNumber2(left.gain_to_target_ratio);
72448
- const rightRatio = toFiniteNumber2(right.gain_to_target_ratio);
72710
+ const leftRatio = toFiniteNumber3(left.gain_to_target_ratio);
72711
+ const rightRatio = toFiniteNumber3(right.gain_to_target_ratio);
72449
72712
  if (leftRatio !== rightRatio) {
72450
72713
  if (leftRatio === null) return 1;
72451
72714
  if (rightRatio === null) return -1;
@@ -75750,6 +76013,7 @@ var EMPTY_OVERVIEW_POOREST_LINES = {
75750
76013
  };
75751
76014
  var EMPTY_OVERVIEW_TREND = {
75752
76015
  shift_mode: "all",
76016
+ granularity: "day",
75753
76017
  points: []
75754
76018
  };
75755
76019
  var EMPTY_IDLE_BREAKDOWN = [];
@@ -75822,8 +76086,11 @@ var normalizePoorestLines = (value) => ({
75822
76086
  });
75823
76087
  var normalizeTrend = (value) => ({
75824
76088
  shift_mode: value?.shift_mode || "all",
76089
+ granularity: value?.granularity === "hour" ? "hour" : "day",
75825
76090
  points: (value?.points || []).map((point) => ({
75826
76091
  date: point?.date,
76092
+ label: point?.label,
76093
+ hour_index: normalizeNumber(point?.hour_index),
75827
76094
  avg_efficiency: normalizeNumber(point?.avg_efficiency)
75828
76095
  }))
75829
76096
  });
@@ -76165,17 +76432,25 @@ var formatSignedIdleDuration = (seconds) => {
76165
76432
  const sign = seconds > 0 ? "+" : "-";
76166
76433
  return `${sign}${formatIdleDuration(Math.abs(seconds))}`;
76167
76434
  };
76168
- var formatComparisonWindow = (dayCount, comparisonStrategy) => {
76435
+ var formatComparisonWindow = ({
76436
+ currentDayCount,
76437
+ previousDayCount,
76438
+ comparisonStrategy,
76439
+ shiftMode
76440
+ }) => {
76169
76441
  if (comparisonStrategy === "previous_full_week") return "last week";
76170
- if (!dayCount || !Number.isFinite(dayCount)) return "previous range";
76171
- return `previous ${dayCount} ${dayCount === 1 ? "day" : "days"}`;
76442
+ if (comparisonStrategy === "matched_range" && currentDayCount === 1 && previousDayCount === 1) {
76443
+ return "previous day";
76444
+ }
76445
+ if (!previousDayCount || !Number.isFinite(previousDayCount)) return "previous range";
76446
+ return `previous ${previousDayCount} ${previousDayCount === 1 ? "day" : "days"}`;
76172
76447
  };
76173
76448
  var buildDeltaBadge = (delta, options) => {
76174
76449
  if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
76175
76450
  return {
76176
76451
  icon: null,
76177
- className: "bg-slate-100 text-slate-500",
76178
- text: `No ${options.comparisonLabel} baseline`
76452
+ className: "bg-slate-100 text-slate-400",
76453
+ text: "\u2014"
76179
76454
  };
76180
76455
  }
76181
76456
  const direction = delta >= 0 ? "up" : "down";
@@ -76186,6 +76461,34 @@ var buildDeltaBadge = (delta, options) => {
76186
76461
  text: `${options.formatter(delta)} vs ${options.comparisonLabel}`
76187
76462
  };
76188
76463
  };
76464
+ var normalizeShiftLabel = (shiftName, shiftMode) => {
76465
+ if (shiftMode === "all") {
76466
+ return "All Shifts";
76467
+ }
76468
+ const trimmedName = shiftName?.trim();
76469
+ if (trimmedName) {
76470
+ const normalizedName = trimmedName.toLowerCase();
76471
+ if (normalizedName === "day") return "Day Shift";
76472
+ if (normalizedName === "night") return "Night Shift";
76473
+ return /shift/i.test(trimmedName) ? trimmedName : `${trimmedName} Shift`;
76474
+ }
76475
+ if (shiftMode === "night") return "Night Shift";
76476
+ return "Day Shift";
76477
+ };
76478
+ var getShiftIcon = (shiftName, shiftMode) => {
76479
+ const normalizedName = (shiftName || "").toLowerCase();
76480
+ const normalizedMode = shiftMode || "day";
76481
+ if (normalizedMode === "all") {
76482
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
76483
+ }
76484
+ if (normalizedName.includes("day") || normalizedName.includes("morning") || normalizedMode === "day") {
76485
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
76486
+ }
76487
+ if (normalizedName.includes("night") || normalizedName.includes("evening") || normalizedMode === "night") {
76488
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
76489
+ }
76490
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
76491
+ };
76189
76492
  var buildLineDeltaTone = (delta, comparisonLabel) => {
76190
76493
  if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
76191
76494
  return {
@@ -76241,6 +76544,8 @@ var OperationsOverviewHeader = React141__default.memo(({
76241
76544
  dateRange,
76242
76545
  displayDateRange,
76243
76546
  trendMode,
76547
+ isLiveScope,
76548
+ liveShiftName,
76244
76549
  lineOptions,
76245
76550
  supervisorOptions,
76246
76551
  selectedSupervisorId,
@@ -76254,6 +76559,15 @@ var OperationsOverviewHeader = React141__default.memo(({
76254
76559
  }) => {
76255
76560
  bumpRenderCounter();
76256
76561
  const subtitleRange = displayDateRange || dateRange;
76562
+ const showLiveShiftMeta = isLiveScope && trendMode !== "all";
76563
+ const liveShiftLabel = React141__default.useMemo(
76564
+ () => normalizeShiftLabel(liveShiftName, trendMode),
76565
+ [liveShiftName, trendMode]
76566
+ );
76567
+ const liveShiftIcon = React141__default.useMemo(
76568
+ () => getShiftIcon(liveShiftName, trendMode),
76569
+ [liveShiftName, trendMode]
76570
+ );
76257
76571
  const [isFilterOpen, setIsFilterOpen] = React141__default.useState(false);
76258
76572
  const [isLinesDropdownOpen, setIsLinesDropdownOpen] = React141__default.useState(false);
76259
76573
  const filterRef = React141__default.useRef(null);
@@ -76370,9 +76684,25 @@ var OperationsOverviewHeader = React141__default.memo(({
76370
76684
  className: "flex-shrink-0 -ml-1"
76371
76685
  }
76372
76686
  ) : /* @__PURE__ */ jsx("div", { className: "w-8 flex-shrink-0" }),
76373
- /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center", children: [
76374
- /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-gray-900 text-center px-1 truncate max-w-[200px]", children: "Operations Overview" }),
76375
- /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-slate-500 text-center mt-0.5", children: mobileSubtitle })
76687
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center min-w-0", children: [
76688
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-1.5 min-w-0 max-w-[240px]", children: [
76689
+ /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-gray-900 leading-tight text-center truncate", children: "Operations Overview" }),
76690
+ isLiveScope ? /* @__PURE__ */ jsx(
76691
+ "div",
76692
+ {
76693
+ "data-testid": "operations-overview-live-indicator",
76694
+ className: "h-2 w-2 rounded-full bg-emerald-500 animate-pulse ring-2 ring-emerald-500/20 flex-shrink-0"
76695
+ }
76696
+ ) : null
76697
+ ] }),
76698
+ /* @__PURE__ */ jsxs("div", { className: "mt-1 flex flex-wrap items-center justify-center gap-x-2 gap-y-1 text-[11px] font-medium text-slate-500 min-w-0", children: [
76699
+ /* @__PURE__ */ jsx("span", { className: "truncate text-center", children: mobileSubtitle }),
76700
+ showLiveShiftMeta ? /* @__PURE__ */ jsx("span", { className: "text-slate-300", children: "|" }) : null,
76701
+ showLiveShiftMeta ? /* @__PURE__ */ jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600 min-w-0", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 justify-center truncate", children: [
76702
+ /* @__PURE__ */ jsx("span", { className: "opacity-75 shrink-0", children: liveShiftIcon }),
76703
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: liveShiftLabel })
76704
+ ] }) }) : null
76705
+ ] })
76376
76706
  ] }),
76377
76707
  /* @__PURE__ */ jsxs("div", { className: "flex-shrink-0 flex items-center gap-1.5", children: [
76378
76708
  /* @__PURE__ */ jsx(
@@ -76391,22 +76721,40 @@ var OperationsOverviewHeader = React141__default.memo(({
76391
76721
  {
76392
76722
  ref: mobileFilterButtonRef,
76393
76723
  onClick: handleFilterToggle,
76394
- className: `p-2 rounded-full transition-colors relative ${isFilterOpen || activeFilterCount > 0 ? "bg-blue-50" : "active:bg-gray-100"}`,
76724
+ className: `p-2 rounded-full transition-colors relative ${isFilterOpen || activeFilterCount > 0 ? "bg-slate-100 text-slate-700" : "active:bg-gray-100 text-slate-600"}`,
76395
76725
  "aria-label": "Open filters",
76396
76726
  children: [
76397
- /* @__PURE__ */ jsx(Filter, { className: `w-5 h-5 ${activeFilterCount > 0 ? "text-blue-600" : "text-gray-700"}` }),
76398
- activeFilterCount > 0 ? /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1 flex items-center justify-center w-4 h-4 bg-blue-600 text-white text-[10px] rounded-full font-bold", children: activeFilterCount }) : null
76727
+ /* @__PURE__ */ jsx(Filter, { className: "w-5 h-5" }),
76728
+ activeFilterCount > 0 ? /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1 flex items-center justify-center w-4 h-4 bg-slate-700 text-white text-[10px] rounded-full font-bold", children: activeFilterCount }) : null
76399
76729
  ]
76400
76730
  }
76401
76731
  )
76402
76732
  ] })
76403
76733
  ] }) }),
76404
- /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center relative min-h-[56px]", children: [
76405
- /* @__PURE__ */ jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center pointer-events-none", children: [
76406
- /* @__PURE__ */ jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight text-center pointer-events-auto leading-tight mb-0.5", children: "Operations Overview" }),
76407
- /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium text-slate-500 text-center pointer-events-auto", children: desktopSubtitle })
76734
+ /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center relative min-h-[64px]", children: [
76735
+ /* @__PURE__ */ jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center min-w-0 max-w-[min(70vw,720px)]", children: [
76736
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-2 min-w-0 max-w-full", children: [
76737
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight leading-tight text-center truncate max-w-full", children: "Operations Overview" }),
76738
+ isLiveScope ? /* @__PURE__ */ jsx(
76739
+ "div",
76740
+ {
76741
+ "data-testid": "operations-overview-live-indicator",
76742
+ className: "h-1.5 w-1.5 md:h-2 md:w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1 flex-shrink-0"
76743
+ }
76744
+ ) : null
76745
+ ] }),
76746
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-center gap-x-3 gap-y-1 text-xs sm:text-sm font-medium text-slate-500 text-center", children: [
76747
+ /* @__PURE__ */ jsx("span", { children: desktopSubtitle }),
76748
+ showLiveShiftMeta ? /* @__PURE__ */ jsxs(Fragment, { children: [
76749
+ /* @__PURE__ */ jsx("span", { className: "text-slate-300", children: "|" }),
76750
+ /* @__PURE__ */ jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 justify-center", children: [
76751
+ /* @__PURE__ */ jsx("span", { className: "opacity-75", children: liveShiftIcon }),
76752
+ liveShiftLabel
76753
+ ] }) })
76754
+ ] }) : null
76755
+ ] })
76408
76756
  ] }),
76409
- /* @__PURE__ */ jsxs("div", { className: "absolute right-0 flex items-center gap-3", children: [
76757
+ /* @__PURE__ */ jsxs("div", { className: "absolute right-0 flex items-center gap-3 shrink-0", children: [
76410
76758
  /* @__PURE__ */ jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsx(
76411
76759
  MonthlyRangeFilter_default,
76412
76760
  {
@@ -76423,12 +76771,12 @@ var OperationsOverviewHeader = React141__default.memo(({
76423
76771
  {
76424
76772
  ref: filterButtonRef,
76425
76773
  onClick: handleFilterToggle,
76426
- className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || activeFilterCount > 0 ? "border-blue-500 bg-blue-50 text-blue-700 ring-1 ring-blue-500" : "border-slate-200 bg-white text-slate-700 hover:bg-slate-50"}`,
76774
+ className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || activeFilterCount > 0 ? "border-slate-300 bg-slate-50 text-slate-700" : "border-slate-200 bg-white text-slate-600 hover:bg-slate-50 hover:text-slate-700"}`,
76427
76775
  "aria-label": "Open filters",
76428
76776
  children: [
76429
- /* @__PURE__ */ jsx(Filter, { className: `w-[18px] h-[18px] ${activeFilterCount > 0 ? "text-blue-600" : "text-slate-500"}` }),
76777
+ /* @__PURE__ */ jsx(Filter, { className: `w-[18px] h-[18px] ${isFilterOpen || activeFilterCount > 0 ? "text-slate-500" : "text-slate-400"}` }),
76430
76778
  "Filters",
76431
- /* @__PURE__ */ jsx(ChevronDown, { className: `w-4 h-4 ml-0.5 transition-transform duration-200 ${isFilterOpen ? "rotate-180" : ""}` })
76779
+ /* @__PURE__ */ jsx(ChevronDown, { className: `w-4 h-4 ml-0.5 text-slate-400 transition-transform duration-200 ${isFilterOpen ? "rotate-180" : ""}` })
76432
76780
  ]
76433
76781
  }
76434
76782
  )
@@ -76556,11 +76904,18 @@ var OverviewSummaryCards = React141__default.memo(({ store }) => {
76556
76904
  const snapshot = useOperationsOverviewSnapshot(store);
76557
76905
  const showSnapshotSkeleton = snapshot.loading && !snapshot.hasLoadedOnce;
76558
76906
  const comparisonLabel = React141__default.useMemo(() => {
76559
- return formatComparisonWindow(
76560
- scope.previous_range?.day_count ?? null,
76561
- scope.comparison_strategy
76562
- );
76563
- }, [scope.comparison_strategy, scope.previous_range?.day_count]);
76907
+ return formatComparisonWindow({
76908
+ currentDayCount: scope.current_range?.day_count ?? null,
76909
+ previousDayCount: scope.previous_range?.day_count ?? null,
76910
+ comparisonStrategy: scope.comparison_strategy,
76911
+ shiftMode: scope.shift_mode
76912
+ });
76913
+ }, [
76914
+ scope.comparison_strategy,
76915
+ scope.current_range?.day_count,
76916
+ scope.previous_range?.day_count,
76917
+ scope.shift_mode
76918
+ ]);
76564
76919
  const [isIdleContributorsOpen, setIsIdleContributorsOpen] = React141__default.useState(false);
76565
76920
  const [isIdleContributorsPinned, setIsIdleContributorsPinned] = React141__default.useState(false);
76566
76921
  const idleContributorsRef = React141__default.useRef(null);
@@ -76650,10 +77005,17 @@ var OverviewSummaryCards = React141__default.memo(({ store }) => {
76650
77005
  roundOne(snapshot.data.summary.plant_efficiency.current),
76651
77006
  "%"
76652
77007
  ] }),
76653
- /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${plantEfficiencyBadge.className}`, children: [
76654
- plantEfficiencyBadge.icon === "up" ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : plantEfficiencyBadge.icon === "down" ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
76655
- /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: plantEfficiencyBadge.text })
76656
- ] })
77008
+ /* @__PURE__ */ jsxs(
77009
+ "div",
77010
+ {
77011
+ "data-testid": "operations-overview-efficiency-delta",
77012
+ className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${plantEfficiencyBadge.className}`,
77013
+ children: [
77014
+ plantEfficiencyBadge.icon === "up" ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : plantEfficiencyBadge.icon === "down" ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
77015
+ /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: plantEfficiencyBadge.text })
77016
+ ]
77017
+ }
77018
+ )
76657
77019
  ] }) : /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No efficiency data available" })
76658
77020
  ] }),
76659
77021
  /* @__PURE__ */ jsxs(
@@ -76699,10 +77061,17 @@ var OverviewSummaryCards = React141__default.memo(({ store }) => {
76699
77061
  /* @__PURE__ */ jsx("div", { className: "mb-1", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Idle Time per Workstation" }) }),
76700
77062
  showSnapshotSkeleton ? /* @__PURE__ */ jsx(OverviewMetricCardSkeleton, {}) : snapshot.data.summary.avg_idle_per_workstation?.current_seconds !== null && snapshot.data.summary.avg_idle_per_workstation?.current_seconds !== void 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:gap-3 mt-1", children: [
76701
77063
  /* @__PURE__ */ jsx("span", { className: "text-2xl sm:text-3xl font-bold text-slate-800 tracking-tight", children: formatIdleDuration(snapshot.data.summary.avg_idle_per_workstation.current_seconds) }),
76702
- /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${idleBadge.className}`, children: [
76703
- idleBadge.icon === "up" ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : idleBadge.icon === "down" ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
76704
- /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: idleBadge.text })
76705
- ] })
77064
+ /* @__PURE__ */ jsxs(
77065
+ "div",
77066
+ {
77067
+ "data-testid": "operations-overview-idle-delta",
77068
+ className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${idleBadge.className}`,
77069
+ children: [
77070
+ idleBadge.icon === "up" ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : idleBadge.icon === "down" ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
77071
+ /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: idleBadge.text })
77072
+ ]
77073
+ }
77074
+ )
76706
77075
  ] }) : /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No idle time data available" })
76707
77076
  ]
76708
77077
  }
@@ -76765,11 +77134,18 @@ var PoorestPerformersCard = React141__default.memo(({
76765
77134
  }
76766
77135
  }, [availableLineModes?.has_output, availableLineModes?.has_uptime, poorestLineMode]);
76767
77136
  const comparisonLabel = React141__default.useMemo(() => {
76768
- return formatComparisonWindow(
76769
- scope.previous_range?.day_count ?? null,
76770
- scope.comparison_strategy
76771
- );
76772
- }, [scope.comparison_strategy, scope.previous_range?.day_count]);
77137
+ return formatComparisonWindow({
77138
+ currentDayCount: scope.current_range?.day_count ?? null,
77139
+ previousDayCount: scope.previous_range?.day_count ?? null,
77140
+ comparisonStrategy: scope.comparison_strategy,
77141
+ shiftMode: scope.shift_mode
77142
+ });
77143
+ }, [
77144
+ scope.comparison_strategy,
77145
+ scope.current_range?.day_count,
77146
+ scope.previous_range?.day_count,
77147
+ scope.shift_mode
77148
+ ]);
76773
77149
  const showSnapshotSkeleton = snapshot.loading && !snapshot.hasLoadedOnce;
76774
77150
  const mergedPoorestLines = React141__default.useMemo(() => {
76775
77151
  const rows = snapshot.data.poorest_lines?.[poorestLineMode] || [];
@@ -76926,7 +77302,8 @@ IdleBreakdownCard.displayName = "IdleBreakdownCard";
76926
77302
  var EfficiencyTrendCard = React141__default.memo(({
76927
77303
  store,
76928
77304
  dateRange,
76929
- appTimezone
77305
+ appTimezone,
77306
+ hourlyLabelStartTime
76930
77307
  }) => {
76931
77308
  bumpRenderCounter();
76932
77309
  const trend = useOperationsOverviewTrend(store);
@@ -76936,7 +77313,41 @@ var EfficiencyTrendCard = React141__default.memo(({
76936
77313
  );
76937
77314
  const isCurrentWeekToDateRange = dateRange.startKey === currentWeekRange.startKey && dateRange.endKey === currentWeekRange.endKey;
76938
77315
  const showInitialSkeleton = trend.loading && trend.lastUpdated === null;
77316
+ const isHourlyTrend = trend.data.granularity === "hour";
76939
77317
  const trendData = React141__default.useMemo(() => {
77318
+ if (isHourlyTrend) {
77319
+ return (trend.data.points || []).map((point, index) => ({
77320
+ name: (() => {
77321
+ const rawLabel = point.label?.trim() || "";
77322
+ if (rawLabel) {
77323
+ return rawLabel;
77324
+ }
77325
+ if (!hourlyLabelStartTime) {
77326
+ return "";
77327
+ }
77328
+ const hourIndex = typeof point.hour_index === "number" ? point.hour_index : index;
77329
+ const [hoursPart, minutesPart] = hourlyLabelStartTime.split(":");
77330
+ const startHours = Number(hoursPart);
77331
+ const startMinutes = Number(minutesPart);
77332
+ if (!Number.isFinite(startHours) || !Number.isFinite(startMinutes)) {
77333
+ return "";
77334
+ }
77335
+ const totalMinutes = startHours * 60 + startMinutes + hourIndex * 60;
77336
+ const hour24 = Math.floor(totalMinutes / 60) % 24;
77337
+ const minutes = totalMinutes % 60;
77338
+ const suffix = hour24 < 12 ? "AM" : "PM";
77339
+ const hour12 = hour24 % 12 || 12;
77340
+ if (minutes === 0) {
77341
+ return `${hour12} ${suffix}`;
77342
+ }
77343
+ return `${hour12}:${minutes.toString().padStart(2, "0")} ${suffix}`;
77344
+ })(),
77345
+ efficiency: (() => {
77346
+ const value = toNumber3(point.avg_efficiency);
77347
+ return value === null ? void 0 : value;
77348
+ })()
77349
+ }));
77350
+ }
76940
77351
  const pointsByDate = new Map(
76941
77352
  (trend.data.points || []).flatMap((point) => {
76942
77353
  if (!point.date) return [];
@@ -76974,12 +77385,19 @@ var EfficiencyTrendCard = React141__default.memo(({
76974
77385
  })()
76975
77386
  };
76976
77387
  });
76977
- }, [currentWeekRange.startKey, isCurrentWeekToDateRange, trend.data.points]);
77388
+ }, [currentWeekRange.startKey, hourlyLabelStartTime, isCurrentWeekToDateRange, isHourlyTrend, trend.data.points]);
76978
77389
  const trendTooltipLabelFormatter = React141__default.useCallback((label, payload) => {
77390
+ if (isHourlyTrend) return label;
76979
77391
  const dayOfWeek = payload?.[0]?.payload?.dayOfWeek;
76980
77392
  if (!dayOfWeek || typeof label !== "string") return label;
76981
77393
  return `${label} (${dayOfWeek})`;
76982
- }, []);
77394
+ }, [isHourlyTrend]);
77395
+ const trendXAxisTickFormatter = React141__default.useCallback((value, index) => {
77396
+ if (!isHourlyTrend) {
77397
+ return typeof value === "string" ? value : String(value ?? "");
77398
+ }
77399
+ return index % 2 === 0 ? typeof value === "string" ? value : String(value ?? "") : "";
77400
+ }, [isHourlyTrend]);
76983
77401
  return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-[0_2px_10px_-3px_rgba(6,81,237,0.1)] border border-slate-100 flex flex-col overflow-hidden text-left", children: [
76984
77402
  /* @__PURE__ */ jsx("div", { className: "px-6 py-5 flex-none flex justify-between items-center border-b border-slate-50/50", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Efficiency Trend" }) }),
76985
77403
  /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-[250px] w-full p-4 pt-4 relative", children: showInitialSkeleton ? /* @__PURE__ */ jsx(OverviewChartSkeleton, {}) : /* @__PURE__ */ jsx("div", { className: "absolute inset-0 pb-2 pr-4 pl-1", children: /* @__PURE__ */ jsx(
@@ -76988,6 +77406,8 @@ var EfficiencyTrendCard = React141__default.memo(({
76988
77406
  data: trendData,
76989
77407
  lines: efficiencyLineConfig,
76990
77408
  xAxisDataKey: "name",
77409
+ xAxisInterval: isHourlyTrend ? 0 : void 0,
77410
+ xAxisTickFormatter: trendXAxisTickFormatter,
76991
77411
  yAxisUnit: "%",
76992
77412
  yAxisDomain: [0, 100],
76993
77413
  showLegend: false,
@@ -77133,7 +77553,8 @@ var useOperationsOverviewRefresh = ({
77133
77553
  endKey,
77134
77554
  trendMode,
77135
77555
  comparisonStrategy,
77136
- isLiveScope
77556
+ isLiveScope,
77557
+ enabled = true
77137
77558
  }) => {
77138
77559
  const lineIdsKey = React141__default.useMemo(() => lineIds.join(","), [lineIds]);
77139
77560
  const scopeSignature = React141__default.useMemo(
@@ -77179,7 +77600,7 @@ var useOperationsOverviewRefresh = ({
77179
77600
  }, []);
77180
77601
  const runRefresh = React141__default.useCallback(
77181
77602
  async (section, begin, onSuccess, onError, request, reason) => {
77182
- if (!supabase || !companyId || lineIds.length === 0) return;
77603
+ if (!enabled || !supabase || !companyId || lineIds.length === 0) return;
77183
77604
  const requestId = requestIdsRef.current[section] + 1;
77184
77605
  requestIdsRef.current[section] = requestId;
77185
77606
  controllersRef.current[section]?.abort();
@@ -77199,7 +77620,7 @@ var useOperationsOverviewRefresh = ({
77199
77620
  onError(error instanceof Error ? error.message : `Failed to refresh ${section}`);
77200
77621
  }
77201
77622
  },
77202
- [companyId, lineIds.length, supabase]
77623
+ [companyId, enabled, lineIds.length, supabase]
77203
77624
  );
77204
77625
  const refreshSnapshot = React141__default.useCallback(
77205
77626
  async (reason) => {
@@ -77369,6 +77790,12 @@ var useOperationsOverviewRefresh = ({
77369
77790
  });
77370
77791
  }, [refreshAll, startPolling, stopPolling]);
77371
77792
  React141__default.useEffect(() => {
77793
+ if (!enabled) {
77794
+ stopPolling("disabled");
77795
+ abortAll();
77796
+ store.reset();
77797
+ return;
77798
+ }
77372
77799
  if (!supabase || !companyId || lineIds.length === 0) {
77373
77800
  stopPolling("scope_invalid");
77374
77801
  abortAll();
@@ -77376,9 +77803,9 @@ var useOperationsOverviewRefresh = ({
77376
77803
  return;
77377
77804
  }
77378
77805
  void refreshAll("scope_change");
77379
- }, [abortAll, companyId, lineIds.length, refreshAll, scopeSignature, stopPolling, store, supabase]);
77806
+ }, [abortAll, companyId, enabled, lineIds.length, refreshAll, scopeSignature, stopPolling, store, supabase]);
77380
77807
  React141__default.useEffect(() => {
77381
- if (!isLiveScope || !supabase || !companyId || lineIds.length === 0) {
77808
+ if (!enabled || !isLiveScope || !supabase || !companyId || lineIds.length === 0) {
77382
77809
  isPageActiveRef.current = false;
77383
77810
  stopPolling("live_scope_disabled");
77384
77811
  return;
@@ -77434,11 +77861,119 @@ var useOperationsOverviewRefresh = ({
77434
77861
  window.removeEventListener("pageshow", handlePageShow);
77435
77862
  window.removeEventListener("pagehide", handlePageHide);
77436
77863
  };
77437
- }, [companyId, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
77864
+ }, [companyId, enabled, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
77865
+ };
77866
+ var parseTimeToMinutes3 = (value) => {
77867
+ if (!value) return null;
77868
+ const parts = value.split(":");
77869
+ if (parts.length < 2) return null;
77870
+ const hours = Number(parts[0]);
77871
+ const minutes = Number(parts[1]);
77872
+ if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return null;
77873
+ if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) return null;
77874
+ return hours * 60 + minutes;
77875
+ };
77876
+ var normalizeShiftId = (value) => {
77877
+ if (typeof value === "number" && Number.isFinite(value)) {
77878
+ return value;
77879
+ }
77880
+ if (typeof value === "string" && value.trim().length > 0) {
77881
+ const parsed = Number(value);
77882
+ return Number.isFinite(parsed) ? parsed : null;
77883
+ }
77884
+ return null;
77885
+ };
77886
+ var classifyShiftBucket = ({
77887
+ shiftName,
77888
+ shiftId,
77889
+ startTime,
77890
+ endTime
77891
+ }) => {
77892
+ const normalizedName = (shiftName || "").trim().toLowerCase();
77893
+ if (normalizedName) {
77894
+ if (["night", "graveyard", "evening"].some((keyword) => normalizedName.includes(keyword))) {
77895
+ return "night";
77896
+ }
77897
+ if (["day", "morning"].some((keyword) => normalizedName.includes(keyword))) {
77898
+ return "day";
77899
+ }
77900
+ }
77901
+ const startMinutes = parseTimeToMinutes3(startTime);
77902
+ const endMinutes = parseTimeToMinutes3(endTime);
77903
+ if (startMinutes !== null) {
77904
+ if (startMinutes >= 4 * 60 && startMinutes < 18 * 60) return "day";
77905
+ return "night";
77906
+ }
77907
+ if (endMinutes !== null) {
77908
+ if (endMinutes >= 6 * 60 && endMinutes <= 21 * 60) return "day";
77909
+ return "night";
77910
+ }
77911
+ const normalizedShiftId = normalizeShiftId(shiftId);
77912
+ if (normalizedShiftId === 0) return "day";
77913
+ if (normalizedShiftId === 1) return "night";
77914
+ return null;
77915
+ };
77916
+ var getShiftWindowsForConfig = (shiftConfig, timezone) => {
77917
+ if (shiftConfig?.shifts && shiftConfig.shifts.length > 0) {
77918
+ return shiftConfig.shifts.map((shift) => ({
77919
+ shiftId: shift.shiftId,
77920
+ shiftName: shift.shiftName,
77921
+ startTime: shift.startTime,
77922
+ endTime: shift.endTime
77923
+ }));
77924
+ }
77925
+ const windows = [];
77926
+ if (shiftConfig?.dayShift) {
77927
+ windows.push({
77928
+ shiftId: shiftConfig.dayShift.id ?? 0,
77929
+ shiftName: shiftConfig.dayShift.name || "Day Shift",
77930
+ startTime: shiftConfig.dayShift.startTime || "06:00",
77931
+ endTime: shiftConfig.dayShift.endTime || "18:00"
77932
+ });
77933
+ }
77934
+ if (shiftConfig?.nightShift) {
77935
+ windows.push({
77936
+ shiftId: shiftConfig.nightShift.id ?? 1,
77937
+ shiftName: shiftConfig.nightShift.name || "Night Shift",
77938
+ startTime: shiftConfig.nightShift.startTime || "18:00",
77939
+ endTime: shiftConfig.nightShift.endTime || "06:00"
77940
+ });
77941
+ }
77942
+ if (windows.length > 0) {
77943
+ return windows;
77944
+ }
77945
+ return [
77946
+ {
77947
+ shiftId: 0,
77948
+ shiftName: "Day Shift",
77949
+ startTime: "06:00",
77950
+ endTime: "18:00"
77951
+ },
77952
+ {
77953
+ shiftId: 1,
77954
+ shiftName: "Night Shift",
77955
+ startTime: "18:00",
77956
+ endTime: "06:00"
77957
+ }
77958
+ ];
77959
+ };
77960
+ var normalizeShiftWindowMinutes = (startTime, endTime) => {
77961
+ const startMinutes = parseTimeToMinutes3(startTime);
77962
+ const endMinutesRaw = parseTimeToMinutes3(endTime);
77963
+ if (startMinutes === null || endMinutesRaw === null) {
77964
+ return null;
77965
+ }
77966
+ let endMinutes = endMinutesRaw;
77967
+ if (endMinutes <= startMinutes) {
77968
+ endMinutes += 24 * 60;
77969
+ }
77970
+ return { startMinutes, endMinutes };
77438
77971
  };
77439
77972
  var PlantHeadView = () => {
77440
77973
  const supabase = useSupabase();
77441
77974
  const entityConfig = useEntityConfig();
77975
+ const factoryViewId = entityConfig.factoryViewId || "factory";
77976
+ const staticShiftConfig = useShiftConfig();
77442
77977
  const appTimezone = useAppTimezone() || "UTC";
77443
77978
  const { navigate } = useNavigation();
77444
77979
  const { accessibleLineIds } = useUserLineAccess();
@@ -77446,11 +77981,22 @@ var PlantHeadView = () => {
77446
77981
  useHideMobileHeader(!!mobileMenuContext);
77447
77982
  const storeRef = React141__default.useRef(createOperationsOverviewStore());
77448
77983
  const store = storeRef.current;
77449
- const [dateRange, setDateRange] = React141__default.useState(() => getCurrentWeekToDateRange(appTimezone));
77450
- const [usesThisWeekComparison, setUsesThisWeekComparison] = React141__default.useState(true);
77984
+ const fallbackOperationalDate = React141__default.useMemo(
77985
+ () => getOperationalDate(appTimezone),
77986
+ [appTimezone]
77987
+ );
77988
+ const [dateRange, setDateRange] = React141__default.useState(() => ({
77989
+ startKey: fallbackOperationalDate,
77990
+ endKey: fallbackOperationalDate
77991
+ }));
77992
+ const [usesThisWeekComparison, setUsesThisWeekComparison] = React141__default.useState(false);
77451
77993
  const [trendMode, setTrendMode] = React141__default.useState("all");
77452
77994
  const [selectedSupervisorId, setSelectedSupervisorId] = React141__default.useState("all");
77453
77995
  const [selectedLineIds, setSelectedLineIds] = React141__default.useState([]);
77996
+ const [isInitialScopeReady, setIsInitialScopeReady] = React141__default.useState(false);
77997
+ const [shiftResolutionTick, setShiftResolutionTick] = React141__default.useState(0);
77998
+ const hasAutoInitializedScopeRef = React141__default.useRef(false);
77999
+ const hasUserAdjustedScopeRef = React141__default.useRef(false);
77454
78000
  React141__default.useEffect(() => {
77455
78001
  trackCorePageView("Operations Overview", {
77456
78002
  dashboard_surface: "operations_overview"
@@ -77472,8 +78018,10 @@ var PlantHeadView = () => {
77472
78018
  return dateRange;
77473
78019
  }, [currentWeekDisplayRange, dateRange, isCurrentWeekToDateRange, usesThisWeekComparison]);
77474
78020
  const normalizedLineIds = React141__default.useMemo(
77475
- () => Array.from(new Set((accessibleLineIds || []).filter(Boolean))).sort(),
77476
- [accessibleLineIds]
78021
+ () => Array.from(new Set(
78022
+ (accessibleLineIds || []).filter(Boolean).filter((lineId) => lineId !== factoryViewId)
78023
+ )).sort(),
78024
+ [accessibleLineIds, factoryViewId]
77477
78025
  );
77478
78026
  const lineIdsKey = React141__default.useMemo(
77479
78027
  () => normalizedLineIds.join(","),
@@ -77547,14 +78095,198 @@ var PlantHeadView = () => {
77547
78095
  () => selectedLineIds.length > 0 ? selectedLineIds : normalizedLineIds,
77548
78096
  [normalizedLineIds, selectedLineIds]
77549
78097
  );
78098
+ const {
78099
+ shiftConfigMap,
78100
+ isLoading: isShiftConfigLoading
78101
+ } = useMultiLineShiftConfigs(scopedLineIds, staticShiftConfig);
78102
+ React141__default.useEffect(() => {
78103
+ if (scopedLineIds.length === 0 || isShiftConfigLoading) {
78104
+ return;
78105
+ }
78106
+ const intervalId = window.setInterval(() => {
78107
+ setShiftResolutionTick((previous) => previous + 1);
78108
+ }, 6e4);
78109
+ return () => {
78110
+ clearInterval(intervalId);
78111
+ };
78112
+ }, [isShiftConfigLoading, scopedLineIds.length]);
78113
+ const shiftResolutionNow = React141__default.useMemo(
78114
+ () => /* @__PURE__ */ new Date(),
78115
+ [shiftResolutionTick]
78116
+ );
78117
+ const earliestDayShiftStartTime = React141__default.useMemo(() => {
78118
+ const candidateStarts = [];
78119
+ scopedLineIds.forEach((lineId) => {
78120
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78121
+ getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
78122
+ const bucket = classifyShiftBucket({
78123
+ shiftName: shift.shiftName,
78124
+ shiftId: shift.shiftId,
78125
+ startTime: shift.startTime,
78126
+ endTime: shift.endTime
78127
+ });
78128
+ const startMinutes = parseTimeToMinutes3(shift.startTime);
78129
+ if (bucket === "day" && startMinutes !== null) {
78130
+ candidateStarts.push(startMinutes);
78131
+ }
78132
+ });
78133
+ });
78134
+ if (candidateStarts.length === 0) {
78135
+ scopedLineIds.forEach((lineId) => {
78136
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78137
+ getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
78138
+ const startMinutes = parseTimeToMinutes3(shift.startTime);
78139
+ if (startMinutes !== null) {
78140
+ candidateStarts.push(startMinutes);
78141
+ }
78142
+ });
78143
+ });
78144
+ }
78145
+ if (candidateStarts.length === 0) {
78146
+ return "06:00";
78147
+ }
78148
+ const earliestMinutes = Math.min(...candidateStarts);
78149
+ const hours = Math.floor(earliestMinutes / 60);
78150
+ const minutes = earliestMinutes % 60;
78151
+ return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
78152
+ }, [appTimezone, scopedLineIds, shiftConfigMap, staticShiftConfig]);
78153
+ const resolvedOperationalToday = React141__default.useMemo(
78154
+ () => getOperationalDate(appTimezone, shiftResolutionNow, earliestDayShiftStartTime),
78155
+ [appTimezone, earliestDayShiftStartTime, shiftResolutionNow]
78156
+ );
78157
+ const activeLineShiftStates = React141__default.useMemo(() => {
78158
+ return scopedLineIds.flatMap((lineId) => {
78159
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78160
+ const activeShift = getActiveShift(appTimezone, shiftConfig, shiftResolutionNow);
78161
+ if (!activeShift) {
78162
+ return [];
78163
+ }
78164
+ const trendBucket = classifyShiftBucket({
78165
+ shiftName: activeShift.shiftName,
78166
+ shiftId: activeShift.shiftId,
78167
+ startTime: activeShift.startTime,
78168
+ endTime: activeShift.endTime
78169
+ });
78170
+ if (!trendBucket || trendBucket === "all") {
78171
+ return [];
78172
+ }
78173
+ return [{
78174
+ lineId,
78175
+ trendMode: trendBucket,
78176
+ shiftId: activeShift.shiftId,
78177
+ shiftName: activeShift.shiftName || null,
78178
+ startTime: activeShift.startTime || null,
78179
+ endTime: activeShift.endTime || null,
78180
+ date: activeShift.date
78181
+ }];
78182
+ });
78183
+ }, [appTimezone, scopedLineIds, shiftConfigMap, shiftResolutionNow, staticShiftConfig]);
78184
+ const hasActiveDayShiftLine = React141__default.useMemo(
78185
+ () => activeLineShiftStates.some((shift) => shift.trendMode === "day" && shift.date === resolvedOperationalToday),
78186
+ [activeLineShiftStates, resolvedOperationalToday]
78187
+ );
78188
+ const hasActiveNightShiftLine = React141__default.useMemo(
78189
+ () => activeLineShiftStates.some((shift) => shift.trendMode === "night" && shift.date === resolvedOperationalToday),
78190
+ [activeLineShiftStates, resolvedOperationalToday]
78191
+ );
78192
+ const resolvedTrendMode = isInitialScopeReady ? trendMode : "all";
78193
+ const hourlyWindowStartTime = React141__default.useMemo(() => {
78194
+ if (scopedLineIds.length === 0) {
78195
+ return null;
78196
+ }
78197
+ const startCandidates = [];
78198
+ const endCandidates = [];
78199
+ scopedLineIds.forEach((lineId) => {
78200
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78201
+ getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
78202
+ const bucket = classifyShiftBucket({
78203
+ shiftName: shift.shiftName,
78204
+ shiftId: shift.shiftId,
78205
+ startTime: shift.startTime,
78206
+ endTime: shift.endTime
78207
+ });
78208
+ if (resolvedTrendMode !== "all" && bucket !== resolvedTrendMode) {
78209
+ return;
78210
+ }
78211
+ const normalizedWindow = normalizeShiftWindowMinutes(shift.startTime, shift.endTime);
78212
+ if (!normalizedWindow) {
78213
+ return;
78214
+ }
78215
+ startCandidates.push(normalizedWindow.startMinutes);
78216
+ endCandidates.push(normalizedWindow.endMinutes);
78217
+ });
78218
+ });
78219
+ if (resolvedTrendMode === "all") {
78220
+ const dayStartCandidates = startCandidates.length > 0 ? scopedLineIds.flatMap((lineId) => {
78221
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78222
+ return getShiftWindowsForConfig(shiftConfig).map((shift) => {
78223
+ const bucket = classifyShiftBucket({
78224
+ shiftName: shift.shiftName,
78225
+ shiftId: shift.shiftId,
78226
+ startTime: shift.startTime,
78227
+ endTime: shift.endTime
78228
+ });
78229
+ return bucket === "day" ? parseTimeToMinutes3(shift.startTime) : null;
78230
+ }).filter((value) => value !== null);
78231
+ }) : [];
78232
+ if (dayStartCandidates.length > 0) {
78233
+ startCandidates.splice(0, startCandidates.length, ...dayStartCandidates);
78234
+ }
78235
+ }
78236
+ if (startCandidates.length === 0 || endCandidates.length === 0) {
78237
+ return null;
78238
+ }
78239
+ const earliestMinutes = Math.min(...startCandidates);
78240
+ const hours = Math.floor(earliestMinutes / 60);
78241
+ const minutes = earliestMinutes % 60;
78242
+ return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
78243
+ }, [appTimezone, resolvedTrendMode, scopedLineIds, shiftConfigMap, staticShiftConfig]);
78244
+ const isShiftScopeResolved = React141__default.useMemo(
78245
+ () => !isShiftConfigLoading,
78246
+ [isShiftConfigLoading]
78247
+ );
77550
78248
  const initializedTimezoneRef = React141__default.useRef(appTimezone);
77551
78249
  React141__default.useEffect(() => {
77552
78250
  if (initializedTimezoneRef.current === appTimezone) return;
77553
- setDateRange(getCurrentWeekToDateRange(appTimezone));
77554
- setUsesThisWeekComparison(true);
78251
+ hasAutoInitializedScopeRef.current = false;
78252
+ hasUserAdjustedScopeRef.current = false;
78253
+ setDateRange({
78254
+ startKey: fallbackOperationalDate,
78255
+ endKey: fallbackOperationalDate
78256
+ });
78257
+ setTrendMode("all");
78258
+ setUsesThisWeekComparison(false);
78259
+ setIsInitialScopeReady(false);
77555
78260
  initializedTimezoneRef.current = appTimezone;
77556
- }, [appTimezone]);
78261
+ }, [appTimezone, fallbackOperationalDate]);
78262
+ React141__default.useEffect(() => {
78263
+ if (hasAutoInitializedScopeRef.current || hasUserAdjustedScopeRef.current) {
78264
+ return;
78265
+ }
78266
+ if (scopedLineIds.length === 0) {
78267
+ return;
78268
+ }
78269
+ if (!isShiftScopeResolved) {
78270
+ return;
78271
+ }
78272
+ setDateRange((previous) => {
78273
+ const nextStartKey = resolvedOperationalToday || fallbackOperationalDate;
78274
+ if (previous.startKey === nextStartKey && previous.endKey === nextStartKey) {
78275
+ return previous;
78276
+ }
78277
+ return {
78278
+ startKey: nextStartKey,
78279
+ endKey: nextStartKey
78280
+ };
78281
+ });
78282
+ setTrendMode("all");
78283
+ setUsesThisWeekComparison(false);
78284
+ hasAutoInitializedScopeRef.current = true;
78285
+ setIsInitialScopeReady(true);
78286
+ }, [fallbackOperationalDate, isShiftScopeResolved, resolvedOperationalToday, scopedLineIds.length]);
77557
78287
  const handleDateRangeChange = React141__default.useCallback((range, meta) => {
78288
+ hasUserAdjustedScopeRef.current = true;
78289
+ setIsInitialScopeReady(true);
77558
78290
  trackCoreEvent("Operations Overview Date Range Changed", {
77559
78291
  start_date: range.startKey,
77560
78292
  end_date: range.endKey
@@ -77571,6 +78303,8 @@ var PlantHeadView = () => {
77571
78303
  });
77572
78304
  }, []);
77573
78305
  const handleTrendModeChange = React141__default.useCallback((mode) => {
78306
+ hasUserAdjustedScopeRef.current = true;
78307
+ setIsInitialScopeReady(true);
77574
78308
  setTrendMode(mode);
77575
78309
  }, []);
77576
78310
  const handleSelectedLineIdsChange = React141__default.useCallback((lineIds) => {
@@ -77597,15 +78331,6 @@ var PlantHeadView = () => {
77597
78331
  params.set("rangeEnd", dateRange.endKey);
77598
78332
  return `/kpis/${lineId}?${params.toString()}`;
77599
78333
  }, [dateRange.endKey, dateRange.startKey]);
77600
- const handleOpenLineMonthlyHistory = React141__default.useCallback((lineId, lineName) => {
77601
- trackCoreEvent("Operations Overview Line Clicked", {
77602
- line_id: lineId,
77603
- line_name: lineName,
77604
- range_start: dateRange.startKey,
77605
- range_end: dateRange.endKey
77606
- });
77607
- navigate(buildLineMonthlyHistoryUrl(lineId));
77608
- }, [buildLineMonthlyHistoryUrl, dateRange.endKey, dateRange.startKey, navigate]);
77609
78334
  const handleViewAllPoorestPerformers = React141__default.useCallback(() => {
77610
78335
  trackCoreEvent("Operations Overview View All Clicked", { section: "poorest_performers" });
77611
78336
  navigate("/kpis?tab=leaderboard");
@@ -77631,16 +78356,65 @@ var PlantHeadView = () => {
77631
78356
  }
77632
78357
  return void 0;
77633
78358
  }, [isCurrentWeekToDateRange, usesThisWeekComparison]);
78359
+ const effectiveDateRange = React141__default.useMemo(() => {
78360
+ if (isInitialScopeReady) {
78361
+ return dateRange;
78362
+ }
78363
+ const nextStartKey = resolvedOperationalToday || fallbackOperationalDate;
78364
+ return {
78365
+ startKey: nextStartKey,
78366
+ endKey: nextStartKey
78367
+ };
78368
+ }, [dateRange, fallbackOperationalDate, isInitialScopeReady, resolvedOperationalToday]);
78369
+ const effectiveTrendMode = React141__default.useMemo(
78370
+ () => resolvedTrendMode,
78371
+ [resolvedTrendMode]
78372
+ );
78373
+ const hourlyLabelStartTime = React141__default.useMemo(() => {
78374
+ if (scopedLineIds.length === 0) {
78375
+ return null;
78376
+ }
78377
+ return hourlyWindowStartTime;
78378
+ }, [hourlyWindowStartTime, scopedLineIds.length]);
78379
+ const isSingleDayScope = React141__default.useMemo(
78380
+ () => effectiveDateRange.startKey === effectiveDateRange.endKey,
78381
+ [effectiveDateRange.endKey, effectiveDateRange.startKey]
78382
+ );
78383
+ const isLiveScope = React141__default.useMemo(
78384
+ () => isSingleDayScope && effectiveDateRange.startKey === resolvedOperationalToday && (effectiveTrendMode === "all" || effectiveTrendMode === "day" && hasActiveDayShiftLine || effectiveTrendMode === "night" && hasActiveNightShiftLine),
78385
+ [
78386
+ effectiveDateRange.startKey,
78387
+ effectiveTrendMode,
78388
+ hasActiveDayShiftLine,
78389
+ hasActiveNightShiftLine,
78390
+ isSingleDayScope,
78391
+ resolvedOperationalToday
78392
+ ]
78393
+ );
78394
+ const handleOpenLineDetails = React141__default.useCallback((lineId, lineName) => {
78395
+ trackCoreEvent("Operations Overview Line Clicked", {
78396
+ line_id: lineId,
78397
+ line_name: lineName,
78398
+ range_start: dateRange.startKey,
78399
+ range_end: dateRange.endKey
78400
+ });
78401
+ if (isLiveScope) {
78402
+ navigate(`/kpis/${lineId}?returnTo=${encodeURIComponent("/")}`);
78403
+ return;
78404
+ }
78405
+ navigate(buildLineMonthlyHistoryUrl(lineId));
78406
+ }, [buildLineMonthlyHistoryUrl, dateRange.endKey, dateRange.startKey, isLiveScope, navigate]);
77634
78407
  useOperationsOverviewRefresh({
77635
78408
  store,
77636
78409
  supabase,
77637
78410
  companyId: entityConfig.companyId,
77638
78411
  lineIds: scopedLineIds,
77639
- startKey: dateRange.startKey,
77640
- endKey: dateRange.endKey,
77641
- trendMode,
78412
+ startKey: effectiveDateRange.startKey,
78413
+ endKey: effectiveDateRange.endKey,
78414
+ trendMode: effectiveTrendMode,
77642
78415
  comparisonStrategy,
77643
- isLiveScope: isCurrentWeekToDateRange
78416
+ isLiveScope,
78417
+ enabled: scopedLineIds.length > 0 && isShiftScopeResolved
77644
78418
  });
77645
78419
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-h-screen bg-slate-50 w-full font-sans", children: [
77646
78420
  /* @__PURE__ */ jsx(
@@ -77649,6 +78423,8 @@ var PlantHeadView = () => {
77649
78423
  dateRange,
77650
78424
  displayDateRange: headerDateRange,
77651
78425
  trendMode,
78426
+ isLiveScope,
78427
+ liveShiftName: isLiveScope && trendMode !== "all" ? trendMode : null,
77652
78428
  lineOptions,
77653
78429
  supervisorOptions,
77654
78430
  selectedSupervisorId,
@@ -77671,7 +78447,7 @@ var PlantHeadView = () => {
77671
78447
  store,
77672
78448
  supervisorsByLineId,
77673
78449
  onViewAll: handleViewAllPoorestPerformers,
77674
- onLineClick: handleOpenLineMonthlyHistory
78450
+ onLineClick: handleOpenLineDetails
77675
78451
  }
77676
78452
  ),
77677
78453
  /* @__PURE__ */ jsx(
@@ -77688,7 +78464,8 @@ var PlantHeadView = () => {
77688
78464
  {
77689
78465
  store,
77690
78466
  dateRange,
77691
- appTimezone
78467
+ appTimezone,
78468
+ hourlyLabelStartTime
77692
78469
  }
77693
78470
  ),
77694
78471
  /* @__PURE__ */ jsx(
@@ -78182,4 +78959,4 @@ var streamProxyConfig = {
78182
78959
  }
78183
78960
  };
78184
78961
 
78185
- export { ACTION_FAMILIES, ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceCycleTimeMetricCards, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, canRoleAccessDashboardPath, canRoleAccessTeamManagement, canRoleAssignFactories, canRoleAssignLines, canRoleChangeRole, canRoleInviteRole, canRoleManageCompany, canRoleManageTargets, canRoleManageUsers, canRoleRemoveUser, canRoleViewClipsCost, canRoleViewUsageStats, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getActionDisplayName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAssignableRoles, getAssignmentColumnLabel, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getCurrentWeekFullRange, getCurrentWeekToDateRange, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getRoleAssignmentKind, getRoleDescription, getRoleLabel, getRoleMetadata, getRoleNavPaths, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getVisibleRolesForCurrentUser, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFactoryScopedRole, isFullMonthRange, isLegacyConfiguration, isPrefetchError, isRecentFlowVideoGridMetricMode, isSafari, isSupervisorRole, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWipGatedVideoGridMetricMode, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeActionFamily, normalizeDateKeyRange, normalizeRoleLevel, normalizeVideoGridMetricMode, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
78962
+ export { ACTION_FAMILIES, ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceCycleTimeMetricCards, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, canRoleAccessDashboardPath, canRoleAccessTeamManagement, canRoleAssignFactories, canRoleAssignLines, canRoleChangeRole, canRoleInviteRole, canRoleManageCompany, canRoleManageTargets, canRoleManageUsers, canRoleRemoveUser, canRoleViewClipsCost, canRoleViewUsageStats, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getActionDisplayName, getActiveShift, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAssignableRoles, getAssignmentColumnLabel, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getCurrentWeekFullRange, getCurrentWeekToDateRange, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getRoleAssignmentKind, getRoleDescription, getRoleLabel, getRoleMetadata, getRoleNavPaths, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getVisibleRolesForCurrentUser, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFactoryScopedRole, isFullMonthRange, isLegacyConfiguration, isLoopbackHostname, isPrefetchError, isRecentFlowVideoGridMetricMode, isSafari, isSupervisorRole, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWipGatedVideoGridMetricMode, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeActionFamily, normalizeDateKeyRange, normalizeRoleLevel, normalizeVideoGridMetricMode, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, shouldEnableLocalDevTestLogin, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };