@optifye/dashboard-core 6.11.5 → 6.11.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -652,6 +652,17 @@ var getMonthKeyBounds = (year, monthIndex) => {
652
652
  const endKey = buildDateKey(year, monthIndex, lastDay);
653
653
  return { startKey, endKey };
654
654
  };
655
+ var getCurrentWeekToDateRange = (timezone, now4 = /* @__PURE__ */ new Date()) => {
656
+ const todayKey = dateFnsTz.formatInTimeZone(now4, timezone || "UTC", "yyyy-MM-dd");
657
+ const todayDate = dateFns.parseISO(`${todayKey}T00:00:00`);
658
+ const dayOfWeek = dateFns.getDay(todayDate);
659
+ const daysSinceMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
660
+ const weekStart = dateFns.subDays(todayDate, daysSinceMonday);
661
+ return {
662
+ startKey: dateFns.format(weekStart, "yyyy-MM-dd"),
663
+ endKey: dateFns.format(todayDate, "yyyy-MM-dd")
664
+ };
665
+ };
655
666
  var normalizeDateKeyRange = (startKey, endKey, minKey, maxKey) => {
656
667
  const clampedStart = startKey < minKey ? minKey : startKey > maxKey ? maxKey : startKey;
657
668
  const clampedEnd = endKey < minKey ? minKey : endKey > maxKey ? maxKey : endKey;
@@ -2710,6 +2721,45 @@ var workspaceService = {
2710
2721
  }
2711
2722
  }
2712
2723
  };
2724
+
2725
+ // src/lib/utils/workspaceHealthSummary.ts
2726
+ var computeWorkspaceHealthSummary = (data, lastUpdated = (/* @__PURE__ */ new Date()).toISOString()) => {
2727
+ const totalWorkspaces = data.length;
2728
+ const healthyWorkspaces = data.filter((workspace) => workspace.status === "healthy").length;
2729
+ const unhealthyWorkspaces = data.filter((workspace) => workspace.status === "unhealthy").length;
2730
+ const warningWorkspaces = data.filter((workspace) => workspace.status === "warning").length;
2731
+ const workspacesWithUptime = data.filter(
2732
+ (workspace) => workspace.hasUptimeData && workspace.uptimePercentage !== void 0 && workspace.uptimeDetails !== void 0
2733
+ );
2734
+ const workspacesWithoutUptimeData = totalWorkspaces - workspacesWithUptime.length;
2735
+ let uptimePercentage = null;
2736
+ let totalDowntimeMinutes;
2737
+ if (workspacesWithUptime.length > 0) {
2738
+ const totalUptime = workspacesWithUptime.reduce(
2739
+ (sum, workspace) => sum + (workspace.uptimePercentage || 0),
2740
+ 0
2741
+ );
2742
+ uptimePercentage = totalUptime / workspacesWithUptime.length;
2743
+ totalDowntimeMinutes = workspacesWithUptime.reduce((sum, workspace) => {
2744
+ if (!workspace.uptimeDetails) {
2745
+ return sum;
2746
+ }
2747
+ return sum + Math.max(0, workspace.uptimeDetails.expectedMinutes - workspace.uptimeDetails.actualMinutes);
2748
+ }, 0);
2749
+ }
2750
+ return {
2751
+ totalWorkspaces,
2752
+ healthyWorkspaces,
2753
+ unhealthyWorkspaces,
2754
+ warningWorkspaces,
2755
+ uptimePercentage,
2756
+ workspacesWithoutUptimeData,
2757
+ totalDowntimeMinutes,
2758
+ lastUpdated
2759
+ };
2760
+ };
2761
+
2762
+ // src/lib/services/workspaceHealthService.ts
2713
2763
  var DATA_PROCESSING_DELAY_MINUTES = 5;
2714
2764
  var WorkspaceHealthService = class _WorkspaceHealthService {
2715
2765
  constructor() {
@@ -2849,6 +2899,24 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2849
2899
  }
2850
2900
  return "down";
2851
2901
  }
2902
+ hasCompletedTimelineData(completedMinutes, shiftStartDate, outputHourly, outputArray, timezone) {
2903
+ if (completedMinutes <= 0) {
2904
+ return false;
2905
+ }
2906
+ for (let minuteIndex = 0; minuteIndex < completedMinutes; minuteIndex++) {
2907
+ const minuteDate = dateFns.addMinutes(shiftStartDate, minuteIndex);
2908
+ const hourKey = dateFnsTz.formatInTimeZone(minuteDate, timezone, "H");
2909
+ const minuteKey = Number.parseInt(dateFnsTz.formatInTimeZone(minuteDate, timezone, "m"), 10);
2910
+ const hourBucket = outputHourly[hourKey];
2911
+ if (Array.isArray(hourBucket) && hourBucket[minuteKey] !== void 0) {
2912
+ return true;
2913
+ }
2914
+ if (minuteIndex < outputArray.length) {
2915
+ return true;
2916
+ }
2917
+ }
2918
+ return false;
2919
+ }
2852
2920
  async getWorkspaceHealthStatus(options = {}) {
2853
2921
  const supabase = _getSupabaseInstance();
2854
2922
  if (!supabase) throw new Error("Supabase client not initialized");
@@ -2903,11 +2971,15 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2903
2971
  if (uptimeDetails) {
2904
2972
  return {
2905
2973
  ...workspace,
2974
+ hasUptimeData: true,
2906
2975
  uptimePercentage: uptimeDetails.percentage,
2907
2976
  uptimeDetails
2908
2977
  };
2909
2978
  }
2910
- return workspace;
2979
+ return {
2980
+ ...workspace,
2981
+ hasUptimeData: false
2982
+ };
2911
2983
  });
2912
2984
  let filteredData = dataWithUptime;
2913
2985
  try {
@@ -3039,6 +3111,33 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
3039
3111
  const record = Array.isArray(data) && data.length > 0 ? data[0] : null;
3040
3112
  const outputHourly = this.normalizeOutputHourly(record?.output_hourly || {});
3041
3113
  const outputArray = Array.isArray(record?.output_array) ? record.output_array : [];
3114
+ const hasData = Boolean(
3115
+ record && this.hasCompletedTimelineData(
3116
+ completedMinutes,
3117
+ shiftStartDate,
3118
+ outputHourly,
3119
+ outputArray,
3120
+ timezone
3121
+ )
3122
+ );
3123
+ if (!hasData) {
3124
+ return {
3125
+ shiftId: queryShiftId,
3126
+ shiftLabel,
3127
+ shiftStart: dateFnsTz.formatInTimeZone(shiftStartDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX"),
3128
+ shiftEnd: dateFnsTz.formatInTimeZone(shiftEndDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX"),
3129
+ totalMinutes,
3130
+ completedMinutes,
3131
+ uptimeMinutes: 0,
3132
+ downtimeMinutes: 0,
3133
+ pendingMinutes,
3134
+ uptimePercentage: 0,
3135
+ hasData: false,
3136
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3137
+ points: [],
3138
+ downtimeSegments: []
3139
+ };
3140
+ }
3042
3141
  const points = [];
3043
3142
  let uptimeMinutes = 0;
3044
3143
  let downtimeMinutes = 0;
@@ -3124,6 +3223,7 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
3124
3223
  downtimeMinutes,
3125
3224
  pendingMinutes,
3126
3225
  uptimePercentage,
3226
+ hasData: true,
3127
3227
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3128
3228
  points,
3129
3229
  downtimeSegments: filteredSegments
@@ -3152,37 +3252,7 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
3152
3252
  async getHealthSummary(lineId, companyId) {
3153
3253
  this.clearCache();
3154
3254
  const workspaces = await this.getWorkspaceHealthStatus({ lineId, companyId });
3155
- const totalWorkspaces = workspaces.length;
3156
- const healthyWorkspaces = workspaces.filter((w) => w.status === "healthy").length;
3157
- const unhealthyWorkspaces = workspaces.filter((w) => w.status === "unhealthy").length;
3158
- const warningWorkspaces = workspaces.filter((w) => w.status === "warning").length;
3159
- let uptimePercentage = 0;
3160
- let totalDowntimeMinutes = 0;
3161
- if (totalWorkspaces > 0) {
3162
- const workspacesWithUptime = workspaces.filter((w) => w.uptimePercentage !== void 0 && w.uptimeDetails !== void 0);
3163
- if (workspacesWithUptime.length > 0) {
3164
- const totalUptime = workspacesWithUptime.reduce((sum, w) => sum + (w.uptimePercentage || 0), 0);
3165
- uptimePercentage = totalUptime / workspacesWithUptime.length;
3166
- totalDowntimeMinutes = workspacesWithUptime.reduce((sum, w) => {
3167
- if (w.uptimeDetails) {
3168
- const downtime = Math.max(0, w.uptimeDetails.expectedMinutes - w.uptimeDetails.actualMinutes);
3169
- return sum + downtime;
3170
- }
3171
- return sum;
3172
- }, 0);
3173
- } else {
3174
- uptimePercentage = healthyWorkspaces / totalWorkspaces * 100;
3175
- }
3176
- }
3177
- return {
3178
- totalWorkspaces,
3179
- healthyWorkspaces,
3180
- unhealthyWorkspaces,
3181
- warningWorkspaces,
3182
- uptimePercentage,
3183
- totalDowntimeMinutes,
3184
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
3185
- };
3255
+ return computeWorkspaceHealthSummary(workspaces);
3186
3256
  }
3187
3257
  async getHealthMetrics(workspaceId, startDate, endDate) {
3188
3258
  const supabase = _getSupabaseInstance();
@@ -3221,7 +3291,8 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
3221
3291
  ...data,
3222
3292
  status,
3223
3293
  timeSinceLastUpdate,
3224
- isStale
3294
+ isStale,
3295
+ hasUptimeData: false
3225
3296
  };
3226
3297
  }
3227
3298
  getStatusPriority(status) {
@@ -15965,7 +16036,8 @@ var useWorkspaceHealthById = (workspaceId, options) => {
15965
16036
  ...healthData,
15966
16037
  status,
15967
16038
  timeSinceLastUpdate,
15968
- isStale: !lastUpdate || now4.getTime() - lastUpdate.getTime() > 15 * 6e4
16039
+ isStale: !lastUpdate || now4.getTime() - lastUpdate.getTime() > 15 * 6e4,
16040
+ hasUptimeData: false
15969
16041
  };
15970
16042
  setWorkspace(workspaceWithStatus);
15971
16043
  } else {
@@ -48017,14 +48089,11 @@ var WorkspaceHealthCard = ({
48017
48089
  };
48018
48090
  const getDowntimeConfig = (uptimeDetails) => {
48019
48091
  if (!uptimeDetails) {
48020
- if (workspace.status === "healthy") {
48021
- return {
48022
- text: "0m",
48023
- className: "text-emerald-600 dark:text-emerald-400",
48024
- label: "Total Downtime"
48025
- };
48026
- }
48027
- return { text: "--", className: "text-slate-400", label: "Total Downtime" };
48092
+ return {
48093
+ text: "--",
48094
+ className: "text-slate-400",
48095
+ label: "Uptime Data"
48096
+ };
48028
48097
  }
48029
48098
  const downtimeMinutes = Math.max(0, uptimeDetails.expectedMinutes - uptimeDetails.actualMinutes);
48030
48099
  if (downtimeMinutes === 0) {
@@ -48083,7 +48152,7 @@ var WorkspaceHealthCard = ({
48083
48152
  ] })
48084
48153
  ] }),
48085
48154
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 pt-3 border-t border-slate-100 dark:border-slate-800", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
48086
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-slate-500 uppercase tracking-wide", children: "Total Downtime" }),
48155
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-slate-500 uppercase tracking-wide", children: downtimeConfig.label }),
48087
48156
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx("text-sm font-semibold", downtimeConfig.className), children: downtimeConfig.text })
48088
48157
  ] }) })
48089
48158
  ] }),
@@ -48106,8 +48175,8 @@ var CompactWorkspaceHealthCard = ({
48106
48175
  className = "",
48107
48176
  onViewDetails
48108
48177
  }) => {
48109
- const downtimeMinutes = workspace.uptimeDetails ? Math.max(0, workspace.uptimeDetails.expectedMinutes - workspace.uptimeDetails.actualMinutes) : null;
48110
- const downtimeLabel = downtimeMinutes === null ? "No downtime data" : downtimeMinutes === 0 ? "No downtime" : `${downtimeMinutes} min down`;
48178
+ const downtimeMinutes = workspace.hasUptimeData && workspace.uptimeDetails ? Math.max(0, workspace.uptimeDetails.expectedMinutes - workspace.uptimeDetails.actualMinutes) : null;
48179
+ const downtimeLabel = !workspace.hasUptimeData ? "Uptime data unavailable" : downtimeMinutes === null ? "No downtime data" : downtimeMinutes === 0 ? "No downtime" : `${downtimeMinutes} min down`;
48111
48180
  const getStatusConfig = () => {
48112
48181
  switch (workspace.status) {
48113
48182
  case "healthy":
@@ -48176,7 +48245,7 @@ var CompactWorkspaceHealthCard = ({
48176
48245
  ] })
48177
48246
  ] }),
48178
48247
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
48179
- workspace.uptimePercentage !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
48248
+ workspace.hasUptimeData && workspace.uptimePercentage !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
48180
48249
  /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs font-medium text-gray-600 dark:text-gray-400", children: [
48181
48250
  workspace.uptimePercentage.toFixed(1),
48182
48251
  "%"
@@ -48184,6 +48253,7 @@ var CompactWorkspaceHealthCard = ({
48184
48253
  downtimeMinutes !== null && downtimeMinutes > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-400 dark:text-gray-400", children: "\u2022" }),
48185
48254
  downtimeLabel && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: downtimeLabel })
48186
48255
  ] }),
48256
+ !workspace.hasUptimeData && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Uptime data unavailable" }),
48187
48257
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: workspace.timeSinceLastUpdate }),
48188
48258
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("h-2 w-2 rounded-full", config.dot) }),
48189
48259
  onViewDetails && /* @__PURE__ */ jsxRuntime.jsx(
@@ -49756,7 +49826,28 @@ var SideNavBar = React141.memo(({
49756
49826
  const [isSettingsOpen, setIsSettingsOpen] = React141.useState(false);
49757
49827
  const settingsTriggerRef = React141.useRef(null);
49758
49828
  const [isAlertsOpen, setIsAlertsOpen] = React141.useState(false);
49759
- const [alertsCount, setAlertsCount] = React141.useState(0);
49829
+ const [alertsCount, setAlertsCount] = React141.useState(null);
49830
+ const [lastViewedCount, setLastViewedCount] = React141.useState(() => {
49831
+ if (typeof window !== "undefined") {
49832
+ return parseInt(localStorage.getItem("lastViewedAlertsCount") || "0", 10);
49833
+ }
49834
+ return 0;
49835
+ });
49836
+ React141.useEffect(() => {
49837
+ if (alertsCount === null) return;
49838
+ setLastViewedCount((prev) => {
49839
+ if (isAlertsOpen) {
49840
+ localStorage.setItem("lastViewedAlertsCount", alertsCount.toString());
49841
+ return alertsCount;
49842
+ }
49843
+ if (alertsCount < prev) {
49844
+ localStorage.setItem("lastViewedAlertsCount", alertsCount.toString());
49845
+ return alertsCount;
49846
+ }
49847
+ return prev;
49848
+ });
49849
+ }, [alertsCount, isAlertsOpen]);
49850
+ const unreadCount = alertsCount !== null ? Math.max(0, alertsCount - lastViewedCount) : 0;
49760
49851
  const alertsTriggerRef = React141.useRef(null);
49761
49852
  const alertsCompanyId = entityConfig.companyId || user?.company_id;
49762
49853
  const showAlertsButton = (role === "supervisor" || role === "optifye") && !!alertsCompanyId && !!supabase;
@@ -50045,10 +50136,7 @@ var SideNavBar = React141.memo(({
50045
50136
  children: [
50046
50137
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
50047
50138
  /* @__PURE__ */ jsxRuntime.jsx(outline.BellIcon, { className: "w-5 h-5 mb-1" }),
50048
- alertsCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "absolute -top-1 -right-1 flex h-2.5 w-2.5", children: [
50049
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75" }),
50050
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2.5 w-2.5 bg-red-500" })
50051
- ] })
50139
+ unreadCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1.5 -right-1.5 flex h-4 min-w-[16px] items-center justify-center rounded-full bg-red-500 px-1 text-[9px] font-bold text-white shadow-sm ring-2 ring-white", children: unreadCount > 99 ? "99+" : unreadCount })
50052
50140
  ] }),
50053
50141
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight mt-1", children: "Alerts" })
50054
50142
  ]
@@ -50200,10 +50288,7 @@ var SideNavBar = React141.memo(({
50200
50288
  children: [
50201
50289
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
50202
50290
  /* @__PURE__ */ jsxRuntime.jsx(outline.BellIcon, { className: getIconClass("/alerts") }),
50203
- alertsCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "absolute -top-1 -right-1 flex h-2.5 w-2.5", children: [
50204
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75" }),
50205
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2.5 w-2.5 bg-red-500" })
50206
- ] })
50291
+ unreadCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1.5 -right-1.5 flex h-4 min-w-[16px] items-center justify-center rounded-full bg-red-500 px-1 text-[9px] font-bold text-white shadow-sm ring-2 ring-white", children: unreadCount > 99 ? "99+" : unreadCount })
50207
50292
  ] }),
50208
50293
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium ml-3", children: "Alerts" })
50209
50294
  ]
@@ -50331,7 +50416,7 @@ var SideNavBar = React141.memo(({
50331
50416
  onClose: () => setIsAlertsOpen(false),
50332
50417
  triggerRef: alertsTriggerRef,
50333
50418
  companyId: alertsCompanyId,
50334
- alertsCount,
50419
+ alertsCount: alertsCount ?? 0,
50335
50420
  onAlertsLoaded: setAlertsCount
50336
50421
  }
50337
50422
  )
@@ -57380,6 +57465,7 @@ var WEEKDAYS4 = ["S", "M", "T", "W", "T", "F", "S"];
57380
57465
  var MonthlyRangeFilter = ({
57381
57466
  month,
57382
57467
  year,
57468
+ timezone,
57383
57469
  value,
57384
57470
  onChange,
57385
57471
  onMonthNavigate,
@@ -57387,32 +57473,34 @@ var MonthlyRangeFilter = ({
57387
57473
  variant = "default",
57388
57474
  showLabel = true
57389
57475
  }) => {
57390
- const presets = [
57476
+ const todayKey = React141.useMemo(
57477
+ () => dateFnsTz.formatInTimeZone(/* @__PURE__ */ new Date(), timezone || "UTC", "yyyy-MM-dd"),
57478
+ [timezone]
57479
+ );
57480
+ const todayDate = React141.useMemo(() => parseDateKeyToDate(todayKey), [todayKey]);
57481
+ const presets = React141.useMemo(() => [
57391
57482
  {
57392
- label: "Last Week",
57393
- getValue: () => ({
57394
- start: dateFns.startOfDay(dateFns.subDays(/* @__PURE__ */ new Date(), 6)),
57395
- end: dateFns.endOfDay(/* @__PURE__ */ new Date())
57396
- })
57483
+ label: "This Week",
57484
+ getValue: () => getCurrentWeekToDateRange(timezone)
57397
57485
  },
57398
57486
  {
57399
57487
  label: "Last Month",
57400
57488
  getValue: () => {
57401
- const lastMonth = dateFns.subMonths(/* @__PURE__ */ new Date(), 1);
57489
+ const lastMonth = dateFns.subMonths(todayDate, 1);
57402
57490
  return {
57403
- start: dateFns.startOfMonth(lastMonth),
57404
- end: dateFns.endOfMonth(lastMonth)
57491
+ startKey: dateFns.format(dateFns.startOfMonth(lastMonth), "yyyy-MM-dd"),
57492
+ endKey: dateFns.format(dateFns.endOfMonth(lastMonth), "yyyy-MM-dd")
57405
57493
  };
57406
57494
  }
57407
57495
  },
57408
57496
  {
57409
57497
  label: "This Month",
57410
57498
  getValue: () => ({
57411
- start: dateFns.startOfMonth(/* @__PURE__ */ new Date()),
57412
- end: dateFns.endOfDay(/* @__PURE__ */ new Date())
57499
+ startKey: dateFns.format(dateFns.startOfMonth(todayDate), "yyyy-MM-dd"),
57500
+ endKey: dateFns.format(todayDate, "yyyy-MM-dd")
57413
57501
  })
57414
57502
  }
57415
- ];
57503
+ ], [timezone, todayDate]);
57416
57504
  const monthBounds = React141.useMemo(() => getMonthKeyBounds(year, month), [year, month]);
57417
57505
  const normalizedRange = React141.useMemo(() => {
57418
57506
  return normalizeDateKeyRange(value.startKey, value.endKey, monthBounds.startKey, monthBounds.endKey);
@@ -57433,15 +57521,15 @@ var MonthlyRangeFilter = ({
57433
57521
  const [rangeEnd, setRangeEnd] = React141.useState(parseDateKeyToDate(normalizedRange.endKey));
57434
57522
  const [selecting, setSelecting] = React141.useState(false);
57435
57523
  const [activePreset, setActivePreset] = React141.useState(null);
57436
- const today = React141.useMemo(() => dateFns.endOfDay(/* @__PURE__ */ new Date()), []);
57524
+ const today = React141.useMemo(() => dateFns.endOfDay(todayDate), [todayDate]);
57437
57525
  React141.useEffect(() => {
57438
57526
  setCalendarMonth(month);
57439
57527
  setCalendarYear(year);
57440
57528
  }, [month, year]);
57441
57529
  React141.useEffect(() => {
57442
57530
  if (isOpen) {
57443
- const start = parseDateKeyToDate(normalizedRange.startKey);
57444
- const end = parseDateKeyToDate(normalizedRange.endKey);
57531
+ const start = parseDateKeyToDate(value.startKey);
57532
+ const end = parseDateKeyToDate(value.endKey);
57445
57533
  setRangeStart(start);
57446
57534
  setRangeEnd(end);
57447
57535
  setSelecting(false);
@@ -57449,11 +57537,11 @@ var MonthlyRangeFilter = ({
57449
57537
  setCalendarYear(year);
57450
57538
  const match = presets.find((p) => {
57451
57539
  const val = p.getValue();
57452
- return dateFns.isSameDay(val.start, start) && dateFns.isSameDay(val.end, end);
57540
+ return val.startKey === value.startKey && val.endKey === value.endKey;
57453
57541
  });
57454
57542
  setActivePreset(match ? match.label : "Custom");
57455
57543
  }
57456
- }, [isOpen, normalizedRange.startKey, normalizedRange.endKey, month, year]);
57544
+ }, [isOpen, month, presets, value.endKey, value.startKey, year]);
57457
57545
  React141.useEffect(() => {
57458
57546
  const handleClickOutside = (event) => {
57459
57547
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
@@ -57483,7 +57571,9 @@ var MonthlyRangeFilter = ({
57483
57571
  }
57484
57572
  };
57485
57573
  const handlePresetClick = (preset) => {
57486
- const { start, end } = preset.getValue();
57574
+ const { startKey, endKey } = preset.getValue();
57575
+ const start = parseDateKeyToDate(startKey);
57576
+ const end = parseDateKeyToDate(endKey);
57487
57577
  setRangeStart(start);
57488
57578
  setRangeEnd(end);
57489
57579
  setSelecting(false);
@@ -57523,8 +57613,7 @@ var MonthlyRangeFilter = ({
57523
57613
  const nextMonthDate = dateFns.addMonths(new Date(calendarYear, calendarMonth), 1);
57524
57614
  const newMonth = nextMonthDate.getMonth();
57525
57615
  const newYear = nextMonthDate.getFullYear();
57526
- const currentDate = /* @__PURE__ */ new Date();
57527
- if (newYear > currentDate.getFullYear() || newYear === currentDate.getFullYear() && newMonth > currentDate.getMonth()) {
57616
+ if (newYear > todayDate.getFullYear() || newYear === todayDate.getFullYear() && newMonth > todayDate.getMonth()) {
57528
57617
  return;
57529
57618
  }
57530
57619
  setCalendarMonth(newMonth);
@@ -57532,7 +57621,7 @@ var MonthlyRangeFilter = ({
57532
57621
  onMonthNavigate?.(newMonth, newYear);
57533
57622
  };
57534
57623
  const canGoPrevious = !(calendarYear === 2023 && calendarMonth === 0);
57535
- const canGoNext = !(calendarYear === (/* @__PURE__ */ new Date()).getFullYear() && calendarMonth === (/* @__PURE__ */ new Date()).getMonth());
57624
+ const canGoNext = !(calendarYear === todayDate.getFullYear() && calendarMonth === todayDate.getMonth());
57536
57625
  const monthDate = React141.useMemo(() => new Date(calendarYear, calendarMonth), [calendarYear, calendarMonth]);
57537
57626
  const calendarDays = React141.useMemo(() => {
57538
57627
  const start = dateFns.startOfMonth(monthDate);
@@ -66713,7 +66802,8 @@ var useWorkspaceHealth = (options) => {
66713
66802
  healthyWorkspaces: 0,
66714
66803
  unhealthyWorkspaces: 0,
66715
66804
  warningWorkspaces: 0,
66716
- uptimePercentage: 100,
66805
+ uptimePercentage: null,
66806
+ workspacesWithoutUptimeData: 0,
66717
66807
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
66718
66808
  });
66719
66809
  const [loading, setLoading] = React141.useState(true);
@@ -66721,36 +66811,10 @@ var useWorkspaceHealth = (options) => {
66721
66811
  const isFetchingRef = React141.useRef(false);
66722
66812
  const refreshIntervalRef = React141.useRef(null);
66723
66813
  const healthTable = databaseConfig?.tables?.workspace_health || "workspace_health_status";
66724
- const computeSummary = React141.useCallback((data) => {
66725
- const total = data.length;
66726
- const healthy = data.filter((w) => w.status === "healthy").length;
66727
- const unhealthy = data.filter((w) => w.status === "unhealthy").length;
66728
- const warning6 = data.filter((w) => w.status === "warning").length;
66729
- let uptimePercentage = total > 0 ? healthy / total * 100 : 100;
66730
- let totalDowntimeMinutes;
66731
- const withUptime = data.filter(
66732
- (w) => w.uptimePercentage !== void 0 && w.uptimeDetails !== void 0
66733
- );
66734
- if (withUptime.length > 0) {
66735
- const totalUptime = withUptime.reduce((sum, w) => sum + (w.uptimePercentage || 0), 0);
66736
- uptimePercentage = totalUptime / withUptime.length;
66737
- totalDowntimeMinutes = withUptime.reduce((sum, w) => {
66738
- if (w.uptimeDetails) {
66739
- return sum + Math.max(0, w.uptimeDetails.expectedMinutes - w.uptimeDetails.actualMinutes);
66740
- }
66741
- return sum;
66742
- }, 0);
66743
- }
66744
- return {
66745
- totalWorkspaces: total,
66746
- healthyWorkspaces: healthy,
66747
- unhealthyWorkspaces: unhealthy,
66748
- warningWorkspaces: warning6,
66749
- uptimePercentage,
66750
- totalDowntimeMinutes,
66751
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
66752
- };
66753
- }, []);
66814
+ const computeSummary = React141.useCallback(
66815
+ (data) => computeWorkspaceHealthSummary(data),
66816
+ []
66817
+ );
66754
66818
  const fetchWorkspacesHealth = React141.useCallback(async () => {
66755
66819
  if (isFetchingRef.current) return;
66756
66820
  if (isShiftConfigLoading) {
@@ -66905,7 +66969,7 @@ var UptimeTimelineStrip = ({
66905
66969
  shiftEnd,
66906
66970
  timezone,
66907
66971
  className = "",
66908
- uptimePercentage = 0,
66972
+ uptimePercentage = null,
66909
66973
  downtimeMinutes = 0
66910
66974
  }) => {
66911
66975
  const segments = React141.useMemo(() => {
@@ -66970,7 +67034,7 @@ var UptimeTimelineStrip = ({
66970
67034
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full rounded-xl border border-dashed border-gray-200 bg-gray-50/50 p-6 text-center text-sm text-gray-600", children: "No uptime data available for this shift yet." });
66971
67035
  }
66972
67036
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative w-full ${className}`, children: [
66973
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center mb-3 text-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-900 font-semibold", children: [
67037
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center mb-3 text-sm", children: typeof uptimePercentage === "number" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-900 font-semibold", children: [
66974
67038
  uptimePercentage.toFixed(1),
66975
67039
  " % uptime ",
66976
67040
  downtimeMinutes > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-600 font-normal", children: [
@@ -66978,7 +67042,7 @@ var UptimeTimelineStrip = ({
66978
67042
  formatDowntimeLabel(downtimeMinutes),
66979
67043
  ")"
66980
67044
  ] })
66981
- ] }) }),
67045
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600 font-medium", children: "Uptime data unavailable" }) }),
66982
67046
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex h-4 overflow-hidden rounded-lg border border-gray-200 shadow-sm bg-white", children: segments.map((segment, index) => {
66983
67047
  const startDate = new Date(segment.startTimestamp);
66984
67048
  const endDate = new Date(segment.endTimestamp);
@@ -67099,7 +67163,8 @@ var WorkspaceUptimeDetailModal = ({
67099
67163
  const downtimeSegments = timeline?.downtimeSegments || [];
67100
67164
  downtimeSegments.length;
67101
67165
  const downtimeMinutes = timeline?.downtimeMinutes ?? 0;
67102
- const uptimePercentage = timeline?.uptimePercentage ?? workspace?.uptimePercentage ?? 0;
67166
+ const hasTimelineData = Boolean(timeline?.hasData);
67167
+ const uptimePercentage = hasTimelineData ? timeline?.uptimePercentage ?? workspace?.uptimePercentage ?? null : null;
67103
67168
  const allInterruptionsSorted = React141.useMemo(
67104
67169
  () => [...downtimeSegments].sort(
67105
67170
  (a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime()
@@ -67221,7 +67286,7 @@ var WorkspaceUptimeDetailModal = ({
67221
67286
  shiftEnd: timeline?.shiftEnd || (/* @__PURE__ */ new Date()).toISOString(),
67222
67287
  timezone,
67223
67288
  uptimePercentage,
67224
- downtimeMinutes
67289
+ downtimeMinutes: hasTimelineData ? downtimeMinutes : 0
67225
67290
  }
67226
67291
  ),
67227
67292
  loading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-gray-600 mt-4", children: [
@@ -67231,7 +67296,7 @@ var WorkspaceUptimeDetailModal = ({
67231
67296
  ] }),
67232
67297
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-4", children: [
67233
67298
  /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-gray-900 uppercase tracking-wider mb-3", children: "Downtime Logs" }),
67234
- downtimeSegments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-gray-100 bg-gray-50/50 px-5 py-4 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-600", children: "No downtime events recorded for this shift." }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
67299
+ !hasTimelineData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-gray-100 bg-gray-50/50 px-5 py-4 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-600", children: "No uptime data available for this shift." }) }) : downtimeSegments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-gray-100 bg-gray-50/50 px-5 py-4 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-600", children: "No downtime events recorded for this shift." }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
67235
67300
  /* @__PURE__ */ jsxRuntime.jsx(
67236
67301
  "div",
67237
67302
  {
@@ -67356,6 +67421,7 @@ var WorkspaceHealthView = ({
67356
67421
  }
67357
67422
  };
67358
67423
  const getUptimeColor = (percentage) => {
67424
+ if (percentage === null) return "text-gray-500 dark:text-gray-400";
67359
67425
  if (percentage >= 97) return "text-green-600 dark:text-green-400";
67360
67426
  if (percentage >= 90) return "text-yellow-600 dark:text-yellow-400";
67361
67427
  return "text-red-600 dark:text-red-400";
@@ -67465,13 +67531,16 @@ var WorkspaceHealthView = ({
67465
67531
  /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: "System Availability" }) }),
67466
67532
  /* @__PURE__ */ jsxRuntime.jsxs(CardContent2, { children: [
67467
67533
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [
67468
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: clsx("text-3xl font-bold", getUptimeColor(summary.uptimePercentage)), children: [
67469
- summary.uptimePercentage.toFixed(1),
67470
- "%"
67471
- ] }),
67472
- summary.uptimePercentage >= 97 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { className: "h-5 w-5 text-green-500" }) : summary.uptimePercentage >= 90 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Activity, { className: "h-5 w-5 text-yellow-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingDown, { className: "h-5 w-5 text-red-500" })
67534
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx("text-3xl font-bold", getUptimeColor(summary.uptimePercentage)), children: summary.uptimePercentage === null ? "No data" : `${summary.uptimePercentage.toFixed(1)}%` }),
67535
+ summary.uptimePercentage === null ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Activity, { className: "h-5 w-5 text-gray-400" }) : summary.uptimePercentage >= 97 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { className: "h-5 w-5 text-green-500" }) : summary.uptimePercentage >= 90 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Activity, { className: "h-5 w-5 text-yellow-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingDown, { className: "h-5 w-5 text-red-500" })
67473
67536
  ] }),
67474
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Overall system uptime today" })
67537
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: summary.uptimePercentage === null ? "Uptime metrics unavailable for visible workspaces" : "Overall system uptime today" }),
67538
+ summary.workspacesWithoutUptimeData > 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-amber-600 mt-1", children: [
67539
+ summary.workspacesWithoutUptimeData,
67540
+ " workspace",
67541
+ summary.workspacesWithoutUptimeData === 1 ? "" : "s",
67542
+ " missing uptime data"
67543
+ ] })
67475
67544
  ] })
67476
67545
  ] }),
67477
67546
  /* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "bg-white", children: [
@@ -69117,6 +69186,155 @@ Please ensure:
69117
69186
  var AuthenticatedTicketsView = withAuth(React141__namespace.default.memo(TicketsView));
69118
69187
  var TicketsView_default = TicketsView;
69119
69188
 
69189
+ // src/lib/utils/improvementDisplay.ts
69190
+ var LINE_WIDE_ISSUE_LABEL = "Line-wide issue";
69191
+ var UNKNOWN_LINE_LABEL = "Unknown line";
69192
+ var UNKNOWN_WORKSTATION_LABEL = "Unknown workstation";
69193
+ var UNASSIGNED_SUPERVISOR_LABEL = "Unassigned";
69194
+ var normalizeLabel = (value) => {
69195
+ if (typeof value !== "string") return void 0;
69196
+ const trimmed = value.trim();
69197
+ return trimmed.length > 0 ? trimmed : void 0;
69198
+ };
69199
+ var toFiniteNumber = (value) => {
69200
+ if (typeof value === "number" && Number.isFinite(value)) return value;
69201
+ if (typeof value === "string" && value.trim().length > 0) {
69202
+ const parsed = Number(value);
69203
+ return Number.isFinite(parsed) ? parsed : null;
69204
+ }
69205
+ return null;
69206
+ };
69207
+ var normalizeSupervisorNames = (supervisors) => {
69208
+ if (!supervisors) return [];
69209
+ if (typeof supervisors === "string") {
69210
+ const label = normalizeLabel(supervisors);
69211
+ return label ? [label] : [];
69212
+ }
69213
+ return supervisors.map((supervisor) => {
69214
+ if (typeof supervisor === "string") {
69215
+ return normalizeLabel(supervisor);
69216
+ }
69217
+ return normalizeLabel(supervisor?.displayName);
69218
+ }).filter((name) => !!name);
69219
+ };
69220
+ var formatImprovementTicketNumber = (issueNumber) => {
69221
+ if (typeof issueNumber !== "number" || !Number.isFinite(issueNumber)) {
69222
+ return null;
69223
+ }
69224
+ return `#${issueNumber}`;
69225
+ };
69226
+ var formatImprovementPieceGain = (pcsGain) => {
69227
+ const rounded = Math.round(pcsGain);
69228
+ return `+${rounded.toLocaleString("en-US")} pcs / day`;
69229
+ };
69230
+ var getPositiveImprovementGain = ({
69231
+ estimated_gain_pieces
69232
+ }) => {
69233
+ const issueGain = toFiniteNumber(estimated_gain_pieces);
69234
+ return {
69235
+ pcsGain: issueGain !== null && issueGain > 0 ? issueGain : null
69236
+ };
69237
+ };
69238
+ var getImprovementDisplayMetadata = ({
69239
+ location,
69240
+ line,
69241
+ workspaceId,
69242
+ supervisors
69243
+ }) => {
69244
+ const supervisorNames = normalizeSupervisorNames(supervisors);
69245
+ const workstationLabel = workspaceId ? normalizeLabel(location) ?? UNKNOWN_WORKSTATION_LABEL : LINE_WIDE_ISSUE_LABEL;
69246
+ const lineLabel = normalizeLabel(line) ?? UNKNOWN_LINE_LABEL;
69247
+ const supervisorLabel = supervisorNames.length > 0 ? supervisorNames.join(", ") : UNASSIGNED_SUPERVISOR_LABEL;
69248
+ return {
69249
+ workstationLabel,
69250
+ lineLabel,
69251
+ supervisorLabel,
69252
+ metadataLabel: [workstationLabel, lineLabel, supervisorLabel].join(" \xB7 ")
69253
+ };
69254
+ };
69255
+ var toFiniteNumber2 = (value) => {
69256
+ if (typeof value === "number" && Number.isFinite(value)) return value;
69257
+ if (typeof value === "string" && value.trim().length > 0) {
69258
+ const parsed = Number(value);
69259
+ return Number.isFinite(parsed) ? parsed : null;
69260
+ }
69261
+ return null;
69262
+ };
69263
+ var getImprovementGainSummary = (recommendation) => {
69264
+ const { pcsGain } = getPositiveImprovementGain(recommendation);
69265
+ if (pcsGain !== null) {
69266
+ return {
69267
+ primary: formatImprovementPieceGain(pcsGain)
69268
+ };
69269
+ }
69270
+ return null;
69271
+ };
69272
+ var needsTargetReadjustment = (recommendation) => {
69273
+ if (recommendation.targets_need_reassignment === true) return true;
69274
+ const metrics2 = recommendation.metrics || {};
69275
+ return metrics2.targets_need_reassignment_current === true;
69276
+ };
69277
+ var compareImprovementRecommendationPriority = (left, right) => {
69278
+ const leftIndustrial = left.industrial_eng_bottleneck ? 1 : 0;
69279
+ const rightIndustrial = right.industrial_eng_bottleneck ? 1 : 0;
69280
+ if (leftIndustrial !== rightIndustrial) {
69281
+ return rightIndustrial - leftIndustrial;
69282
+ }
69283
+ const leftGain = toFiniteNumber2(left.estimated_gain_pieces);
69284
+ const rightGain = toFiniteNumber2(right.estimated_gain_pieces);
69285
+ if (leftGain !== rightGain) {
69286
+ if (leftGain === null) return 1;
69287
+ if (rightGain === null) return -1;
69288
+ return rightGain - leftGain;
69289
+ }
69290
+ const leftRatio = toFiniteNumber2(left.gain_to_target_ratio);
69291
+ const rightRatio = toFiniteNumber2(right.gain_to_target_ratio);
69292
+ if (leftRatio !== rightRatio) {
69293
+ if (leftRatio === null) return 1;
69294
+ if (rightRatio === null) return -1;
69295
+ return rightRatio - leftRatio;
69296
+ }
69297
+ return (left.issue_number || Number.MAX_SAFE_INTEGER) - (right.issue_number || Number.MAX_SAFE_INTEGER);
69298
+ };
69299
+ var ImprovementRecommendationSignals = ({
69300
+ recommendation,
69301
+ className
69302
+ }) => {
69303
+ const gainSummary = getImprovementGainSummary(recommendation);
69304
+ const showTargetReadjustment = needsTargetReadjustment(recommendation);
69305
+ if (!gainSummary && !showTargetReadjustment) {
69306
+ return null;
69307
+ }
69308
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: className || "flex flex-wrap items-center gap-x-4 gap-y-3", children: [
69309
+ gainSummary && /* @__PURE__ */ jsxRuntime.jsxs(
69310
+ "span",
69311
+ {
69312
+ "data-testid": "improvement-gain-chip",
69313
+ className: "inline-flex items-center gap-1.5 rounded-full border border-emerald-200 bg-emerald-50 px-3 py-1.5 text-sm font-medium text-emerald-700 shadow-sm",
69314
+ children: [
69315
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-trending-up w-4 h-4", children: [
69316
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "22 7 13.5 15.5 8.5 10.5 2 17" }),
69317
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "16 7 22 7 22 13" })
69318
+ ] }),
69319
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: gainSummary.primary })
69320
+ ]
69321
+ }
69322
+ ),
69323
+ showTargetReadjustment && /* @__PURE__ */ jsxRuntime.jsxs(
69324
+ "span",
69325
+ {
69326
+ "data-testid": "targets-readjustment-chip",
69327
+ className: "inline-flex items-center gap-1.5 rounded-full border border-amber-200 bg-white px-3 py-1.5 text-sm font-medium text-amber-700 shadow-sm",
69328
+ children: [
69329
+ /* @__PURE__ */ jsxRuntime.jsx(outline.CalendarIcon, { className: "h-4 w-4 text-amber-600" }),
69330
+ "Targets need readjustment"
69331
+ ]
69332
+ }
69333
+ )
69334
+ ] });
69335
+ };
69336
+ var ImprovementRecommendationSignals_default = ImprovementRecommendationSignals;
69337
+
69120
69338
  // src/lib/api/s3-clips-parser.ts
69121
69339
  function parseS3Uri(s3Uri, sopCategories) {
69122
69340
  const path = new URL(s3Uri).pathname;
@@ -69294,6 +69512,24 @@ var buildInitials = (name) => {
69294
69512
  const second = parts.length > 1 ? parts[1]?.[0] || "" : "";
69295
69513
  return `${first}${second}`.toUpperCase();
69296
69514
  };
69515
+ var getQueryParam = (value) => {
69516
+ if (typeof value === "string") {
69517
+ const trimmed = value.trim();
69518
+ return trimmed.length > 0 ? trimmed : null;
69519
+ }
69520
+ if (Array.isArray(value)) {
69521
+ const firstValue = value[0];
69522
+ return getQueryParam(firstValue);
69523
+ }
69524
+ return null;
69525
+ };
69526
+ var getQueryParamFromAsPath = (asPath, key) => {
69527
+ if (!asPath || !asPath.includes("?")) return null;
69528
+ const queryString = asPath.split("?")[1]?.split("#")[0];
69529
+ if (!queryString) return null;
69530
+ const value = new URLSearchParams(queryString).get(key);
69531
+ return getQueryParam(value ?? void 0);
69532
+ };
69297
69533
  var ClipVideoCarousel = ({ clips, clipsService }) => {
69298
69534
  const [currentIndex, setCurrentIndex] = React141.useState(0);
69299
69535
  const [videos, setVideos] = React141.useState([]);
@@ -69615,6 +69851,7 @@ var EvidenceCarousel = ({ evidence, clipsService }) => {
69615
69851
  };
69616
69852
  var ImprovementCenterView = () => {
69617
69853
  const { navigate } = useNavigation();
69854
+ const router$1 = router.useRouter();
69618
69855
  const supabase = useSupabase();
69619
69856
  const { user } = useAuth();
69620
69857
  const dashboardConfig = useDashboardConfig();
@@ -69625,6 +69862,7 @@ var ImprovementCenterView = () => {
69625
69862
  const [selectedShift, setSelectedShift] = React141.useState("all");
69626
69863
  const [selectedWeeksRange, setSelectedWeeksRange] = React141.useState("all");
69627
69864
  const [selectedMemberId, setSelectedMemberId] = React141.useState("all");
69865
+ const [selectedSortBy, setSelectedSortBy] = React141.useState("all");
69628
69866
  const [recommendations, setRecommendations] = React141.useState([]);
69629
69867
  const [isLoading, setIsLoading] = React141.useState(false);
69630
69868
  const [loadError, setLoadError] = React141.useState(null);
@@ -69663,14 +69901,6 @@ var ImprovementCenterView = () => {
69663
69901
  if (day % 10 === 3) return "rd";
69664
69902
  return "th";
69665
69903
  };
69666
- const formatOpenedDate = (firstSeenAt) => {
69667
- if (!firstSeenAt) return void 0;
69668
- const zoned = toZonedDate(firstSeenAt);
69669
- if (!zoned) return void 0;
69670
- const day = zoned.getDate();
69671
- const month = zoned.toLocaleString("en-US", { month: "short" });
69672
- return `${day}${getDaySuffix(day)} ${month}`;
69673
- };
69674
69904
  const formatMonthDay = (date) => {
69675
69905
  const month = date.toLocaleString("en-US", { month: "short" });
69676
69906
  return `${month} ${date.getDate()}`;
@@ -69752,6 +69982,9 @@ var ImprovementCenterView = () => {
69752
69982
  return map;
69753
69983
  }, [companyLines, configuredLines]);
69754
69984
  const companyId = user?.company_id || entityConfig.companyId;
69985
+ const focusIssueId = React141.useMemo(() => {
69986
+ return getQueryParam(router$1.query.focusIssueId) || getQueryParamFromAsPath(router$1.asPath, "focusIssueId");
69987
+ }, [router$1.asPath, router$1.query.focusIssueId]);
69755
69988
  const clipsService = React141.useMemo(() => {
69756
69989
  try {
69757
69990
  return new S3ClipsSupabaseService(dashboardConfig);
@@ -69759,6 +69992,11 @@ var ImprovementCenterView = () => {
69759
69992
  return null;
69760
69993
  }
69761
69994
  }, [dashboardConfig]);
69995
+ const { supervisorsByLineId } = useSupervisorsByLineIds(scopeLineIds, {
69996
+ enabled: !!companyId && scopeLineIds.length > 0,
69997
+ companyId,
69998
+ useBackend: true
69999
+ });
69762
70000
  React141.useEffect(() => {
69763
70001
  let cancelled = false;
69764
70002
  const loadTeamMembers = async () => {
@@ -69870,8 +70108,17 @@ var ImprovementCenterView = () => {
69870
70108
  const teamMembersById = React141.useMemo(() => {
69871
70109
  return new Map(teamMembers.map((member) => [member.id, member]));
69872
70110
  }, [teamMembers]);
70111
+ const getRecommendationDisplayMetadata = React141__namespace.default.useCallback((rec) => {
70112
+ const supervisors = rec.line_id ? supervisorsByLineId.get(rec.line_id) || [] : [];
70113
+ return getImprovementDisplayMetadata({
70114
+ location: rec.location,
70115
+ line: rec.line,
70116
+ workspaceId: rec.workspace_id,
70117
+ supervisors
70118
+ });
70119
+ }, [supervisorsByLineId]);
69873
70120
  const filteredRecommendations = React141.useMemo(() => {
69874
- return recommendations.filter((rec) => {
70121
+ const sortedRecommendations = recommendations.filter((rec) => {
69875
70122
  if (selectedLineId !== "all" && rec.line_id !== selectedLineId) return false;
69876
70123
  if (selectedStatus === "resolved" && rec.ticket_status !== "solved") return false;
69877
70124
  if (selectedStatus === "unresolved" && rec.ticket_status === "solved") return false;
@@ -69885,12 +70132,44 @@ var ImprovementCenterView = () => {
69885
70132
  if (selectedMemberId !== "all" && !(rec.assigned_user_ids?.includes(selectedMemberId) || rec.assigned_to_user_id === selectedMemberId)) return false;
69886
70133
  return true;
69887
70134
  }).sort((a, b) => {
69888
- const aIndustrial = a.industrial_eng_bottleneck ? 1 : 0;
69889
- const bIndustrial = b.industrial_eng_bottleneck ? 1 : 0;
69890
- if (aIndustrial !== bIndustrial) return bIndustrial - aIndustrial;
69891
- return (a.issue_number || 0) - (b.issue_number || 0);
70135
+ if (selectedSortBy === "highest_to_lowest") {
70136
+ const gainA = toFiniteNumber2(a.estimated_gain_pieces) || 0;
70137
+ const gainB = toFiniteNumber2(b.estimated_gain_pieces) || 0;
70138
+ if (gainA !== gainB) {
70139
+ return gainB - gainA;
70140
+ }
70141
+ } else if (selectedSortBy === "lowest_to_highest") {
70142
+ const gainA = toFiniteNumber2(a.estimated_gain_pieces) || 0;
70143
+ const gainB = toFiniteNumber2(b.estimated_gain_pieces) || 0;
70144
+ if (gainA !== gainB) {
70145
+ return gainA - gainB;
70146
+ }
70147
+ }
70148
+ return compareImprovementRecommendationPriority(a, b);
69892
70149
  });
69893
- }, [recommendations, selectedLineId, selectedStatus, selectedShift, selectedWeeksRange, selectedMemberId]);
70150
+ if (!focusIssueId) {
70151
+ return sortedRecommendations;
70152
+ }
70153
+ const focusedIndex = sortedRecommendations.findIndex((rec) => rec.issue_id === focusIssueId);
70154
+ if (focusedIndex <= 0) {
70155
+ return sortedRecommendations;
70156
+ }
70157
+ const focusedItem = sortedRecommendations[focusedIndex];
70158
+ return [
70159
+ focusedItem,
70160
+ ...sortedRecommendations.slice(0, focusedIndex),
70161
+ ...sortedRecommendations.slice(focusedIndex + 1)
70162
+ ];
70163
+ }, [
70164
+ focusIssueId,
70165
+ recommendations,
70166
+ selectedLineId,
70167
+ selectedMemberId,
70168
+ selectedShift,
70169
+ selectedStatus,
70170
+ selectedWeeksRange,
70171
+ selectedSortBy
70172
+ ]);
69894
70173
  const stats = React141.useMemo(() => {
69895
70174
  const baseFiltered = recommendations.filter((rec) => {
69896
70175
  if (selectedLineId !== "all" && rec.line_id !== selectedLineId) return false;
@@ -69919,7 +70198,8 @@ var ImprovementCenterView = () => {
69919
70198
  status: selectedStatus,
69920
70199
  shift: selectedShift,
69921
70200
  weeks_range: selectedWeeksRange,
69922
- member_id: selectedMemberId
70201
+ member_id: selectedMemberId,
70202
+ sort_by: selectedSortBy
69923
70203
  }
69924
70204
  });
69925
70205
  setSelectedLineId("all");
@@ -69927,6 +70207,7 @@ var ImprovementCenterView = () => {
69927
70207
  setSelectedShift("all");
69928
70208
  setSelectedWeeksRange("all");
69929
70209
  setSelectedMemberId("all");
70210
+ setSelectedSortBy("all");
69930
70211
  };
69931
70212
  const shiftOptions = React141.useMemo(() => {
69932
70213
  const shifts = /* @__PURE__ */ new Set();
@@ -70006,6 +70287,14 @@ var ImprovementCenterView = () => {
70006
70287
  });
70007
70288
  setSelectedLineId(lineId);
70008
70289
  };
70290
+ const handleSortByChange = (sortBy) => {
70291
+ trackCoreEvent("Improvement Center Filter Applied", {
70292
+ filter_type: "sort_by",
70293
+ filter_value: sortBy,
70294
+ previous_value: selectedSortBy
70295
+ });
70296
+ setSelectedSortBy(sortBy);
70297
+ };
70009
70298
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen bg-gray-50 flex flex-col", children: [
70010
70299
  /* @__PURE__ */ jsxRuntime.jsx("header", { className: "sticky top-0 z-30 bg-white border-b border-gray-200 flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 sm:px-6 lg:px-8 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
70011
70300
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-4 min-w-[120px]", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -70045,11 +70334,11 @@ var ImprovementCenterView = () => {
70045
70334
  "button",
70046
70335
  {
70047
70336
  onClick: () => setIsFilterOpen(!isFilterOpen),
70048
- className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || (selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all") ? "bg-blue-50 border-blue-200 text-blue-700" : "bg-white border-gray-200 text-gray-700 hover:bg-gray-50"}`,
70337
+ className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || (selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all" || selectedSortBy !== "all") ? "bg-blue-50 border-blue-200 text-blue-700" : "bg-white border-gray-200 text-gray-700 hover:bg-gray-50"}`,
70049
70338
  children: [
70050
70339
  /* @__PURE__ */ jsxRuntime.jsx(outline.FunnelIcon, { className: "w-4 h-4" }),
70051
70340
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Filters" }),
70052
- (selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all") && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-5 h-5 bg-blue-100 text-blue-700 text-xs rounded-full font-bold ml-1", children: [selectedShift, selectedWeeksRange, selectedMemberId, selectedLineId].filter((v) => v !== "all").length }),
70341
+ (selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all" || selectedSortBy !== "all") && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-5 h-5 bg-blue-100 text-blue-700 text-xs rounded-full font-bold ml-1", children: [selectedShift, selectedWeeksRange, selectedMemberId, selectedLineId].filter((v) => v !== "all").length + (selectedSortBy !== "all" ? 1 : 0) }),
70053
70342
  /* @__PURE__ */ jsxRuntime.jsx(outline.ChevronDownIcon, { className: `w-3 h-3 ml-1 transition-transform ${isFilterOpen ? "rotate-180" : ""}` })
70054
70343
  ]
70055
70344
  }
@@ -70057,7 +70346,7 @@ var ImprovementCenterView = () => {
70057
70346
  isFilterOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 top-full mt-2 w-72 bg-white rounded-xl shadow-xl border border-gray-100 p-4 z-50 animate-in fade-in zoom-in-95 duration-100", children: [
70058
70347
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
70059
70348
  /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Filter View" }),
70060
- (selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all") && /* @__PURE__ */ jsxRuntime.jsx(
70349
+ (selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all" || selectedSortBy !== "all") && /* @__PURE__ */ jsxRuntime.jsx(
70061
70350
  "button",
70062
70351
  {
70063
70352
  onClick: clearFilters,
@@ -70067,6 +70356,7 @@ var ImprovementCenterView = () => {
70067
70356
  )
70068
70357
  ] }),
70069
70358
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: [
70359
+ { value: selectedSortBy, onChange: handleSortByChange, options: [{ id: "all", label: "All" }, { id: "highest_to_lowest", label: "Highest to Lowest" }, { id: "lowest_to_highest", label: "Lowest to Highest" }], label: "Priority" },
70070
70360
  { value: selectedShift, onChange: handleShiftFilterChange, options: shiftOptions, label: "Shift" },
70071
70361
  { value: selectedWeeksRange, onChange: handleWeeksFilterChange, options: weekOptions.map((o) => o.id), labels: weekOptions, label: "Duration" },
70072
70362
  { value: selectedMemberId, onChange: handleMemberFilterChange, options: ["all", ...teamMembers.map((m) => m.id)], labels: teamMembers, label: "Member" },
@@ -70082,12 +70372,19 @@ var ImprovementCenterView = () => {
70082
70372
  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` },
70083
70373
  children: filter2.options.map((opt) => {
70084
70374
  const val = typeof opt === "string" ? opt : opt.id;
70085
- let label = val;
70086
- if (filter2.labels) {
70087
- const found = filter2.labels.find((l) => (l.id || l.user_id || l) === val);
70375
+ let label;
70376
+ if (val === "all") {
70377
+ label = filter2.label === "Priority" ? "All Priorities" : `All ${filter2.label}s`;
70378
+ } else if (typeof opt === "object" && opt !== null && typeof opt.label === "string" && opt.label.length > 0) {
70379
+ label = opt.label;
70380
+ } else if (filter2.labels) {
70381
+ const found = filter2.labels.find(
70382
+ (l) => (l.id || l.user_id || l) === val
70383
+ );
70088
70384
  label = found ? found.label || found.name || found : val;
70385
+ } else {
70386
+ label = val;
70089
70387
  }
70090
- if (val === "all") label = `All ${filter2.label}s`;
70091
70388
  return /* @__PURE__ */ jsxRuntime.jsx("option", { value: val, children: label }, val);
70092
70389
  })
70093
70390
  }
@@ -70100,23 +70397,25 @@ var ImprovementCenterView = () => {
70100
70397
  filteredRecommendations.length > 0 ? filteredRecommendations.map((rec, index) => {
70101
70398
  const weeksOpen = rec.weeks_open || 1;
70102
70399
  const openLabel = weeksOpen <= 1 ? "Opened this week" : `Opened for ${weeksOpen} weeks`;
70103
- formatOpenedDate(rec.first_seen_at);
70104
70400
  const periodLabel = formatPeriodRange(rec.period_start, rec.period_end);
70105
70401
  const description = stripPeriodFromDescription(rec.description, rec.period_start, rec.period_end);
70402
+ const ticketLabel = formatImprovementTicketNumber(rec.issue_number) || `#${index + 1}`;
70403
+ const displayMetadata = getRecommendationDisplayMetadata(rec);
70404
+ const hasSignalContent = Boolean(
70405
+ rec.resolution_instructions || rec.targets_need_reassignment || rec.estimated_gain_pieces !== void 0 || rec.metrics && Object.keys(rec.metrics).length > 0
70406
+ );
70106
70407
  return /* @__PURE__ */ jsxRuntime.jsx(
70107
70408
  motion.div,
70108
70409
  {
70109
70410
  initial: { opacity: 0, y: 20 },
70110
70411
  animate: { opacity: 1, y: 0 },
70111
70412
  transition: { delay: index * 0.1 },
70413
+ "data-testid": `improvement-card-${rec.issue_id}`,
70112
70414
  className: `bg-white rounded-xl shadow-sm border overflow-hidden ${rec.ticket_status === "solved" ? "border-green-200" : "border-gray-200"}`,
70113
70415
  children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-5 relative", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col lg:flex-row gap-5", children: [
70114
70416
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
70115
70417
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2 mb-3", children: [
70116
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-sm font-semibold text-gray-600 bg-gray-100 border border-gray-200", children: [
70117
- "#",
70118
- rec.issue_number ?? index + 1
70119
- ] }),
70418
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-sm font-semibold text-gray-600 bg-gray-100 border border-gray-200", children: ticketLabel }),
70120
70419
  rec.ticket_status === "solved" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-sm font-medium bg-emerald-50 text-emerald-700 border border-emerald-100", children: [
70121
70420
  /* @__PURE__ */ jsxRuntime.jsx(outline.CheckCircleIcon, { className: "w-4 h-4" }),
70122
70421
  "Resolved"
@@ -70145,32 +70444,44 @@ var ImprovementCenterView = () => {
70145
70444
  ] })
70146
70445
  ] }),
70147
70446
  /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-900 mb-2", children: rec.title }),
70148
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-base text-gray-500 mb-3", children: [
70149
- rec.location,
70150
- " \xB7 ",
70151
- rec.line,
70152
- (rec.shift_label || rec.shift_id !== void 0) && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "uppercase tracking-wide text-sm ml-1", children: [
70153
- "\xB7 ",
70154
- rec.shift_label || `Shift ${rec.shift_id}`
70155
- ] }),
70156
- periodLabel && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
70157
- " \xB7 ",
70158
- periodLabel
70159
- ] })
70160
- ] }),
70447
+ /* @__PURE__ */ jsxRuntime.jsxs(
70448
+ "p",
70449
+ {
70450
+ className: "text-base text-gray-500 mb-3",
70451
+ title: displayMetadata.metadataLabel,
70452
+ children: [
70453
+ displayMetadata.workstationLabel,
70454
+ " \xB7 ",
70455
+ displayMetadata.lineLabel,
70456
+ " \xB7 ",
70457
+ displayMetadata.supervisorLabel,
70458
+ (rec.shift_label || rec.shift_id !== void 0) && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "uppercase tracking-wide text-sm ml-1", children: [
70459
+ "\xB7 ",
70460
+ rec.shift_label || `Shift ${rec.shift_id}`
70461
+ ] }),
70462
+ periodLabel && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
70463
+ " \xB7 ",
70464
+ periodLabel
70465
+ ] })
70466
+ ]
70467
+ }
70468
+ ),
70161
70469
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base text-gray-600 leading-relaxed", children: description }),
70162
- rec.resolution_instructions && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group inline-flex mt-4", children: [
70163
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-sm font-medium bg-blue-50 text-blue-600 border border-blue-200 cursor-help transition-colors group-hover:bg-blue-100", children: [
70164
- /* @__PURE__ */ jsxRuntime.jsx(outline.EyeIcon, { className: "w-4 h-4" }),
70165
- "Resolution Goal"
70166
- ] }),
70167
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-0 bottom-full mb-2 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-150 z-50 pointer-events-none", children: [
70168
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-xl border border-gray-100 p-4 w-80", children: [
70169
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-500 uppercase tracking-wide mb-1.5", children: "How this ticket gets resolved" }),
70170
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base text-gray-700 leading-relaxed", children: rec.resolution_instructions })
70470
+ hasSignalContent && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 flex flex-wrap items-center gap-x-4 gap-y-3", children: [
70471
+ rec.resolution_instructions && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group inline-flex", children: [
70472
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-sm font-medium bg-blue-50 text-blue-600 border border-blue-200 cursor-help transition-colors group-hover:bg-blue-100 shadow-sm", children: [
70473
+ /* @__PURE__ */ jsxRuntime.jsx(outline.EyeIcon, { className: "w-4 h-4" }),
70474
+ "Resolve"
70171
70475
  ] }),
70172
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-4 top-full w-0 h-0 border-l-[6px] border-r-[6px] border-t-[6px] border-transparent border-t-white", style: { filter: "drop-shadow(0 1px 1px rgba(0,0,0,0.05))" } })
70173
- ] })
70476
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-0 bottom-full mb-2 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-150 z-50 pointer-events-none", children: [
70477
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-xl border border-gray-100 p-4 w-80", children: [
70478
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-500 uppercase tracking-wide mb-1.5", children: "How this ticket gets resolved" }),
70479
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base text-gray-700 leading-relaxed", children: rec.resolution_instructions })
70480
+ ] }),
70481
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-6 top-full w-0 h-0 border-l-[6px] border-r-[6px] border-t-[6px] border-transparent border-t-white", style: { filter: "drop-shadow(0 1px 1px rgba(0,0,0,0.05))" } })
70482
+ ] })
70483
+ ] }),
70484
+ /* @__PURE__ */ jsxRuntime.jsx(ImprovementRecommendationSignals_default, { recommendation: rec })
70174
70485
  ] })
70175
70486
  ] }),
70176
70487
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full lg:w-5/12 bg-gray-50 rounded-lg p-4 border border-gray-100 flex-shrink-0", children: Array.isArray(rec.evidence) && rec.evidence.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -70190,8 +70501,8 @@ var ImprovementCenterView = () => {
70190
70501
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-16 bg-white rounded-xl border border-gray-200 shadow-sm", children: [
70191
70502
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto flex items-center justify-center w-16 h-16 rounded-full bg-green-50 mb-4", children: /* @__PURE__ */ jsxRuntime.jsx(outline.CheckCircleIcon, { className: "w-8 h-8 text-green-500" }) }),
70192
70503
  /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-900", children: "No tickets found" }),
70193
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-gray-500 max-w-md mx-auto", children: selectedLineId !== "all" || selectedStatus !== "all" || selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" ? "Try adjusting your filters to see more results." : "All monitored long-term patterns were evaluated and remained within limits. This is a success state!" }),
70194
- (selectedLineId !== "all" || selectedStatus !== "all" || selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all") && /* @__PURE__ */ jsxRuntime.jsx(
70504
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-gray-500 max-w-md mx-auto", children: selectedLineId !== "all" || selectedStatus !== "all" || selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedSortBy !== "all" ? "Try adjusting your filters to see more results." : "All monitored long-term patterns were evaluated and remained within limits. This is a success state!" }),
70505
+ (selectedLineId !== "all" || selectedStatus !== "all" || selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedSortBy !== "all") && /* @__PURE__ */ jsxRuntime.jsx(
70195
70506
  "button",
70196
70507
  {
70197
70508
  onClick: clearFilters,
@@ -72265,7 +72576,7 @@ var EMPTY_OVERVIEW = {
72265
72576
  },
72266
72577
  summary: {
72267
72578
  plant_efficiency: { current: null, previous: null, delta_pp: null },
72268
- avg_idle_per_workstation: { current_seconds: null, previous_seconds: null, delta_seconds: null }
72579
+ avg_idle_per_workstation: { current_seconds: null, previous_seconds: null, delta_seconds: null, top_contributors: [] }
72269
72580
  },
72270
72581
  poorest_lines: { output: [], uptime: [] },
72271
72582
  trend: { shift_mode: "all", points: [] },
@@ -72291,15 +72602,6 @@ var toNumber3 = (value) => {
72291
72602
  return null;
72292
72603
  };
72293
72604
  var roundOne = (value) => Math.round(value * 10) / 10;
72294
- var getLastSevenDayRange = (timezone) => {
72295
- const todayKey = dateFnsTz.formatInTimeZone(/* @__PURE__ */ new Date(), timezone || "UTC", "yyyy-MM-dd");
72296
- const endDate = dateFns.parseISO(`${todayKey}T00:00:00`);
72297
- const startDate = dateFns.subDays(endDate, 6);
72298
- return {
72299
- startKey: dateFns.format(startDate, "yyyy-MM-dd"),
72300
- endKey: dateFns.format(endDate, "yyyy-MM-dd")
72301
- };
72302
- };
72303
72605
  var formatIdleDuration = (seconds) => {
72304
72606
  if (seconds === null || seconds === void 0 || !Number.isFinite(seconds)) {
72305
72607
  return "--";
@@ -72314,23 +72616,11 @@ var formatComparisonWindow = (dayCount) => {
72314
72616
  if (!dayCount || !Number.isFinite(dayCount)) return "previous range";
72315
72617
  return `previous ${dayCount} ${dayCount === 1 ? "day" : "days"}`;
72316
72618
  };
72317
- var shuffle = (items) => {
72318
- const next = [...items];
72319
- for (let i = next.length - 1; i > 0; i -= 1) {
72320
- const swapIndex = Math.floor(Math.random() * (i + 1));
72321
- [next[i], next[swapIndex]] = [next[swapIndex], next[i]];
72322
- }
72323
- return next;
72324
- };
72325
72619
  var buildImprovementMetric = (recommendation) => {
72620
+ const { pcsGain } = getPositiveImprovementGain(recommendation);
72326
72621
  const metrics2 = recommendation.metrics || {};
72327
- const efficiencyGain = toNumber3(metrics2.efficiency_gain_pct);
72328
- if (efficiencyGain !== null) {
72329
- return `+${roundOne(efficiencyGain)}% Efficiency`;
72330
- }
72331
- const outputGain = toNumber3(metrics2.output_gain);
72332
- if (outputGain !== null) {
72333
- return `+${Math.round(outputGain)} Units`;
72622
+ if (pcsGain !== null) {
72623
+ return formatImprovementPieceGain(pcsGain);
72334
72624
  }
72335
72625
  const idleMinutes = toNumber3(metrics2.idle_minutes);
72336
72626
  if (idleMinutes !== null) {
@@ -72342,14 +72632,6 @@ var buildImprovementMetric = (recommendation) => {
72342
72632
  }
72343
72633
  return "Review Issue";
72344
72634
  };
72345
- var buildImprovementImpact = (recommendation) => {
72346
- if (recommendation.issue_severity !== void 0 && recommendation.issue_severity !== null) {
72347
- if (recommendation.issue_severity >= 3) return "High";
72348
- if (recommendation.issue_severity >= 2) return "Medium";
72349
- return "Low";
72350
- }
72351
- return "Medium";
72352
- };
72353
72635
  var buildDeltaBadge = (delta, options) => {
72354
72636
  if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
72355
72637
  return {
@@ -72407,12 +72689,15 @@ var OverviewIdleBreakdownSkeleton = () => /* @__PURE__ */ jsxRuntime.jsxs("div",
72407
72689
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-slate-200 rounded w-20" })
72408
72690
  ] }, i)) })
72409
72691
  ] });
72410
- var OverviewImprovementsSkeleton = () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4 py-3", children: Array.from({ length: 3 }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
72411
- /* @__PURE__ */ jsxRuntime.jsx(SectionPulse, { className: "h-4 w-4 rounded-full" }),
72412
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-2", children: [
72413
- /* @__PURE__ */ jsxRuntime.jsx(SectionPulse, { className: "h-3 w-40" }),
72414
- /* @__PURE__ */ jsxRuntime.jsx(SectionPulse, { className: "h-2.5 w-24" })
72415
- ] })
72692
+ var OverviewImprovementsSkeleton = () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4 py-3", children: Array.from({ length: 3 }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4", children: [
72693
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0 pr-4", children: [
72694
+ /* @__PURE__ */ jsxRuntime.jsx(SectionPulse, { className: "h-5 w-10 rounded-full flex-shrink-0" }),
72695
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-2 min-w-0", children: [
72696
+ /* @__PURE__ */ jsxRuntime.jsx(SectionPulse, { className: "h-3 w-40" }),
72697
+ /* @__PURE__ */ jsxRuntime.jsx(SectionPulse, { className: "h-2.5 w-24" })
72698
+ ] })
72699
+ ] }),
72700
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end flex-shrink-0 ml-4", children: /* @__PURE__ */ jsxRuntime.jsx(SectionPulse, { className: "h-6 w-20 rounded-full" }) })
72416
72701
  ] }, index)) });
72417
72702
  var PlantHeadView = () => {
72418
72703
  const supabase = useSupabase();
@@ -72422,7 +72707,7 @@ var PlantHeadView = () => {
72422
72707
  const { accessibleLineIds } = useUserLineAccess();
72423
72708
  const mobileMenuContext = useMobileMenu();
72424
72709
  useHideMobileHeader(!!mobileMenuContext);
72425
- const [dateRange, setDateRange] = React141__namespace.default.useState(() => getLastSevenDayRange("UTC"));
72710
+ const [dateRange, setDateRange] = React141__namespace.default.useState(() => getCurrentWeekToDateRange(appTimezone));
72426
72711
  const [trendMode, setTrendMode] = React141__namespace.default.useState("all");
72427
72712
  const [poorestLineMode, setPoorestLineMode] = React141__namespace.default.useState("output");
72428
72713
  const [overview, setOverview] = React141__namespace.default.useState(EMPTY_OVERVIEW);
@@ -72436,9 +72721,12 @@ var PlantHeadView = () => {
72436
72721
  const [improvements, setImprovements] = React141__namespace.default.useState([]);
72437
72722
  const [isImprovementsLoading, setIsImprovementsLoading] = React141__namespace.default.useState(false);
72438
72723
  const [isFilterOpen, setIsFilterOpen] = React141__namespace.default.useState(false);
72724
+ const [isIdleContributorsOpen, setIsIdleContributorsOpen] = React141__namespace.default.useState(false);
72725
+ const [isIdleContributorsPinned, setIsIdleContributorsPinned] = React141__namespace.default.useState(false);
72439
72726
  const filterRef = React141__namespace.default.useRef(null);
72440
72727
  const filterButtonRef = React141__namespace.default.useRef(null);
72441
72728
  const mobileFilterButtonRef = React141__namespace.default.useRef(null);
72729
+ const idleContributorsRef = React141__namespace.default.useRef(null);
72442
72730
  React141__namespace.default.useEffect(() => {
72443
72731
  trackCorePageView("Operations Overview");
72444
72732
  }, []);
@@ -72479,11 +72767,11 @@ var PlantHeadView = () => {
72479
72767
  document.removeEventListener("mousedown", handleClickOutside);
72480
72768
  };
72481
72769
  }, []);
72482
- const hasInitializedRangeRef = React141__namespace.default.useRef(false);
72770
+ const initializedTimezoneRef = React141__namespace.default.useRef(appTimezone);
72483
72771
  React141__namespace.default.useEffect(() => {
72484
- if (hasInitializedRangeRef.current) return;
72485
- setDateRange(getLastSevenDayRange(appTimezone));
72486
- hasInitializedRangeRef.current = true;
72772
+ if (initializedTimezoneRef.current === appTimezone) return;
72773
+ setDateRange(getCurrentWeekToDateRange(appTimezone));
72774
+ initializedTimezoneRef.current = appTimezone;
72487
72775
  }, [appTimezone]);
72488
72776
  const companyId = entityConfig.companyId;
72489
72777
  const scopedLineIds = React141__namespace.default.useMemo(
@@ -72494,6 +72782,10 @@ var PlantHeadView = () => {
72494
72782
  () => scopedLineIds.slice().sort().join(","),
72495
72783
  [scopedLineIds]
72496
72784
  );
72785
+ React141__namespace.default.useEffect(() => {
72786
+ setIsIdleContributorsOpen(false);
72787
+ setIsIdleContributorsPinned(false);
72788
+ }, [companyId, dateRange.endKey, dateRange.startKey, lineIdsKey, trendMode]);
72497
72789
  const { supervisorsByLineId } = useSupervisorsByLineIds(scopedLineIds, {
72498
72790
  enabled: !!companyId && scopedLineIds.length > 0,
72499
72791
  companyId,
@@ -72691,11 +72983,16 @@ var PlantHeadView = () => {
72691
72983
  const scopedRecommendations = (response.recommendations || []).filter((recommendation) => {
72692
72984
  return !recommendation.line_id || allowedLineIds.has(recommendation.line_id);
72693
72985
  });
72694
- const nextImprovements = shuffle(scopedRecommendations).slice(0, 3).map((recommendation) => ({
72695
- id: recommendation.id,
72986
+ const nextImprovements = [...scopedRecommendations].sort(compareImprovementRecommendationPriority).slice(0, 3).map((recommendation) => ({
72987
+ id: recommendation.issue_id || recommendation.id,
72988
+ issueId: recommendation.issue_id || recommendation.id,
72989
+ issueNumber: recommendation.issue_number,
72696
72990
  title: recommendation.title?.trim() || "Untitled issue",
72697
- impact: buildImprovementImpact(recommendation),
72698
- metric: buildImprovementMetric(recommendation)
72991
+ metric: buildImprovementMetric(recommendation),
72992
+ location: recommendation.location,
72993
+ line: recommendation.line,
72994
+ lineId: recommendation.line_id,
72995
+ workspaceId: recommendation.workspace_id
72699
72996
  }));
72700
72997
  setImprovements(nextImprovements);
72701
72998
  };
@@ -72741,7 +73038,99 @@ var PlantHeadView = () => {
72741
73038
  comparisonLabel
72742
73039
  });
72743
73040
  }, [comparisonLabel, overview.summary?.avg_idle_per_workstation?.delta_seconds]);
73041
+ const canInspectIdleContributors = React141__namespace.default.useMemo(() => {
73042
+ return !isSnapshotLoading && overview.summary?.avg_idle_per_workstation?.current_seconds !== null && overview.summary?.avg_idle_per_workstation?.current_seconds !== void 0;
73043
+ }, [isSnapshotLoading, overview.summary?.avg_idle_per_workstation?.current_seconds]);
73044
+ const idleTopContributors = React141__namespace.default.useMemo(() => {
73045
+ return (overview.summary?.avg_idle_per_workstation?.top_contributors || []).map((item) => ({
73046
+ workspaceId: item.workspace_id || "",
73047
+ workspaceName: item.workspace_name?.trim() || item.workspace_id || "Unknown",
73048
+ lineId: item.line_id || "",
73049
+ lineName: item.line_name?.trim() || "Unknown Line",
73050
+ avgIdleSeconds: toNumber3(item.avg_idle_seconds)
73051
+ })).slice(0, 5);
73052
+ }, [overview.summary?.avg_idle_per_workstation?.top_contributors]);
73053
+ const showIdleContributorLineNames = React141__namespace.default.useMemo(() => {
73054
+ return (overview.scope?.line_count ?? 0) > 1;
73055
+ }, [overview.scope?.line_count]);
73056
+ const closeIdleContributors = React141__namespace.default.useCallback(() => {
73057
+ setIsIdleContributorsOpen(false);
73058
+ setIsIdleContributorsPinned(false);
73059
+ }, []);
73060
+ const handleIdleContributorsToggle = React141__namespace.default.useCallback(() => {
73061
+ if (!canInspectIdleContributors) return;
73062
+ setIsIdleContributorsPinned((prev) => {
73063
+ const next = !prev;
73064
+ setIsIdleContributorsOpen(next);
73065
+ return next;
73066
+ });
73067
+ }, [canInspectIdleContributors]);
73068
+ const handleIdleContributorsKeyDown = React141__namespace.default.useCallback((event) => {
73069
+ if (!canInspectIdleContributors) return;
73070
+ if (event.key === "Enter" || event.key === " ") {
73071
+ event.preventDefault();
73072
+ handleIdleContributorsToggle();
73073
+ return;
73074
+ }
73075
+ if (event.key === "Escape") {
73076
+ event.preventDefault();
73077
+ closeIdleContributors();
73078
+ }
73079
+ }, [canInspectIdleContributors, closeIdleContributors, handleIdleContributorsToggle]);
73080
+ React141__namespace.default.useEffect(() => {
73081
+ if (!isIdleContributorsOpen) return void 0;
73082
+ const handleClickOutside = (event) => {
73083
+ if (!isIdleContributorsPinned) return;
73084
+ if (idleContributorsRef.current && !idleContributorsRef.current.contains(event.target)) {
73085
+ closeIdleContributors();
73086
+ }
73087
+ };
73088
+ const handleEscape = (event) => {
73089
+ if (event.key === "Escape") {
73090
+ closeIdleContributors();
73091
+ }
73092
+ };
73093
+ document.addEventListener("mousedown", handleClickOutside);
73094
+ document.addEventListener("touchstart", handleClickOutside);
73095
+ document.addEventListener("keydown", handleEscape);
73096
+ return () => {
73097
+ document.removeEventListener("mousedown", handleClickOutside);
73098
+ document.removeEventListener("touchstart", handleClickOutside);
73099
+ document.removeEventListener("keydown", handleEscape);
73100
+ };
73101
+ }, [closeIdleContributors, isIdleContributorsOpen, isIdleContributorsPinned]);
73102
+ const currentWeekRange = React141__namespace.default.useMemo(
73103
+ () => getCurrentWeekToDateRange(appTimezone),
73104
+ [appTimezone]
73105
+ );
73106
+ const isCurrentWeekToDateRange = dateRange.startKey === currentWeekRange.startKey && dateRange.endKey === currentWeekRange.endKey;
72744
73107
  const trendData = React141__namespace.default.useMemo(() => {
73108
+ const pointsByDate = new Map(
73109
+ (overview.trend?.points || []).flatMap((point) => {
73110
+ if (!point.date) return [];
73111
+ const pointDate = parseDateKeyToDate(point.date);
73112
+ return [[point.date, {
73113
+ name: dateFns.format(pointDate, "MMM d"),
73114
+ dayOfWeek: dateFns.format(pointDate, "EEEE"),
73115
+ efficiency: (() => {
73116
+ const value = toNumber3(point.avg_efficiency);
73117
+ return value === null ? void 0 : value;
73118
+ })()
73119
+ }]];
73120
+ })
73121
+ );
73122
+ if (isCurrentWeekToDateRange) {
73123
+ const weekStart = parseDateKeyToDate(currentWeekRange.startKey);
73124
+ return Array.from({ length: 7 }, (_, index) => {
73125
+ const date = dateFns.addDays(weekStart, index);
73126
+ const dateKey = dateFns.format(date, "yyyy-MM-dd");
73127
+ return pointsByDate.get(dateKey) || {
73128
+ name: dateFns.format(date, "MMM d"),
73129
+ dayOfWeek: dateFns.format(date, "EEEE"),
73130
+ efficiency: void 0
73131
+ };
73132
+ });
73133
+ }
72745
73134
  return (overview.trend?.points || []).map((point) => {
72746
73135
  const pointDate = point.date ? parseDateKeyToDate(point.date) : null;
72747
73136
  return {
@@ -72753,7 +73142,7 @@ var PlantHeadView = () => {
72753
73142
  })()
72754
73143
  };
72755
73144
  });
72756
- }, [overview.trend?.points]);
73145
+ }, [currentWeekRange.startKey, isCurrentWeekToDateRange, overview.trend?.points]);
72757
73146
  const trendPlayKey = React141__namespace.default.useMemo(() => {
72758
73147
  return `${trendViewOpenNonce}:${trendFetchNonce}`;
72759
73148
  }, [trendFetchNonce, trendViewOpenNonce]);
@@ -72800,6 +73189,33 @@ var PlantHeadView = () => {
72800
73189
  if (!dayOfWeek || typeof label !== "string") return label;
72801
73190
  return `${label} (${dayOfWeek})`;
72802
73191
  }, []);
73192
+ const displayImprovements = React141__namespace.default.useMemo(() => {
73193
+ return improvements.map((item) => {
73194
+ const supervisors = item.lineId ? supervisorsByLineId.get(item.lineId) || [] : [];
73195
+ return {
73196
+ ...item,
73197
+ ticketLabel: formatImprovementTicketNumber(item.issueNumber),
73198
+ ...getImprovementDisplayMetadata({
73199
+ location: item.location,
73200
+ line: item.line,
73201
+ workspaceId: item.workspaceId,
73202
+ supervisors
73203
+ })
73204
+ };
73205
+ });
73206
+ }, [improvements, supervisorsByLineId]);
73207
+ const mobileSubtitle = React141__namespace.default.useMemo(() => {
73208
+ if (isCurrentWeekToDateRange) {
73209
+ return `Week of ${dateFns.format(parseDateKeyToDate(dateRange.startKey), "do MMM")}`;
73210
+ }
73211
+ return `${dateFns.format(parseDateKeyToDate(dateRange.startKey), "do MMM")} - ${dateFns.format(parseDateKeyToDate(dateRange.endKey), "do MMM, yyyy")}`;
73212
+ }, [dateRange.endKey, dateRange.startKey, isCurrentWeekToDateRange]);
73213
+ const desktopSubtitle = React141__namespace.default.useMemo(() => {
73214
+ if (isCurrentWeekToDateRange) {
73215
+ return `Week of ${dateFns.format(parseDateKeyToDate(dateRange.startKey), "do MMMM, yyyy")}`;
73216
+ }
73217
+ return `${dateFns.format(parseDateKeyToDate(dateRange.startKey), "do MMMM, yyyy")} - ${dateFns.format(parseDateKeyToDate(dateRange.endKey), "do MMMM, yyyy")}`;
73218
+ }, [dateRange.endKey, dateRange.startKey, isCurrentWeekToDateRange]);
72803
73219
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-h-screen bg-slate-50 w-full font-sans", children: [
72804
73220
  /* @__PURE__ */ jsxRuntime.jsx("header", { className: "sticky top-0 z-10 bg-white border-b flex-shrink-0 shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 sm:px-4 md:px-6 py-2 sm:py-3 relative", children: [
72805
73221
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
@@ -72812,11 +73228,7 @@ var PlantHeadView = () => {
72812
73228
  ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 flex-shrink-0" }),
72813
73229
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center", children: [
72814
73230
  /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-gray-900 text-center px-1 truncate max-w-[200px]", children: "Operations Overview" }),
72815
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] font-medium text-slate-500 text-center mt-0.5", children: [
72816
- dateFns.format(parseDateKeyToDate(dateRange.startKey), "do MMM"),
72817
- " - ",
72818
- dateFns.format(parseDateKeyToDate(dateRange.endKey), "do MMM, yyyy")
72819
- ] })
73231
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium text-slate-500 text-center mt-0.5", children: mobileSubtitle })
72820
73232
  ] }),
72821
73233
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 flex items-center gap-1.5", children: [
72822
73234
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -72848,11 +73260,7 @@ var PlantHeadView = () => {
72848
73260
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center relative min-h-[56px]", children: [
72849
73261
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center pointer-events-none", children: [
72850
73262
  /* @__PURE__ */ jsxRuntime.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" }),
72851
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs sm:text-sm font-medium text-slate-500 text-center pointer-events-auto", children: [
72852
- dateFns.format(parseDateKeyToDate(dateRange.startKey), "do MMMM, yyyy"),
72853
- " - ",
72854
- dateFns.format(parseDateKeyToDate(dateRange.endKey), "do MMMM, yyyy")
72855
- ] })
73263
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm font-medium text-slate-500 text-center pointer-events-auto", children: desktopSubtitle })
72856
73264
  ] }),
72857
73265
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 flex items-center gap-3", children: [
72858
73266
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -72940,16 +73348,92 @@ var PlantHeadView = () => {
72940
73348
  /* @__PURE__ */ jsxRuntime.jsxs(
72941
73349
  "div",
72942
73350
  {
72943
- className: "bg-white rounded-xl shadow-sm border border-slate-100 p-4 md:p-5 flex flex-col justify-center min-h-[100px] text-left",
73351
+ ref: idleContributorsRef,
73352
+ "data-testid": "idle-kpi-card-region",
73353
+ className: "relative",
73354
+ onMouseEnter: () => {
73355
+ if (canInspectIdleContributors) {
73356
+ setIsIdleContributorsOpen(true);
73357
+ }
73358
+ },
73359
+ onMouseLeave: () => {
73360
+ if (!isIdleContributorsPinned) {
73361
+ setIsIdleContributorsOpen(false);
73362
+ }
73363
+ },
73364
+ onFocus: () => {
73365
+ if (canInspectIdleContributors) {
73366
+ setIsIdleContributorsOpen(true);
73367
+ }
73368
+ },
73369
+ onBlur: (event) => {
73370
+ if (isIdleContributorsPinned) return;
73371
+ const nextTarget = event.relatedTarget;
73372
+ if (nextTarget && idleContributorsRef.current?.contains(nextTarget)) return;
73373
+ setIsIdleContributorsOpen(false);
73374
+ },
72944
73375
  children: [
72945
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-between items-center mb-1", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Idle Time per Workstation" }) }),
72946
- isSnapshotLoading ? /* @__PURE__ */ jsxRuntime.jsx(OverviewMetricCardSkeleton, {}) : overview.summary?.avg_idle_per_workstation?.current_seconds !== null && overview.summary?.avg_idle_per_workstation?.current_seconds !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:gap-3 mt-1", children: [
72947
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-2xl sm:text-3xl font-bold text-slate-800 tracking-tight", children: formatIdleDuration(overview.summary.avg_idle_per_workstation.current_seconds) }),
72948
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${idleBadge.className}`, children: [
72949
- idleBadge.icon === "up" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : idleBadge.icon === "down" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
72950
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm font-medium", children: idleBadge.text })
72951
- ] })
72952
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No idle time data available" })
73376
+ /* @__PURE__ */ jsxRuntime.jsxs(
73377
+ "div",
73378
+ {
73379
+ "data-testid": "idle-kpi-card",
73380
+ role: canInspectIdleContributors ? "button" : void 0,
73381
+ tabIndex: canInspectIdleContributors ? 0 : -1,
73382
+ "aria-controls": canInspectIdleContributors ? "idle-kpi-popover" : void 0,
73383
+ "aria-expanded": canInspectIdleContributors ? isIdleContributorsOpen : void 0,
73384
+ className: `bg-white rounded-xl border p-4 md:p-5 flex flex-col justify-center min-h-[100px] text-left transition-all ${canInspectIdleContributors ? "cursor-pointer hover:shadow-md focus:outline-none focus:ring-2 focus:ring-indigo-200" : ""} ${isIdleContributorsOpen ? "shadow-md border-indigo-100" : "shadow-sm border-slate-100"}`,
73385
+ onClick: handleIdleContributorsToggle,
73386
+ onKeyDown: handleIdleContributorsKeyDown,
73387
+ children: [
73388
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Idle Time per Workstation" }) }),
73389
+ isSnapshotLoading ? /* @__PURE__ */ jsxRuntime.jsx(OverviewMetricCardSkeleton, {}) : overview.summary?.avg_idle_per_workstation?.current_seconds !== null && overview.summary?.avg_idle_per_workstation?.current_seconds !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:gap-3 mt-1", children: [
73390
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-2xl sm:text-3xl font-bold text-slate-800 tracking-tight", children: formatIdleDuration(overview.summary.avg_idle_per_workstation.current_seconds) }),
73391
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${idleBadge.className}`, children: [
73392
+ idleBadge.icon === "up" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : idleBadge.icon === "down" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
73393
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm font-medium", children: idleBadge.text })
73394
+ ] })
73395
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No idle time data available" })
73396
+ ]
73397
+ }
73398
+ ),
73399
+ canInspectIdleContributors && isIdleContributorsOpen ? /* @__PURE__ */ jsxRuntime.jsxs(
73400
+ "div",
73401
+ {
73402
+ id: "idle-kpi-popover",
73403
+ "data-testid": "idle-kpi-popover",
73404
+ className: "absolute left-0 right-0 top-full z-20 mt-2 bg-white p-4 border border-gray-100 shadow-xl rounded-xl sm:left-auto sm:right-0 sm:w-[320px] min-w-[280px]",
73405
+ children: [
73406
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 pb-3 mb-3 border-b border-slate-100", children: [
73407
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2.5 h-2.5 rounded-full flex-shrink-0 bg-red-500" }),
73408
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-slate-800 text-[15px]", children: "Idle Time per Workstation" })
73409
+ ] }),
73410
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
73411
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] font-bold uppercase tracking-wider text-slate-400 mb-3", children: "TOP CONTRIBUTORS" }),
73412
+ idleTopContributors.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2.5", children: idleTopContributors.map((contributor, index) => /* @__PURE__ */ jsxRuntime.jsxs(
73413
+ "div",
73414
+ {
73415
+ className: "flex items-start justify-between gap-3",
73416
+ children: [
73417
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
73418
+ /* @__PURE__ */ jsxRuntime.jsx(
73419
+ "div",
73420
+ {
73421
+ className: "text-slate-600 text-[13px] truncate",
73422
+ title: contributor.workspaceName,
73423
+ children: contributor.workspaceName
73424
+ }
73425
+ ),
73426
+ showIdleContributorLineNames && contributor.lineName ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[11px] font-medium text-slate-400 truncate", title: contributor.lineName, children: contributor.lineName }) : null
73427
+ ] }),
73428
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-slate-500 text-[13px] text-right whitespace-nowrap", children: formatIdleDuration(contributor.avgIdleSeconds) })
73429
+ ]
73430
+ },
73431
+ `${contributor.workspaceId || contributor.workspaceName}-${index}`
73432
+ )) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-dashed border-slate-200 bg-slate-50 px-3 py-2 text-xs text-slate-500", children: "No workstation idle averages available for this range." })
73433
+ ] })
73434
+ ]
73435
+ }
73436
+ ) : null
72953
73437
  ]
72954
73438
  }
72955
73439
  )
@@ -73103,24 +73587,48 @@ var PlantHeadView = () => {
73103
73587
  }
73104
73588
  )
73105
73589
  ] }),
73106
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 p-0 flex flex-col px-5 py-2 justify-start overflow-auto", children: isImprovementsLoading ? /* @__PURE__ */ jsxRuntime.jsx(OverviewImprovementsSkeleton, {}) : improvements.length > 0 ? improvements.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
73590
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 p-0 flex flex-col px-5 py-2 justify-start overflow-auto", children: isImprovementsLoading ? /* @__PURE__ */ jsxRuntime.jsx(OverviewImprovementsSkeleton, {}) : displayImprovements.length > 0 ? displayImprovements.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
73107
73591
  "div",
73108
73592
  {
73593
+ "data-testid": `plant-head-improvement-${item.issueId}`,
73109
73594
  onClick: () => {
73110
- trackCoreEvent("Operations Overview Improvement Clicked", { issue_id: item.id, title: item.title });
73111
- navigate("/improvement-center");
73595
+ trackCoreEvent("Operations Overview Improvement Clicked", {
73596
+ issue_id: item.issueId,
73597
+ issue_number: item.issueNumber,
73598
+ title: item.title
73599
+ });
73600
+ const params = new URLSearchParams({
73601
+ focusIssueId: item.issueId
73602
+ });
73603
+ navigate(`/improvement-center?${params.toString()}`);
73112
73604
  },
73113
73605
  className: "flex items-center justify-between py-3 border-b border-slate-50 last:border-0 group cursor-pointer",
73114
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0 pr-4", children: [
73115
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { className: "w-4 h-4 text-slate-400 group-hover:text-indigo-500 transition-colors" }) }),
73116
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
73117
- /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-[13px] font-semibold text-slate-800 truncate transition-colors group-hover:text-indigo-600 mb-0.5", children: item.title }),
73118
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-[10px] font-medium text-slate-400", children: [
73119
- "Impact: ",
73120
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-500 font-semibold", children: item.impact })
73606
+ children: [
73607
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0 pr-4", children: [
73608
+ item.ticketLabel && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center rounded-full border border-indigo-100 bg-indigo-50 px-2 py-0.5 text-[10px] font-semibold text-indigo-600", children: item.ticketLabel }) }),
73609
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
73610
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 min-w-0 mb-0.5", children: /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-[13px] font-semibold text-slate-800 truncate transition-colors group-hover:text-indigo-600", children: item.title }) }),
73611
+ /* @__PURE__ */ jsxRuntime.jsx(
73612
+ "p",
73613
+ {
73614
+ className: "text-[10px] font-medium text-slate-400 truncate",
73615
+ title: item.metadataLabel,
73616
+ children: item.metadataLabel
73617
+ }
73618
+ )
73121
73619
  ] })
73122
- ] })
73123
- ] })
73620
+ ] }),
73621
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end flex-shrink-0 ml-4", children: /* @__PURE__ */ jsxRuntime.jsxs(
73622
+ "span",
73623
+ {
73624
+ className: `inline-flex items-center gap-1 rounded-full border px-2.5 py-0.5 text-[11px] ${item.metric.includes("pcs / day") || item.metric.includes("gain") ? "border-emerald-100 bg-emerald-50 text-emerald-700" : item.metric.includes("Idle") ? "border-amber-100 bg-amber-50 text-amber-700" : "border-slate-100 bg-slate-50 text-slate-600"}`,
73625
+ children: [
73626
+ (item.metric.includes("pcs / day") || item.metric.includes("gain")) && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { className: "h-3 w-3" }),
73627
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: item.metric })
73628
+ ]
73629
+ }
73630
+ ) })
73631
+ ]
73124
73632
  },
73125
73633
  item.id
73126
73634
  )) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-8 text-center text-sm text-slate-400", children: "No open improvement issues" }) })
@@ -73908,6 +74416,7 @@ exports.getCoreSessionReplayUrl = getCoreSessionReplayUrl;
73908
74416
  exports.getCurrentShift = getCurrentShift;
73909
74417
  exports.getCurrentShiftForLine = getCurrentShiftForLine;
73910
74418
  exports.getCurrentTimeInZone = getCurrentTimeInZone;
74419
+ exports.getCurrentWeekToDateRange = getCurrentWeekToDateRange;
73911
74420
  exports.getDashboardHeaderTimeInZone = getDashboardHeaderTimeInZone;
73912
74421
  exports.getDateKeyFromDate = getDateKeyFromDate;
73913
74422
  exports.getDaysDifferenceInZone = getDaysDifferenceInZone;