@optifye/dashboard-core 6.10.52 → 6.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,22 +1,22 @@
1
- import * as React26 from 'react';
2
- import React26__default, { createContext, useRef, useCallback, useState, useMemo, useEffect, forwardRef, useImperativeHandle, useLayoutEffect, memo as memo$1, useContext, useId, Children, isValidElement, useInsertionEffect, Fragment as Fragment$1, createElement, Component } from 'react';
1
+ import * as React141 from 'react';
2
+ import React141__default, { createContext, useRef, useCallback, useState, useMemo, useEffect, forwardRef, useImperativeHandle, useLayoutEffect, memo as memo$1, useContext, useId, Children, isValidElement, useInsertionEffect, Fragment as Fragment$1, createElement, Component } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { useRouter } from 'next/router';
5
5
  import { fromZonedTime, formatInTimeZone, toZonedTime } from 'date-fns-tz';
6
- import { endOfDay, startOfDay, endOfMonth, startOfMonth, isSameDay, eachDayOfInterval, getDay, isWithinInterval, format, addDays, differenceInMinutes, addMinutes, subDays, subMonths, addMonths, parseISO, isValid, formatDistanceToNow, isToday, isFuture, isBefore } from 'date-fns';
6
+ import { endOfDay, startOfDay, startOfMonth, isSameDay, endOfMonth, eachDayOfInterval, getDay, isWithinInterval, format, addDays, differenceInMinutes, addMinutes, subDays, subMonths, addMonths, parseISO, isValid, formatDistanceToNow, isToday, isFuture, isBefore } from 'date-fns';
7
7
  import mixpanel from 'mixpanel-browser';
8
8
  import { EventEmitter } from 'events';
9
9
  import { createClient, REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js';
10
10
  import Hls, { Events, ErrorTypes } from 'hls.js';
11
11
  import useSWR from 'swr';
12
12
  import { memo, noop, warning, invariant, progress, secondsToMilliseconds, millisecondsToSeconds } from 'motion-utils';
13
- import { Camera, AlertTriangle, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, Filter, X, Coffee, Plus, ArrowLeft, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ArrowDown, ArrowUp, ChevronLeft, ChevronRight, TrendingUp, Sparkles, Pause, Play, Wrench, XCircle, Package, UserX, Zap, HelpCircle, Tag, Palette, CheckCircle2, RefreshCw, TrendingDown, FolderOpen, Folder, Sliders, Activity, Layers, Search, Edit2, ArrowRight, CheckCircle, User, Users, Shield, Building2, Mail, Lock, Info, Share2, Trophy, Target, Download, Sun, Moon, MousePointer, UserPlus, UserCog, Trash2, Eye, MoreVertical, BarChart3, Pencil, UserCheck, LogOut, Film, MessageSquare, Menu, Send, Copy, Settings, LifeBuoy, EyeOff, UserCircle, Flame, Crown, Medal } from 'lucide-react';
13
+ import { Camera, AlertTriangle, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, Filter, X, Coffee, Plus, ArrowLeft, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ArrowDown, ArrowUp, ChevronLeft, ChevronRight, TrendingUp, Sparkles, Pause, Play, Wrench, XCircle, Package, UserX, Zap, HelpCircle, Tag, Palette, CheckCircle2, RefreshCw, TrendingDown, FolderOpen, Folder, Sliders, Activity, Layers, Search, Edit2, ArrowRight, CheckCircle, User, Users, Shield, Building2, Mail, Lock, Info, Share2, Trophy, Target, Download, Sun, Moon, MousePointer, UserPlus, UserCog, Trash2, Eye, MoreVertical, BarChart3, Pencil, UserCheck, LogOut, Film, MessageSquare, Menu, Send, Copy, Bell, ArrowUpRight, Settings, LifeBuoy, EyeOff, Flame, Crown, Medal } from 'lucide-react';
14
14
  import { toast } from 'sonner';
15
15
  import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, ReferenceLine, Tooltip, Legend, Bar, LabelList, ResponsiveContainer, LineChart as LineChart$1, Line, PieChart, Pie, Cell, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
16
16
  import { Slot } from '@radix-ui/react-slot';
17
17
  import * as SelectPrimitive from '@radix-ui/react-select';
18
18
  import { DayPicker, useNavigation as useNavigation$1 } from 'react-day-picker';
19
- import { AdjustmentsHorizontalIcon, ClockIcon, UsersIcon, UserCircleIcon, TicketIcon, CurrencyDollarIcon, QuestionMarkCircleIcon, XMarkIcon, ArrowRightIcon, Bars3Icon, HomeIcon, TrophyIcon, ChartBarIcon, LightBulbIcon, CubeIcon, HeartIcon, Cog6ToothIcon, ChevronRightIcon, ArrowRightStartOnRectangleIcon, CalendarIcon, ChevronDownIcon, ChevronLeftIcon, ExclamationCircleIcon, EnvelopeIcon, DocumentTextIcon, ChevronUpIcon, ArrowDownTrayIcon, CheckCircleIcon, ChatBubbleLeftRightIcon, XCircleIcon, FunnelIcon, EyeIcon, InformationCircleIcon, ArrowLeftIcon, PlayCircleIcon } from '@heroicons/react/24/outline';
19
+ import { AdjustmentsHorizontalIcon, ClockIcon, UsersIcon, UserCircleIcon, TicketIcon, CurrencyDollarIcon, QuestionMarkCircleIcon, XMarkIcon, ArrowRightIcon, Bars3Icon, HomeIcon, VideoCameraIcon, TrophyIcon, ChartBarIcon, LightBulbIcon, CubeIcon, HeartIcon, BellIcon, Cog6ToothIcon, ChevronRightIcon, ArrowRightStartOnRectangleIcon, ExclamationCircleIcon, ExclamationTriangleIcon, CalendarIcon, ChevronDownIcon, ChevronLeftIcon, EnvelopeIcon, DocumentTextIcon, ChevronUpIcon, ArrowDownTrayIcon, CheckCircleIcon, ChatBubbleLeftRightIcon, XCircleIcon, FunnelIcon, EyeIcon, InformationCircleIcon, ArrowLeftIcon, PlayCircleIcon } from '@heroicons/react/24/outline';
20
20
  import { CheckIcon } from '@heroicons/react/24/solid';
21
21
  import html2canvas from 'html2canvas';
22
22
  import jsPDF, { jsPDF as jsPDF$1 } from 'jspdf';
@@ -400,14 +400,14 @@ var useIdleTimeVlmConfig = () => {
400
400
  }
401
401
  return context;
402
402
  };
403
- var DashboardConfigContext = React26.createContext(void 0);
403
+ var DashboardConfigContext = React141.createContext(void 0);
404
404
  var DashboardProvider = ({ config: userProvidedConfig, children }) => {
405
- const fullConfig = React26.useMemo(() => mergeWithDefaultConfig(userProvidedConfig), [userProvidedConfig]);
405
+ const fullConfig = React141.useMemo(() => mergeWithDefaultConfig(userProvidedConfig), [userProvidedConfig]);
406
406
  _setDashboardConfigInstance(fullConfig);
407
- React26.useEffect(() => {
407
+ React141.useEffect(() => {
408
408
  _setDashboardConfigInstance(fullConfig);
409
409
  }, [fullConfig]);
410
- React26.useEffect(() => {
410
+ React141.useEffect(() => {
411
411
  if (!fullConfig.theme) return;
412
412
  const styleId = "dashboard-core-theme-vars";
413
413
  let styleEl = document.getElementById(styleId);
@@ -433,7 +433,7 @@ var DashboardProvider = ({ config: userProvidedConfig, children }) => {
433
433
  return /* @__PURE__ */ jsx(DashboardConfigContext.Provider, { value: fullConfig, children: /* @__PURE__ */ jsx(IdleTimeVlmConfigProvider, { children }) });
434
434
  };
435
435
  var useDashboardConfig = () => {
436
- const ctx = React26.useContext(DashboardConfigContext);
436
+ const ctx = React141.useContext(DashboardConfigContext);
437
437
  if (!ctx) throw new Error("useDashboardConfig must be used within a DashboardProvider");
438
438
  return ctx;
439
439
  };
@@ -3857,6 +3857,208 @@ var ApiClient = class {
3857
3857
  };
3858
3858
  ApiClient.DEFAULT_TIMEOUT = 3e5;
3859
3859
 
3860
+ // src/lib/utils/roleMetadata.ts
3861
+ var FACTORY_SCOPED_ROLE_SET = /* @__PURE__ */ new Set(["plant_head", "industrial_engineer"]);
3862
+ var ROLE_ORDER = [
3863
+ "optifye",
3864
+ "owner",
3865
+ "it",
3866
+ "plant_head",
3867
+ "industrial_engineer",
3868
+ "supervisor"
3869
+ ];
3870
+ var FULL_DASHBOARD_PATHS = [
3871
+ "/",
3872
+ "/leaderboard",
3873
+ "/kpis",
3874
+ "/targets",
3875
+ "/shifts",
3876
+ "/supervisor-management",
3877
+ "/skus",
3878
+ "/help",
3879
+ "/health",
3880
+ "/profile",
3881
+ "/workspace",
3882
+ "/factory-view",
3883
+ "/team-management",
3884
+ "/tickets",
3885
+ "/improvement-center"
3886
+ ];
3887
+ var LIVE_MONITOR_DASHBOARD_PATHS = [
3888
+ "/",
3889
+ "/live-monitor",
3890
+ ...FULL_DASHBOARD_PATHS.filter((path) => path !== "/")
3891
+ ];
3892
+ var SUPERVISOR_PATHS = [
3893
+ "/",
3894
+ "/leaderboard",
3895
+ "/kpis",
3896
+ "/targets",
3897
+ "/shifts",
3898
+ "/skus",
3899
+ "/help",
3900
+ "/health",
3901
+ "/profile",
3902
+ "/workspace",
3903
+ "/tickets",
3904
+ "/improvement-center"
3905
+ ];
3906
+ var ROLE_METADATA = {
3907
+ optifye: {
3908
+ label: "Optifye",
3909
+ description: "Full platform access - Optifye team member",
3910
+ assignmentKind: "global",
3911
+ navPaths: LIVE_MONITOR_DASHBOARD_PATHS
3912
+ },
3913
+ owner: {
3914
+ label: "Owner",
3915
+ description: "Company-wide access - Can manage all users and settings",
3916
+ assignmentKind: "company",
3917
+ navPaths: LIVE_MONITOR_DASHBOARD_PATHS
3918
+ },
3919
+ it: {
3920
+ label: "IT",
3921
+ description: "Company-wide access - IT personnel with full company access",
3922
+ assignmentKind: "company",
3923
+ navPaths: FULL_DASHBOARD_PATHS
3924
+ },
3925
+ plant_head: {
3926
+ label: "Plant Head",
3927
+ description: "Factory-level access - Can manage supervisors and factory settings",
3928
+ assignmentKind: "factory",
3929
+ navPaths: LIVE_MONITOR_DASHBOARD_PATHS
3930
+ },
3931
+ industrial_engineer: {
3932
+ label: "Industrial Engineer",
3933
+ description: "Factory-level access - Can manage supervisors and factory performance scope",
3934
+ assignmentKind: "factory",
3935
+ navPaths: FULL_DASHBOARD_PATHS
3936
+ },
3937
+ supervisor: {
3938
+ label: "Supervisor",
3939
+ description: "Line-level access - Can monitor assigned production lines",
3940
+ assignmentKind: "line",
3941
+ navPaths: SUPERVISOR_PATHS
3942
+ }
3943
+ };
3944
+ var normalizeRoleLevel = (role) => {
3945
+ if (!role) return null;
3946
+ return Object.prototype.hasOwnProperty.call(ROLE_METADATA, role) ? role : null;
3947
+ };
3948
+ var getRoleMetadata = (role) => {
3949
+ const normalizedRole = normalizeRoleLevel(role);
3950
+ return normalizedRole ? ROLE_METADATA[normalizedRole] : null;
3951
+ };
3952
+ var getRoleLabel = (role) => {
3953
+ return getRoleMetadata(role)?.label || (role || "Unknown");
3954
+ };
3955
+ var getRoleDescription = (role) => {
3956
+ return getRoleMetadata(role)?.description || "";
3957
+ };
3958
+ var isFactoryScopedRole = (role) => {
3959
+ const normalizedRole = normalizeRoleLevel(role);
3960
+ return normalizedRole ? FACTORY_SCOPED_ROLE_SET.has(normalizedRole) : false;
3961
+ };
3962
+ var isSupervisorRole = (role) => normalizeRoleLevel(role) === "supervisor";
3963
+ var canRoleManageUsers = (role) => {
3964
+ const normalizedRole = normalizeRoleLevel(role);
3965
+ return normalizedRole === "optifye" || normalizedRole === "owner" || normalizedRole === "it" || isFactoryScopedRole(normalizedRole);
3966
+ };
3967
+ var canRoleManageTargets = (role) => {
3968
+ const normalizedRole = normalizeRoleLevel(role);
3969
+ return normalizedRole === "optifye" || normalizedRole === "owner" || normalizedRole === "it" || isFactoryScopedRole(normalizedRole);
3970
+ };
3971
+ var canRoleViewUsageStats = (role) => {
3972
+ const normalizedRole = normalizeRoleLevel(role);
3973
+ return normalizedRole === "optifye" || normalizedRole === "owner" || normalizedRole === "it";
3974
+ };
3975
+ var canRoleAccessTeamManagement = (role) => {
3976
+ return canRoleManageUsers(role);
3977
+ };
3978
+ var getRoleNavPaths = (role) => {
3979
+ return getRoleMetadata(role)?.navPaths || [];
3980
+ };
3981
+ var getVisibleRolesForCurrentUser = (currentRole) => {
3982
+ const normalizedRole = normalizeRoleLevel(currentRole);
3983
+ const visibleRolesByCurrentRole = {
3984
+ optifye: ROLE_ORDER,
3985
+ owner: ["owner", "it", "plant_head", "industrial_engineer", "supervisor"],
3986
+ it: ["it", "plant_head", "industrial_engineer", "supervisor"],
3987
+ plant_head: ["plant_head", "supervisor"],
3988
+ industrial_engineer: ["industrial_engineer", "supervisor"],
3989
+ supervisor: ["supervisor"]
3990
+ };
3991
+ return normalizedRole ? visibleRolesByCurrentRole[normalizedRole] : ["supervisor"];
3992
+ };
3993
+ var getAssignableRoles = (currentRole, options = {}) => {
3994
+ const normalizedRole = normalizeRoleLevel(currentRole);
3995
+ const isSuperAdminOptifye = !!options.isSuperAdminOptifye;
3996
+ if (!normalizedRole) return [];
3997
+ if (normalizedRole === "optifye") {
3998
+ return isSuperAdminOptifye ? ["owner", "it", "plant_head", "industrial_engineer", "supervisor"] : ["it", "plant_head", "industrial_engineer", "supervisor"];
3999
+ }
4000
+ if (normalizedRole === "owner") {
4001
+ return ["it", "plant_head", "industrial_engineer", "supervisor"];
4002
+ }
4003
+ if (normalizedRole === "it") {
4004
+ return ["plant_head", "industrial_engineer", "supervisor"];
4005
+ }
4006
+ if (isFactoryScopedRole(normalizedRole)) {
4007
+ return ["supervisor"];
4008
+ }
4009
+ return [];
4010
+ };
4011
+ var canRoleInviteRole = (currentRole, targetRole, options = {}) => {
4012
+ const normalizedTargetRole = normalizeRoleLevel(targetRole);
4013
+ if (!normalizedTargetRole) return false;
4014
+ return getAssignableRoles(currentRole, options).includes(normalizedTargetRole);
4015
+ };
4016
+ var canRoleAssignLines = (currentRole, targetRole) => {
4017
+ const normalizedCurrentRole = normalizeRoleLevel(currentRole);
4018
+ const normalizedTargetRole = normalizeRoleLevel(targetRole);
4019
+ if (normalizedTargetRole !== "supervisor") return false;
4020
+ return normalizedCurrentRole === "optifye" || normalizedCurrentRole === "owner" || normalizedCurrentRole === "it" || isFactoryScopedRole(normalizedCurrentRole);
4021
+ };
4022
+ var canRoleAssignFactories = (currentRole, targetRole) => {
4023
+ const normalizedCurrentRole = normalizeRoleLevel(currentRole);
4024
+ const normalizedTargetRole = normalizeRoleLevel(targetRole);
4025
+ if (!normalizedTargetRole || !isFactoryScopedRole(normalizedTargetRole)) return false;
4026
+ return normalizedCurrentRole === "optifye" || normalizedCurrentRole === "owner" || normalizedCurrentRole === "it";
4027
+ };
4028
+ var canRoleChangeRole = (currentRole, targetRole, options = {}) => {
4029
+ const normalizedCurrentRole = normalizeRoleLevel(currentRole);
4030
+ const normalizedTargetRole = normalizeRoleLevel(targetRole);
4031
+ const isSuperAdminOptifye = !!options.isSuperAdminOptifye;
4032
+ if (!normalizedCurrentRole || !normalizedTargetRole) return false;
4033
+ if (normalizedCurrentRole === "optifye") {
4034
+ if (isSuperAdminOptifye) return true;
4035
+ return ["it", "plant_head", "industrial_engineer", "supervisor"].includes(normalizedTargetRole);
4036
+ }
4037
+ if (normalizedCurrentRole === "owner") {
4038
+ return ["plant_head", "industrial_engineer", "supervisor"].includes(normalizedTargetRole);
4039
+ }
4040
+ if (normalizedCurrentRole === "it") {
4041
+ return ["plant_head", "industrial_engineer", "supervisor"].includes(normalizedTargetRole);
4042
+ }
4043
+ return false;
4044
+ };
4045
+ var canRoleRemoveUser = (currentRole, targetRole, options = {}) => {
4046
+ const normalizedCurrentRole = normalizeRoleLevel(currentRole);
4047
+ const normalizedTargetRole = normalizeRoleLevel(targetRole);
4048
+ const isSuperAdminOptifye = !!options.isSuperAdminOptifye;
4049
+ if (!normalizedCurrentRole || !normalizedTargetRole) return false;
4050
+ if (normalizedCurrentRole === "optifye") return isSuperAdminOptifye;
4051
+ if (normalizedCurrentRole === "owner" || normalizedCurrentRole === "it") {
4052
+ return ["plant_head", "industrial_engineer", "supervisor"].includes(normalizedTargetRole);
4053
+ }
4054
+ return false;
4055
+ };
4056
+ var getAssignmentColumnLabel = (role) => {
4057
+ if (isFactoryScopedRole(role)) return "Factories";
4058
+ if (isSupervisorRole(role)) return "Lines";
4059
+ return "Assignments";
4060
+ };
4061
+
3860
4062
  // src/lib/services/authService.ts
3861
4063
  var AuthService = class {
3862
4064
  /**
@@ -3976,7 +4178,7 @@ var AuthService = class {
3976
4178
  first_login_completed: enrichedUser.profile.first_login_completed,
3977
4179
  properties: {
3978
4180
  company_id: enrichedUser.company_id,
3979
- access_level: enrichedUser.permissions.is_owner || enrichedUser.permissions.is_optifye_admin ? "company" : enrichedUser.permissions.is_plant_head ? "factory" : "line",
4181
+ access_level: enrichedUser.permissions.is_owner || enrichedUser.permissions.is_optifye_admin ? "company" : isFactoryScopedRole(enrichedUser.role) ? "factory" : "line",
3980
4182
  line_ids: line_ids.length > 0 ? line_ids : void 0,
3981
4183
  factory_ids: factory_ids.length > 0 ? factory_ids : void 0,
3982
4184
  // Include permissions for easy access
@@ -5561,6 +5763,25 @@ var CLIP_COUNTS_CACHE_TTL = 30 * 1e3;
5561
5763
  var CLIP_BY_ID_CACHE_TTL = 2 * 60 * 1e3;
5562
5764
  var CLIP_BY_ID_CACHE_MAX = 200;
5563
5765
  var CLIPS_INIT_CACHE_TTL = 30 * 1e3;
5766
+ var parseFiniteNumber = (value) => {
5767
+ if (typeof value === "number" && Number.isFinite(value)) {
5768
+ return value;
5769
+ }
5770
+ if (typeof value === "string" && value.trim().length > 0) {
5771
+ const parsed = Number(value);
5772
+ if (Number.isFinite(parsed)) {
5773
+ return parsed;
5774
+ }
5775
+ }
5776
+ return void 0;
5777
+ };
5778
+ var getClipCycleTimeFrames = (metadata) => {
5779
+ const flattenedCycleTime = parseFiniteNumber(metadata?.cycle_time);
5780
+ if (flattenedCycleTime !== void 0) {
5781
+ return flattenedCycleTime;
5782
+ }
5783
+ return parseFiniteNumber(metadata?.request?.metadata?.cycle_time);
5784
+ };
5564
5785
  var getSupabaseClient = () => {
5565
5786
  const existing = _getSupabaseInstanceOptional();
5566
5787
  if (existing) {
@@ -6070,20 +6291,31 @@ var S3ClipsSupabaseService = class {
6070
6291
  limit
6071
6292
  });
6072
6293
  console.log(`[S3ClipsSupabase] Fetched ${response.clips?.length || 0} ${type} clips`);
6073
- const transformedClips = (response.clips || []).map((clip) => ({
6074
- id: clip.clip_id,
6075
- src: clip.playlist,
6076
- // Raw playlist content
6077
- timestamp: clip.timestamp,
6078
- // Use pre-formatted timestamp from API (already in 12-hour format with seconds)
6079
- severity: this.getSeverityFromClipType(clip.clip_type_name),
6080
- description: this.getDescriptionFromClipType(clip.clip_type_name),
6081
- type: clip.clip_type_name,
6082
- originalUri: `clips:${clip.clip_id}`,
6083
- cycle_time_seconds: clip.metadata?.request?.metadata?.cycle_time ? clip.metadata.request.metadata.cycle_time / (clip.metadata?.playlist?.fps || 20) : void 0,
6084
- creation_timestamp: clip.created_at,
6085
- percentile: clip.cycle_time_percentile || clip.idle_time_percentile
6086
- }));
6294
+ const transformedClips = (response.clips || []).map((clip) => {
6295
+ const clipId = clip.id ?? clip.clip_id;
6296
+ const clipType = clip.type ?? clip.clip_type_name;
6297
+ const cycleTimeSeconds = parseFiniteNumber(clip.cycle_time_seconds) ?? (() => {
6298
+ const cycleTimeFrames = getClipCycleTimeFrames(clip.metadata);
6299
+ return cycleTimeFrames !== void 0 ? cycleTimeFrames / (clip.metadata?.playlist?.fps || 20) : void 0;
6300
+ })();
6301
+ return {
6302
+ id: clipId,
6303
+ src: clip.src ?? clip.playlist,
6304
+ // Current API returns src; keep playlist fallback for legacy responses
6305
+ timestamp: clip.timestamp,
6306
+ // Use pre-formatted timestamp from API (already in 12-hour format with seconds)
6307
+ severity: clip.severity ?? this.getSeverityFromClipType(clipType),
6308
+ description: clip.description ?? this.getDescriptionFromClipType(clipType),
6309
+ type: clipType,
6310
+ originalUri: clip.originalUri ?? `clips:${clipId}`,
6311
+ cycle_time_seconds: cycleTimeSeconds,
6312
+ creation_timestamp: clip.creation_timestamp ?? clip.created_at,
6313
+ percentile: clip.percentile ?? clip.cycle_time_percentile ?? clip.idle_time_percentile,
6314
+ duration: clip.duration,
6315
+ idle_start_time: clip.idle_start_time,
6316
+ idle_end_time: clip.idle_end_time
6317
+ };
6318
+ });
6087
6319
  return {
6088
6320
  clips: transformedClips,
6089
6321
  total: response.total || transformedClips.length,
@@ -6113,10 +6345,13 @@ var S3ClipsSupabaseService = class {
6113
6345
  */
6114
6346
  getSeverityFromClipType(clipType) {
6115
6347
  switch (clipType) {
6348
+ case "long_cycle_time":
6349
+ case "worst_cycle_time":
6116
6350
  case "sop_deviations":
6117
6351
  return "high";
6118
6352
  case "idle_time":
6119
6353
  return "medium";
6354
+ case "best_cycle_time":
6120
6355
  case "cycle_completion":
6121
6356
  default:
6122
6357
  return "low";
@@ -6128,11 +6363,14 @@ var S3ClipsSupabaseService = class {
6128
6363
  */
6129
6364
  getDescriptionFromClipType(clipType) {
6130
6365
  const descriptions = {
6366
+ "long_cycle_time": "Long Cycle Time Detected",
6131
6367
  "idle_time": "Idle Time Detected",
6368
+ "best_cycle_time": "Best Cycle Time Performance",
6369
+ "worst_cycle_time": "Worst Cycle Time Performance",
6132
6370
  "sop_deviations": "SOP Deviations",
6133
6371
  "cycle_completion": "Cycle Completion"
6134
6372
  };
6135
- return descriptions[clipType] || "Analysis Clip";
6373
+ return clipType ? descriptions[clipType] || "Analysis Clip" : "Analysis Clip";
6136
6374
  }
6137
6375
  };
6138
6376
 
@@ -6895,6 +7133,9 @@ var InvitationService = class {
6895
7133
  if (existingUser) {
6896
7134
  throw new Error("A user with this email address already exists in the system.");
6897
7135
  }
7136
+ if (input.role_level === "industrial_engineer" && (!input.factory_ids || input.factory_ids.length === 0)) {
7137
+ throw new Error("Industrial Engineer invitations require at least one factory assignment.");
7138
+ }
6898
7139
  const invitationData = {
6899
7140
  email: input.email.toLowerCase().trim(),
6900
7141
  company_id: input.company_id,
@@ -6905,7 +7146,7 @@ var InvitationService = class {
6905
7146
  if (input.role_level === "supervisor" && input.line_ids && input.line_ids.length > 0) {
6906
7147
  invitationData.line_ids = input.line_ids;
6907
7148
  }
6908
- if (input.role_level === "plant_head" && input.factory_ids && input.factory_ids.length > 0) {
7149
+ if ((input.role_level === "plant_head" || input.role_level === "industrial_engineer") && input.factory_ids && input.factory_ids.length > 0) {
6909
7150
  invitationData.factory_ids = input.factory_ids;
6910
7151
  }
6911
7152
  console.log("[InvitationService] Final invitationData being inserted:", invitationData);
@@ -7615,6 +7856,8 @@ async function fetchIdleTimeReasons(params) {
7615
7856
  data: {
7616
7857
  total_idle_time_seconds: 0,
7617
7858
  total_clips_analyzed: 0,
7859
+ scope_work_seconds: null,
7860
+ scope_workspace_count: 0,
7618
7861
  reasons: []
7619
7862
  },
7620
7863
  error: "Request failed"
@@ -7632,6 +7875,8 @@ async function fetchIdleTimeReasons(params) {
7632
7875
  return {
7633
7876
  total_idle_time_seconds: 0,
7634
7877
  total_clips_analyzed: 0,
7878
+ scope_work_seconds: null,
7879
+ scope_workspace_count: 0,
7635
7880
  reasons: []
7636
7881
  };
7637
7882
  }
@@ -7639,7 +7884,9 @@ async function fetchIdleTimeReasons(params) {
7639
7884
  function transformToChartData(data) {
7640
7885
  return data.reasons.map((reason) => ({
7641
7886
  name: formatReasonLabel(reason.reason),
7642
- value: reason.percentage
7887
+ value: reason.percentage,
7888
+ totalDurationSeconds: reason.total_duration_seconds,
7889
+ efficiencyLossPercentage: reason.efficiency_loss_percentage ?? null
7643
7890
  }));
7644
7891
  }
7645
7892
  function formatReasonLabel(reason) {
@@ -8047,6 +8294,18 @@ var lineLeaderboardService = {
8047
8294
  return data?.entries ?? [];
8048
8295
  }
8049
8296
  };
8297
+
8298
+ // src/lib/services/alertsService.ts
8299
+ var alertsService = {
8300
+ async getCurrentAlerts(supabase, companyId) {
8301
+ const query = `?company_id=${encodeURIComponent(companyId)}`;
8302
+ return fetchBackendJson(supabase, `/api/alerts/current${query}`);
8303
+ },
8304
+ async getSummary(supabase, companyId) {
8305
+ const query = `?company_id=${encodeURIComponent(companyId)}`;
8306
+ return fetchBackendJson(supabase, `/api/alerts/summary${query}`);
8307
+ }
8308
+ };
8050
8309
  var SupabaseContext = createContext(void 0);
8051
8310
  var SupabaseProvider = ({ client, children }) => {
8052
8311
  _setSupabaseInstance(client);
@@ -8822,7 +9081,7 @@ var useMobileMenu = () => {
8822
9081
  };
8823
9082
  var useHideMobileHeader = (shouldHide = true) => {
8824
9083
  const context = useMobileMenu();
8825
- React26__default.useEffect(() => {
9084
+ React141__default.useEffect(() => {
8826
9085
  if (context && shouldHide) {
8827
9086
  context.setHideMobileHeader(true);
8828
9087
  return () => {
@@ -14825,10 +15084,7 @@ var useSKUs = (companyId) => {
14825
15084
  // src/lib/hooks/useCanSaveTargets.ts
14826
15085
  var useCanSaveTargets = () => {
14827
15086
  const { user } = useAuth();
14828
- if (user?.role_level === "optifye") {
14829
- return true;
14830
- }
14831
- return user?.role_level === "owner" || user?.role_level === "plant_head";
15087
+ return canRoleManageTargets(user?.role_level);
14832
15088
  };
14833
15089
  function useTicketHistory(companyId) {
14834
15090
  const [tickets, setTickets] = useState([]);
@@ -16130,12 +16386,7 @@ var useFormatNumber = () => {
16130
16386
  function useAccessControl() {
16131
16387
  const { user } = useAuth();
16132
16388
  const userRole = useMemo(() => {
16133
- if (!user?.role_level) return null;
16134
- const roleLevel = user.role_level;
16135
- if (roleLevel === "owner" || roleLevel === "it" || roleLevel === "plant_head" || roleLevel === "supervisor" || roleLevel === "optifye") {
16136
- return roleLevel;
16137
- }
16138
- return "supervisor";
16389
+ return normalizeRoleLevel(user?.role_level) || null;
16139
16390
  }, [user?.role_level]);
16140
16391
  const assignedLineIds = useMemo(() => {
16141
16392
  if (!user) return [];
@@ -16147,89 +16398,15 @@ function useAccessControl() {
16147
16398
  }, [user]);
16148
16399
  const assignedFactoryIds = useMemo(() => {
16149
16400
  if (!user) return [];
16150
- if (user.role_level === "plant_head") {
16401
+ if (isFactoryScopedRole(user.role_level)) {
16151
16402
  const factories = user.properties?.factory_id || user.properties?.factory_ids || [];
16152
16403
  return Array.isArray(factories) ? factories : [];
16153
16404
  }
16154
16405
  return [];
16155
16406
  }, [user]);
16156
- const roleAccessMap = {
16157
- optifye: [
16158
- "/",
16159
- "/leaderboard",
16160
- "/kpis",
16161
- "/targets",
16162
- "/shifts",
16163
- "/supervisor-management",
16164
- "/skus",
16165
- "/help",
16166
- "/health",
16167
- "/profile",
16168
- "/workspace",
16169
- "/factory-view",
16170
- "/team-management"
16171
- ],
16172
- owner: [
16173
- "/",
16174
- "/leaderboard",
16175
- "/kpis",
16176
- "/targets",
16177
- "/shifts",
16178
- "/supervisor-management",
16179
- "/skus",
16180
- "/help",
16181
- "/health",
16182
- "/profile",
16183
- "/workspace",
16184
- "/factory-view",
16185
- "/team-management"
16186
- ],
16187
- it: [
16188
- "/",
16189
- "/leaderboard",
16190
- "/kpis",
16191
- "/targets",
16192
- "/shifts",
16193
- "/supervisor-management",
16194
- "/skus",
16195
- "/help",
16196
- "/health",
16197
- "/profile",
16198
- "/workspace",
16199
- "/factory-view",
16200
- "/team-management"
16201
- ],
16202
- plant_head: [
16203
- "/",
16204
- "/leaderboard",
16205
- "/kpis",
16206
- "/targets",
16207
- "/shifts",
16208
- "/supervisor-management",
16209
- "/skus",
16210
- "/help",
16211
- "/health",
16212
- "/profile",
16213
- "/workspace",
16214
- "/factory-view",
16215
- "/team-management"
16216
- ],
16217
- supervisor: [
16218
- "/",
16219
- "/leaderboard",
16220
- "/kpis",
16221
- "/targets",
16222
- "/shifts",
16223
- "/skus",
16224
- "/help",
16225
- "/health",
16226
- "/profile",
16227
- "/workspace"
16228
- ]
16229
- };
16230
16407
  const accessiblePages = useMemo(() => {
16231
16408
  if (!userRole) return [];
16232
- return roleAccessMap[userRole] || [];
16409
+ return getRoleNavPaths(userRole);
16233
16410
  }, [userRole]);
16234
16411
  const hasAccess = useMemo(() => {
16235
16412
  return (path) => {
@@ -16279,111 +16456,50 @@ function useTeamManagementPermissions() {
16279
16456
  * Can the current user assign lines to this user?
16280
16457
  */
16281
16458
  canAssignLines: (targetUser) => {
16282
- if (!currentRole) return false;
16283
- if (currentRole === "optifye") return true;
16284
- if ((currentRole === "owner" || currentRole === "it") && targetUser.role_level === "supervisor") {
16285
- return true;
16286
- }
16287
- if (currentRole === "plant_head" && targetUser.role_level === "supervisor") {
16288
- return true;
16289
- }
16290
- return false;
16459
+ return canRoleAssignLines(currentRole, targetUser.role_level);
16291
16460
  },
16292
16461
  /**
16293
16462
  * Can the current user assign factories to this user?
16294
16463
  */
16295
16464
  canAssignFactories: (targetUser) => {
16296
- if (!currentRole) return false;
16297
- if (currentRole === "optifye") return true;
16298
- if ((currentRole === "owner" || currentRole === "it") && targetUser.role_level === "plant_head") {
16299
- return true;
16300
- }
16301
- return false;
16465
+ return canRoleAssignFactories(currentRole, targetUser.role_level);
16302
16466
  },
16303
16467
  /**
16304
16468
  * Can the current user change this user's role?
16305
16469
  */
16306
16470
  canChangeRole: (targetUser) => {
16307
- if (!currentRole) return false;
16308
- if (currentRole === "optifye") return true;
16309
- if (currentRole === "owner" || currentRole === "it") {
16310
- return ["plant_head", "supervisor"].includes(targetUser.role_level);
16311
- }
16312
- return false;
16471
+ return canRoleChangeRole(currentRole, targetUser.role_level, { isSuperAdminOptifye });
16313
16472
  },
16314
16473
  /**
16315
16474
  * Can the current user remove this user?
16316
16475
  */
16317
16476
  canRemoveUser: (targetUser) => {
16318
- if (!currentRole) return false;
16319
- if (currentRole === "optifye") return true;
16320
- if (currentRole === "owner" || currentRole === "it") {
16321
- return ["plant_head", "supervisor"].includes(targetUser.role_level);
16322
- }
16323
- return false;
16477
+ return canRoleRemoveUser(currentRole, targetUser.role_level, { isSuperAdminOptifye });
16324
16478
  },
16325
16479
  /**
16326
16480
  * Get list of roles the current user can assign
16327
16481
  * NOTE: Optifye role can ONLY be assigned from database directly, never from frontend
16328
16482
  */
16329
16483
  availableRolesToAssign: () => {
16330
- if (!currentRole) return [];
16331
- if (currentRole === "optifye") {
16332
- if (isSuperAdminOptifye) {
16333
- return ["owner", "it", "plant_head", "supervisor"];
16334
- }
16335
- return ["it", "plant_head", "supervisor"];
16336
- }
16337
- if (currentRole === "owner") {
16338
- return ["it", "plant_head", "supervisor"];
16339
- }
16340
- if (currentRole === "it") {
16341
- return ["plant_head", "supervisor"];
16342
- }
16343
- if (currentRole === "plant_head") {
16344
- return ["supervisor"];
16345
- }
16346
- return [];
16484
+ return getAssignableRoles(currentRole, { isSuperAdminOptifye });
16347
16485
  },
16348
16486
  /**
16349
16487
  * Can the current user invite someone with this role?
16350
16488
  */
16351
16489
  canInviteRole: (role) => {
16352
- if (!currentRole) return false;
16353
- if (currentRole === "optifye") {
16354
- if (role === "owner") {
16355
- return isSuperAdminOptifye;
16356
- }
16357
- return true;
16358
- }
16359
- if (currentRole === "owner") {
16360
- return ["it", "plant_head", "supervisor"].includes(role);
16361
- }
16362
- if (currentRole === "it") {
16363
- return ["plant_head", "supervisor"].includes(role);
16364
- }
16365
- if (currentRole === "plant_head") {
16366
- return role === "supervisor";
16367
- }
16368
- return false;
16490
+ return canRoleInviteRole(currentRole, role, { isSuperAdminOptifye });
16369
16491
  },
16370
16492
  /**
16371
16493
  * Get the name of the assignment column for a user
16372
16494
  */
16373
16495
  getAssignmentColumnName: (targetUser) => {
16374
- if (targetUser.role_level === "plant_head") {
16375
- return "Factories";
16376
- }
16377
- if (targetUser.role_level === "supervisor") {
16378
- return "Lines";
16379
- }
16380
- return "Assignments";
16496
+ return getAssignmentColumnLabel(targetUser.role_level);
16381
16497
  },
16382
16498
  /**
16383
16499
  * Should the assignment column be shown?
16384
16500
  */
16385
16501
  showAssignmentColumn: () => {
16386
- return !!currentRole && ["optifye", "owner", "it", "plant_head"].includes(currentRole);
16502
+ return !!currentRole && (currentRole === "optifye" || currentRole === "owner" || currentRole === "it" || isFactoryScopedRole(currentRole));
16387
16503
  }
16388
16504
  };
16389
16505
  }
@@ -20238,7 +20354,7 @@ var getStoredWorkspaceMappings = () => {
20238
20354
  var getDefaultTabForWorkspace = (workspaceId, displayName) => {
20239
20355
  return "overview";
20240
20356
  };
20241
- var getWorkspaceNavigationParams = (workspaceId, displayName, lineId) => {
20357
+ var getWorkspaceNavigationParams = (workspaceId, displayName, lineId, returnTo) => {
20242
20358
  const defaultTab = getDefaultTabForWorkspace();
20243
20359
  const params = new URLSearchParams();
20244
20360
  params.set("displayName", displayName);
@@ -20246,6 +20362,9 @@ var getWorkspaceNavigationParams = (workspaceId, displayName, lineId) => {
20246
20362
  if (lineId) {
20247
20363
  params.set("lineId", lineId);
20248
20364
  }
20365
+ if (returnTo) {
20366
+ params.set("returnTo", returnTo);
20367
+ }
20249
20368
  return `?${params.toString()}`;
20250
20369
  };
20251
20370
 
@@ -20541,14 +20660,18 @@ var formatIdleTime = (idleTimeInSeconds) => {
20541
20660
  if (!idleTimeInSeconds || idleTimeInSeconds <= 0) {
20542
20661
  return "0s";
20543
20662
  }
20544
- const hours = Math.floor(idleTimeInSeconds / 3600);
20663
+ const days = Math.floor(idleTimeInSeconds / 86400);
20664
+ const hours = Math.floor(idleTimeInSeconds % 86400 / 3600);
20545
20665
  const minutes = Math.floor(idleTimeInSeconds % 3600 / 60);
20546
20666
  const seconds = Math.floor(idleTimeInSeconds % 60);
20547
20667
  const parts = [];
20668
+ if (days > 0) {
20669
+ parts.push(`${days}d`);
20670
+ }
20548
20671
  if (hours > 0) {
20549
20672
  parts.push(`${hours}h`);
20550
20673
  }
20551
- if (minutes > 0 || hours > 0) {
20674
+ if (minutes > 0 || hours > 0 || days > 0) {
20552
20675
  parts.push(`${minutes}m`);
20553
20676
  }
20554
20677
  parts.push(`${seconds}s`);
@@ -20595,7 +20718,7 @@ var MotionConfigContext = createContext({
20595
20718
  });
20596
20719
 
20597
20720
  // ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs
20598
- var PopChildMeasure = class extends React26.Component {
20721
+ var PopChildMeasure = class extends React141.Component {
20599
20722
  getSnapshotBeforeUpdate(prevProps) {
20600
20723
  const element = this.props.childRef.current;
20601
20724
  if (element && prevProps.isPresent && !this.props.isPresent) {
@@ -20650,7 +20773,7 @@ function PopChild({ children, isPresent }) {
20650
20773
  document.head.removeChild(style);
20651
20774
  };
20652
20775
  }, [isPresent]);
20653
- return jsx(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, children: React26.cloneElement(children, { ref }) });
20776
+ return jsx(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, children: React141.cloneElement(children, { ref }) });
20654
20777
  }
20655
20778
 
20656
20779
  // ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PresenceChild.mjs
@@ -20687,7 +20810,7 @@ var PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, pre
20687
20810
  useMemo(() => {
20688
20811
  presenceChildren.forEach((_, key) => presenceChildren.set(key, false));
20689
20812
  }, [isPresent]);
20690
- React26.useEffect(() => {
20813
+ React141.useEffect(() => {
20691
20814
  !isPresent && !presenceChildren.size && onExitComplete && onExitComplete();
20692
20815
  }, [isPresent]);
20693
20816
  if (mode === "popLayout") {
@@ -28521,12 +28644,12 @@ var withAuth = (WrappedComponent2, options) => {
28521
28644
  requireAuth: true,
28522
28645
  ...options
28523
28646
  };
28524
- const WithAuthComponent = React26.memo(function WithAuthComponent2(props) {
28647
+ const WithAuthComponent = React141.memo(function WithAuthComponent2(props) {
28525
28648
  const { session, loading, error } = useAuth();
28526
28649
  const router = useRouter();
28527
- const [localLoading, setLocalLoading] = React26.useState(loading);
28528
- const [loadingTimeoutReached, setLoadingTimeoutReached] = React26.useState(false);
28529
- React26.useEffect(() => {
28650
+ const [localLoading, setLocalLoading] = React141.useState(loading);
28651
+ const [loadingTimeoutReached, setLoadingTimeoutReached] = React141.useState(false);
28652
+ React141.useEffect(() => {
28530
28653
  if (process.env.NODE_ENV === "development" && process.env.DEBUG_AUTH === "true") {
28531
28654
  console.log("withAuth state:", {
28532
28655
  loading,
@@ -28536,7 +28659,7 @@ var withAuth = (WrappedComponent2, options) => {
28536
28659
  });
28537
28660
  }
28538
28661
  }, [session, loading, error]);
28539
- const handleLoadingTimeout = React26.useCallback(() => {
28662
+ const handleLoadingTimeout = React141.useCallback(() => {
28540
28663
  console.warn("[withAuth] Loading timeout reached");
28541
28664
  setLoadingTimeoutReached(true);
28542
28665
  if (typeof window !== "undefined" && localStorage.getItem("sb-zmzewpwerpaupoaoeqhh-auth-token")) {
@@ -28547,13 +28670,13 @@ var withAuth = (WrappedComponent2, options) => {
28547
28670
  router.replace(defaultOptions.redirectTo);
28548
28671
  }
28549
28672
  }, [router]);
28550
- React26.useEffect(() => {
28673
+ React141.useEffect(() => {
28551
28674
  if (!loading && defaultOptions.requireAuth && !session && !error) {
28552
28675
  console.log("[withAuth] No session found, redirecting to login");
28553
28676
  router.replace(defaultOptions.redirectTo);
28554
28677
  }
28555
28678
  }, [session, loading, router, error]);
28556
- React26.useEffect(() => {
28679
+ React141.useEffect(() => {
28557
28680
  setLocalLoading(loading);
28558
28681
  }, [loading]);
28559
28682
  if (loading || localLoading) {
@@ -28616,18 +28739,11 @@ function withAccessControl(WrappedComponent2, options = {}) {
28616
28739
  if (keyIndex >= 0 && keyIndex < segments.length - 1) return segments[keyIndex + 1];
28617
28740
  return null;
28618
28741
  };
28619
- const roleAccessMap = {
28620
- optifye: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/improvement-center", "/tickets"],
28621
- owner: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/improvement-center", "/tickets"],
28622
- it: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/improvement-center", "/tickets"],
28623
- plant_head: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/improvement-center", "/tickets"],
28624
- supervisor: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/skus", "/help", "/health", "/profile", "/workspace", "/improvement-center", "/tickets"]
28625
- };
28626
28742
  const canAccessPath = (path) => {
28627
28743
  if (!user || !role) return false;
28628
28744
  if (isSuperAdmin) return true;
28629
28745
  const basePath = getBasePath(path);
28630
- const allowed = roleAccessMap[role] || [];
28746
+ const allowed = getRoleNavPaths(role);
28631
28747
  if (!allowed.includes(basePath)) {
28632
28748
  return false;
28633
28749
  }
@@ -29028,8 +29144,8 @@ function getRoleConfig(role) {
29028
29144
  switch (role) {
29029
29145
  case "optifye":
29030
29146
  return {
29031
- label: "Optifye",
29032
- description: "Full platform access - Optifye team member",
29147
+ label: getRoleLabel(role),
29148
+ description: getRoleDescription(role),
29033
29149
  icon: Star,
29034
29150
  bgColor: "bg-gradient-to-r from-purple-50 to-pink-50",
29035
29151
  textColor: "text-purple-700",
@@ -29037,8 +29153,8 @@ function getRoleConfig(role) {
29037
29153
  };
29038
29154
  case "owner":
29039
29155
  return {
29040
- label: "Owner",
29041
- description: "Company-wide access - Can manage all users and settings",
29156
+ label: getRoleLabel(role),
29157
+ description: getRoleDescription(role),
29042
29158
  icon: Shield,
29043
29159
  bgColor: "bg-blue-50",
29044
29160
  textColor: "text-blue-700",
@@ -29046,8 +29162,8 @@ function getRoleConfig(role) {
29046
29162
  };
29047
29163
  case "it":
29048
29164
  return {
29049
- label: "IT",
29050
- description: "Company-wide access - IT personnel with full company access",
29165
+ label: getRoleLabel(role),
29166
+ description: getRoleDescription(role),
29051
29167
  icon: Wrench,
29052
29168
  bgColor: "bg-teal-50",
29053
29169
  textColor: "text-teal-700",
@@ -29055,17 +29171,26 @@ function getRoleConfig(role) {
29055
29171
  };
29056
29172
  case "plant_head":
29057
29173
  return {
29058
- label: "Plant Head",
29059
- description: "Factory-level access - Can manage supervisors and factory settings",
29174
+ label: getRoleLabel(role),
29175
+ description: getRoleDescription(role),
29060
29176
  icon: Users,
29061
29177
  bgColor: "bg-blue-50",
29062
29178
  textColor: "text-blue-700",
29063
29179
  borderColor: "border-blue-200"
29064
29180
  };
29181
+ case "industrial_engineer":
29182
+ return {
29183
+ label: getRoleLabel(role),
29184
+ description: getRoleDescription(role),
29185
+ icon: Users,
29186
+ bgColor: "bg-amber-50",
29187
+ textColor: "text-amber-700",
29188
+ borderColor: "border-amber-200"
29189
+ };
29065
29190
  case "supervisor":
29066
29191
  return {
29067
- label: "Supervisor",
29068
- description: "Line-level access - Can monitor assigned production lines",
29192
+ label: getRoleLabel(role),
29193
+ description: getRoleDescription(role),
29069
29194
  icon: User,
29070
29195
  bgColor: "bg-blue-50",
29071
29196
  textColor: "text-blue-700",
@@ -29173,7 +29298,7 @@ var SignupWithInvitation = ({
29173
29298
  if (invitation.line_ids && invitation.line_ids.length > 0) {
29174
29299
  properties.line_id = invitation.line_ids;
29175
29300
  }
29176
- } else if (invitation.role_level === "plant_head") {
29301
+ } else if (invitation.role_level === "plant_head" || invitation.role_level === "industrial_engineer") {
29177
29302
  properties.access_level = "factory";
29178
29303
  if (invitation.factory_ids && invitation.factory_ids.length > 0) {
29179
29304
  properties.factory_ids = invitation.factory_ids;
@@ -29264,7 +29389,7 @@ var SignupWithInvitation = ({
29264
29389
  ] })
29265
29390
  ] })
29266
29391
  ] }),
29267
- invitation.role_level === "plant_head" && invitation.factory_ids && invitation.factory_ids.length > 0 && /* @__PURE__ */ jsxs("div", { className: "md:col-span-2", children: [
29392
+ (invitation.role_level === "plant_head" || invitation.role_level === "industrial_engineer") && invitation.factory_ids && invitation.factory_ids.length > 0 && /* @__PURE__ */ jsxs("div", { className: "md:col-span-2", children: [
29268
29393
  /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600 mb-1", children: "Assigned Factories" }),
29269
29394
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
29270
29395
  /* @__PURE__ */ jsx(Building2, { className: "w-4 h-4 text-indigo-600" }),
@@ -29486,11 +29611,11 @@ var BarChartComponent = ({
29486
29611
  aspect = 2,
29487
29612
  ...restOfChartProps
29488
29613
  }) => {
29489
- const containerRef = React26__default.useRef(null);
29490
- const [containerReady, setContainerReady] = React26__default.useState(false);
29614
+ const containerRef = React141__default.useRef(null);
29615
+ const [containerReady, setContainerReady] = React141__default.useState(false);
29491
29616
  const themeConfig = useThemeConfig();
29492
29617
  const { formatNumber } = useFormatNumber();
29493
- React26__default.useEffect(() => {
29618
+ React141__default.useEffect(() => {
29494
29619
  const checkContainerDimensions = () => {
29495
29620
  if (containerRef.current) {
29496
29621
  const rect = containerRef.current.getBoundingClientRect();
@@ -29604,7 +29729,7 @@ var BarChartComponent = ({
29604
29729
  }
29605
29730
  return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: chartContent });
29606
29731
  };
29607
- var BarChart = React26__default.memo(BarChartComponent, (prevProps, nextProps) => {
29732
+ var BarChart = React141__default.memo(BarChartComponent, (prevProps, nextProps) => {
29608
29733
  if (prevProps.xAxisDataKey !== nextProps.xAxisDataKey || prevProps.xAxisLabel !== nextProps.xAxisLabel || prevProps.yAxisLabel !== nextProps.yAxisLabel || prevProps.yAxisUnit !== nextProps.yAxisUnit || JSON.stringify(prevProps.referenceLines || []) !== JSON.stringify(nextProps.referenceLines || []) || prevProps.layout !== nextProps.layout || prevProps.className !== nextProps.className || prevProps.showGrid !== nextProps.showGrid || prevProps.showLegend !== nextProps.showLegend || prevProps.showTooltip !== nextProps.showTooltip || prevProps.responsive !== nextProps.responsive || prevProps.aspect !== nextProps.aspect) {
29609
29734
  return false;
29610
29735
  }
@@ -29650,13 +29775,14 @@ var LineChartComponent = ({
29650
29775
  showTooltip = true,
29651
29776
  responsive = true,
29652
29777
  aspect = 2,
29778
+ fillContainer = false,
29653
29779
  ...restOfChartProps
29654
29780
  }) => {
29655
- const containerRef = React26__default.useRef(null);
29656
- const [containerReady, setContainerReady] = React26__default.useState(false);
29781
+ const containerRef = React141__default.useRef(null);
29782
+ const [containerReady, setContainerReady] = React141__default.useState(false);
29657
29783
  const themeConfig = useThemeConfig();
29658
29784
  const { formatNumber } = useFormatNumber();
29659
- React26__default.useEffect(() => {
29785
+ React141__default.useEffect(() => {
29660
29786
  const checkContainerDimensions = () => {
29661
29787
  if (containerRef.current) {
29662
29788
  const rect = containerRef.current.getBoundingClientRect();
@@ -29684,8 +29810,8 @@ var LineChartComponent = ({
29684
29810
  const defaultTooltipFormatter = (value, name, props) => {
29685
29811
  const formattedValue = typeof value === "number" ? formatNumber(value) : value;
29686
29812
  return [
29687
- /* @__PURE__ */ jsx("span", { children: `${formattedValue}${yAxisUnit || ""}` }, `tt-val-${name}-${value}`),
29688
- name
29813
+ /* @__PURE__ */ jsx("span", { className: "text-gray-900", children: `${formattedValue}${yAxisUnit || ""}` }, `tt-val-${name}-${value}`),
29814
+ /* @__PURE__ */ jsx("span", { className: "text-gray-500", children: name }, `tt-name-${name}`)
29689
29815
  ];
29690
29816
  };
29691
29817
  const defaultColors = [
@@ -29721,7 +29847,7 @@ var LineChartComponent = ({
29721
29847
  stroke: axisStrokeColor
29722
29848
  }
29723
29849
  ),
29724
- showTooltip && /* @__PURE__ */ jsx(Tooltip, { formatter: tooltipFormatter || defaultTooltipFormatter, cursor: { strokeDasharray: "3 3" } }),
29850
+ showTooltip && /* @__PURE__ */ jsx(Tooltip, { formatter: tooltipFormatter || defaultTooltipFormatter, itemStyle: { color: "#111827" }, cursor: { strokeDasharray: "3 3" } }),
29725
29851
  showLegend && /* @__PURE__ */ jsx(Legend, { payload: legendPayload }),
29726
29852
  lines.map((lineConfig, index) => {
29727
29853
  const lineProps = {
@@ -29747,15 +29873,15 @@ var LineChartComponent = ({
29747
29873
  "div",
29748
29874
  {
29749
29875
  ref: containerRef,
29750
- className: clsx("w-full h-auto", className),
29751
- style: { aspectRatio: `${aspect}/1`, minHeight: "50px", minWidth: "100px" },
29876
+ className: clsx(fillContainer ? "w-full h-full" : "w-full h-auto", className),
29877
+ style: fillContainer ? { height: "100%", minHeight: "50px", minWidth: "100px" } : { aspectRatio: `${aspect}/1`, minHeight: "50px", minWidth: "100px" },
29752
29878
  children: containerReady ? /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: chartContent }) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 rounded-lg", children: /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-sm", children: "Loading chart..." }) })
29753
29879
  }
29754
29880
  );
29755
29881
  }
29756
29882
  return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: chartContent });
29757
29883
  };
29758
- var LineChart = React26__default.memo(LineChartComponent, (prevProps, nextProps) => {
29884
+ var LineChart = React141__default.memo(LineChartComponent, (prevProps, nextProps) => {
29759
29885
  if (prevProps.xAxisDataKey !== nextProps.xAxisDataKey || prevProps.xAxisLabel !== nextProps.xAxisLabel || prevProps.yAxisLabel !== nextProps.yAxisLabel || prevProps.yAxisUnit !== nextProps.yAxisUnit || prevProps.className !== nextProps.className || prevProps.showGrid !== nextProps.showGrid || prevProps.showLegend !== nextProps.showLegend || prevProps.showTooltip !== nextProps.showTooltip || prevProps.responsive !== nextProps.responsive || prevProps.aspect !== nextProps.aspect || JSON.stringify(prevProps.yAxisDomain) !== JSON.stringify(nextProps.yAxisDomain)) {
29760
29886
  return false;
29761
29887
  }
@@ -29849,7 +29975,7 @@ var OutputProgressChartComponent = ({
29849
29975
  ] }) })
29850
29976
  ] }) });
29851
29977
  };
29852
- var OutputProgressChart = React26__default.memo(OutputProgressChartComponent);
29978
+ var OutputProgressChart = React141__default.memo(OutputProgressChartComponent);
29853
29979
  OutputProgressChart.displayName = "OutputProgressChart";
29854
29980
  var LargeOutputProgressChart = ({
29855
29981
  currentOutput,
@@ -29989,7 +30115,7 @@ var CycleTimeChartComponent = ({
29989
30115
  }
29990
30116
  ) }) });
29991
30117
  };
29992
- var CycleTimeChart = React26__default.memo(CycleTimeChartComponent, (prevProps, nextProps) => {
30118
+ var CycleTimeChart = React141__default.memo(CycleTimeChartComponent, (prevProps, nextProps) => {
29993
30119
  if (prevProps.className !== nextProps.className) {
29994
30120
  return false;
29995
30121
  }
@@ -30015,8 +30141,8 @@ var CycleTimeOverTimeChart = ({
30015
30141
  className = ""
30016
30142
  }) => {
30017
30143
  const MAX_DATA_POINTS = 40;
30018
- const containerRef = React26__default.useRef(null);
30019
- const [containerReady, setContainerReady] = React26__default.useState(false);
30144
+ const containerRef = React141__default.useRef(null);
30145
+ const [containerReady, setContainerReady] = React141__default.useState(false);
30020
30146
  const getHourFromTimeString = (timeStr) => {
30021
30147
  const [hours, minutes] = timeStr.split(":");
30022
30148
  return parseInt(hours);
@@ -30027,10 +30153,10 @@ var CycleTimeOverTimeChart = ({
30027
30153
  };
30028
30154
  const displayData = getDisplayData(data);
30029
30155
  const DURATION = displayData.length;
30030
- const [animatedData, setAnimatedData] = React26__default.useState(Array(DURATION).fill(0));
30031
- const prevDataRef = React26__default.useRef(Array(DURATION).fill(0));
30032
- const animationFrameRef = React26__default.useRef(null);
30033
- const animateToNewData = React26__default.useCallback((targetData) => {
30156
+ const [animatedData, setAnimatedData] = React141__default.useState(Array(DURATION).fill(0));
30157
+ const prevDataRef = React141__default.useRef(Array(DURATION).fill(0));
30158
+ const animationFrameRef = React141__default.useRef(null);
30159
+ const animateToNewData = React141__default.useCallback((targetData) => {
30034
30160
  const startData = [...prevDataRef.current];
30035
30161
  const startTime = performance.now();
30036
30162
  const duration = 1200;
@@ -30060,7 +30186,7 @@ var CycleTimeOverTimeChart = ({
30060
30186
  }
30061
30187
  animationFrameRef.current = requestAnimationFrame(animate);
30062
30188
  }, []);
30063
- React26__default.useEffect(() => {
30189
+ React141__default.useEffect(() => {
30064
30190
  if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
30065
30191
  const processedData = getDisplayData(data);
30066
30192
  animateToNewData(processedData);
@@ -30071,7 +30197,7 @@ var CycleTimeOverTimeChart = ({
30071
30197
  }
30072
30198
  };
30073
30199
  }, [data, animateToNewData]);
30074
- React26__default.useEffect(() => {
30200
+ React141__default.useEffect(() => {
30075
30201
  const checkContainerDimensions = () => {
30076
30202
  if (containerRef.current) {
30077
30203
  const rect = containerRef.current.getBoundingClientRect();
@@ -30314,7 +30440,7 @@ var CycleTimeOverTimeChart = ({
30314
30440
  }
30315
30441
  );
30316
30442
  };
30317
- var Card = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
30443
+ var Card = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
30318
30444
  "div",
30319
30445
  {
30320
30446
  ref,
@@ -30326,7 +30452,7 @@ var Card = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
30326
30452
  }
30327
30453
  ));
30328
30454
  Card.displayName = "Card";
30329
- var CardHeader = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
30455
+ var CardHeader = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
30330
30456
  "div",
30331
30457
  {
30332
30458
  ref,
@@ -30335,7 +30461,7 @@ var CardHeader = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE
30335
30461
  }
30336
30462
  ));
30337
30463
  CardHeader.displayName = "CardHeader";
30338
- var CardTitle = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
30464
+ var CardTitle = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
30339
30465
  "h3",
30340
30466
  {
30341
30467
  ref,
@@ -30347,7 +30473,7 @@ var CardTitle = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE_
30347
30473
  }
30348
30474
  ));
30349
30475
  CardTitle.displayName = "CardTitle";
30350
- var CardDescription = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
30476
+ var CardDescription = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
30351
30477
  "p",
30352
30478
  {
30353
30479
  ref,
@@ -30356,9 +30482,9 @@ var CardDescription = React26.forwardRef(({ className, ...props }, ref) => /* @_
30356
30482
  }
30357
30483
  ));
30358
30484
  CardDescription.displayName = "CardDescription";
30359
- var CardContent = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
30485
+ var CardContent = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
30360
30486
  CardContent.displayName = "CardContent";
30361
- var CardFooter = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
30487
+ var CardFooter = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
30362
30488
  "div",
30363
30489
  {
30364
30490
  ref,
@@ -30434,7 +30560,7 @@ var buttonVariants = cva(
30434
30560
  }
30435
30561
  }
30436
30562
  );
30437
- var Button = React26.forwardRef(
30563
+ var Button = React141.forwardRef(
30438
30564
  ({ className, variant, size, asChild = false, ...props }, ref) => {
30439
30565
  const Comp = asChild ? Slot : "button";
30440
30566
  return /* @__PURE__ */ jsx(
@@ -30461,9 +30587,9 @@ var HourlyOutputChartComponent = ({
30461
30587
  timezone,
30462
30588
  className = ""
30463
30589
  }) => {
30464
- const containerRef = React26__default.useRef(null);
30465
- const [containerReady, setContainerReady] = React26__default.useState(false);
30466
- const [containerWidth, setContainerWidth] = React26__default.useState(0);
30590
+ const containerRef = React141__default.useRef(null);
30591
+ const [containerReady, setContainerReady] = React141__default.useState(false);
30592
+ const [containerWidth, setContainerWidth] = React141__default.useState(0);
30467
30593
  const getTimeFromTimeString2 = (timeStr) => {
30468
30594
  const [hours, minutes] = timeStr.split(":");
30469
30595
  const hour = parseInt(hours);
@@ -30472,13 +30598,13 @@ var HourlyOutputChartComponent = ({
30472
30598
  return { hour, minute, decimalHour };
30473
30599
  };
30474
30600
  const shiftStartTime = getTimeFromTimeString2(shiftStart);
30475
- React26__default.useMemo(() => {
30601
+ React141__default.useMemo(() => {
30476
30602
  if (!shiftDate || !timezone) return null;
30477
30603
  const hour = shiftStartTime.hour.toString().padStart(2, "0");
30478
30604
  const minute = shiftStartTime.minute.toString().padStart(2, "0");
30479
30605
  return fromZonedTime(`${shiftDate}T${hour}:${minute}:00`, timezone);
30480
30606
  }, [shiftDate, timezone, shiftStartTime.hour, shiftStartTime.minute]);
30481
- const idleClipRanges = React26__default.useMemo(() => {
30607
+ const idleClipRanges = React141__default.useMemo(() => {
30482
30608
  if (!idleTimeClips || idleTimeClips.length === 0) return [];
30483
30609
  return idleTimeClips.map((clip) => ({
30484
30610
  id: clip.id,
@@ -30486,7 +30612,7 @@ var HourlyOutputChartComponent = ({
30486
30612
  end: clip.idle_end_time ? new Date(clip.idle_end_time) : null
30487
30613
  })).filter((clip) => clip.start && clip.end);
30488
30614
  }, [idleTimeClips]);
30489
- React26__default.useCallback((rangeStart, rangeEnd) => {
30615
+ React141__default.useCallback((rangeStart, rangeEnd) => {
30490
30616
  if (!rangeStart || !rangeEnd || idleClipRanges.length === 0) {
30491
30617
  return "Reason unavailable";
30492
30618
  }
@@ -30503,7 +30629,7 @@ var HourlyOutputChartComponent = ({
30503
30629
  }
30504
30630
  return classification.label.replace(/_/g, " ");
30505
30631
  }, [idleClipRanges, idleTimeClipClassifications]);
30506
- const { shiftDuration, shiftEndTime, hasPartialLastHour } = React26__default.useMemo(() => {
30632
+ const { shiftDuration, shiftEndTime, hasPartialLastHour } = React141__default.useMemo(() => {
30507
30633
  console.log("[HourlyOutputChart] Calculating shift duration with:", {
30508
30634
  shiftStart,
30509
30635
  shiftEnd,
@@ -30538,12 +30664,12 @@ var HourlyOutputChartComponent = ({
30538
30664
  }, [shiftEnd, shiftStartTime.decimalHour]);
30539
30665
  const SHIFT_DURATION = shiftDuration;
30540
30666
  shiftEndTime ? shiftEndTime.hour : (shiftStartTime.hour + SHIFT_DURATION) % 24;
30541
- const [animatedData, setAnimatedData] = React26__default.useState(
30667
+ const [animatedData, setAnimatedData] = React141__default.useState(
30542
30668
  () => Array(SHIFT_DURATION).fill(0)
30543
30669
  );
30544
- const prevDataRef = React26__default.useRef(Array(SHIFT_DURATION).fill(0));
30545
- const animationFrameRef = React26__default.useRef(null);
30546
- React26__default.useEffect(() => {
30670
+ const prevDataRef = React141__default.useRef(Array(SHIFT_DURATION).fill(0));
30671
+ const animationFrameRef = React141__default.useRef(null);
30672
+ React141__default.useEffect(() => {
30547
30673
  setAnimatedData((prev) => {
30548
30674
  if (prev.length !== SHIFT_DURATION) {
30549
30675
  return Array(SHIFT_DURATION).fill(0);
@@ -30552,14 +30678,14 @@ var HourlyOutputChartComponent = ({
30552
30678
  });
30553
30679
  prevDataRef.current = Array(SHIFT_DURATION).fill(0);
30554
30680
  }, [SHIFT_DURATION]);
30555
- const [idleBarState, setIdleBarState] = React26__default.useState({
30681
+ const [idleBarState, setIdleBarState] = React141__default.useState({
30556
30682
  visible: showIdleTime,
30557
30683
  key: 0,
30558
30684
  shouldAnimate: false
30559
30685
  });
30560
- const prevShowIdleTimeRef = React26__default.useRef(showIdleTime);
30561
- const stateUpdateTimeoutRef = React26__default.useRef(null);
30562
- React26__default.useEffect(() => {
30686
+ const prevShowIdleTimeRef = React141__default.useRef(showIdleTime);
30687
+ const stateUpdateTimeoutRef = React141__default.useRef(null);
30688
+ React141__default.useEffect(() => {
30563
30689
  if (stateUpdateTimeoutRef.current) {
30564
30690
  clearTimeout(stateUpdateTimeoutRef.current);
30565
30691
  }
@@ -30584,7 +30710,7 @@ var HourlyOutputChartComponent = ({
30584
30710
  }
30585
30711
  };
30586
30712
  }, [showIdleTime]);
30587
- const animateToNewData = React26__default.useCallback((targetData) => {
30713
+ const animateToNewData = React141__default.useCallback((targetData) => {
30588
30714
  const startData = [...prevDataRef.current];
30589
30715
  const startTime = performance.now();
30590
30716
  const duration = 1200;
@@ -30614,7 +30740,7 @@ var HourlyOutputChartComponent = ({
30614
30740
  }
30615
30741
  animationFrameRef.current = requestAnimationFrame(animate);
30616
30742
  }, []);
30617
- React26__default.useEffect(() => {
30743
+ React141__default.useEffect(() => {
30618
30744
  if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
30619
30745
  const shiftData = data.slice(0, SHIFT_DURATION);
30620
30746
  animateToNewData(shiftData);
@@ -30625,7 +30751,7 @@ var HourlyOutputChartComponent = ({
30625
30751
  }
30626
30752
  };
30627
30753
  }, [data, animateToNewData]);
30628
- React26__default.useEffect(() => {
30754
+ React141__default.useEffect(() => {
30629
30755
  const checkContainerDimensions = () => {
30630
30756
  if (containerRef.current) {
30631
30757
  const rect = containerRef.current.getBoundingClientRect();
@@ -30651,7 +30777,7 @@ var HourlyOutputChartComponent = ({
30651
30777
  clearTimeout(fallbackTimeout);
30652
30778
  };
30653
30779
  }, []);
30654
- const xAxisConfig = React26__default.useMemo(() => {
30780
+ const xAxisConfig = React141__default.useMemo(() => {
30655
30781
  if (containerWidth >= 960) {
30656
30782
  return { interval: 0, angle: -45, height: 92, tickFont: 10, tickMargin: 12 };
30657
30783
  }
@@ -30660,7 +30786,7 @@ var HourlyOutputChartComponent = ({
30660
30786
  }
30661
30787
  return { interval: 0, angle: -30, height: 64, tickFont: 9, tickMargin: 6 };
30662
30788
  }, [containerWidth]);
30663
- const formatHour = React26__default.useCallback((hourIndex) => {
30789
+ const formatHour = React141__default.useCallback((hourIndex) => {
30664
30790
  const isLastHour = hourIndex === SHIFT_DURATION - 1;
30665
30791
  const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
30666
30792
  const startHour = Math.floor(startDecimalHour) % 24;
@@ -30684,7 +30810,7 @@ var HourlyOutputChartComponent = ({
30684
30810
  };
30685
30811
  return `${formatTime5(startHour, startMinute)}-${formatTime5(endHour, endMinute)}`;
30686
30812
  }, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
30687
- const formatTimeRange2 = React26__default.useCallback((hourIndex) => {
30813
+ const formatTimeRange2 = React141__default.useCallback((hourIndex) => {
30688
30814
  const isLastHour = hourIndex === SHIFT_DURATION - 1;
30689
30815
  const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
30690
30816
  const startHour = Math.floor(startDecimalHour) % 24;
@@ -30705,7 +30831,7 @@ var HourlyOutputChartComponent = ({
30705
30831
  };
30706
30832
  return `${formatTime5(startHour, startMinute)} - ${formatTime5(endHour, endMinute)}`;
30707
30833
  }, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
30708
- const chartData = React26__default.useMemo(() => {
30834
+ const chartData = React141__default.useMemo(() => {
30709
30835
  return Array.from({ length: SHIFT_DURATION }, (_, i) => {
30710
30836
  const actualHour = (shiftStartTime.hour + i) % 24;
30711
30837
  const startMinute = shiftStartTime.minute;
@@ -30775,7 +30901,7 @@ var HourlyOutputChartComponent = ({
30775
30901
  };
30776
30902
  });
30777
30903
  }, [animatedData, data, pphThreshold, idleTimeHourly, shiftStartTime.hour, shiftStartTime.minute, shiftEndTime, formatHour, formatTimeRange2, SHIFT_DURATION]);
30778
- const IdleBar = React26__default.useMemo(() => {
30904
+ const IdleBar = React141__default.useMemo(() => {
30779
30905
  if (!idleBarState.visible) return null;
30780
30906
  return /* @__PURE__ */ jsx(
30781
30907
  Bar,
@@ -31103,7 +31229,7 @@ var HourlyOutputChartComponent = ({
31103
31229
  }
31104
31230
  );
31105
31231
  };
31106
- var HourlyOutputChart = React26__default.memo(HourlyOutputChartComponent, (prevProps, nextProps) => {
31232
+ var HourlyOutputChart = React141__default.memo(HourlyOutputChartComponent, (prevProps, nextProps) => {
31107
31233
  if (prevProps.pphThreshold !== nextProps.pphThreshold || prevProps.shiftStart !== nextProps.shiftStart || prevProps.shiftEnd !== nextProps.shiftEnd || prevProps.shiftDate !== nextProps.shiftDate || prevProps.timezone !== nextProps.timezone || prevProps.showIdleTime !== nextProps.showIdleTime || prevProps.className !== nextProps.className) {
31108
31234
  return false;
31109
31235
  }
@@ -31166,7 +31292,7 @@ function getTrendArrowAndColor(trend) {
31166
31292
  return { arrow: "\u2192", color: "text-gray-400" };
31167
31293
  }
31168
31294
  }
31169
- var VideoCard = React26__default.memo(({
31295
+ var VideoCard = React141__default.memo(({
31170
31296
  workspace,
31171
31297
  hlsUrl,
31172
31298
  shouldPlay,
@@ -31346,7 +31472,7 @@ var logDebug2 = (...args) => {
31346
31472
  if (!DEBUG_DASHBOARD_LOGS2) return;
31347
31473
  console.log(...args);
31348
31474
  };
31349
- var VideoGridView = React26__default.memo(({
31475
+ var VideoGridView = React141__default.memo(({
31350
31476
  workspaces,
31351
31477
  selectedLine,
31352
31478
  className = "",
@@ -31583,7 +31709,8 @@ var VideoGridView = React26__default.memo(({
31583
31709
  action_count: workspace.action_count
31584
31710
  });
31585
31711
  const displayName = getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
31586
- const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id);
31712
+ const currentPath = (router.asPath || "/").split("#")[0];
31713
+ const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id, currentPath);
31587
31714
  router.push(`/workspace/${workspaceId}${navParams}`);
31588
31715
  }, [router, prewarmClipsInit]);
31589
31716
  const handleStreamError = useCallback((workspaceId, options) => {
@@ -31715,7 +31842,7 @@ var VideoGridView = React26__default.memo(({
31715
31842
  ) }) });
31716
31843
  });
31717
31844
  VideoGridView.displayName = "VideoGridView";
31718
- var MapGridView = React26__default.memo(({
31845
+ var MapGridView = React141__default.memo(({
31719
31846
  workspaces,
31720
31847
  className = "",
31721
31848
  displayNames = {},
@@ -31790,7 +31917,8 @@ var MapGridView = React26__default.memo(({
31790
31917
  });
31791
31918
  const displayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
31792
31919
  getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
31793
- const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id);
31920
+ const currentPath = (router.asPath || "/").split("#")[0];
31921
+ const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id, currentPath);
31794
31922
  router.push(`/workspace/${workspaceId}${navParams}`);
31795
31923
  }, [router, displayNames, prewarmClipsInit]);
31796
31924
  const activePositions = useMemo(() => {
@@ -32536,7 +32664,7 @@ var UptimeLineChartComponent = ({ points, className = "" }) => {
32536
32664
  )
32537
32665
  ] }) }) });
32538
32666
  };
32539
- var UptimeLineChart = React26__default.memo(UptimeLineChartComponent);
32667
+ var UptimeLineChart = React141__default.memo(UptimeLineChartComponent);
32540
32668
  var padTime = (value) => value.toString().padStart(2, "0");
32541
32669
  var parseTime = (timeValue) => {
32542
32670
  if (!timeValue) return null;
@@ -32745,10 +32873,10 @@ var HourlyUptimeChartComponent = ({
32745
32873
  elapsedMinutes,
32746
32874
  className = ""
32747
32875
  }) => {
32748
- const containerRef = React26__default.useRef(null);
32749
- const [containerReady, setContainerReady] = React26__default.useState(false);
32750
- const [containerWidth, setContainerWidth] = React26__default.useState(0);
32751
- const uptimeSeries = React26__default.useMemo(() => buildUptimeSeries({
32876
+ const containerRef = React141__default.useRef(null);
32877
+ const [containerReady, setContainerReady] = React141__default.useState(false);
32878
+ const [containerWidth, setContainerWidth] = React141__default.useState(0);
32879
+ const uptimeSeries = React141__default.useMemo(() => buildUptimeSeries({
32752
32880
  idleTimeHourly,
32753
32881
  shiftStart,
32754
32882
  shiftEnd,
@@ -32757,11 +32885,11 @@ var HourlyUptimeChartComponent = ({
32757
32885
  elapsedMinutes
32758
32886
  }), [idleTimeHourly, shiftStart, shiftEnd, shiftDate, timezone, elapsedMinutes]);
32759
32887
  const hasAggregateData = Boolean(hourlyAggregates && hourlyAggregates.length > 0);
32760
- const shiftStartTime = React26__default.useMemo(
32888
+ const shiftStartTime = React141__default.useMemo(
32761
32889
  () => getTimeFromTimeString(shiftStart),
32762
32890
  [shiftStart]
32763
32891
  );
32764
- const { shiftDuration, shiftEndTime } = React26__default.useMemo(() => {
32892
+ const { shiftDuration, shiftEndTime } = React141__default.useMemo(() => {
32765
32893
  if (!shiftEnd) {
32766
32894
  const fallbackHours = uptimeSeries.shiftMinutes > 0 ? Math.ceil(uptimeSeries.shiftMinutes / 60) : 0;
32767
32895
  return { shiftDuration: fallbackHours, shiftEndTime: null };
@@ -32775,7 +32903,7 @@ var HourlyUptimeChartComponent = ({
32775
32903
  const hourCount = hasPartial ? Math.ceil(duration) : Math.round(duration);
32776
32904
  return { shiftDuration: hourCount, shiftEndTime: endTime };
32777
32905
  }, [shiftEnd, shiftStartTime.decimalHour, uptimeSeries.shiftMinutes]);
32778
- const formatHour = React26__default.useCallback((hourIndex) => {
32906
+ const formatHour = React141__default.useCallback((hourIndex) => {
32779
32907
  const isLastHour = hourIndex === shiftDuration - 1;
32780
32908
  const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
32781
32909
  const startHour = Math.floor(startDecimalHour) % 24;
@@ -32800,7 +32928,7 @@ var HourlyUptimeChartComponent = ({
32800
32928
  };
32801
32929
  return `${formatTime5(startHour, startMinute)}-${formatTime5(endHour, endMinute)}`;
32802
32930
  }, [shiftDuration, shiftStartTime.decimalHour, shiftEndTime]);
32803
- const formatTimeRange2 = React26__default.useCallback((hourIndex) => {
32931
+ const formatTimeRange2 = React141__default.useCallback((hourIndex) => {
32804
32932
  const isLastHour = hourIndex === shiftDuration - 1;
32805
32933
  const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
32806
32934
  const startHour = Math.floor(startDecimalHour) % 24;
@@ -32822,7 +32950,7 @@ var HourlyUptimeChartComponent = ({
32822
32950
  };
32823
32951
  return `${formatTime5(startHour, startMinute)} - ${formatTime5(endHour, endMinute)}`;
32824
32952
  }, [shiftDuration, shiftStartTime.decimalHour, shiftEndTime]);
32825
- const chartData = React26__default.useMemo(() => {
32953
+ const chartData = React141__default.useMemo(() => {
32826
32954
  if (shiftDuration <= 0) return [];
32827
32955
  if (hasAggregateData) {
32828
32956
  return hourlyAggregates.map((entry, hourIndex) => ({
@@ -32864,7 +32992,7 @@ var HourlyUptimeChartComponent = ({
32864
32992
  }, [hasAggregateData, hourlyAggregates, uptimeSeries.points, uptimeSeries.elapsedMinutes, uptimeSeries.shiftMinutes, shiftDuration, formatHour, formatTimeRange2]);
32865
32993
  const maxYValue = 100;
32866
32994
  const yAxisTicks = [0, 25, 50, 75, 100];
32867
- React26__default.useEffect(() => {
32995
+ React141__default.useEffect(() => {
32868
32996
  const checkContainerDimensions = () => {
32869
32997
  if (containerRef.current) {
32870
32998
  const rect = containerRef.current.getBoundingClientRect();
@@ -32890,7 +33018,7 @@ var HourlyUptimeChartComponent = ({
32890
33018
  clearTimeout(fallbackTimeout);
32891
33019
  };
32892
33020
  }, []);
32893
- const xAxisConfig = React26__default.useMemo(() => {
33021
+ const xAxisConfig = React141__default.useMemo(() => {
32894
33022
  if (containerWidth >= 960) {
32895
33023
  return { interval: 0, angle: -45, height: 92, tickFont: 10, tickMargin: 12, labelMode: "full" };
32896
33024
  }
@@ -32899,7 +33027,7 @@ var HourlyUptimeChartComponent = ({
32899
33027
  }
32900
33028
  return { interval: 0, angle: -30, height: 64, tickFont: 9, tickMargin: 6, labelMode: "start" };
32901
33029
  }, [containerWidth]);
32902
- const formatXAxisTick = React26__default.useCallback((raw) => {
33030
+ const formatXAxisTick = React141__default.useCallback((raw) => {
32903
33031
  const label = typeof raw === "string" ? raw : String(raw);
32904
33032
  if (xAxisConfig.labelMode === "full") return label;
32905
33033
  const parts = label.split("-");
@@ -33105,7 +33233,7 @@ var HourlyUptimeChartComponent = ({
33105
33233
  }
33106
33234
  );
33107
33235
  };
33108
- var HourlyUptimeChart = React26__default.memo(HourlyUptimeChartComponent);
33236
+ var HourlyUptimeChart = React141__default.memo(HourlyUptimeChartComponent);
33109
33237
  var DEFAULT_COLORS2 = ["#00AB45", "#ef4444"];
33110
33238
  var UptimeDonutChartComponent = ({
33111
33239
  data,
@@ -33175,7 +33303,7 @@ var UptimeDonutChartComponent = ({
33175
33303
  ] }) })
33176
33304
  ] }) });
33177
33305
  };
33178
- var UptimeDonutChart = React26__default.memo(UptimeDonutChartComponent);
33306
+ var UptimeDonutChart = React141__default.memo(UptimeDonutChartComponent);
33179
33307
  UptimeDonutChart.displayName = "UptimeDonutChart";
33180
33308
  var TrendIcon = ({ trend }) => {
33181
33309
  if (trend === "up") {
@@ -33294,7 +33422,7 @@ var EmptyStateMessage = ({
33294
33422
  iconClassName
33295
33423
  }) => {
33296
33424
  let IconContent = null;
33297
- if (React26__default.isValidElement(iconType)) {
33425
+ if (React141__default.isValidElement(iconType)) {
33298
33426
  IconContent = iconType;
33299
33427
  } else if (typeof iconType === "string") {
33300
33428
  const MappedIcon = IconMap[iconType];
@@ -35579,7 +35707,7 @@ function Skeleton({ className, ...props }) {
35579
35707
  var Select = SelectPrimitive.Root;
35580
35708
  var SelectGroup = SelectPrimitive.Group;
35581
35709
  var SelectValue = SelectPrimitive.Value;
35582
- var SelectTrigger = React26.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
35710
+ var SelectTrigger = React141.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
35583
35711
  SelectPrimitive.Trigger,
35584
35712
  {
35585
35713
  ref,
@@ -35595,7 +35723,7 @@ var SelectTrigger = React26.forwardRef(({ className, children, ...props }, ref)
35595
35723
  }
35596
35724
  ));
35597
35725
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
35598
- var SelectScrollUpButton = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
35726
+ var SelectScrollUpButton = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
35599
35727
  SelectPrimitive.ScrollUpButton,
35600
35728
  {
35601
35729
  ref,
@@ -35605,7 +35733,7 @@ var SelectScrollUpButton = React26.forwardRef(({ className, ...props }, ref) =>
35605
35733
  }
35606
35734
  ));
35607
35735
  SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
35608
- var SelectScrollDownButton = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
35736
+ var SelectScrollDownButton = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
35609
35737
  SelectPrimitive.ScrollDownButton,
35610
35738
  {
35611
35739
  ref,
@@ -35615,7 +35743,7 @@ var SelectScrollDownButton = React26.forwardRef(({ className, ...props }, ref) =
35615
35743
  }
35616
35744
  ));
35617
35745
  SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
35618
- var SelectContent = React26.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
35746
+ var SelectContent = React141.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
35619
35747
  SelectPrimitive.Content,
35620
35748
  {
35621
35749
  ref,
@@ -35643,7 +35771,7 @@ var SelectContent = React26.forwardRef(({ className, children, position = "poppe
35643
35771
  }
35644
35772
  ) }));
35645
35773
  SelectContent.displayName = SelectPrimitive.Content.displayName;
35646
- var SelectLabel = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
35774
+ var SelectLabel = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
35647
35775
  SelectPrimitive.Label,
35648
35776
  {
35649
35777
  ref,
@@ -35652,7 +35780,7 @@ var SelectLabel = React26.forwardRef(({ className, ...props }, ref) => /* @__PUR
35652
35780
  }
35653
35781
  ));
35654
35782
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
35655
- var SelectItem = React26.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
35783
+ var SelectItem = React141.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
35656
35784
  SelectPrimitive.Item,
35657
35785
  {
35658
35786
  ref,
@@ -35668,7 +35796,7 @@ var SelectItem = React26.forwardRef(({ className, children, ...props }, ref) =>
35668
35796
  }
35669
35797
  ));
35670
35798
  SelectItem.displayName = SelectPrimitive.Item.displayName;
35671
- var SelectSeparator = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
35799
+ var SelectSeparator = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
35672
35800
  SelectPrimitive.Separator,
35673
35801
  {
35674
35802
  ref,
@@ -35967,7 +36095,7 @@ var TimePickerDropdown = ({
35967
36095
  ] })
35968
36096
  ] });
35969
36097
  };
35970
- var SilentErrorBoundary = class extends React26__default.Component {
36098
+ var SilentErrorBoundary = class extends React141__default.Component {
35971
36099
  constructor(props) {
35972
36100
  super(props);
35973
36101
  this.handleClearAndReload = () => {
@@ -42481,6 +42609,32 @@ var STATIC_COLORS = {
42481
42609
  };
42482
42610
  var PRODUCTIVE_COLOR = "#00AB45";
42483
42611
  var IDLE_COLOR = "#e5e7eb";
42612
+ var formatDuration = (seconds) => {
42613
+ if (seconds === null || seconds === void 0 || !Number.isFinite(seconds)) {
42614
+ return "--";
42615
+ }
42616
+ const wholeSeconds = Math.max(0, Math.round(seconds));
42617
+ const days = Math.floor(wholeSeconds / 86400);
42618
+ const hours = Math.floor(wholeSeconds % 86400 / 3600);
42619
+ const minutes = Math.floor(wholeSeconds % 3600 / 60);
42620
+ const remainingSeconds = wholeSeconds % 60;
42621
+ if (days > 0) {
42622
+ return `${days}d ${hours}h ${minutes}m ${remainingSeconds}s`;
42623
+ }
42624
+ if (hours > 0) {
42625
+ return `${hours}h ${minutes}m ${remainingSeconds}s`;
42626
+ }
42627
+ if (minutes > 0) {
42628
+ return `${minutes}m ${remainingSeconds}s`;
42629
+ }
42630
+ return `${remainingSeconds}s`;
42631
+ };
42632
+ var formatPercentage = (value) => {
42633
+ if (value === null || value === void 0 || !Number.isFinite(value)) {
42634
+ return "--";
42635
+ }
42636
+ return `${value.toFixed(1)}%`;
42637
+ };
42484
42638
  var getColorForEntry = (name, index) => {
42485
42639
  const normalized = name.trim().toLowerCase();
42486
42640
  if (normalized === "productive" || normalized === "productive time") {
@@ -42495,11 +42649,37 @@ var getColorForEntry = (name, index) => {
42495
42649
  const snakeCaseName = name.replace(/ /g, "_");
42496
42650
  return getReasonColor(snakeCaseName, index);
42497
42651
  };
42498
- var CustomTooltip = ({ active, payload }) => {
42652
+ var CustomTooltip = ({ active, payload, hideTotalDuration }) => {
42499
42653
  if (active && payload && payload.length) {
42500
- return /* @__PURE__ */ jsxs("div", { className: "bg-white p-2 border border-gray-200 shadow-md rounded-md text-xs z-50", children: [
42501
- /* @__PURE__ */ jsx("p", { className: "font-medium", children: payload[0].name }),
42502
- /* @__PURE__ */ jsx("p", { className: "text-gray-500", children: `${payload[0].value.toFixed(1)}%` })
42654
+ const datum = payload[0]?.payload;
42655
+ const contributors = datum?.contributors || [];
42656
+ const fill = payload[0]?.payload?.fill || payload[0]?.fill || getColorForEntry(payload[0].name, 0);
42657
+ return /* @__PURE__ */ jsxs("div", { className: "bg-white/95 backdrop-blur-sm p-3 border border-gray-200 shadow-xl rounded-lg z-50 min-w-[200px]", children: [
42658
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 mb-2 pb-1 border-b border-gray-100", children: [
42659
+ /* @__PURE__ */ jsx("div", { className: "w-2.5 h-2.5 rounded-full flex-shrink-0", style: { backgroundColor: fill } }),
42660
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-slate-800 text-sm", children: payload[0].name.replace(/_/g, " ") })
42661
+ ] }),
42662
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 text-xs", children: [
42663
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center gap-3", children: [
42664
+ /* @__PURE__ */ jsx("span", { className: "text-slate-500", children: "Share of idle time" }),
42665
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-slate-800", children: `${payload[0].value.toFixed(1)}%` })
42666
+ ] }),
42667
+ !hideTotalDuration && datum?.totalDurationSeconds !== void 0 ? /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center gap-3", children: [
42668
+ /* @__PURE__ */ jsx("span", { className: "text-slate-500", children: "Total Duration" }),
42669
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-slate-800", children: formatDuration(datum.totalDurationSeconds) })
42670
+ ] }) : null,
42671
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center gap-3", children: [
42672
+ /* @__PURE__ */ jsx("span", { className: "text-slate-500", children: "Efficiency Loss" }),
42673
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-slate-800", children: formatPercentage(datum?.efficiencyLossPercentage) })
42674
+ ] })
42675
+ ] }),
42676
+ contributors.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-2 pt-2 border-t border-gray-100", children: [
42677
+ /* @__PURE__ */ jsx("p", { className: "text-[9px] font-semibold uppercase tracking-wider text-slate-400 mb-1.5", children: "Top Workstations" }),
42678
+ /* @__PURE__ */ jsx("div", { className: "space-y-1", children: contributors.slice(0, 3).map((contributor) => /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2 text-[10px]", children: [
42679
+ /* @__PURE__ */ jsx("span", { className: "text-slate-700 truncate max-w-[120px]", children: contributor.workspaceName }),
42680
+ /* @__PURE__ */ jsx("span", { className: "text-slate-500 text-right whitespace-nowrap", children: `${formatDuration(contributor.totalDurationSeconds)} \u2022 ${Number(contributor.percentageWithinReason || 0).toFixed(1)}%` })
42681
+ ] }, `${payload[0].name}-${contributor.workspaceId}`)) })
42682
+ ] }) : null
42503
42683
  ] });
42504
42684
  }
42505
42685
  return null;
@@ -42536,10 +42716,11 @@ var ErrorState = ({ error }) => /* @__PURE__ */ jsx("div", { className: "w-full
42536
42716
  var IdleTimeReasonChartComponent = ({
42537
42717
  data,
42538
42718
  isLoading = false,
42539
- error = null
42719
+ error = null,
42720
+ hideTotalDuration = false
42540
42721
  }) => {
42541
- const [activeData, setActiveData] = React26__default.useState([]);
42542
- React26__default.useEffect(() => {
42722
+ const [activeData, setActiveData] = React141__default.useState([]);
42723
+ React141__default.useEffect(() => {
42543
42724
  if (activeData.length > 0) {
42544
42725
  setActiveData([]);
42545
42726
  }
@@ -42554,7 +42735,7 @@ var IdleTimeReasonChartComponent = ({
42554
42735
  setActiveData([]);
42555
42736
  }
42556
42737
  }, [data]);
42557
- React26__default.useEffect(() => {
42738
+ React141__default.useEffect(() => {
42558
42739
  if (!data || data.length === 0) return;
42559
42740
  data.forEach((entry, index) => {
42560
42741
  if (entry.name.toLowerCase().includes("other")) {
@@ -42562,7 +42743,7 @@ var IdleTimeReasonChartComponent = ({
42562
42743
  }
42563
42744
  });
42564
42745
  }, [data]);
42565
- const pieKey = React26__default.useMemo(() => {
42746
+ const pieKey = React141__default.useMemo(() => {
42566
42747
  return activeData.map((d) => `${d.name}-${d.value}`).join("|");
42567
42748
  }, [activeData]);
42568
42749
  if (isLoading) {
@@ -42589,19 +42770,29 @@ var IdleTimeReasonChartComponent = ({
42589
42770
  }
42590
42771
  .recharts-wrapper {
42591
42772
  outline: none !important;
42773
+ overflow: visible !important;
42774
+ }
42775
+ .recharts-tooltip-wrapper {
42776
+ z-index: 1000 !important;
42777
+ }
42778
+ .recharts-responsive-container {
42779
+ overflow: visible !important;
42780
+ }
42781
+ .recharts-surface {
42782
+ overflow: visible !important;
42592
42783
  }
42593
42784
  ` }),
42594
42785
  /* @__PURE__ */ jsxs(
42595
42786
  "div",
42596
42787
  {
42597
- className: "w-full h-full flex items-center overflow-hidden focus:outline-none",
42788
+ className: "w-full h-full flex items-center overflow-visible focus:outline-none",
42598
42789
  tabIndex: -1,
42599
42790
  onFocus: (e) => e.currentTarget.blur(),
42600
42791
  children: [
42601
42792
  /* @__PURE__ */ jsx(
42602
42793
  "div",
42603
42794
  {
42604
- className: "flex-1 h-full min-w-0 relative focus:outline-none",
42795
+ className: "flex-1 h-full min-w-0 relative focus:outline-none overflow-visible",
42605
42796
  tabIndex: -1,
42606
42797
  onFocus: (e) => e.currentTarget.blur(),
42607
42798
  children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(PieChart, { margin: { top: 0, right: 0, bottom: 0, left: 0 }, children: [
@@ -42633,11 +42824,11 @@ var IdleTimeReasonChartComponent = ({
42633
42824
  },
42634
42825
  pieKey
42635
42826
  ),
42636
- /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(CustomTooltip, {}) })
42827
+ /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(CustomTooltip, { hideTotalDuration }) })
42637
42828
  ] }) })
42638
42829
  }
42639
42830
  ),
42640
- /* @__PURE__ */ jsx("div", { className: "w-[45%] max-w-[140px] pl-2 flex flex-col justify-center h-full overflow-y-auto", children: /* @__PURE__ */ jsx("ul", { className: "text-xs space-y-1.5", children: data.map((entry, index) => /* @__PURE__ */ jsxs("li", { className: "flex items-start", children: [
42831
+ /* @__PURE__ */ jsx("div", { className: "w-[50%] max-w-[200px] pl-1 pr-1 flex flex-col justify-center h-full overflow-y-auto", children: /* @__PURE__ */ jsx("ul", { className: "text-xs space-y-1.5", children: data.map((entry, index) => /* @__PURE__ */ jsxs("li", { className: "flex items-start", children: [
42641
42832
  /* @__PURE__ */ jsx(
42642
42833
  "span",
42643
42834
  {
@@ -42645,14 +42836,14 @@ var IdleTimeReasonChartComponent = ({
42645
42836
  style: { backgroundColor: getColorForEntry(entry.name, index) }
42646
42837
  }
42647
42838
  ),
42648
- /* @__PURE__ */ jsx("span", { className: "text-gray-600 leading-tight text-[10px] sm:text-xs break-words", children: entry.name })
42839
+ /* @__PURE__ */ jsx("span", { className: "text-gray-600 leading-tight text-[11px] sm:text-xs break-words", children: entry.name.replace(/_/g, " ") })
42649
42840
  ] }, `item-${index}`)) }) })
42650
42841
  ]
42651
42842
  }
42652
42843
  )
42653
42844
  ] });
42654
42845
  };
42655
- var IdleTimeReasonChart = React26__default.memo(IdleTimeReasonChartComponent);
42846
+ var IdleTimeReasonChart = React141__default.memo(IdleTimeReasonChartComponent);
42656
42847
  IdleTimeReasonChart.displayName = "IdleTimeReasonChart";
42657
42848
  var IdleTimeReasonChart_default = IdleTimeReasonChart;
42658
42849
  var DEFAULT_PERFORMANCE_DATA = {
@@ -46874,11 +47065,11 @@ var getWorkspaceStyles = (position, isPlaceholder = false) => {
46874
47065
  ${isPlaceholder ? "cursor-default" : ""}`;
46875
47066
  };
46876
47067
  var formatPercentRange = (min, max) => {
46877
- const format7 = (value) => Number.isInteger(value) ? `${value}` : value.toFixed(1);
47068
+ const format8 = (value) => Number.isInteger(value) ? `${value}` : value.toFixed(1);
46878
47069
  if (min >= 100 || max >= 100) {
46879
- return `${format7(min)}+%`;
47070
+ return `${format8(min)}+%`;
46880
47071
  }
46881
- return `${format7(min)}-${format7(max)}%`;
47072
+ return `${format8(min)}-${format8(max)}%`;
46882
47073
  };
46883
47074
  var Legend6 = ({ useBottleneckLabel = false, legend }) => {
46884
47075
  const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
@@ -46912,7 +47103,7 @@ var arePropsEqual = (prevProps, nextProps) => {
46912
47103
  return prevProps.data.efficiency === nextProps.data.efficiency && prevProps.data.trend_score === nextProps.data.trend_score && prevProps.data.workspace_id === nextProps.data.workspace_id && prevProps.data.workspace_name === nextProps.data.workspace_name && prevProps.isBottleneck === nextProps.isBottleneck && prevProps.isLowEfficiency === nextProps.isLowEfficiency && prevProps.isVeryLowEfficiency === nextProps.isVeryLowEfficiency && prevLegend.green_min === nextLegend.green_min && prevLegend.green_max === nextLegend.green_max && prevLegend.yellow_min === nextLegend.yellow_min && prevLegend.yellow_max === nextLegend.yellow_max && prevLegend.red_min === nextLegend.red_min && prevLegend.red_max === nextLegend.red_max && prevLegend.critical_threshold === nextLegend.critical_threshold && // Position doesn't need deep equality check as it's generally static
46913
47104
  prevProps.position.id === nextProps.position.id;
46914
47105
  };
46915
- var WorkspaceGridItem = React26__default.memo(({
47106
+ var WorkspaceGridItem = React141__default.memo(({
46916
47107
  data,
46917
47108
  position,
46918
47109
  isBottleneck = false,
@@ -46941,7 +47132,8 @@ var WorkspaceGridItem = React26__default.memo(({
46941
47132
  e.preventDefault();
46942
47133
  if (isInactive) return;
46943
47134
  const displayName = getWorkspaceDisplayName(data.workspace_name, data.line_id);
46944
- const navParams = getWorkspaceNavigationParams(data.workspace_id, displayName, data.line_id);
47135
+ const currentPath = typeof window !== "undefined" ? `${window.location.pathname}${window.location.search}` : "/";
47136
+ const navParams = getWorkspaceNavigationParams(data.workspace_id, displayName, data.line_id, currentPath);
46945
47137
  navigate(`/workspace/${data.workspace_id}${navParams}`, {
46946
47138
  trackingEvent: {
46947
47139
  name: "Workspace Detail Clicked",
@@ -47006,7 +47198,7 @@ var WorkspaceGridItem = React26__default.memo(({
47006
47198
  );
47007
47199
  }, arePropsEqual);
47008
47200
  WorkspaceGridItem.displayName = "WorkspaceGridItem";
47009
- var WorkspaceGrid = React26__default.memo(({
47201
+ var WorkspaceGrid = React141__default.memo(({
47010
47202
  workspaces,
47011
47203
  isPdfMode = false,
47012
47204
  customWorkspacePositions,
@@ -47261,7 +47453,7 @@ var KPICard = ({
47261
47453
  }) => {
47262
47454
  useThemeConfig();
47263
47455
  const { formatNumber } = useFormatNumber();
47264
- const trendInfo = React26__default.useMemo(() => {
47456
+ const trendInfo = React141__default.useMemo(() => {
47265
47457
  let trendValue = trend || "neutral";
47266
47458
  if (change !== void 0 && trend === void 0) {
47267
47459
  trendValue = change > 0 ? "up" : change < 0 ? "down" : "neutral";
@@ -47288,7 +47480,7 @@ var KPICard = ({
47288
47480
  const shouldShowTrend = !(change === 0 && trend === void 0);
47289
47481
  return { trendValue, Icon: Icon2, colorClass, bgClass, shouldShowTrend };
47290
47482
  }, [trend, change]);
47291
- const formattedValue = React26__default.useMemo(() => {
47483
+ const formattedValue = React141__default.useMemo(() => {
47292
47484
  if (title === "Quality Compliance" && typeof value === "number") {
47293
47485
  return value.toFixed(1);
47294
47486
  }
@@ -47302,7 +47494,7 @@ var KPICard = ({
47302
47494
  }
47303
47495
  return value;
47304
47496
  }, [value, title]);
47305
- const formattedChange = React26__default.useMemo(() => {
47497
+ const formattedChange = React141__default.useMemo(() => {
47306
47498
  if (change === void 0 || change === 0 && !showZeroChange) return null;
47307
47499
  const absChange = Math.abs(change);
47308
47500
  return formatNumber(absChange, { minimumFractionDigits: 0, maximumFractionDigits: 1 });
@@ -47740,7 +47932,7 @@ var WorkspaceHealthCard = ({
47740
47932
  onClick(workspace);
47741
47933
  }
47742
47934
  };
47743
- const formatDuration4 = (minutes) => {
47935
+ const formatDuration5 = (minutes) => {
47744
47936
  if (!minutes || minutes <= 0) return "0 min";
47745
47937
  const rounded = Math.max(Math.round(minutes), 0);
47746
47938
  const days = Math.floor(rounded / 1440);
@@ -47806,7 +47998,7 @@ var WorkspaceHealthCard = ({
47806
47998
  };
47807
47999
  }
47808
48000
  return {
47809
- text: `${formatDuration4(downtimeMinutes)}`,
48001
+ text: `${formatDuration5(downtimeMinutes)}`,
47810
48002
  className: downtimeMinutes > 60 ? "text-rose-600 dark:text-rose-400" : "text-amber-600 dark:text-amber-400",
47811
48003
  label: "Total Downtime"
47812
48004
  };
@@ -48782,7 +48974,7 @@ var Breadcrumbs = ({ items }) => {
48782
48974
  }
48783
48975
  }
48784
48976
  };
48785
- return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "mb-1 flex items-center space-x-1 text-xs font-medium text-gray-500 dark:text-gray-400", children: items.map((item, index) => /* @__PURE__ */ jsxs(React26__default.Fragment, { children: [
48977
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "mb-1 flex items-center space-x-1 text-xs font-medium text-gray-500 dark:text-gray-400", children: items.map((item, index) => /* @__PURE__ */ jsxs(React141__default.Fragment, { children: [
48786
48978
  index > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3 text-gray-400 dark:text-gray-500" }),
48787
48979
  /* @__PURE__ */ jsxs(
48788
48980
  "span",
@@ -48844,29 +49036,27 @@ var UserProfileDropdown = ({ config }) => {
48844
49036
  }
48845
49037
  }
48846
49038
  };
48847
- const defaultAvatar = /* @__PURE__ */ jsx(UserCircle, { className: "h-7 w-7 text-gray-500 dark:text-gray-400" });
49039
+ const fullName = user?.user_metadata?.full_name;
49040
+ const triggerLabel = config.showName !== false ? fullName || user.email || "Account" : "Account";
48848
49041
  return /* @__PURE__ */ jsxs("div", { className: "relative", ref: dropdownRef, children: [
48849
- /* @__PURE__ */ jsxs(
49042
+ /* @__PURE__ */ jsx(
48850
49043
  "button",
48851
49044
  {
48852
49045
  type: "button",
48853
- className: "flex items-center gap-2 rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800",
49046
+ className: "flex items-center rounded-md px-2 py-1.5 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:text-gray-200 dark:hover:bg-gray-800 dark:focus:ring-offset-gray-800",
48854
49047
  onClick: () => setIsOpen(!isOpen),
48855
49048
  "aria-haspopup": "true",
48856
49049
  "aria-expanded": isOpen,
48857
49050
  "aria-label": "User menu",
48858
- children: [
48859
- config.customAvatar ? config.customAvatar : config.showAvatar !== false && user?.user_metadata?.avatar_url ? /* @__PURE__ */ jsx("img", { className: "h-8 w-8 rounded-full", src: user.user_metadata.avatar_url, alt: "User avatar" }) : defaultAvatar,
48860
- config.showName !== false && user?.user_metadata?.full_name && /* @__PURE__ */ jsx("span", { className: "hidden md:block text-sm font-medium text-gray-700 dark:text-gray-200", children: user.user_metadata.full_name })
48861
- ]
49051
+ children: /* @__PURE__ */ jsx("span", { className: "truncate max-w-[180px]", children: triggerLabel })
48862
49052
  }
48863
49053
  ),
48864
49054
  isOpen && /* @__PURE__ */ jsxs("div", { className: "origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg py-1 bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5 dark:ring-gray-700 focus:outline-none z-50", children: [
48865
- config.showName !== false && user?.user_metadata?.full_name && /* @__PURE__ */ jsxs("div", { className: "px-4 py-2 md:hidden", children: [
48866
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-900 dark:text-white truncate", children: user.user_metadata.full_name }),
49055
+ config.showName !== false && fullName && /* @__PURE__ */ jsxs("div", { className: "px-4 py-2 md:hidden", children: [
49056
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-900 dark:text-white truncate", children: fullName }),
48867
49057
  user.email && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 truncate", children: user.email })
48868
49058
  ] }),
48869
- user?.user_metadata?.full_name && /* @__PURE__ */ jsx("div", { className: "md:hidden h-px bg-gray-200 dark:bg-gray-700 my-1" }),
49059
+ fullName && /* @__PURE__ */ jsx("div", { className: "md:hidden h-px bg-gray-200 dark:bg-gray-700 my-1" }),
48870
49060
  menuItems.map(
48871
49061
  (item) => item.isDivider ? /* @__PURE__ */ jsx("div", { className: "h-px bg-gray-200 dark:bg-gray-700 my-1" }, item.key) : /* @__PURE__ */ jsxs(
48872
49062
  "button",
@@ -49108,6 +49298,211 @@ var SettingsPopup = ({
49108
49298
  document.body
49109
49299
  );
49110
49300
  };
49301
+ var formatPercent = (value) => typeof value === "number" && Number.isFinite(value) ? `${value.toFixed(1)}%` : "N/A";
49302
+ var formatRelativeTime2 = (value) => {
49303
+ const parsed = new Date(value);
49304
+ if (Number.isNaN(parsed.getTime())) return "Just now";
49305
+ const diffMs = parsed.getTime() - Date.now();
49306
+ const absSeconds = Math.round(Math.abs(diffMs) / 1e3);
49307
+ const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
49308
+ if (absSeconds < 60) return rtf.format(Math.round(diffMs / 1e3), "second");
49309
+ if (absSeconds < 3600) return rtf.format(Math.round(diffMs / 6e4), "minute");
49310
+ if (absSeconds < 86400) return rtf.format(Math.round(diffMs / 36e5), "hour");
49311
+ return rtf.format(Math.round(diffMs / 864e5), "day");
49312
+ };
49313
+ var AlertsPopup = ({
49314
+ isOpen,
49315
+ onClose,
49316
+ triggerRef,
49317
+ companyId,
49318
+ alertsCount = 0,
49319
+ onAlertsLoaded
49320
+ }) => {
49321
+ const supabase = useSupabase();
49322
+ const popupRef = useRef(null);
49323
+ const [position, setPosition] = useState({ top: 0, left: 90, width: 360 });
49324
+ const [mounted, setMounted] = useState(false);
49325
+ const [alerts, setAlerts] = useState([]);
49326
+ const [isLoading, setIsLoading] = useState(false);
49327
+ const [error, setError] = useState(null);
49328
+ const loadAlerts = useCallback(async () => {
49329
+ if (!supabase || !companyId) {
49330
+ setAlerts([]);
49331
+ onAlertsLoaded?.(0);
49332
+ return;
49333
+ }
49334
+ try {
49335
+ setIsLoading(true);
49336
+ setError(null);
49337
+ const response = await alertsService.getCurrentAlerts(supabase, companyId);
49338
+ const nextAlerts = response?.alerts || [];
49339
+ setAlerts(nextAlerts);
49340
+ onAlertsLoaded?.(response?.total ?? nextAlerts.length);
49341
+ } catch (err) {
49342
+ const message = err instanceof Error ? err.message : "Failed to load alerts";
49343
+ setAlerts([]);
49344
+ setError(message);
49345
+ onAlertsLoaded?.(0);
49346
+ } finally {
49347
+ setIsLoading(false);
49348
+ }
49349
+ }, [companyId, onAlertsLoaded, supabase]);
49350
+ useEffect(() => {
49351
+ setMounted(true);
49352
+ }, []);
49353
+ useEffect(() => {
49354
+ if (!isOpen) return;
49355
+ void loadAlerts();
49356
+ }, [isOpen, loadAlerts]);
49357
+ const updatePosition = useCallback(() => {
49358
+ const viewportHeight = window.innerHeight;
49359
+ const viewportWidth = window.innerWidth;
49360
+ if (viewportWidth < 768) {
49361
+ const mobileWidth = Math.max(240, Math.min(360, viewportWidth - 32));
49362
+ setPosition({
49363
+ top: Math.max(16, (viewportHeight - 280) / 2),
49364
+ left: Math.max(16, (viewportWidth - mobileWidth) / 2),
49365
+ width: mobileWidth
49366
+ });
49367
+ return;
49368
+ }
49369
+ if (!triggerRef.current) return;
49370
+ const rect = triggerRef.current.getBoundingClientRect();
49371
+ const popupHeight = 280;
49372
+ let top = rect.bottom - popupHeight + 40;
49373
+ if (top < 16) top = 16;
49374
+ if (top + popupHeight > viewportHeight - 16) {
49375
+ top = viewportHeight - popupHeight - 16;
49376
+ }
49377
+ setPosition({
49378
+ top,
49379
+ left: 88,
49380
+ // Sidebar width (80px) + gap (8px)
49381
+ width: 360
49382
+ });
49383
+ }, [triggerRef]);
49384
+ useEffect(() => {
49385
+ if (isOpen) {
49386
+ updatePosition();
49387
+ window.addEventListener("resize", updatePosition);
49388
+ window.addEventListener("scroll", updatePosition);
49389
+ }
49390
+ return () => {
49391
+ window.removeEventListener("resize", updatePosition);
49392
+ window.removeEventListener("scroll", updatePosition);
49393
+ };
49394
+ }, [isOpen, updatePosition]);
49395
+ useEffect(() => {
49396
+ const handleClickOutside = (event) => {
49397
+ const target = event.target;
49398
+ const clickedTrigger = triggerRef.current?.contains(target) ?? false;
49399
+ if (popupRef.current && !popupRef.current.contains(target) && !clickedTrigger) {
49400
+ onClose();
49401
+ }
49402
+ };
49403
+ const handleEscape = (event) => {
49404
+ if (event.key === "Escape") {
49405
+ onClose();
49406
+ }
49407
+ };
49408
+ if (isOpen) {
49409
+ document.addEventListener("mousedown", handleClickOutside);
49410
+ document.addEventListener("keydown", handleEscape);
49411
+ }
49412
+ return () => {
49413
+ document.removeEventListener("mousedown", handleClickOutside);
49414
+ document.removeEventListener("keydown", handleEscape);
49415
+ };
49416
+ }, [isOpen, onClose, triggerRef]);
49417
+ if (!mounted) return null;
49418
+ return createPortal(
49419
+ /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsxs(
49420
+ motion.div,
49421
+ {
49422
+ ref: popupRef,
49423
+ initial: { opacity: 0, x: -12, scale: 0.95 },
49424
+ animate: { opacity: 1, x: 0, scale: 1 },
49425
+ exit: { opacity: 0, x: -12, scale: 0.95 },
49426
+ transition: {
49427
+ duration: 0.2,
49428
+ ease: [0.16, 1, 0.3, 1]
49429
+ },
49430
+ style: {
49431
+ position: "fixed",
49432
+ top: position.top,
49433
+ left: position.left,
49434
+ width: position.width,
49435
+ zIndex: 2147483647
49436
+ },
49437
+ className: "bg-white rounded-[16px] shadow-xl border border-gray-100 max-w-[calc(100vw-32px)] overflow-hidden flex flex-col",
49438
+ children: [
49439
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-5 py-4 border-b border-gray-50 bg-[#fafafa]", children: [
49440
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
49441
+ /* @__PURE__ */ jsx("h3", { className: "text-[14px] font-bold text-[#111827] uppercase tracking-wide", children: "Recent Alerts" }),
49442
+ alertsCount > 0 && /* @__PURE__ */ jsxs("span", { className: "bg-[#eff6ff] text-[#2563eb] text-[11px] font-bold px-2 py-0.5 rounded-full", children: [
49443
+ alertsCount,
49444
+ " Active"
49445
+ ] })
49446
+ ] }),
49447
+ /* @__PURE__ */ jsx(
49448
+ "button",
49449
+ {
49450
+ onClick: onClose,
49451
+ className: "text-gray-400 hover:text-gray-600 focus:outline-none p-1.5 -mr-1.5 rounded-lg hover:bg-gray-100 transition-colors",
49452
+ children: /* @__PURE__ */ jsx(XMarkIcon, { className: "w-[18px] h-[18px]", strokeWidth: 2 })
49453
+ }
49454
+ )
49455
+ ] }),
49456
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col max-h-[380px] overflow-y-auto", children: [
49457
+ isLoading && /* @__PURE__ */ jsx("div", { className: "px-5 py-10 text-sm text-gray-500", children: "Loading current shift alerts..." }),
49458
+ !isLoading && error && /* @__PURE__ */ jsx("div", { className: "px-5 py-10 text-sm text-red-600", children: error }),
49459
+ !isLoading && !error && alerts.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-5 py-10 text-sm text-gray-500", children: "No active alerts for the current shift." }),
49460
+ !isLoading && !error && alerts.map((alert2, index) => {
49461
+ const isCritical = typeof alert2.delta_efficiency === "number" && alert2.delta_efficiency <= -10;
49462
+ const description = `${alert2.monitoring_mode === "uptime" ? "Uptime" : "Output"} efficiency is ${formatPercent(alert2.current_efficiency)} vs last week's ${formatPercent(alert2.baseline_efficiency)} average.`;
49463
+ return /* @__PURE__ */ jsx(
49464
+ motion.div,
49465
+ {
49466
+ initial: { opacity: 0, y: 10 },
49467
+ animate: { opacity: 1, y: 0 },
49468
+ transition: {
49469
+ duration: 0.2,
49470
+ delay: index * 0.05 + 0.1,
49471
+ ease: [0.16, 1, 0.3, 1]
49472
+ },
49473
+ className: "px-5 py-5 border-b border-gray-50 hover:bg-[#f8fafc] transition-colors",
49474
+ children: /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
49475
+ /* @__PURE__ */ jsx("div", { className: `shrink-0 flex items-start pt-0.5 ${isCritical ? "text-[#ef4444]" : "text-[#f59e0b]"}`, children: isCritical ? /* @__PURE__ */ jsx(ExclamationCircleIcon, { className: "w-5 h-5", strokeWidth: 1.5 }) : /* @__PURE__ */ jsx(ExclamationTriangleIcon, { className: "w-5 h-5", strokeWidth: 1.5 }) }),
49476
+ /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
49477
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-start mb-1.5", children: [
49478
+ /* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold text-[#111827]", children: alert2.line_name }),
49479
+ /* @__PURE__ */ jsx("span", { className: "text-[12px] text-[#94a3b8] font-medium whitespace-nowrap ml-3", children: formatRelativeTime2(alert2.evaluated_at) })
49480
+ ] }),
49481
+ /* @__PURE__ */ jsxs("p", { className: "text-[12px] font-medium text-[#475569] uppercase tracking-wide", children: [
49482
+ alert2.monitoring_mode === "uptime" ? "Uptime" : "Output",
49483
+ " regression"
49484
+ ] }),
49485
+ /* @__PURE__ */ jsx("p", { className: "text-[13.5px] text-[#64748b] leading-[1.45] mt-1", children: description }),
49486
+ /* @__PURE__ */ jsxs("p", { className: "text-[12px] text-[#94a3b8] mt-2", children: [
49487
+ "Delta ",
49488
+ formatPercent(alert2.delta_efficiency),
49489
+ " across ",
49490
+ alert2.baseline_sample_size,
49491
+ " historical shifts"
49492
+ ] })
49493
+ ] })
49494
+ ] })
49495
+ },
49496
+ alert2.id
49497
+ );
49498
+ })
49499
+ ] })
49500
+ ]
49501
+ }
49502
+ ) }),
49503
+ document.body
49504
+ );
49505
+ };
49111
49506
  var SideNavBar = memo$1(({
49112
49507
  // These props are accepted but not used in this implementation
49113
49508
  navItems = [],
@@ -49121,17 +49516,13 @@ var SideNavBar = memo$1(({
49121
49516
  const router = useRouter();
49122
49517
  const { navigate } = useNavigation();
49123
49518
  const { signOut, user } = useAuth();
49519
+ const supabase = useSupabase();
49124
49520
  const entityConfig = useEntityConfig();
49125
49521
  const dashboardConfig = useDashboardConfig();
49126
49522
  const isSuperAdmin = user?.scope_mode === "SUPER_ADMIN" || !!user?.access_scope?.is_super_admin;
49127
49523
  const role = user?.role_level;
49128
- const roleAccessMap = {
49129
- optifye: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/tickets", "/improvement-center"],
49130
- owner: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/tickets", "/improvement-center"],
49131
- it: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/tickets", "/improvement-center"],
49132
- plant_head: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/tickets", "/improvement-center"],
49133
- supervisor: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/skus", "/help", "/health", "/profile", "/workspace", "/tickets", "/improvement-center"]
49134
- };
49524
+ const roleNavPaths = useMemo(() => getRoleNavPaths(role), [role]);
49525
+ const showLiveMonitorLink = roleNavPaths.includes("/live-monitor");
49135
49526
  const getBasePath = useCallback((path) => {
49136
49527
  const firstSegment = path.split("?")[0].split("/").filter(Boolean)[0];
49137
49528
  return firstSegment ? `/${firstSegment}` : "/";
@@ -49140,9 +49531,8 @@ var SideNavBar = memo$1(({
49140
49531
  if (!role) return false;
49141
49532
  if (isSuperAdmin) return true;
49142
49533
  const basePath = getBasePath(path);
49143
- const allowedPaths = roleAccessMap[role] || [];
49144
- return allowedPaths.includes(basePath);
49145
- }, [role, isSuperAdmin, getBasePath]);
49534
+ return roleNavPaths.includes(basePath);
49535
+ }, [role, isSuperAdmin, getBasePath, roleNavPaths]);
49146
49536
  const lineId = entityConfig.defaultLineId || LINE_1_UUID;
49147
49537
  const skuEnabled = dashboardConfig?.skuConfig?.enabled || false;
49148
49538
  dashboardConfig?.supervisorConfig?.enabled || false;
@@ -49183,6 +49573,17 @@ var SideNavBar = memo$1(({
49183
49573
  });
49184
49574
  onMobileMenuClose?.();
49185
49575
  }, [navigate, onMobileMenuClose]);
49576
+ const handleLiveClick = useCallback(() => {
49577
+ navigate("/live-monitor", {
49578
+ trackingEvent: {
49579
+ name: "Live Monitor Clicked",
49580
+ properties: {
49581
+ source: "side_nav"
49582
+ }
49583
+ }
49584
+ });
49585
+ onMobileMenuClose?.();
49586
+ }, [navigate, onMobileMenuClose]);
49186
49587
  const handleKPIsClick = useCallback(() => {
49187
49588
  navigate(`/kpis`, {
49188
49589
  trackingEvent: {
@@ -49318,6 +49719,37 @@ var SideNavBar = memo$1(({
49318
49719
  }, [navigate, onMobileMenuClose]);
49319
49720
  const [isSettingsOpen, setIsSettingsOpen] = useState(false);
49320
49721
  const settingsTriggerRef = useRef(null);
49722
+ const [isAlertsOpen, setIsAlertsOpen] = useState(false);
49723
+ const [alertsCount, setAlertsCount] = useState(0);
49724
+ const alertsTriggerRef = useRef(null);
49725
+ const alertsCompanyId = entityConfig.companyId || user?.company_id;
49726
+ const showAlertsButton = (role === "supervisor" || role === "optifye") && !!alertsCompanyId && !!supabase;
49727
+ const refreshAlertsSummary = useCallback(async () => {
49728
+ if (!showAlertsButton || !supabase || !alertsCompanyId) {
49729
+ setAlertsCount(0);
49730
+ return;
49731
+ }
49732
+ try {
49733
+ const summary = await alertsService.getSummary(supabase, alertsCompanyId);
49734
+ setAlertsCount(summary?.total_current_alerts || 0);
49735
+ } catch (error) {
49736
+ console.error("Failed to fetch alerts summary:", error);
49737
+ setAlertsCount(0);
49738
+ }
49739
+ }, [alertsCompanyId, showAlertsButton, supabase]);
49740
+ useEffect(() => {
49741
+ if (!showAlertsButton) {
49742
+ setAlertsCount(0);
49743
+ return;
49744
+ }
49745
+ void refreshAlertsSummary();
49746
+ const intervalId = window.setInterval(() => {
49747
+ void refreshAlertsSummary();
49748
+ }, 5 * 60 * 1e3);
49749
+ return () => {
49750
+ window.clearInterval(intervalId);
49751
+ };
49752
+ }, [refreshAlertsSummary, showAlertsButton]);
49321
49753
  const settingsItems = useMemo(() => {
49322
49754
  const items = [
49323
49755
  ...canAccessPath("/targets") ? [{
@@ -49412,6 +49844,7 @@ var SideNavBar = memo$1(({
49412
49844
  onMobileMenuClose?.();
49413
49845
  }, [navigate, onMobileMenuClose]);
49414
49846
  const homeButtonClasses = useMemo(() => getButtonClasses("/"), [getButtonClasses, pathname]);
49847
+ const liveButtonClasses = useMemo(() => getButtonClasses("/live-monitor"), [getButtonClasses, pathname]);
49415
49848
  const leaderboardButtonClasses = useMemo(() => getButtonClasses("/leaderboard"), [getButtonClasses, pathname]);
49416
49849
  const kpisButtonClasses = useMemo(() => getButtonClasses("/kpis"), [getButtonClasses, pathname]);
49417
49850
  const improvementButtonClasses = useMemo(() => getButtonClasses("/improvement-center"), [getButtonClasses, pathname]);
@@ -49425,6 +49858,12 @@ var SideNavBar = memo$1(({
49425
49858
  ${isActive ? "bg-blue-50/80 text-blue-600 font-medium" : "hover:bg-gray-50 text-gray-500 hover:text-gray-700 font-medium active:bg-gray-100"}
49426
49859
  transition-all duration-200 ease-out focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2`;
49427
49860
  }, [isSettingsOpen, settingsItems]);
49861
+ const alertsButtonClasses = useMemo(() => {
49862
+ const isActive = isAlertsOpen;
49863
+ return `w-full flex flex-col items-center justify-center py-4 sm:py-3 px-2 sm:px-1 rounded-lg relative group min-h-[44px] sm:min-h-0
49864
+ ${isActive ? "bg-blue-50/80 text-blue-600 font-medium" : "hover:bg-gray-50 text-gray-500 hover:text-gray-700 font-medium active:bg-gray-100"}
49865
+ transition-all duration-200 ease-out focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2`;
49866
+ }, [isAlertsOpen]);
49428
49867
  const NavigationContent = () => /* @__PURE__ */ jsxs(Fragment, { children: [
49429
49868
  /* @__PURE__ */ jsx("div", { className: "w-full py-6 px-4 flex-shrink-0", children: /* @__PURE__ */ jsx(
49430
49869
  "button",
@@ -49436,21 +49875,38 @@ var SideNavBar = memo$1(({
49436
49875
  }
49437
49876
  ) }),
49438
49877
  /* @__PURE__ */ jsxs("div", { className: "flex-1 w-full py-6 px-4 overflow-y-auto", children: [
49439
- /* @__PURE__ */ jsx("div", { className: "mb-6", children: canAccessPath("/") && /* @__PURE__ */ jsxs(
49440
- "button",
49441
- {
49442
- onClick: handleHomeClick,
49443
- className: homeButtonClasses,
49444
- "aria-label": "Home",
49445
- tabIndex: 0,
49446
- role: "tab",
49447
- "aria-selected": pathname === "/" || pathname.startsWith("//"),
49448
- children: [
49449
- /* @__PURE__ */ jsx(HomeIcon, { className: "w-5 h-5 mb-1" }),
49450
- /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Home" })
49451
- ]
49452
- }
49453
- ) }),
49878
+ /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
49879
+ canAccessPath("/") && /* @__PURE__ */ jsxs(
49880
+ "button",
49881
+ {
49882
+ onClick: handleHomeClick,
49883
+ className: homeButtonClasses,
49884
+ "aria-label": "Home",
49885
+ tabIndex: 0,
49886
+ role: "tab",
49887
+ "aria-selected": pathname === "/" || pathname.startsWith("//"),
49888
+ children: [
49889
+ /* @__PURE__ */ jsx(HomeIcon, { className: "w-5 h-5 mb-1" }),
49890
+ /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Home" })
49891
+ ]
49892
+ }
49893
+ ),
49894
+ showLiveMonitorLink && canAccessPath("/live-monitor") && /* @__PURE__ */ jsxs(
49895
+ "button",
49896
+ {
49897
+ onClick: handleLiveClick,
49898
+ className: `${liveButtonClasses} mt-3`,
49899
+ "aria-label": "Monitor",
49900
+ tabIndex: 0,
49901
+ role: "tab",
49902
+ "aria-selected": pathname === "/live-monitor" || pathname.startsWith("/live-monitor/"),
49903
+ children: [
49904
+ /* @__PURE__ */ jsx(VideoCameraIcon, { className: "w-5 h-5 mb-1" }),
49905
+ /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Monitor" })
49906
+ ]
49907
+ }
49908
+ )
49909
+ ] }),
49454
49910
  /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
49455
49911
  canAccessPath("/leaderboard") && /* @__PURE__ */ jsxs(
49456
49912
  "button",
@@ -49530,22 +49986,55 @@ var SideNavBar = memo$1(({
49530
49986
  )
49531
49987
  ] })
49532
49988
  ] }),
49533
- settingsItems.length > 0 && /* @__PURE__ */ jsx("div", { className: "w-full py-5 px-4 border-t border-gray-100 flex-shrink-0", children: /* @__PURE__ */ jsxs(
49534
- "button",
49535
- {
49536
- ref: settingsTriggerRef,
49537
- onClick: () => setIsSettingsOpen(!isSettingsOpen),
49538
- className: settingsButtonClasses,
49539
- "aria-label": "Settings",
49540
- tabIndex: 0,
49541
- role: "tab",
49542
- "aria-selected": isSettingsOpen || settingsItems.some((item) => item.isActive),
49543
- children: [
49544
- /* @__PURE__ */ jsx(Cog6ToothIcon, { className: "w-5 h-5 mb-1" }),
49545
- /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Settings" })
49546
- ]
49547
- }
49548
- ) })
49989
+ /* @__PURE__ */ jsxs("div", { className: "w-full py-4 px-4 border-t border-gray-100 flex-shrink-0 flex flex-col gap-2", children: [
49990
+ showAlertsButton && /* @__PURE__ */ jsxs(
49991
+ "button",
49992
+ {
49993
+ ref: alertsTriggerRef,
49994
+ onClick: () => {
49995
+ setIsAlertsOpen(!isAlertsOpen);
49996
+ setIsSettingsOpen(false);
49997
+ if (!isAlertsOpen) {
49998
+ void refreshAlertsSummary();
49999
+ }
50000
+ },
50001
+ className: alertsButtonClasses,
50002
+ "aria-label": "Alerts",
50003
+ tabIndex: 0,
50004
+ role: "tab",
50005
+ "aria-selected": isAlertsOpen,
50006
+ children: [
50007
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
50008
+ /* @__PURE__ */ jsx(BellIcon, { className: "w-5 h-5 mb-1" }),
50009
+ alertsCount > 0 && /* @__PURE__ */ jsxs("span", { className: "absolute -top-1 -right-1 flex h-2.5 w-2.5", children: [
50010
+ /* @__PURE__ */ jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75" }),
50011
+ /* @__PURE__ */ jsx("span", { className: "relative inline-flex rounded-full h-2.5 w-2.5 bg-red-500" })
50012
+ ] })
50013
+ ] }),
50014
+ /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight mt-1", children: "Alerts" })
50015
+ ]
50016
+ }
50017
+ ),
50018
+ settingsItems.length > 0 && /* @__PURE__ */ jsxs(
50019
+ "button",
50020
+ {
50021
+ ref: settingsTriggerRef,
50022
+ onClick: () => {
50023
+ setIsSettingsOpen(!isSettingsOpen);
50024
+ setIsAlertsOpen(false);
50025
+ },
50026
+ className: settingsButtonClasses,
50027
+ "aria-label": "Settings",
50028
+ tabIndex: 0,
50029
+ role: "tab",
50030
+ "aria-selected": isSettingsOpen || settingsItems.some((item) => item.isActive),
50031
+ children: [
50032
+ /* @__PURE__ */ jsx(Cog6ToothIcon, { className: "w-5 h-5 mb-1" }),
50033
+ /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Settings" })
50034
+ ]
50035
+ }
50036
+ )
50037
+ ] })
49549
50038
  ] });
49550
50039
  const MobileNavigationContent = () => {
49551
50040
  const isActive = (path) => {
@@ -49580,6 +50069,18 @@ var SideNavBar = memo$1(({
49580
50069
  ]
49581
50070
  }
49582
50071
  ),
50072
+ showLiveMonitorLink && canAccessPath("/live-monitor") && /* @__PURE__ */ jsxs(
50073
+ "button",
50074
+ {
50075
+ onClick: handleMobileNavClick(handleLiveClick),
50076
+ className: `${getMobileButtonClass("/live-monitor")} mt-2`,
50077
+ "aria-label": "Monitor",
50078
+ children: [
50079
+ /* @__PURE__ */ jsx(VideoCameraIcon, { className: getIconClass("/live-monitor") }),
50080
+ /* @__PURE__ */ jsx("span", { className: "text-base font-medium", children: "Monitor" })
50081
+ ]
50082
+ }
50083
+ ),
49583
50084
  /* @__PURE__ */ jsxs("div", { className: "mt-6 space-y-2", children: [
49584
50085
  canAccessPath("/leaderboard") && /* @__PURE__ */ jsxs(
49585
50086
  "button",
@@ -49643,9 +50144,31 @@ var SideNavBar = memo$1(({
49643
50144
  }
49644
50145
  )
49645
50146
  ] }),
49646
- settingsItems.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-8 pt-6 border-t border-gray-100", children: [
50147
+ /* @__PURE__ */ jsxs("div", { className: "mt-8 pt-6 border-t border-gray-100", children: [
49647
50148
  /* @__PURE__ */ jsx("h3", { className: "px-5 mb-3 text-[10px] font-bold text-gray-400 uppercase tracking-widest", children: "Settings & Support" }),
49648
50149
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
50150
+ showAlertsButton && /* @__PURE__ */ jsxs(
50151
+ "button",
50152
+ {
50153
+ onClick: () => {
50154
+ setIsAlertsOpen(true);
50155
+ void refreshAlertsSummary();
50156
+ onMobileMenuClose?.();
50157
+ },
50158
+ className: getMobileButtonClass("/alerts"),
50159
+ "aria-label": "Alerts",
50160
+ children: [
50161
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
50162
+ /* @__PURE__ */ jsx(BellIcon, { className: getIconClass("/alerts") }),
50163
+ alertsCount > 0 && /* @__PURE__ */ jsxs("span", { className: "absolute -top-1 -right-1 flex h-2.5 w-2.5", children: [
50164
+ /* @__PURE__ */ jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75" }),
50165
+ /* @__PURE__ */ jsx("span", { className: "relative inline-flex rounded-full h-2.5 w-2.5 bg-red-500" })
50166
+ ] })
50167
+ ] }),
50168
+ /* @__PURE__ */ jsx("span", { className: "text-base font-medium ml-3", children: "Alerts" })
50169
+ ]
50170
+ }
50171
+ ),
49649
50172
  canAccessPath("/targets") && /* @__PURE__ */ jsxs(
49650
50173
  "button",
49651
50174
  {
@@ -49760,7 +50283,18 @@ var SideNavBar = memo$1(({
49760
50283
  ] }),
49761
50284
  /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx(MobileNavigationContent, {}) })
49762
50285
  ] })
49763
- ] })
50286
+ ] }),
50287
+ /* @__PURE__ */ jsx(
50288
+ AlertsPopup,
50289
+ {
50290
+ isOpen: isAlertsOpen,
50291
+ onClose: () => setIsAlertsOpen(false),
50292
+ triggerRef: alertsTriggerRef,
50293
+ companyId: alertsCompanyId,
50294
+ alertsCount,
50295
+ onAlertsLoaded: setAlertsCount
50296
+ }
50297
+ )
49764
50298
  ] });
49765
50299
  });
49766
50300
  SideNavBar.displayName = "SideNavBar";
@@ -49937,7 +50471,7 @@ var AwardBadge = ({
49937
50471
  }) => {
49938
50472
  const styles2 = getBadgeStyles(type);
49939
50473
  const Icon2 = CustomIcon || getDefaultIcon(type);
49940
- const randomDelay = React26__default.useMemo(() => Math.random() * 2, []);
50474
+ const randomDelay = React141__default.useMemo(() => Math.random() * 2, []);
49941
50475
  const floatingAnimation = {
49942
50476
  animate: {
49943
50477
  y: [0, -10, 0],
@@ -51967,18 +52501,20 @@ var InviteUserDialog = ({
51967
52501
  const [isSubmitting, setIsSubmitting] = useState(false);
51968
52502
  const [error, setError] = useState(null);
51969
52503
  const isSuperAdminOptifye = user?.role_level === "optifye" && (user?.scope_mode === "SUPER_ADMIN" || !!user?.access_scope?.is_super_admin);
51970
- const canInviteOwner = isSuperAdminOptifye;
51971
- const canInviteIT = user?.role_level === "owner" || user?.role_level === "optifye";
51972
- const canInvitePlantHead = user?.role_level === "owner" || user?.role_level === "it" || user?.role_level === "optifye";
51973
- const canInviteSupervisor = ["owner", "it", "plant_head", "optifye"].includes(user?.role_level || "");
52504
+ const canInviteOwner = canRoleInviteRole(user?.role_level, "owner", { isSuperAdminOptifye });
52505
+ const canInviteIT = canRoleInviteRole(user?.role_level, "it", { isSuperAdminOptifye });
52506
+ const canInvitePlantHead = canRoleInviteRole(user?.role_level, "plant_head", { isSuperAdminOptifye });
52507
+ const canInviteIndustrialEngineer = canRoleInviteRole(user?.role_level, "industrial_engineer", { isSuperAdminOptifye });
52508
+ const canInviteSupervisor = canRoleInviteRole(user?.role_level, "supervisor", { isSuperAdminOptifye });
51974
52509
  const invitableRoles = useMemo(() => {
51975
52510
  const roles = [];
51976
52511
  if (canInviteOwner) roles.push("owner");
51977
52512
  if (canInviteIT) roles.push("it");
51978
52513
  if (canInvitePlantHead) roles.push("plant_head");
52514
+ if (canInviteIndustrialEngineer) roles.push("industrial_engineer");
51979
52515
  if (canInviteSupervisor) roles.push("supervisor");
51980
52516
  return roles;
51981
- }, [canInviteOwner, canInviteIT, canInvitePlantHead, canInviteSupervisor]);
52517
+ }, [canInviteOwner, canInviteIT, canInvitePlantHead, canInviteIndustrialEngineer, canInviteSupervisor]);
51982
52518
  const filteredLines = useMemo(() => {
51983
52519
  const search = lineSearch.trim().toLowerCase();
51984
52520
  if (!search) return availableLines;
@@ -52055,6 +52591,10 @@ var InviteUserDialog = ({
52055
52591
  setError("Only super-admin Optifye users can create owner users.");
52056
52592
  return;
52057
52593
  }
52594
+ if (selectedRole === "industrial_engineer" && selectedFactories.length === 0) {
52595
+ setError("Select at least one factory for an industrial engineer.");
52596
+ return;
52597
+ }
52058
52598
  const companyId = entityConfig?.companyId || user?.properties?.company_id;
52059
52599
  if (!companyId) {
52060
52600
  setError("Company ID not found. Please refresh and try again.");
@@ -52078,7 +52618,7 @@ var InviteUserDialog = ({
52078
52618
  role_level: selectedRole,
52079
52619
  company_id: companyId,
52080
52620
  line_ids: selectedRole === "supervisor" ? selectedLines : void 0,
52081
- factory_ids: selectedRole === "plant_head" ? selectedFactories : void 0,
52621
+ factory_ids: isFactoryScopedRole(selectedRole) ? selectedFactories : void 0,
52082
52622
  created_by: user?.id
52083
52623
  }
52084
52624
  });
@@ -52316,6 +52856,33 @@ var InviteUserDialog = ({
52316
52856
  ]
52317
52857
  }
52318
52858
  ),
52859
+ canInviteIndustrialEngineer && /* @__PURE__ */ jsxs(
52860
+ "label",
52861
+ {
52862
+ className: cn(
52863
+ "flex items-start gap-3 p-4 border-2 rounded-lg cursor-pointer transition-all duration-200",
52864
+ selectedRole === "industrial_engineer" ? "border-amber-500 bg-amber-50" : "border-gray-200 hover:border-gray-300 hover:bg-gray-50"
52865
+ ),
52866
+ children: [
52867
+ /* @__PURE__ */ jsx(
52868
+ "input",
52869
+ {
52870
+ type: "radio",
52871
+ name: "role",
52872
+ value: "industrial_engineer",
52873
+ checked: selectedRole === "industrial_engineer",
52874
+ onChange: (e) => setSelectedRole(e.target.value),
52875
+ className: "mt-1",
52876
+ disabled: isSubmitting
52877
+ }
52878
+ ),
52879
+ /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
52880
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 mb-1", children: /* @__PURE__ */ jsx(RoleBadge_default, { role: "industrial_engineer", size: "sm" }) }),
52881
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600", children: "Factory-level access. Can manage supervisors and factory performance scope." })
52882
+ ] })
52883
+ ]
52884
+ }
52885
+ ),
52319
52886
  canInviteSupervisor && /* @__PURE__ */ jsxs(
52320
52887
  "label",
52321
52888
  {
@@ -52345,14 +52912,18 @@ var InviteUserDialog = ({
52345
52912
  )
52346
52913
  ] })
52347
52914
  ] }),
52348
- selectedRole === "plant_head" && /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-slate-200 bg-slate-50 p-4 space-y-3", children: [
52915
+ isFactoryScopedRole(selectedRole) && /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-slate-200 bg-slate-50 p-4 space-y-3", children: [
52349
52916
  /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
52350
52917
  /* @__PURE__ */ jsxs("div", { children: [
52351
52918
  /* @__PURE__ */ jsxs("p", { className: "text-sm font-medium text-gray-800 flex items-center gap-1.5", children: [
52352
52919
  /* @__PURE__ */ jsx(Building2, { className: "w-4 h-4 text-blue-600" }),
52353
52920
  "Factory Access"
52354
52921
  ] }),
52355
- /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 mt-1", children: "Choose the factories this plant head will manage." })
52922
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 mt-1", children: [
52923
+ "Choose the factories this ",
52924
+ selectedRole === "industrial_engineer" ? "industrial engineer" : "plant head",
52925
+ " will manage."
52926
+ ] })
52356
52927
  ] }),
52357
52928
  /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium bg-white border border-gray-200 text-gray-600 rounded-full px-2 py-1", children: [
52358
52929
  selectedFactories.length,
@@ -52577,16 +53148,6 @@ var InviteUserDialog = ({
52577
53148
  }
52578
53149
  );
52579
53150
  };
52580
- var getRoleLabel = (role) => {
52581
- const labels = {
52582
- "supervisor": "Supervisor",
52583
- "plant_head": "Plant Head",
52584
- "it": "IT",
52585
- "owner": "Owner",
52586
- "optifye": "Optifye Admin"
52587
- };
52588
- return labels[role] || role;
52589
- };
52590
53151
  var ChangeRoleDialog = ({
52591
53152
  user,
52592
53153
  availableRoles,
@@ -53538,7 +54099,7 @@ var FactoryAssignmentDropdown = ({
53538
54099
  )
53539
54100
  ] });
53540
54101
  };
53541
- function formatDuration(ms) {
54102
+ function formatDuration2(ms) {
53542
54103
  if (ms === void 0 || ms === null) return "No data";
53543
54104
  if (ms === 0) return "0m";
53544
54105
  const hours = Math.floor(ms / (1e3 * 60 * 60));
@@ -53582,7 +54143,7 @@ var UserUsageStats = ({
53582
54143
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
53583
54144
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-sm", children: [
53584
54145
  /* @__PURE__ */ jsx(Clock, { className: "w-3.5 h-3.5 text-gray-400" }),
53585
- /* @__PURE__ */ jsx("span", { className: hasUsage ? getUsageColorClass(todayUsage.total_ms) : "text-gray-400", children: formatDuration(todayUsage?.total_ms) })
54146
+ /* @__PURE__ */ jsx("span", { className: hasUsage ? getUsageColorClass(todayUsage.total_ms) : "text-gray-400", children: formatDuration2(todayUsage?.total_ms) })
53586
54147
  ] }),
53587
54148
  showViewButton && onViewDetails && /* @__PURE__ */ jsx(
53588
54149
  "button",
@@ -53598,14 +54159,14 @@ var UserUsageStats = ({
53598
54159
  /* @__PURE__ */ jsx(Activity, { className: "w-3 h-3 text-green-500" }),
53599
54160
  /* @__PURE__ */ jsxs("span", { children: [
53600
54161
  "Active: ",
53601
- formatDuration(todayUsage?.active_ms)
54162
+ formatDuration2(todayUsage?.active_ms)
53602
54163
  ] })
53603
54164
  ] }),
53604
54165
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
53605
54166
  /* @__PURE__ */ jsx(Eye, { className: "w-3 h-3 text-amber-500" }),
53606
54167
  /* @__PURE__ */ jsxs("span", { children: [
53607
54168
  "Passive: ",
53608
- formatDuration(todayUsage?.passive_ms)
54169
+ formatDuration2(todayUsage?.passive_ms)
53609
54170
  ] })
53610
54171
  ] })
53611
54172
  ] })
@@ -53800,7 +54361,7 @@ function DailyBarChart({
53800
54361
  /* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full bg-gray-300" }),
53801
54362
  /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
53802
54363
  "Average Daily usage: ",
53803
- /* @__PURE__ */ jsx("span", { className: "text-gray-900 font-semibold", children: avgDailyMs > 0 ? formatDuration(avgDailyMs) : "0m" })
54364
+ /* @__PURE__ */ jsx("span", { className: "text-gray-900 font-semibold", children: avgDailyMs > 0 ? formatDuration2(avgDailyMs) : "0m" })
53804
54365
  ] })
53805
54366
  ] }),
53806
54367
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-6 text-xs font-medium text-gray-500", children: [
@@ -53893,7 +54454,7 @@ function DailyBarChart({
53893
54454
  hasData ? /* @__PURE__ */ jsxs(Fragment, { children: [
53894
54455
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-2", children: [
53895
54456
  /* @__PURE__ */ jsx("span", { className: "text-gray-500 text-xs", children: "Total" }),
53896
- /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-900 text-sm", children: formatDuration(data.total_duration_ms) })
54457
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-900 text-sm", children: formatDuration2(data.total_duration_ms) })
53897
54458
  ] }),
53898
54459
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
53899
54460
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center text-xs", children: [
@@ -53901,14 +54462,14 @@ function DailyBarChart({
53901
54462
  /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 bg-green-500 rounded-full" }),
53902
54463
  "Active"
53903
54464
  ] }),
53904
- /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700", children: formatDuration(data.active_duration_ms) })
54465
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700", children: formatDuration2(data.active_duration_ms) })
53905
54466
  ] }),
53906
54467
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center text-xs", children: [
53907
54468
  /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-gray-500", children: [
53908
54469
  /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 bg-amber-400 rounded-full" }),
53909
54470
  "Passive"
53910
54471
  ] }),
53911
- /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700", children: formatDuration(data.passive_duration_ms) })
54472
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700", children: formatDuration2(data.passive_duration_ms) })
53912
54473
  ] })
53913
54474
  ] })
53914
54475
  ] }) : /* @__PURE__ */ jsx("div", { className: "text-gray-400 text-xs italic", children: "No data recorded" })
@@ -54039,15 +54600,7 @@ var UserManagementTable = ({
54039
54600
  const permissions = useTeamManagementPermissions();
54040
54601
  const { user: currentUser } = useAuth();
54041
54602
  const availableRoles = useMemo(() => {
54042
- const currentRole = currentUser?.role_level;
54043
- const roleHierarchy = {
54044
- "optifye": ["optifye", "owner", "it", "plant_head", "supervisor"],
54045
- "owner": ["owner", "it", "plant_head", "supervisor"],
54046
- "it": ["it", "plant_head", "supervisor"],
54047
- "plant_head": ["plant_head", "supervisor"],
54048
- "supervisor": ["supervisor"]
54049
- };
54050
- return roleHierarchy[currentRole] || ["supervisor"];
54603
+ return getVisibleRolesForCurrentUser(currentUser?.role_level);
54051
54604
  }, [currentUser]);
54052
54605
  const [searchTerm, setSearchTerm] = useState("");
54053
54606
  const [roleFilter, setRoleFilter] = useState("all");
@@ -54144,10 +54697,48 @@ var UserManagementTable = ({
54144
54697
  }
54145
54698
  return [];
54146
54699
  };
54700
+ const getLineIdsFromUser = (user) => {
54701
+ const properties = user.properties || {};
54702
+ const rawLineIds = properties.line_ids ?? properties.line_id;
54703
+ if (Array.isArray(rawLineIds)) {
54704
+ return rawLineIds.filter((lineId) => typeof lineId === "string" && lineId.length > 0);
54705
+ }
54706
+ if (typeof rawLineIds === "string" && rawLineIds.length > 0) {
54707
+ return [rawLineIds];
54708
+ }
54709
+ return [];
54710
+ };
54711
+ const canOfferIndustrialEngineerRole = (user) => {
54712
+ if (getFactoryIdsFromUser(user).length > 0) {
54713
+ return true;
54714
+ }
54715
+ const lineIds = getLineIdsFromUser(user);
54716
+ if (lineIds.length === 0) {
54717
+ return false;
54718
+ }
54719
+ const lineFactoryById = new Map(
54720
+ availableLines.map((line) => [line.id, line.factory_id])
54721
+ );
54722
+ return lineIds.some((lineId) => {
54723
+ const factoryId = lineFactoryById.get(lineId);
54724
+ return typeof factoryId === "string" && factoryId.length > 0;
54725
+ });
54726
+ };
54727
+ const getAvailableRolesForUser = (user) => {
54728
+ const baseRoles = permissions.availableRolesToAssign();
54729
+ let filteredRoles = baseRoles;
54730
+ if (baseRoles.includes("industrial_engineer") && !canOfferIndustrialEngineerRole(user)) {
54731
+ filteredRoles = baseRoles.filter((role) => role !== "industrial_engineer");
54732
+ }
54733
+ if (!filteredRoles.includes(user.role_level)) {
54734
+ return [user.role_level, ...filteredRoles];
54735
+ }
54736
+ return filteredRoles;
54737
+ };
54147
54738
  const formatAssignments = (user) => {
54148
54739
  if (user.role_level === "owner" || user.role_level === "it") return "Company-wide";
54149
54740
  if (user.role_level === "optifye") return "All companies";
54150
- if (user.role_level === "plant_head") {
54741
+ if (isFactoryScopedRole(user.role_level)) {
54151
54742
  if (user.assigned_factories && user.assigned_factories.length > 0) {
54152
54743
  return user.assigned_factories.join(", ");
54153
54744
  }
@@ -54228,11 +54819,12 @@ var UserManagementTable = ({
54228
54819
  className: "px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white",
54229
54820
  children: [
54230
54821
  /* @__PURE__ */ jsx("option", { value: "all", children: "All Roles" }),
54231
- availableRoles.includes("optifye") && /* @__PURE__ */ jsx("option", { value: "optifye", children: "Optifye" }),
54232
- availableRoles.includes("owner") && /* @__PURE__ */ jsx("option", { value: "owner", children: "Owner" }),
54233
- availableRoles.includes("it") && /* @__PURE__ */ jsx("option", { value: "it", children: "IT" }),
54234
- availableRoles.includes("plant_head") && /* @__PURE__ */ jsx("option", { value: "plant_head", children: "Plant Head" }),
54235
- availableRoles.includes("supervisor") && /* @__PURE__ */ jsx("option", { value: "supervisor", children: "Supervisor" })
54822
+ availableRoles.includes("optifye") && /* @__PURE__ */ jsx("option", { value: "optifye", children: getRoleLabel("optifye") }),
54823
+ availableRoles.includes("owner") && /* @__PURE__ */ jsx("option", { value: "owner", children: getRoleLabel("owner") }),
54824
+ availableRoles.includes("it") && /* @__PURE__ */ jsx("option", { value: "it", children: getRoleLabel("it") }),
54825
+ availableRoles.includes("plant_head") && /* @__PURE__ */ jsx("option", { value: "plant_head", children: getRoleLabel("plant_head") }),
54826
+ availableRoles.includes("industrial_engineer") && /* @__PURE__ */ jsx("option", { value: "industrial_engineer", children: getRoleLabel("industrial_engineer") }),
54827
+ availableRoles.includes("supervisor") && /* @__PURE__ */ jsx("option", { value: "supervisor", children: getRoleLabel("supervisor") })
54236
54828
  ]
54237
54829
  }
54238
54830
  )
@@ -54350,7 +54942,7 @@ var UserManagementTable = ({
54350
54942
  onUpdate: onLineAssignmentUpdate || (async () => {
54351
54943
  })
54352
54944
  }
54353
- ) : user.role_level === "plant_head" ? (() => {
54945
+ ) : isFactoryScopedRole(user.role_level) ? (() => {
54354
54946
  const canEditFactoryAssignments = permissions.canAssignFactories(user) && !!onFactoryAssignmentUpdate;
54355
54947
  if (!canEditFactoryAssignments) {
54356
54948
  return /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-900", children: formatAssignments(user) });
@@ -54380,7 +54972,7 @@ var UserManagementTable = ({
54380
54972
  setShowUsageDetailModal(true);
54381
54973
  },
54382
54974
  className: "group flex items-center gap-3 hover:bg-gray-50 -mx-2 px-2 py-1.5 rounded-lg transition-all duration-200",
54383
- children: isUsageLoading ? /* @__PURE__ */ jsx("div", { className: "animate-pulse bg-gray-200 h-5 w-20 rounded" }) : /* @__PURE__ */ jsx("span", { className: `text-base font-semibold ${avgDailyUsage?.[user.user_id] && avgDailyUsage[user.user_id] > 0 ? "text-gray-900 group-hover:text-blue-600" : "text-gray-400"} transition-colors`, children: formatDuration(avgDailyUsage?.[user.user_id] || 0) })
54975
+ children: isUsageLoading ? /* @__PURE__ */ jsx("div", { className: "animate-pulse bg-gray-200 h-5 w-20 rounded" }) : /* @__PURE__ */ jsx("span", { className: `text-base font-semibold ${avgDailyUsage?.[user.user_id] && avgDailyUsage[user.user_id] > 0 ? "text-gray-900 group-hover:text-blue-600" : "text-gray-400"} transition-colors`, children: formatDuration2(avgDailyUsage?.[user.user_id] || 0) })
54384
54976
  }
54385
54977
  ) : /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-400", children: "-" }) }),
54386
54978
  /* @__PURE__ */ jsx("td", { className: "px-6 py-4 whitespace-nowrap text-right", children: hasActions && /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
@@ -54530,7 +55122,7 @@ var UserManagementTable = ({
54530
55122
  ChangeRoleDialog,
54531
55123
  {
54532
55124
  user: selectedUser,
54533
- availableRoles: permissions.availableRolesToAssign(),
55125
+ availableRoles: getAvailableRolesForUser(selectedUser),
54534
55126
  onConfirm: handleRoleChangeConfirm,
54535
55127
  onClose: () => {
54536
55128
  setShowChangeRoleDialog(false);
@@ -56269,7 +56861,7 @@ function HomeView({
56269
56861
  animate: { opacity: 1, scale: 1 },
56270
56862
  transition: { duration: 0.3 },
56271
56863
  className: "h-full",
56272
- children: React26__default.createElement(WorkspaceGrid, {
56864
+ children: React141__default.createElement(WorkspaceGrid, {
56273
56865
  workspaces: workspaceMetrics,
56274
56866
  lineNames,
56275
56867
  factoryView: factoryViewId,
@@ -56300,7 +56892,7 @@ function HomeView({
56300
56892
  animate: { opacity: 1, scale: 1 },
56301
56893
  transition: { duration: 0.3 },
56302
56894
  className: "h-full",
56303
- children: React26__default.createElement(WorkspaceGrid, {
56895
+ children: React141__default.createElement(WorkspaceGrid, {
56304
56896
  workspaces: [],
56305
56897
  // Show empty grid while loading
56306
56898
  lineNames,
@@ -56367,7 +56959,7 @@ function HomeView({
56367
56959
  }
56368
56960
  );
56369
56961
  }
56370
- var AuthenticatedHomeView = withAuth(React26__default.memo(HomeView));
56962
+ var AuthenticatedHomeView = withAuth(React141__default.memo(HomeView));
56371
56963
  var HomeView_default = HomeView;
56372
56964
  function withWorkspaceDisplayNames(Component3, options = {}) {
56373
56965
  const {
@@ -56777,7 +57369,7 @@ var MonthlyRangeFilter = ({
56777
57369
  label: "This Month",
56778
57370
  getValue: () => ({
56779
57371
  start: startOfMonth(/* @__PURE__ */ new Date()),
56780
- end: endOfMonth(/* @__PURE__ */ new Date())
57372
+ end: endOfDay(/* @__PURE__ */ new Date())
56781
57373
  })
56782
57374
  }
56783
57375
  ];
@@ -56801,6 +57393,7 @@ var MonthlyRangeFilter = ({
56801
57393
  const [rangeEnd, setRangeEnd] = useState(parseDateKeyToDate(normalizedRange.endKey));
56802
57394
  const [selecting, setSelecting] = useState(false);
56803
57395
  const [activePreset, setActivePreset] = useState(null);
57396
+ const today = useMemo(() => endOfDay(/* @__PURE__ */ new Date()), []);
56804
57397
  useEffect(() => {
56805
57398
  setCalendarMonth(month);
56806
57399
  setCalendarYear(year);
@@ -56831,6 +57424,9 @@ var MonthlyRangeFilter = ({
56831
57424
  return () => document.removeEventListener("mousedown", handleClickOutside);
56832
57425
  }, []);
56833
57426
  const handleDayClick = (day) => {
57427
+ if (startOfDay(day) > startOfDay(today)) {
57428
+ return;
57429
+ }
56834
57430
  setActivePreset("Custom");
56835
57431
  if (!selecting || !rangeStart) {
56836
57432
  setRangeStart(day);
@@ -56863,9 +57459,13 @@ var MonthlyRangeFilter = ({
56863
57459
  };
56864
57460
  const handleApply = () => {
56865
57461
  if (rangeStart) {
56866
- const endDate = rangeEnd || rangeStart;
56867
- const startKey = format(rangeStart, "yyyy-MM-dd");
56868
- const endKey = format(endDate, "yyyy-MM-dd");
57462
+ const boundedStart = startOfDay(rangeStart) > startOfDay(today) ? startOfDay(today) : startOfDay(rangeStart);
57463
+ const candidateEnd = rangeEnd || rangeStart;
57464
+ const boundedEnd = startOfDay(candidateEnd) > startOfDay(today) ? startOfDay(today) : startOfDay(candidateEnd);
57465
+ const start = boundedStart <= boundedEnd ? boundedStart : boundedEnd;
57466
+ const end = boundedStart <= boundedEnd ? boundedEnd : boundedStart;
57467
+ const startKey = format(start, "yyyy-MM-dd");
57468
+ const endKey = format(end, "yyyy-MM-dd");
56869
57469
  onChange({ startKey, endKey });
56870
57470
  setIsOpen(false);
56871
57471
  }
@@ -57046,6 +57646,7 @@ var MonthlyRangeFilter = ({
57046
57646
  const isEnd = isRangeEnd(day);
57047
57647
  const isSingleDaySelection = isStart && (!rangeEnd || rangeEnd && isSameDay(rangeStart, rangeEnd));
57048
57648
  const dayNum = day.getDate();
57649
+ const isFutureDay = startOfDay(day) > startOfDay(today);
57049
57650
  return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
57050
57651
  inRange && !isStart && !isEnd && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 -inset-x-0.5 bg-[#EEF2FF] z-0" }),
57051
57652
  inRange && isStart && !isSingleDaySelection && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 left-1/2 bg-[#EEF2FF] z-0" }),
@@ -57055,10 +57656,12 @@ var MonthlyRangeFilter = ({
57055
57656
  {
57056
57657
  type: "button",
57057
57658
  onClick: () => handleDayClick(day),
57659
+ disabled: isFutureDay,
57058
57660
  className: clsx(
57059
57661
  "h-10 w-full flex items-center justify-center text-sm font-semibold transition-all duration-150 relative z-10",
57662
+ isFutureDay && "text-gray-200 cursor-not-allowed",
57060
57663
  // Not in range
57061
- !inRange && "text-gray-700 hover:bg-gray-50 rounded-lg",
57664
+ !isFutureDay && !inRange && "text-gray-700 hover:bg-gray-50 rounded-lg",
57062
57665
  // Middle of range
57063
57666
  inRange && !isStart && !isEnd && "text-[#4F46E5]",
57064
57667
  // Start/End of range or Single selection
@@ -57096,7 +57699,7 @@ var MetricCards = memo$1(({
57096
57699
  variants: containerVariants,
57097
57700
  initial: "initial",
57098
57701
  animate: "animate",
57099
- className: `grid grid-cols-1 sm:grid-cols-2 ${showIdleTime ? "lg:grid-cols-4" : "lg:grid-cols-3"} gap-3 sm:gap-4 mb-2 md:h-[35vh] h-auto`,
57702
+ className: `grid grid-cols-1 sm:grid-cols-2 ${showIdleTime ? "lg:grid-cols-4" : "lg:grid-cols-3"} gap-3 sm:gap-4 mb-2 h-auto lg:flex-[2] lg:min-h-[250px]`,
57100
57703
  children: [
57101
57704
  /* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[240px] sm:h-[260px] md:h-auto", children: [
57102
57705
  /* @__PURE__ */ jsx("h2", { className: "text-sm sm:text-base font-bold text-gray-700 mb-2 text-center", children: "Line Output" }),
@@ -57145,7 +57748,23 @@ var MetricCards = memo$1(({
57145
57748
  if (prevProps.efficiencyLegend !== nextProps.efficiencyLegend) return false;
57146
57749
  const prevMetrics = prevProps.lineInfo.metrics;
57147
57750
  const nextMetrics = nextProps.lineInfo.metrics;
57148
- const idleTimeChanged = prevProps.idleTimeData?.isLoading !== nextProps.idleTimeData?.isLoading || prevProps.idleTimeData?.error !== nextProps.idleTimeData?.error || prevProps.idleTimeData?.chartData?.length !== nextProps.idleTimeData?.chartData?.length || prevProps.idleTimeData?.data?.total_idle_time_seconds !== nextProps.idleTimeData?.data?.total_idle_time_seconds;
57751
+ const prevIdleChartSignature = JSON.stringify(
57752
+ (prevProps.idleTimeData?.chartData || []).map((entry) => ({
57753
+ name: entry.name,
57754
+ value: entry.value,
57755
+ totalDurationSeconds: entry.totalDurationSeconds ?? null,
57756
+ efficiencyLossPercentage: entry.efficiencyLossPercentage ?? null
57757
+ }))
57758
+ );
57759
+ const nextIdleChartSignature = JSON.stringify(
57760
+ (nextProps.idleTimeData?.chartData || []).map((entry) => ({
57761
+ name: entry.name,
57762
+ value: entry.value,
57763
+ totalDurationSeconds: entry.totalDurationSeconds ?? null,
57764
+ efficiencyLossPercentage: entry.efficiencyLossPercentage ?? null
57765
+ }))
57766
+ );
57767
+ const idleTimeChanged = prevProps.idleTimeData?.isLoading !== nextProps.idleTimeData?.isLoading || prevProps.idleTimeData?.error !== nextProps.idleTimeData?.error || prevIdleChartSignature !== nextIdleChartSignature || prevProps.idleTimeData?.data?.total_idle_time_seconds !== nextProps.idleTimeData?.data?.total_idle_time_seconds || prevProps.idleTimeData?.data?.scope_work_seconds !== nextProps.idleTimeData?.data?.scope_work_seconds;
57149
57768
  if (idleTimeChanged) return false;
57150
57769
  return prevMetrics.current_output === nextMetrics.current_output && prevMetrics.line_threshold === nextMetrics.line_threshold && prevMetrics.underperforming_workspaces === nextMetrics.underperforming_workspaces && prevMetrics.total_workspaces === nextMetrics.total_workspaces && prevMetrics.avg_efficiency === nextMetrics.avg_efficiency;
57151
57770
  });
@@ -57164,7 +57783,7 @@ var LineUptimeMetricCards = memo$1(({
57164
57783
  variants: containerVariants,
57165
57784
  initial: "initial",
57166
57785
  animate: "animate",
57167
- className: `grid grid-cols-1 sm:grid-cols-2 ${showIdleTime ? "lg:grid-cols-4" : "lg:grid-cols-3"} gap-3 sm:gap-4 mb-2 md:h-[35vh] h-auto`,
57786
+ className: `grid grid-cols-1 sm:grid-cols-2 ${showIdleTime ? "lg:grid-cols-4" : "lg:grid-cols-3"} gap-3 sm:gap-4 mb-2 h-auto lg:flex-[2] lg:min-h-[250px]`,
57168
57787
  children: [
57169
57788
  /* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[240px] sm:h-[260px] md:h-auto", children: [
57170
57789
  /* @__PURE__ */ jsx("h2", { className: "text-sm sm:text-base font-bold text-gray-700 mb-2 text-center", children: "Utilization" }),
@@ -57232,7 +57851,7 @@ var BottomSection = memo$1(({
57232
57851
  variants: containerVariants,
57233
57852
  initial: "initial",
57234
57853
  animate: "animate",
57235
- className: "grid grid-cols-1 lg:grid-cols-5 gap-3 sm:gap-4 md:h-[calc(57vh-4rem)] h-auto md:mt-0 mt-4",
57854
+ className: "grid grid-cols-1 lg:grid-cols-5 gap-3 sm:gap-4 h-auto mt-4 lg:mt-0 lg:flex-[3] lg:min-h-[300px]",
57236
57855
  children: [
57237
57856
  /* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "lg:col-span-2 bg-white rounded-xl shadow-sm p-3 sm:p-4 flex flex-col overflow-hidden h-[350px] sm:h-[400px] md:h-auto", children: [
57238
57857
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-2", children: [
@@ -57399,7 +58018,7 @@ var UptimeBottomSection = memo$1(({
57399
58018
  variants: containerVariants,
57400
58019
  initial: "initial",
57401
58020
  animate: "animate",
57402
- className: "grid grid-cols-1 lg:grid-cols-5 gap-3 sm:gap-4 md:h-[calc(57vh-4rem)] h-auto md:mt-0 mt-4",
58021
+ className: "grid grid-cols-1 lg:grid-cols-5 gap-3 sm:gap-4 h-auto mt-4 lg:mt-0 lg:flex-[3] lg:min-h-[300px]",
57403
58022
  children: [
57404
58023
  /* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "lg:col-span-2 bg-white rounded-xl shadow-sm p-3 sm:p-4 flex flex-col overflow-hidden h-[350px] sm:h-[400px] md:h-auto", children: [
57405
58024
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-2", children: [
@@ -58637,7 +59256,7 @@ var KPIDetailView = ({
58637
59256
  initial: "initial",
58638
59257
  animate: "animate",
58639
59258
  exit: "exit",
58640
- className: "space-y-6 md:space-y-0",
59259
+ className: "space-y-6 md:space-y-0 lg:h-[calc(100vh-12rem)] lg:min-h-0 lg:flex lg:flex-col lg:gap-3",
58641
59260
  children: resolvedLineInfo && /* @__PURE__ */ jsxs(Fragment, { children: [
58642
59261
  isUptimeMode ? /* @__PURE__ */ jsx(
58643
59262
  LineUptimeMetricCards,
@@ -58734,7 +59353,7 @@ var KPIDetailView = ({
58734
59353
  initial: "initial",
58735
59354
  animate: "animate",
58736
59355
  exit: "exit",
58737
- className: "space-y-6 md:space-y-0",
59356
+ className: "space-y-6 md:space-y-0 lg:h-[calc(100vh-12rem)] lg:min-h-0 lg:flex lg:flex-col lg:gap-3",
58738
59357
  children: resolvedLineInfo && /* @__PURE__ */ jsxs(Fragment, { children: [
58739
59358
  isUptimeMode ? /* @__PURE__ */ jsx(
58740
59359
  LineUptimeMetricCards,
@@ -58829,7 +59448,7 @@ var getMonthDateInfo = (timezone) => {
58829
59448
  const monthEndDate = fromZonedTime(`${monthEndKey}T23:59:59`, timezone);
58830
59449
  return { startDate, endDate, monthEndDate };
58831
59450
  };
58832
- var LeaderboardCountdown = ({ targetDate, format: format7, finishedLabel = "Finished", placeholder = "--", onFinished }) => {
59451
+ var LeaderboardCountdown = ({ targetDate, format: format8, finishedLabel = "Finished", placeholder = "--", onFinished }) => {
58833
59452
  const [time2, setTime] = useState("");
58834
59453
  const hasFinishedRef = useRef(false);
58835
59454
  useEffect(() => {
@@ -58851,7 +59470,7 @@ var LeaderboardCountdown = ({ targetDate, format: format7, finishedLabel = "Fini
58851
59470
  }
58852
59471
  return;
58853
59472
  }
58854
- if (format7 === "days") {
59473
+ if (format8 === "days") {
58855
59474
  const days = Math.floor(diff / (1e3 * 60 * 60 * 24));
58856
59475
  const hours = Math.floor(diff % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60));
58857
59476
  setTime(`${days} days ${hours} hours`);
@@ -58866,7 +59485,7 @@ var LeaderboardCountdown = ({ targetDate, format: format7, finishedLabel = "Fini
58866
59485
  tick();
58867
59486
  const interval = setInterval(tick, 1e3);
58868
59487
  return () => clearInterval(interval);
58869
- }, [targetDate, format7, finishedLabel, placeholder, onFinished]);
59488
+ }, [targetDate, format8, finishedLabel, placeholder, onFinished]);
58870
59489
  return /* @__PURE__ */ jsx(Fragment, { children: time2 });
58871
59490
  };
58872
59491
  var LinesLeaderboard = ({
@@ -58887,18 +59506,18 @@ var LinesLeaderboard = ({
58887
59506
  setViewType
58888
59507
  }) => {
58889
59508
  const formatEfficiency = (value) => typeof value === "number" && Number.isFinite(value) ? `${value.toFixed(1)}%` : "--";
58890
- const assignedLineIdSet = React26__default.useMemo(
59509
+ const assignedLineIdSet = React141__default.useMemo(
58891
59510
  () => new Set(assignedLineIds || []),
58892
59511
  [assignedLineIds]
58893
59512
  );
58894
- const canClickLine = React26__default.useCallback(
59513
+ const canClickLine = React141__default.useCallback(
58895
59514
  (lineId) => {
58896
59515
  if (!assignedLineIds) return true;
58897
59516
  return assignedLineIdSet.has(lineId);
58898
59517
  },
58899
59518
  [assignedLineIds, assignedLineIdSet]
58900
59519
  );
58901
- const handleTimeRangeChange = React26__default.useCallback((newRange) => {
59520
+ const handleTimeRangeChange = React141__default.useCallback((newRange) => {
58902
59521
  if (newRange === timeRange) return;
58903
59522
  trackCoreEvent("Leaderboard Time Range Changed", {
58904
59523
  from_range: timeRange,
@@ -58909,7 +59528,7 @@ var LinesLeaderboard = ({
58909
59528
  });
58910
59529
  setTimeRange(newRange);
58911
59530
  }, [timeRange, lines.length, monthlyEfficiencyByLineId, setTimeRange]);
58912
- const handleLeaderboardLineClick = React26__default.useCallback((item, clickSource) => {
59531
+ const handleLeaderboardLineClick = React141__default.useCallback((item, clickSource) => {
58913
59532
  if (!canClickLine(item.line.id)) return;
58914
59533
  trackCoreEvent("Leaderboard Line Clicked", {
58915
59534
  line_id: item.line.id,
@@ -58923,8 +59542,8 @@ var LinesLeaderboard = ({
58923
59542
  });
58924
59543
  onLineClick(item.line);
58925
59544
  }, [canClickLine, onLineClick, timeRange]);
58926
- const viewLoadedTrackedRef = React26__default.useRef(null);
58927
- const leaderboardData = React26__default.useMemo(() => {
59545
+ const viewLoadedTrackedRef = React141__default.useRef(null);
59546
+ const leaderboardData = React141__default.useMemo(() => {
58928
59547
  const loading = timeRange === "today" ? isLoadingToday : isLoadingMonthly;
58929
59548
  const efficiencyMap = timeRange === "today" ? todayEfficiencyByLineId : monthlyEfficiencyByLineId;
58930
59549
  return lines.map((line) => {
@@ -58955,7 +59574,7 @@ var LinesLeaderboard = ({
58955
59574
  isLoadingToday,
58956
59575
  isLoadingMonthly
58957
59576
  ]);
58958
- React26__default.useEffect(() => {
59577
+ React141__default.useEffect(() => {
58959
59578
  const isLoading = timeRange === "today" ? isLoadingToday : isLoadingMonthly;
58960
59579
  const trackingKey = `${timeRange}-${leaderboardData.length}`;
58961
59580
  if (leaderboardData.length > 0 && !isLoading && viewLoadedTrackedRef.current !== trackingKey) {
@@ -58981,7 +59600,7 @@ var LinesLeaderboard = ({
58981
59600
  const countdownTarget = timeRange === "monthly" ? monthEndDate : shiftEndDate;
58982
59601
  const countdownFormat = timeRange === "monthly" ? "days" : "clock";
58983
59602
  const countdownFinishedLabel = timeRange === "monthly" ? "Finished" : "Shift Ended";
58984
- const handleCountdownFinished = React26__default.useCallback(() => {
59603
+ const handleCountdownFinished = React141__default.useCallback(() => {
58985
59604
  trackCoreEvent("Leaderboard Countdown Finished", {
58986
59605
  countdown_type: timeRange === "monthly" ? "month_end" : "shift_end",
58987
59606
  time_range: timeRange,
@@ -59008,7 +59627,7 @@ var LinesLeaderboard = ({
59008
59627
  return "bg-white border-gray-100";
59009
59628
  }
59010
59629
  };
59011
- React26__default.useEffect(() => {
59630
+ React141__default.useEffect(() => {
59012
59631
  const style = document.createElement("style");
59013
59632
  style.innerHTML = `
59014
59633
  @keyframes float {
@@ -59195,7 +59814,7 @@ var LineCard = ({
59195
59814
  supervisors
59196
59815
  }) => {
59197
59816
  const isUptimeLine = (line.monitoring_mode ?? "output") === "uptime";
59198
- const isOnTrack = React26__default.useMemo(() => {
59817
+ const isOnTrack = React141__default.useMemo(() => {
59199
59818
  if (!kpis) return null;
59200
59819
  return isEfficiencyOnTrack(kpis.efficiency.value);
59201
59820
  }, [kpis]);
@@ -59386,46 +60005,46 @@ var KPIsOverviewView = ({
59386
60005
  const configuredTimezone = dbTimezone || dateTimeConfig.defaultTimezone || "UTC";
59387
60006
  const { startDate: monthStartDate, endDate: monthEndDateKey, monthEndDate } = getMonthDateInfo(configuredTimezone);
59388
60007
  const isSuperAdmin = user?.scope_mode === "SUPER_ADMIN" || !!user?.access_scope?.is_super_admin;
59389
- const scopedLineIds = React26__default.useMemo(
60008
+ const scopedLineIds = React141__default.useMemo(
59390
60009
  () => Array.isArray(user?.access_scope?.line_ids) ? user.access_scope.line_ids.filter((lineId) => typeof lineId === "string" && lineId.length > 0) : [],
59391
60010
  [user?.access_scope?.line_ids]
59392
60011
  );
59393
60012
  const hasCanonicalScope = !!user?.scope_mode || !!user?.access_scope;
59394
60013
  const scopeRole = (user?.role_level || user?.role || "").toLowerCase();
59395
- const isStrictLineScopedRole = scopeRole === "supervisor" || scopeRole === "plant_head";
59396
- const resolvedAssignedLineIds = React26__default.useMemo(() => {
60014
+ const isStrictLineScopedRole = scopeRole === "supervisor" || isFactoryScopedRole(scopeRole);
60015
+ const resolvedAssignedLineIds = React141__default.useMemo(() => {
59397
60016
  if (isSuperAdmin) return [];
59398
60017
  if (scopedLineIds.length > 0) return scopedLineIds;
59399
60018
  if (lineIds && lineIds.length > 0) return lineIds;
59400
60019
  if (isStrictLineScopedRole && hasCanonicalScope) return [];
59401
60020
  return [];
59402
60021
  }, [isSuperAdmin, scopedLineIds, lineIds, isStrictLineScopedRole, hasCanonicalScope]);
59403
- const assignedLineIdSet = React26__default.useMemo(
60022
+ const assignedLineIdSet = React141__default.useMemo(
59404
60023
  () => new Set(resolvedAssignedLineIds),
59405
60024
  [resolvedAssignedLineIds]
59406
60025
  );
59407
- const metricsLineIds = React26__default.useMemo(() => {
60026
+ const metricsLineIds = React141__default.useMemo(() => {
59408
60027
  if (isSuperAdmin) {
59409
60028
  return lineIds ?? [];
59410
60029
  }
59411
60030
  return resolvedAssignedLineIds;
59412
60031
  }, [isSuperAdmin, lineIds, resolvedAssignedLineIds]);
59413
60032
  const assignedLineIdsForLeaderboard = isSuperAdmin ? void 0 : resolvedAssignedLineIds;
59414
- const leaderboardLinesForView = React26__default.useMemo(() => {
60033
+ const leaderboardLinesForView = React141__default.useMemo(() => {
59415
60034
  const targetMode = viewType === "machine" ? "uptime" : "output";
59416
60035
  return leaderboardLines.filter((line) => (line.monitoring_mode ?? "output") === targetMode);
59417
60036
  }, [leaderboardLines, viewType]);
59418
- const linesForView = React26__default.useMemo(() => {
60037
+ const linesForView = React141__default.useMemo(() => {
59419
60038
  const targetMode = viewType === "machine" ? "uptime" : "output";
59420
60039
  return lines.filter((line) => (line.monitoring_mode ?? "output") === targetMode);
59421
60040
  }, [lines, viewType]);
59422
- const relevantLinesForMode = React26__default.useMemo(() => {
60041
+ const relevantLinesForMode = React141__default.useMemo(() => {
59423
60042
  if (activeTab === "leaderboard") {
59424
60043
  return leaderboardLines.length > 0 ? leaderboardLines : lines;
59425
60044
  }
59426
60045
  return lines;
59427
60046
  }, [activeTab, leaderboardLines, lines]);
59428
- const { hasUptime, hasOutput } = React26__default.useMemo(() => {
60047
+ const { hasUptime, hasOutput } = React141__default.useMemo(() => {
59429
60048
  let uptime = false;
59430
60049
  let output = false;
59431
60050
  for (const line of relevantLinesForMode) {
@@ -59450,7 +60069,7 @@ var KPIsOverviewView = ({
59450
60069
  const currentShiftDetails = getCurrentShift(configuredTimezone, shiftConfig);
59451
60070
  const currentShiftDate = currentShiftDetails.date;
59452
60071
  const currentShiftId = currentShiftDetails.shiftId;
59453
- const shiftEndDate = React26__default.useMemo(
60072
+ const shiftEndDate = React141__default.useMemo(
59454
60073
  () => getShiftEndDate(currentShiftDetails, configuredTimezone),
59455
60074
  [currentShiftDetails, configuredTimezone]
59456
60075
  );
@@ -59464,15 +60083,15 @@ var KPIsOverviewView = ({
59464
60083
  lineId: factoryViewId,
59465
60084
  userAccessibleLineIds: metricsLineIds
59466
60085
  });
59467
- const defaultKPIs = React26__default.useMemo(() => createDefaultKPIs(), []);
59468
- const kpisByLineId = React26__default.useMemo(() => {
60086
+ const defaultKPIs = React141__default.useMemo(() => createDefaultKPIs(), []);
60087
+ const kpisByLineId = React141__default.useMemo(() => {
59469
60088
  const map = /* @__PURE__ */ new Map();
59470
60089
  lineMetrics.forEach((row) => {
59471
60090
  if (row?.line_id) map.set(row.line_id, buildKPIsFromLineMetricsRow(row));
59472
60091
  });
59473
60092
  return map;
59474
60093
  }, [lineMetrics]);
59475
- const supervisorLineIds = React26__default.useMemo(
60094
+ const supervisorLineIds = React141__default.useMemo(
59476
60095
  () => (leaderboardLines.length > 0 ? leaderboardLines : lines).map((l) => l.id),
59477
60096
  [leaderboardLines, lines]
59478
60097
  );
@@ -60434,7 +61053,7 @@ var LeaderboardDetailView = memo$1(({
60434
61053
  return () => document.removeEventListener("mousedown", handleClickOutside);
60435
61054
  }, []);
60436
61055
  const [isMobile, setIsMobile] = useState(false);
60437
- React26__default.useEffect(() => {
61056
+ React141__default.useEffect(() => {
60438
61057
  const checkMobile = () => setIsMobile(window.innerWidth < 640);
60439
61058
  checkMobile();
60440
61059
  window.addEventListener("resize", checkMobile);
@@ -62693,7 +63312,7 @@ var ShiftsView = ({
62693
63312
  ] })
62694
63313
  ] });
62695
63314
  };
62696
- var AuthenticatedShiftsView = withAuth(React26__default.memo(ShiftsView));
63315
+ var AuthenticatedShiftsView = withAuth(React141__default.memo(ShiftsView));
62697
63316
  var ShiftsView_default = ShiftsView;
62698
63317
 
62699
63318
  // src/views/TargetsView.utils.ts
@@ -64383,7 +65002,7 @@ var TargetsView = ({
64383
65002
  };
64384
65003
  var TargetsViewWithDisplayNames = withAllWorkspaceDisplayNames(TargetsView);
64385
65004
  var TargetsView_default = TargetsViewWithDisplayNames;
64386
- var AuthenticatedTargetsView = withAuth(React26__default.memo(TargetsViewWithDisplayNames));
65005
+ var AuthenticatedTargetsView = withAuth(React141__default.memo(TargetsViewWithDisplayNames));
64387
65006
 
64388
65007
  // src/views/workspace-detail-view.utils.ts
64389
65008
  var formatDateInTimezone = (date = /* @__PURE__ */ new Date(), timezone, options) => {
@@ -64437,25 +65056,6 @@ var getInitialTab = (sourceType, defaultTab, fromMonthly, urlDate) => {
64437
65056
  return "overview";
64438
65057
  };
64439
65058
  var DEBUG_DASHBOARD2 = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
64440
- var SHORT_DESKTOP_QUERY = "(min-width: 1024px) and (max-height: 850px)";
64441
- var useMediaQuery = (query) => {
64442
- const [matches, setMatches] = useState(false);
64443
- useEffect(() => {
64444
- if (typeof window === "undefined" || !window.matchMedia) {
64445
- return;
64446
- }
64447
- const mediaQueryList = window.matchMedia(query);
64448
- const onChange = () => setMatches(mediaQueryList.matches);
64449
- onChange();
64450
- if (typeof mediaQueryList.addEventListener === "function") {
64451
- mediaQueryList.addEventListener("change", onChange);
64452
- return () => mediaQueryList.removeEventListener("change", onChange);
64453
- }
64454
- mediaQueryList.addListener(onChange);
64455
- return () => mediaQueryList.removeListener(onChange);
64456
- }, [query]);
64457
- return matches;
64458
- };
64459
65059
  var chartCardVariants = {
64460
65060
  initial: { opacity: 0, y: 10 },
64461
65061
  animate: {
@@ -64533,9 +65133,8 @@ var WorkspaceDetailView = ({
64533
65133
  const [usingFallbackData, setUsingFallbackData] = useState(false);
64534
65134
  const { isIdleTimeVlmEnabled } = useIdleTimeVlmConfig();
64535
65135
  const [showChartIdleTime, setShowChartIdleTime] = useState(false);
64536
- const isShortDesktop = useMediaQuery(SHORT_DESKTOP_QUERY);
64537
- const desktopTopSectionClass = isShortDesktop ? "flex-none min-h-[340px]" : "flex-[3] min-h-0";
64538
- const desktopBottomSectionClass = isShortDesktop ? "flex-none min-h-[300px]" : "flex-[2] min-h-0";
65136
+ const desktopTopSectionClass = "flex-[3] min-h-0";
65137
+ const desktopBottomSectionClass = "flex-[2] min-h-0";
64539
65138
  const dashboardConfig = useDashboardConfig();
64540
65139
  const { legend: efficiencyLegend } = useEfficiencyLegend();
64541
65140
  const prewarmedClipsRef = useRef(/* @__PURE__ */ new Set());
@@ -65123,19 +65722,13 @@ var WorkspaceDetailView = ({
65123
65722
  shiftId: idleClipShiftId,
65124
65723
  enabled: idleClipFetchEnabled
65125
65724
  });
65126
- const handleBackNavigation = () => {
65725
+ const fallbackReturnUrl = returnUrl || "/";
65726
+ const appendReturnUrl = useCallback((params) => {
65127
65727
  if (returnUrl) {
65128
- if (onNavigate) {
65129
- onNavigate(returnUrl);
65130
- }
65131
- return;
65132
- }
65133
- if (activeTab === "monthly_history") {
65134
- if (onNavigate) {
65135
- onNavigate("/");
65136
- }
65137
- return;
65728
+ params.set("returnTo", returnUrl);
65138
65729
  }
65730
+ }, [returnUrl]);
65731
+ const handleBackNavigation = () => {
65139
65732
  if (date || shift) {
65140
65733
  setActiveTab("monthly_history");
65141
65734
  if (onNavigate) {
@@ -65149,8 +65742,22 @@ var WorkspaceDetailView = ({
65149
65742
  if (effectiveLineId) {
65150
65743
  params.set("lineId", effectiveLineId);
65151
65744
  }
65745
+ appendReturnUrl(params);
65152
65746
  onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
65153
65747
  }
65748
+ return;
65749
+ }
65750
+ if (activeTab === "monthly_history") {
65751
+ if (onNavigate) {
65752
+ onNavigate(fallbackReturnUrl);
65753
+ }
65754
+ return;
65755
+ }
65756
+ if (returnUrl) {
65757
+ if (onNavigate) {
65758
+ onNavigate(returnUrl);
65759
+ }
65760
+ return;
65154
65761
  } else {
65155
65762
  if (previousView === "line_monthly_history") {
65156
65763
  setActiveTab("monthly_history");
@@ -65165,11 +65772,12 @@ var WorkspaceDetailView = ({
65165
65772
  if (effectiveLineId) {
65166
65773
  params.set("lineId", effectiveLineId);
65167
65774
  }
65775
+ appendReturnUrl(params);
65168
65776
  onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
65169
65777
  }
65170
65778
  } else {
65171
65779
  if (onNavigate) {
65172
- onNavigate("/");
65780
+ onNavigate(fallbackReturnUrl);
65173
65781
  }
65174
65782
  }
65175
65783
  }
@@ -65228,7 +65836,7 @@ var WorkspaceDetailView = ({
65228
65836
  /* @__PURE__ */ jsx(
65229
65837
  BackButton,
65230
65838
  {
65231
- onClick: () => onNavigate && onNavigate("/"),
65839
+ onClick: () => onNavigate && onNavigate(fallbackReturnUrl),
65232
65840
  text: "Return to Dashboard",
65233
65841
  size: "default",
65234
65842
  "aria-label": "Return to dashboard"
@@ -65242,7 +65850,7 @@ var WorkspaceDetailView = ({
65242
65850
  /* @__PURE__ */ jsx(
65243
65851
  BackButton,
65244
65852
  {
65245
- onClick: () => onNavigate && onNavigate("/"),
65853
+ onClick: () => onNavigate && onNavigate(fallbackReturnUrl),
65246
65854
  text: "Return to Dashboard",
65247
65855
  size: "default",
65248
65856
  "aria-label": "Return to dashboard"
@@ -65513,7 +66121,7 @@ var WorkspaceDetailView = ({
65513
66121
  ] })
65514
66122
  ] }),
65515
66123
  /* @__PURE__ */ jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4", children: [
65516
- activeTab === "overview" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full lg:h-[calc(100vh-10rem)] overflow-y-auto lg:min-h-0", children: [
66124
+ activeTab === "overview" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full lg:h-[calc(100vh-12rem)] overflow-y-auto lg:min-h-0 pb-4", children: [
65517
66125
  /* @__PURE__ */ jsxs("div", { className: "block lg:hidden space-y-6 pb-6", children: [
65518
66126
  !shouldShowCycleTimeChart && !isUptimeMode && /* @__PURE__ */ jsxs(
65519
66127
  motion.div,
@@ -65855,6 +66463,7 @@ var WorkspaceDetailView = ({
65855
66463
  if (effectiveLineId) {
65856
66464
  params.set("lineId", effectiveLineId);
65857
66465
  }
66466
+ appendReturnUrl(params);
65858
66467
  onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
65859
66468
  }
65860
66469
  },
@@ -66215,7 +66824,7 @@ var formatTime4 = (date, timezone) => new Intl.DateTimeFormat("en-IN", {
66215
66824
  hour12: true,
66216
66825
  timeZone: timezone
66217
66826
  }).format(date);
66218
- var formatDuration2 = (minutes) => {
66827
+ var formatDuration3 = (minutes) => {
66219
66828
  if (minutes < 1) return "<1 min";
66220
66829
  if (minutes < 60) return `${minutes} min`;
66221
66830
  const hours = Math.floor(minutes / 60);
@@ -66328,7 +66937,7 @@ var UptimeTimelineStrip = ({
66328
66937
  if (segment.length > 1) {
66329
66938
  endDate.setMinutes(endDate.getMinutes() + 1);
66330
66939
  }
66331
- const tooltip = `${STATUS_TITLES[segment.status]} \u2022 ${formatDuration2(segment.length)} (${formatTime4(
66940
+ const tooltip = `${STATUS_TITLES[segment.status]} \u2022 ${formatDuration3(segment.length)} (${formatTime4(
66332
66941
  startDate,
66333
66942
  timezone
66334
66943
  )} - ${formatTime4(endDate, timezone)})`;
@@ -66361,7 +66970,7 @@ var UptimeTimelineStrip = ({
66361
66970
  };
66362
66971
  var UptimeTimelineStrip_default = UptimeTimelineStrip;
66363
66972
  var SHORT_INTERRUPT_THRESHOLD_MINUTES = 3;
66364
- var formatDuration3 = (minutes) => {
66973
+ var formatDuration4 = (minutes) => {
66365
66974
  if (!minutes || minutes <= 0) return "0 min";
66366
66975
  const rounded = Math.max(Math.round(minutes), 0);
66367
66976
  const days = Math.floor(rounded / 1440);
@@ -66380,7 +66989,7 @@ var formatDowntimeLabel2 = (minutes, includeSuffix = true) => {
66380
66989
  if (!minutes || minutes <= 0) {
66381
66990
  return includeSuffix ? "No downtime" : "0 min";
66382
66991
  }
66383
- const label = formatDuration3(minutes);
66992
+ const label = formatDuration4(minutes);
66384
66993
  return includeSuffix ? `${label} down` : label;
66385
66994
  };
66386
66995
  var formatTimeRange = (start, end, timezone) => {
@@ -67136,6 +67745,7 @@ var TeamManagementView = ({
67136
67745
  owners: 0,
67137
67746
  it: 0,
67138
67747
  plantHeads: 0,
67748
+ industrialEngineers: 0,
67139
67749
  supervisors: 0,
67140
67750
  optifye: 0
67141
67751
  });
@@ -67149,8 +67759,8 @@ var TeamManagementView = ({
67149
67759
  }
67150
67760
  return [];
67151
67761
  }, []);
67152
- const plantHeadFactoryIds = useMemo(() => {
67153
- if (user?.role_level !== "plant_head") return [];
67762
+ const factoryScopedRoleFactoryIds = useMemo(() => {
67763
+ if (!isFactoryScopedRole(user?.role_level)) return [];
67154
67764
  const scopedFactoryIds = normalizeIds(user?.access_scope?.factory_ids);
67155
67765
  if (scopedFactoryIds.length > 0) {
67156
67766
  return Array.from(new Set(scopedFactoryIds));
@@ -67168,8 +67778,8 @@ var TeamManagementView = ({
67168
67778
  window.dispatchEvent(new Event("rbac:refresh-scope"));
67169
67779
  }
67170
67780
  }, []);
67171
- const canAddUsers = user?.role_level === "owner" || user?.role_level === "it" || user?.role_level === "plant_head" || user?.role_level === "optifye";
67172
- const canViewUsageStats = user?.role_level === "owner" || user?.role_level === "it" || user?.role_level === "optifye";
67781
+ const canAddUsers = canRoleManageUsers(user?.role_level);
67782
+ const canViewUsageStats = canRoleViewUsageStats(user?.role_level);
67173
67783
  const pageCompanyId = entityConfig?.companyId || user?.properties?.company_id;
67174
67784
  const companyIdForUsage = pageCompanyId;
67175
67785
  const usageDateRange = useMemo(() => {
@@ -67203,8 +67813,8 @@ var TeamManagementView = ({
67203
67813
  }, {});
67204
67814
  }, [usageData, usageDateRange.daysElapsed]);
67205
67815
  const pageTitle = "Team Management";
67206
- const pageDescription = user?.role_level === "owner" || user?.role_level === "it" || user?.role_level === "optifye" ? "Manage team members and view their daily usage" : "Manage supervisors in your factory";
67207
- const hasAccess = user ? user.role_level === void 0 || ["optifye", "owner", "it", "plant_head"].includes(user.role_level) : false;
67816
+ const pageDescription = canViewUsageStats ? "Manage team members and view their daily usage" : "Manage supervisors in your factory";
67817
+ const hasAccess = user ? user.role_level === void 0 || canRoleAccessTeamManagement(user.role_level) : false;
67208
67818
  const loadData = useCallback(async () => {
67209
67819
  if (!supabase) {
67210
67820
  setError("Supabase client not available. Please refresh the page.");
@@ -67251,8 +67861,8 @@ var TeamManagementView = ({
67251
67861
  setAvailableFactories(factories || []);
67252
67862
  setAvailableLines(lines);
67253
67863
  console.log("[TeamManagementView] Company-scoped team view - Company:", companyId, "Loaded factories:", factories?.length, "lines:", lines?.length);
67254
- } else if (user?.role_level === "plant_head") {
67255
- if (plantHeadFactoryIds.length > 0) {
67864
+ } else if (isFactoryScopedRole(user?.role_level)) {
67865
+ if (factoryScopedRoleFactoryIds.length > 0) {
67256
67866
  if (companyId) {
67257
67867
  const linesResponse = await fetch(`${backendUrl}/api/lines?company_id=${companyId}`, {
67258
67868
  headers: {
@@ -67265,9 +67875,9 @@ var TeamManagementView = ({
67265
67875
  }
67266
67876
  const linesData = await linesResponse.json();
67267
67877
  const allLines = linesData.lines || [];
67268
- const lines = allLines.filter((line) => plantHeadFactoryIds.includes(line.factory_id));
67878
+ const lines = allLines.filter((line) => factoryScopedRoleFactoryIds.includes(line.factory_id));
67269
67879
  setAvailableLines(lines);
67270
- console.log("[TeamManagementView] Plant Head - Factories:", plantHeadFactoryIds, "Loaded lines:", lines?.length);
67880
+ console.log("[TeamManagementView] Factory-scoped team view - Factories:", factoryScopedRoleFactoryIds, "Loaded lines:", lines?.length);
67271
67881
  }
67272
67882
  } else if (entityConfig?.factoryId) {
67273
67883
  const linesResponse = await fetch(`${backendUrl}/api/lines?factory_id=${entityConfig.factoryId}`, {
@@ -67304,12 +67914,12 @@ var TeamManagementView = ({
67304
67914
  setAvailableFactories([]);
67305
67915
  console.log("[TeamManagementView] Fallback - Company:", companyId, "Loaded lines:", lines?.length);
67306
67916
  }
67307
- const usersPromise = user?.role_level === "plant_head" ? (async () => {
67308
- if (plantHeadFactoryIds.length === 0) {
67917
+ const usersPromise = isFactoryScopedRole(user?.role_level) ? (async () => {
67918
+ if (factoryScopedRoleFactoryIds.length === 0) {
67309
67919
  return [];
67310
67920
  }
67311
67921
  const results = await Promise.allSettled(
67312
- plantHeadFactoryIds.map((factoryId) => userManagementService.getFactoryUsers(factoryId))
67922
+ factoryScopedRoleFactoryIds.map((factoryId) => userManagementService.getFactoryUsers(factoryId))
67313
67923
  );
67314
67924
  const successful = results.filter(
67315
67925
  (result) => result.status === "fulfilled"
@@ -67341,6 +67951,7 @@ var TeamManagementView = ({
67341
67951
  owners: userStats.owners,
67342
67952
  it: userStats.it,
67343
67953
  plantHeads: userStats.plant_heads,
67954
+ industrialEngineers: userStats.industrial_engineers,
67344
67955
  supervisors: userStats.supervisors,
67345
67956
  optifye: 0
67346
67957
  });
@@ -67351,7 +67962,7 @@ var TeamManagementView = ({
67351
67962
  } finally {
67352
67963
  setIsLoading(false);
67353
67964
  }
67354
- }, [supabase, user, pageCompanyId, entityConfig?.factoryId, plantHeadFactoryIds]);
67965
+ }, [supabase, user, pageCompanyId, entityConfig?.factoryId, factoryScopedRoleFactoryIds]);
67355
67966
  useEffect(() => {
67356
67967
  const companyId = pageCompanyId;
67357
67968
  const canLoad = hasAccess && user && !!companyId;
@@ -67457,7 +68068,7 @@ var TeamManagementView = ({
67457
68068
  {
67458
68069
  iconType: AlertCircle,
67459
68070
  title: "Access Denied",
67460
- message: "You don't have permission to view this page. Only owners, IT, plant heads, and Optifye users can access team management."
68071
+ message: `You don't have permission to view this page. Only ${getRoleLabel("owner")}, ${getRoleLabel("it")}, ${getRoleLabel("plant_head")}, ${getRoleLabel("industrial_engineer")}, and ${getRoleLabel("optifye")} users can access team management.`
67461
68072
  }
67462
68073
  ) });
67463
68074
  }
@@ -67624,7 +68235,7 @@ function BottleneckClipsView({
67624
68235
  ) })
67625
68236
  ] }) });
67626
68237
  }
67627
- var AuthenticatedBottleneckClipsView = withAuth(React26__default.memo(BottleneckClipsView));
68238
+ var AuthenticatedBottleneckClipsView = withAuth(React141__default.memo(BottleneckClipsView));
67628
68239
  var BottleneckClipsView_default = BottleneckClipsView;
67629
68240
 
67630
68241
  // src/lib/services/ticketService.ts
@@ -68455,7 +69066,7 @@ Please ensure:
68455
69066
  )
68456
69067
  ] });
68457
69068
  }
68458
- var AuthenticatedTicketsView = withAuth(React26__default.memo(TicketsView));
69069
+ var AuthenticatedTicketsView = withAuth(React141__default.memo(TicketsView));
68459
69070
  var TicketsView_default = TicketsView;
68460
69071
 
68461
69072
  // src/lib/api/s3-clips-parser.ts
@@ -68635,6 +69246,74 @@ var buildInitials = (name) => {
68635
69246
  const second = parts.length > 1 ? parts[1]?.[0] || "" : "";
68636
69247
  return `${first}${second}`.toUpperCase();
68637
69248
  };
69249
+ var MOCK_IE_TEAM_USER_ID = "mock-industrial-engineering-team";
69250
+ var MOCK_IE_TICKET_ID = "mock-ie-rack-too-far-away";
69251
+ var getRandomVideoGalleryClips = (recommendations, maxClips = 3) => {
69252
+ const seen = /* @__PURE__ */ new Set();
69253
+ const candidates = [];
69254
+ recommendations.forEach((rec) => {
69255
+ if (!Array.isArray(rec.evidence)) return;
69256
+ rec.evidence.forEach((evidenceItem) => {
69257
+ if (evidenceItem.type !== "video_gallery" || !Array.isArray(evidenceItem.clips)) return;
69258
+ evidenceItem.clips.forEach((rawClip) => {
69259
+ if (!rawClip || typeof rawClip.clip_id !== "string") return;
69260
+ const key = `${rawClip.clip_id}:${rawClip.workspace_id || ""}`;
69261
+ if (seen.has(key)) return;
69262
+ seen.add(key);
69263
+ candidates.push({
69264
+ clip_id: rawClip.clip_id,
69265
+ workspace_id: typeof rawClip.workspace_id === "string" ? rawClip.workspace_id : void 0,
69266
+ cycle_time_seconds: typeof rawClip.cycle_time_seconds === "number" ? rawClip.cycle_time_seconds : void 0,
69267
+ cycle_sec: typeof rawClip.cycle_sec === "number" ? rawClip.cycle_sec : void 0
69268
+ });
69269
+ });
69270
+ });
69271
+ });
69272
+ for (let i = candidates.length - 1; i > 0; i -= 1) {
69273
+ const j = Math.floor(Math.random() * (i + 1));
69274
+ [candidates[i], candidates[j]] = [candidates[j], candidates[i]];
69275
+ }
69276
+ return candidates.slice(0, Math.max(1, maxClips));
69277
+ };
69278
+ var buildIEMockRecommendation = (recommendations, lineNameById) => {
69279
+ const now4 = /* @__PURE__ */ new Date();
69280
+ const firstSeen = new Date(now4.getTime() - 3 * 24 * 60 * 60 * 1e3).toISOString();
69281
+ const sampleRec = recommendations.find((rec) => !!rec.line_id) || recommendations[0];
69282
+ const lineId = sampleRec?.line_id;
69283
+ const line = lineId ? lineNameById.get(lineId) || sampleRec?.line || "Line 1" : sampleRec?.line || "Line 1";
69284
+ const shiftLabel = sampleRec?.shift_label;
69285
+ const shiftId = sampleRec?.shift_id;
69286
+ const randomClips = getRandomVideoGalleryClips(recommendations, 3);
69287
+ return {
69288
+ id: MOCK_IE_TICKET_ID,
69289
+ issue_id: MOCK_IE_TICKET_ID,
69290
+ issue_number: 0,
69291
+ issue_status: "open",
69292
+ template_code: "ie_rack_too_far_away_mock",
69293
+ type: "cycle_time",
69294
+ title: "Rack too far away",
69295
+ location: "Industrial Engineering Review",
69296
+ line,
69297
+ line_id: lineId,
69298
+ description: "We analyzed 30 slow clips and saw that the top reason was the operator having to reach for the desk.",
69299
+ resolution_instructions: "Completion condition: Move the rack 3 inches closer to the operator for better ergonomic posture.",
69300
+ shift_id: shiftId,
69301
+ shift_label: shiftLabel,
69302
+ first_seen_at: firstSeen,
69303
+ visible_since: firstSeen,
69304
+ weeks_open: 1,
69305
+ ticket_status: "active",
69306
+ assigned_to_user_id: MOCK_IE_TEAM_USER_ID,
69307
+ assigned_user_ids: [MOCK_IE_TEAM_USER_ID],
69308
+ evidence: randomClips.length > 0 ? [
69309
+ {
69310
+ type: "video_gallery",
69311
+ title: "Slow clips analyzed",
69312
+ clips: randomClips
69313
+ }
69314
+ ] : []
69315
+ };
69316
+ };
68638
69317
  var ClipVideoCarousel = ({ clips, clipsService }) => {
68639
69318
  const [currentIndex, setCurrentIndex] = useState(0);
68640
69319
  const [videos, setVideos] = useState([]);
@@ -69057,12 +69736,12 @@ var ImprovementCenterView = () => {
69057
69736
  }, [user]);
69058
69737
  const assignedFactoryIds = useMemo(() => {
69059
69738
  if (!user) return [];
69060
- if (user.role_level !== "plant_head") return [];
69739
+ if (!isFactoryScopedRole(user.role_level)) return [];
69061
69740
  const factories = user.properties?.factory_id || user.properties?.factory_ids || [];
69062
69741
  return Array.isArray(factories) ? factories : [];
69063
69742
  }, [user]);
69064
69743
  const plantHeadLineIds = useMemo(() => {
69065
- if (user?.role_level !== "plant_head" || companyLines.length === 0) return [];
69744
+ if (!isFactoryScopedRole(user?.role_level) || companyLines.length === 0) return [];
69066
69745
  const factorySet = new Set(assignedFactoryIds);
69067
69746
  return companyLines.filter((line) => line.factoryId === void 0 || line.factoryId === null || factorySet.has(line.factoryId)).map((line) => line.id);
69068
69747
  }, [assignedFactoryIds, companyLines, user?.role_level]);
@@ -69070,7 +69749,7 @@ var ImprovementCenterView = () => {
69070
69749
  if (user?.role_level === "supervisor") {
69071
69750
  return assignedLineIds;
69072
69751
  }
69073
- if (user?.role_level === "plant_head") {
69752
+ if (isFactoryScopedRole(user?.role_level)) {
69074
69753
  if (plantHeadLineIds.length > 0) return plantHeadLineIds;
69075
69754
  return companyLineIds.length > 0 ? companyLineIds : configuredLineIds;
69076
69755
  }
@@ -69093,6 +69772,21 @@ var ImprovementCenterView = () => {
69093
69772
  return map;
69094
69773
  }, [companyLines, configuredLines]);
69095
69774
  const companyId = user?.company_id || entityConfig.companyId;
69775
+ const industrialEngineeringTeamMember = useMemo(
69776
+ () => ({
69777
+ id: MOCK_IE_TEAM_USER_ID,
69778
+ name: "Industrial Engineering Team",
69779
+ role: "industrial_engineering",
69780
+ initials: "IE"
69781
+ }),
69782
+ []
69783
+ );
69784
+ const teamMembersWithIETeam = useMemo(() => {
69785
+ if (teamMembers.some((member) => member.id === MOCK_IE_TEAM_USER_ID)) {
69786
+ return teamMembers;
69787
+ }
69788
+ return [...teamMembers, industrialEngineeringTeamMember];
69789
+ }, [teamMembers, industrialEngineeringTeamMember]);
69096
69790
  const clipsService = useMemo(() => {
69097
69791
  try {
69098
69792
  return new S3ClipsSupabaseService(dashboardConfig);
@@ -69106,24 +69800,42 @@ var ImprovementCenterView = () => {
69106
69800
  if (!supabase || !companyId) return;
69107
69801
  try {
69108
69802
  const userService2 = createUserManagementService(supabase);
69109
- const supervisors = await userService2.getCompanyUsers(companyId, "supervisor");
69803
+ const roleFilters = ["supervisor", "owner", "industrial_engineer"];
69804
+ const roleResults = await Promise.allSettled(
69805
+ roleFilters.map((role) => userService2.getCompanyUsers(companyId, role))
69806
+ );
69807
+ roleResults.forEach((result, index) => {
69808
+ if (result.status === "rejected") {
69809
+ console.warn(
69810
+ `[ImprovementCenterView] Failed to load ${roleFilters[index]} users`,
69811
+ result.reason
69812
+ );
69813
+ }
69814
+ });
69815
+ const users = roleResults.flatMap(
69816
+ (result) => result.status === "fulfilled" ? result.value : []
69817
+ );
69110
69818
  if (cancelled) return;
69111
- const members = supervisors.map((user2) => {
69819
+ const membersById = /* @__PURE__ */ new Map();
69820
+ users.forEach((user2) => {
69112
69821
  const rawName = user2.first_name ? `${user2.first_name}${user2.last_name ? " " + user2.last_name : ""}` : user2.properties?.full_name || user2.email?.split("@")[0] || "Unknown";
69113
- return {
69114
- id: user2.user_id,
69115
- name: rawName,
69116
- role: user2.role_level,
69117
- initials: buildInitials(rawName),
69118
- email: user2.email,
69119
- profilePhotoUrl: user2.profile_photo_url
69120
- };
69822
+ if (!membersById.has(user2.user_id)) {
69823
+ membersById.set(user2.user_id, {
69824
+ id: user2.user_id,
69825
+ name: rawName,
69826
+ role: user2.role_level,
69827
+ initials: buildInitials(rawName),
69828
+ email: user2.email,
69829
+ profilePhotoUrl: user2.profile_photo_url
69830
+ });
69831
+ }
69121
69832
  });
69833
+ const members = Array.from(membersById.values());
69122
69834
  members.sort((a, b) => a.name.localeCompare(b.name));
69123
69835
  setTeamMembers(members);
69124
69836
  } catch (error) {
69125
69837
  if (!cancelled) {
69126
- console.error("[ImprovementCenterView] Failed to load supervisors", error);
69838
+ console.error("[ImprovementCenterView] Failed to load assignee members", error);
69127
69839
  setTeamMembers([]);
69128
69840
  }
69129
69841
  }
@@ -69186,7 +69898,12 @@ var ImprovementCenterView = () => {
69186
69898
  };
69187
69899
  });
69188
69900
  const allowed = new Set(scopeLineIds);
69189
- setRecommendations(recs.filter((r2) => !r2.line_id || allowed.has(r2.line_id)));
69901
+ const scopedRecommendations = recs.filter((r2) => !r2.line_id || allowed.has(r2.line_id));
69902
+ const mockRecommendation = buildIEMockRecommendation(scopedRecommendations, lineNameById);
69903
+ setRecommendations([
69904
+ mockRecommendation,
69905
+ ...scopedRecommendations.filter((recommendation) => recommendation.id !== MOCK_IE_TICKET_ID)
69906
+ ]);
69190
69907
  } catch (err) {
69191
69908
  if (cancelled) return;
69192
69909
  setLoadError(err?.message || "Failed to load recommendations");
@@ -69199,10 +69916,10 @@ var ImprovementCenterView = () => {
69199
69916
  return () => {
69200
69917
  cancelled = true;
69201
69918
  };
69202
- }, [supabase, companyId, scopeLineIdsKey]);
69919
+ }, [supabase, companyId, scopeLineIdsKey, lineNameById]);
69203
69920
  const teamMembersById = useMemo(() => {
69204
- return new Map(teamMembers.map((member) => [member.id, member]));
69205
- }, [teamMembers]);
69921
+ return new Map(teamMembersWithIETeam.map((member) => [member.id, member]));
69922
+ }, [teamMembersWithIETeam]);
69206
69923
  const filteredRecommendations = useMemo(() => {
69207
69924
  return recommendations.filter((rec) => {
69208
69925
  if (selectedLineId !== "all" && rec.line_id !== selectedLineId) return false;
@@ -69217,7 +69934,12 @@ var ImprovementCenterView = () => {
69217
69934
  }
69218
69935
  if (selectedMemberId !== "all" && !(rec.assigned_user_ids?.includes(selectedMemberId) || rec.assigned_to_user_id === selectedMemberId)) return false;
69219
69936
  return true;
69220
- }).sort((a, b) => (a.issue_number || 0) - (b.issue_number || 0));
69937
+ }).sort((a, b) => {
69938
+ const aIndustrial = a.industrial_eng_bottleneck ? 1 : 0;
69939
+ const bIndustrial = b.industrial_eng_bottleneck ? 1 : 0;
69940
+ if (aIndustrial !== bIndustrial) return bIndustrial - aIndustrial;
69941
+ return (a.issue_number || 0) - (b.issue_number || 0);
69942
+ });
69221
69943
  }, [recommendations, selectedLineId, selectedStatus, selectedShift, selectedWeeksRange, selectedMemberId]);
69222
69944
  const stats = useMemo(() => {
69223
69945
  const baseFiltered = recommendations.filter((rec) => {
@@ -69315,7 +70037,7 @@ var ImprovementCenterView = () => {
69315
70037
  setSelectedWeeksRange(weeksRange);
69316
70038
  };
69317
70039
  const handleMemberFilterChange = (memberId) => {
69318
- const memberName = memberId === "all" ? "all" : teamMembers.find((m) => m.id === memberId)?.name || memberId;
70040
+ const memberName = memberId === "all" ? "all" : teamMembersWithIETeam.find((member) => member.id === memberId)?.name || memberId;
69319
70041
  trackCoreEvent("Improvement Center Filter Applied", {
69320
70042
  filter_type: "member",
69321
70043
  filter_value: memberName,
@@ -69397,7 +70119,7 @@ var ImprovementCenterView = () => {
69397
70119
  /* @__PURE__ */ jsx("div", { className: "space-y-3", children: [
69398
70120
  { value: selectedShift, onChange: handleShiftFilterChange, options: shiftOptions, label: "Shift" },
69399
70121
  { value: selectedWeeksRange, onChange: handleWeeksFilterChange, options: weekOptions.map((o) => o.id), labels: weekOptions, label: "Duration" },
69400
- { value: selectedMemberId, onChange: handleMemberFilterChange, options: ["all", ...teamMembers.map((m) => m.id)], labels: teamMembers, label: "Member" },
70122
+ { value: selectedMemberId, onChange: handleMemberFilterChange, options: ["all", ...teamMembersWithIETeam.map((m) => m.id)], labels: teamMembersWithIETeam, label: "Member" },
69401
70123
  { value: selectedLineId, onChange: handleLineFilterChange, options: lineOptions.map((o) => o.id), labels: lineOptions, label: "Line" }
69402
70124
  ].map((filter2, idx) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
69403
70125
  /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: filter2.label }),
@@ -69614,7 +70336,7 @@ var ThreadSidebar = ({
69614
70336
  ] }) })
69615
70337
  ] });
69616
70338
  };
69617
- var ProfilePicture = React26__default.memo(({
70339
+ var ProfilePicture = React141__default.memo(({
69618
70340
  alt = "Axel",
69619
70341
  className = "",
69620
70342
  size = "md",
@@ -71585,6 +72307,840 @@ var AIAgentView = () => {
71585
72307
  ] });
71586
72308
  };
71587
72309
  var AIAgentView_default = AIAgentView;
72310
+ var EMPTY_OVERVIEW = {
72311
+ scope: {
72312
+ current_range: { day_count: null },
72313
+ previous_range: { day_count: null },
72314
+ available_line_modes: { has_output: false, has_uptime: false }
72315
+ },
72316
+ summary: {
72317
+ plant_efficiency: { current: null, previous: null, delta_pp: null },
72318
+ avg_idle_per_workstation: { current_seconds: null, previous_seconds: null, delta_seconds: null }
72319
+ },
72320
+ poorest_lines: { output: [], uptime: [] },
72321
+ trend: { shift_mode: "all", points: [] },
72322
+ idle_reason_breakdown: []
72323
+ };
72324
+ var efficiencyLineConfig = [
72325
+ {
72326
+ dataKey: "efficiency",
72327
+ name: "Efficiency",
72328
+ stroke: "#00AB45",
72329
+ strokeWidth: 3,
72330
+ type: "monotone",
72331
+ dot: { r: 4, fill: "#00AB45", strokeWidth: 2, stroke: "#fff" },
72332
+ activeDot: { r: 6, strokeWidth: 0, fill: "#00AB45" }
72333
+ }
72334
+ ];
72335
+ var toNumber3 = (value) => {
72336
+ if (typeof value === "number" && Number.isFinite(value)) return value;
72337
+ if (typeof value === "string" && value.trim().length > 0) {
72338
+ const parsed = Number(value);
72339
+ return Number.isFinite(parsed) ? parsed : null;
72340
+ }
72341
+ return null;
72342
+ };
72343
+ var roundOne = (value) => Math.round(value * 10) / 10;
72344
+ var getLastSevenDayRange = (timezone) => {
72345
+ const todayKey = formatInTimeZone(/* @__PURE__ */ new Date(), timezone || "UTC", "yyyy-MM-dd");
72346
+ const endDate = parseISO(`${todayKey}T00:00:00`);
72347
+ const startDate = subDays(endDate, 6);
72348
+ return {
72349
+ startKey: format(startDate, "yyyy-MM-dd"),
72350
+ endKey: format(endDate, "yyyy-MM-dd")
72351
+ };
72352
+ };
72353
+ var formatIdleDuration = (seconds) => {
72354
+ if (seconds === null || seconds === void 0 || !Number.isFinite(seconds)) {
72355
+ return "--";
72356
+ }
72357
+ const wholeSeconds = Math.max(0, Math.round(seconds));
72358
+ const minutes = Math.floor(wholeSeconds / 60);
72359
+ const remainingSeconds = wholeSeconds % 60;
72360
+ if (minutes > 0) {
72361
+ return `${minutes}m ${remainingSeconds}s`;
72362
+ }
72363
+ return `${remainingSeconds}s`;
72364
+ };
72365
+ var formatSignedIdleDuration = (seconds) => {
72366
+ const sign = seconds > 0 ? "+" : "-";
72367
+ return `${sign}${formatIdleDuration(Math.abs(seconds))}`;
72368
+ };
72369
+ var formatComparisonWindow = (dayCount) => {
72370
+ if (!dayCount || !Number.isFinite(dayCount)) return "previous range";
72371
+ return `previous ${dayCount} ${dayCount === 1 ? "day" : "days"}`;
72372
+ };
72373
+ var shuffle = (items) => {
72374
+ const next = [...items];
72375
+ for (let i = next.length - 1; i > 0; i -= 1) {
72376
+ const swapIndex = Math.floor(Math.random() * (i + 1));
72377
+ [next[i], next[swapIndex]] = [next[swapIndex], next[i]];
72378
+ }
72379
+ return next;
72380
+ };
72381
+ var buildImprovementMetric = (recommendation) => {
72382
+ const metrics2 = recommendation.metrics || {};
72383
+ const efficiencyGain = toNumber3(metrics2.efficiency_gain_pct);
72384
+ if (efficiencyGain !== null) {
72385
+ return `+${roundOne(efficiencyGain)}% Efficiency`;
72386
+ }
72387
+ const outputGain = toNumber3(metrics2.output_gain);
72388
+ if (outputGain !== null) {
72389
+ return `+${Math.round(outputGain)} Units`;
72390
+ }
72391
+ const idleMinutes = toNumber3(metrics2.idle_minutes);
72392
+ if (idleMinutes !== null) {
72393
+ return `-${Math.round(idleMinutes)}m Idle`;
72394
+ }
72395
+ const impactText = recommendation.impact?.trim();
72396
+ if (impactText) {
72397
+ return impactText.length > 22 ? `${impactText.slice(0, 22).trim()}...` : impactText;
72398
+ }
72399
+ return "Review Issue";
72400
+ };
72401
+ var buildImprovementImpact = (recommendation) => {
72402
+ if (recommendation.issue_severity !== void 0 && recommendation.issue_severity !== null) {
72403
+ if (recommendation.issue_severity >= 3) return "High";
72404
+ if (recommendation.issue_severity >= 2) return "Medium";
72405
+ return "Low";
72406
+ }
72407
+ return "Medium";
72408
+ };
72409
+ var buildDeltaBadge = (delta, options) => {
72410
+ if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
72411
+ return {
72412
+ icon: null,
72413
+ className: "bg-slate-100 text-slate-500",
72414
+ text: `No ${options.comparisonLabel} baseline`
72415
+ };
72416
+ }
72417
+ const direction = delta >= 0 ? "up" : "down";
72418
+ const isGood = options.positiveIsGood ? delta >= 0 : delta <= 0;
72419
+ return {
72420
+ icon: direction,
72421
+ className: isGood ? "bg-[#ecfdf5] text-[#059669]" : "bg-[#FEF2F2] text-[#DC2626]",
72422
+ text: `${options.formatter(delta)} vs ${options.comparisonLabel}`
72423
+ };
72424
+ };
72425
+ var buildLineDeltaTone = (delta, comparisonLabel) => {
72426
+ if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
72427
+ return {
72428
+ className: "text-slate-400",
72429
+ text: `No ${comparisonLabel} baseline`
72430
+ };
72431
+ }
72432
+ return {
72433
+ className: delta >= 0 ? "text-[#059669]" : "text-[#DC2626]",
72434
+ text: `${delta >= 0 ? "+" : ""}${roundOne(delta)}% vs ${comparisonLabel}`
72435
+ };
72436
+ };
72437
+ var SectionPulse = ({ className }) => /* @__PURE__ */ jsx("div", { className: `animate-pulse rounded-md bg-slate-200/70 ${className || ""}` });
72438
+ var OverviewMetricCardSkeleton = () => /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-3", children: [
72439
+ /* @__PURE__ */ jsx(SectionPulse, { className: "h-8 w-32" }),
72440
+ /* @__PURE__ */ jsx(SectionPulse, { className: "h-6 w-44 rounded-full" })
72441
+ ] });
72442
+ var OverviewListSkeleton = ({ rows = 3 }) => /* @__PURE__ */ jsx("div", { className: "space-y-4 py-3", children: Array.from({ length: rows }).map((_, index) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
72443
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
72444
+ /* @__PURE__ */ jsx(SectionPulse, { className: "h-8 w-8 rounded-full" }),
72445
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
72446
+ /* @__PURE__ */ jsx(SectionPulse, { className: "h-3 w-28" }),
72447
+ /* @__PURE__ */ jsx(SectionPulse, { className: "h-2.5 w-20" })
72448
+ ] })
72449
+ ] }),
72450
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
72451
+ /* @__PURE__ */ jsx(SectionPulse, { className: "h-4 w-12" }),
72452
+ /* @__PURE__ */ jsx(SectionPulse, { className: "h-6 w-10 rounded-full" })
72453
+ ] })
72454
+ ] }, index)) });
72455
+ var OverviewChartSkeleton = () => /* @__PURE__ */ jsx("div", { className: "w-full h-full animate-pulse", children: /* @__PURE__ */ jsx("div", { className: "h-full rounded-xl bg-gradient-to-b from-slate-100 to-slate-50 p-4", children: /* @__PURE__ */ jsx("div", { className: "h-full rounded-lg border border-dashed border-slate-200 bg-white/70 px-3 py-4", children: /* @__PURE__ */ jsx("div", { className: "flex h-full items-end gap-3", children: Array.from({ length: 7 }).map((_, index) => /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-1 flex-col justify-end gap-2", children: [
72456
+ /* @__PURE__ */ jsx(SectionPulse, { className: `w-full rounded-md ${index % 3 === 0 ? "h-24" : index % 3 === 1 ? "h-32" : "h-20"}` }),
72457
+ /* @__PURE__ */ jsx(SectionPulse, { className: "h-2.5 w-8 self-center" })
72458
+ ] }, index)) }) }) }) });
72459
+ var OverviewIdleBreakdownSkeleton = () => /* @__PURE__ */ jsxs("div", { className: "w-full h-full flex items-center overflow-hidden animate-pulse", children: [
72460
+ /* @__PURE__ */ jsx("div", { className: "flex-1 h-full min-w-0 relative flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-32 h-32 rounded-full bg-slate-200" }) }),
72461
+ /* @__PURE__ */ jsx("div", { className: "w-[50%] max-w-[200px] pl-2 flex flex-col justify-center h-full space-y-2", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
72462
+ /* @__PURE__ */ jsx("div", { className: "w-2.5 h-2.5 rounded-full bg-slate-200 mr-1.5" }),
72463
+ /* @__PURE__ */ jsx("div", { className: "h-3 bg-slate-200 rounded w-20" })
72464
+ ] }, i)) })
72465
+ ] });
72466
+ var OverviewImprovementsSkeleton = () => /* @__PURE__ */ jsx("div", { className: "space-y-4 py-3", children: Array.from({ length: 3 }).map((_, index) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
72467
+ /* @__PURE__ */ jsx(SectionPulse, { className: "h-4 w-4 rounded-full" }),
72468
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-2", children: [
72469
+ /* @__PURE__ */ jsx(SectionPulse, { className: "h-3 w-40" }),
72470
+ /* @__PURE__ */ jsx(SectionPulse, { className: "h-2.5 w-24" })
72471
+ ] })
72472
+ ] }, index)) });
72473
+ var PlantHeadView = () => {
72474
+ const supabase = useSupabase();
72475
+ const entityConfig = useEntityConfig();
72476
+ const appTimezone = useAppTimezone() || "UTC";
72477
+ const { navigate } = useNavigation();
72478
+ const { accessibleLineIds } = useUserLineAccess();
72479
+ const mobileMenuContext = useMobileMenu();
72480
+ useHideMobileHeader(!!mobileMenuContext);
72481
+ const [dateRange, setDateRange] = React141__default.useState(() => getLastSevenDayRange("UTC"));
72482
+ const [trendMode, setTrendMode] = React141__default.useState("all");
72483
+ const [poorestLineMode, setPoorestLineMode] = React141__default.useState("output");
72484
+ const [overview, setOverview] = React141__default.useState(EMPTY_OVERVIEW);
72485
+ const [isSnapshotLoading, setIsSnapshotLoading] = React141__default.useState(false);
72486
+ const [isTrendLoading, setIsTrendLoading] = React141__default.useState(false);
72487
+ const [trendFetchNonce, setTrendFetchNonce] = React141__default.useState(0);
72488
+ const [trendViewOpenNonce] = React141__default.useState(() => Date.now());
72489
+ const [idleReasonBreakdown, setIdleReasonBreakdown] = React141__default.useState([]);
72490
+ const [isIdleReasonBreakdownLoading, setIsIdleReasonBreakdownLoading] = React141__default.useState(false);
72491
+ const [improvements, setImprovements] = React141__default.useState([]);
72492
+ const [isImprovementsLoading, setIsImprovementsLoading] = React141__default.useState(false);
72493
+ const [isFilterOpen, setIsFilterOpen] = React141__default.useState(false);
72494
+ const filterRef = React141__default.useRef(null);
72495
+ const filterButtonRef = React141__default.useRef(null);
72496
+ const mobileFilterButtonRef = React141__default.useRef(null);
72497
+ React141__default.useEffect(() => {
72498
+ function handleClickOutside(event) {
72499
+ if (filterRef.current && !filterRef.current.contains(event.target) && filterButtonRef.current && !filterButtonRef.current.contains(event.target) && mobileFilterButtonRef.current && !mobileFilterButtonRef.current.contains(event.target)) {
72500
+ setIsFilterOpen(false);
72501
+ }
72502
+ }
72503
+ document.addEventListener("mousedown", handleClickOutside);
72504
+ return () => {
72505
+ document.removeEventListener("mousedown", handleClickOutside);
72506
+ };
72507
+ }, []);
72508
+ const hasInitializedRangeRef = React141__default.useRef(false);
72509
+ React141__default.useEffect(() => {
72510
+ if (hasInitializedRangeRef.current) return;
72511
+ setDateRange(getLastSevenDayRange(appTimezone));
72512
+ hasInitializedRangeRef.current = true;
72513
+ }, [appTimezone]);
72514
+ const companyId = entityConfig.companyId;
72515
+ const scopedLineIds = React141__default.useMemo(
72516
+ () => Array.from(new Set((accessibleLineIds || []).filter(Boolean))),
72517
+ [accessibleLineIds]
72518
+ );
72519
+ const lineIdsKey = React141__default.useMemo(
72520
+ () => scopedLineIds.slice().sort().join(","),
72521
+ [scopedLineIds]
72522
+ );
72523
+ const { supervisorsByLineId } = useSupervisorsByLineIds(scopedLineIds, {
72524
+ enabled: !!companyId && scopedLineIds.length > 0,
72525
+ companyId,
72526
+ useBackend: true
72527
+ });
72528
+ React141__default.useEffect(() => {
72529
+ if (!supabase || !companyId) return void 0;
72530
+ if (scopedLineIds.length === 0) {
72531
+ setOverview(EMPTY_OVERVIEW);
72532
+ setIdleReasonBreakdown([]);
72533
+ setIsSnapshotLoading(false);
72534
+ return void 0;
72535
+ }
72536
+ let cancelled = false;
72537
+ setOverview((prev) => ({
72538
+ ...prev,
72539
+ scope: EMPTY_OVERVIEW.scope,
72540
+ summary: EMPTY_OVERVIEW.summary,
72541
+ poorest_lines: EMPTY_OVERVIEW.poorest_lines
72542
+ }));
72543
+ setIsSnapshotLoading(true);
72544
+ const fetchOverviewSnapshot = async () => {
72545
+ const params = new URLSearchParams({
72546
+ company_id: companyId,
72547
+ start_date: dateRange.startKey,
72548
+ end_date: dateRange.endKey,
72549
+ trend_shift_mode: trendMode,
72550
+ line_ids: scopedLineIds.join(",")
72551
+ });
72552
+ const response = await fetchBackendJson(
72553
+ supabase,
72554
+ `/api/dashboard/operations-overview/snapshot?${params.toString()}`
72555
+ );
72556
+ if (!cancelled) {
72557
+ setOverview((prev) => ({
72558
+ ...prev,
72559
+ scope: response.scope || EMPTY_OVERVIEW.scope,
72560
+ summary: response.summary || EMPTY_OVERVIEW.summary,
72561
+ poorest_lines: response.poorest_lines || EMPTY_OVERVIEW.poorest_lines
72562
+ }));
72563
+ }
72564
+ };
72565
+ fetchOverviewSnapshot().catch((error) => {
72566
+ console.error("[PlantHeadView] Failed to fetch operations overview snapshot", error);
72567
+ if (!cancelled) {
72568
+ setOverview((prev) => ({
72569
+ ...prev,
72570
+ scope: EMPTY_OVERVIEW.scope,
72571
+ summary: EMPTY_OVERVIEW.summary,
72572
+ poorest_lines: EMPTY_OVERVIEW.poorest_lines
72573
+ }));
72574
+ }
72575
+ }).finally(() => {
72576
+ if (!cancelled) {
72577
+ setIsSnapshotLoading(false);
72578
+ }
72579
+ });
72580
+ return () => {
72581
+ cancelled = true;
72582
+ };
72583
+ }, [
72584
+ companyId,
72585
+ dateRange.endKey,
72586
+ dateRange.startKey,
72587
+ lineIdsKey,
72588
+ scopedLineIds,
72589
+ supabase,
72590
+ trendMode
72591
+ ]);
72592
+ React141__default.useEffect(() => {
72593
+ if (!supabase || !companyId) return void 0;
72594
+ if (scopedLineIds.length === 0) {
72595
+ setOverview((prev) => ({
72596
+ ...prev,
72597
+ trend: EMPTY_OVERVIEW.trend
72598
+ }));
72599
+ setIsTrendLoading(false);
72600
+ return void 0;
72601
+ }
72602
+ let cancelled = false;
72603
+ setIsTrendLoading(true);
72604
+ const fetchOverviewTrend = async () => {
72605
+ const params = new URLSearchParams({
72606
+ company_id: companyId,
72607
+ start_date: dateRange.startKey,
72608
+ end_date: dateRange.endKey,
72609
+ trend_shift_mode: trendMode,
72610
+ line_ids: scopedLineIds.join(",")
72611
+ });
72612
+ const response = await fetchBackendJson(
72613
+ supabase,
72614
+ `/api/dashboard/operations-overview/trend?${params.toString()}`
72615
+ );
72616
+ if (!cancelled) {
72617
+ setOverview((prev) => ({
72618
+ ...prev,
72619
+ trend: response.trend || EMPTY_OVERVIEW.trend
72620
+ }));
72621
+ setTrendFetchNonce((prev) => prev + 1);
72622
+ }
72623
+ };
72624
+ fetchOverviewTrend().catch((error) => {
72625
+ console.error("[PlantHeadView] Failed to fetch operations overview trend", error);
72626
+ }).finally(() => {
72627
+ if (!cancelled) {
72628
+ setIsTrendLoading(false);
72629
+ }
72630
+ });
72631
+ return () => {
72632
+ cancelled = true;
72633
+ };
72634
+ }, [
72635
+ companyId,
72636
+ dateRange.endKey,
72637
+ dateRange.startKey,
72638
+ lineIdsKey,
72639
+ scopedLineIds,
72640
+ supabase,
72641
+ trendMode
72642
+ ]);
72643
+ React141__default.useEffect(() => {
72644
+ if (!supabase || !companyId) return void 0;
72645
+ if (scopedLineIds.length === 0) {
72646
+ setIdleReasonBreakdown([]);
72647
+ setIsIdleReasonBreakdownLoading(false);
72648
+ return void 0;
72649
+ }
72650
+ let cancelled = false;
72651
+ setIdleReasonBreakdown([]);
72652
+ setIsIdleReasonBreakdownLoading(true);
72653
+ const fetchIdleReasonBreakdown = async () => {
72654
+ const params = new URLSearchParams({
72655
+ company_id: companyId,
72656
+ start_date: dateRange.startKey,
72657
+ end_date: dateRange.endKey,
72658
+ trend_shift_mode: trendMode,
72659
+ line_ids: scopedLineIds.join(",")
72660
+ });
72661
+ const response = await fetchBackendJson(
72662
+ supabase,
72663
+ `/api/dashboard/operations-overview/idle-reason-breakdown?${params.toString()}`
72664
+ );
72665
+ if (!cancelled) {
72666
+ setIdleReasonBreakdown(response.idle_reason_breakdown || []);
72667
+ }
72668
+ };
72669
+ fetchIdleReasonBreakdown().catch((error) => {
72670
+ console.error("[PlantHeadView] Failed to fetch idle reason breakdown", error);
72671
+ if (!cancelled) {
72672
+ setIdleReasonBreakdown([]);
72673
+ }
72674
+ }).finally(() => {
72675
+ if (!cancelled) {
72676
+ setIsIdleReasonBreakdownLoading(false);
72677
+ }
72678
+ });
72679
+ return () => {
72680
+ cancelled = true;
72681
+ };
72682
+ }, [
72683
+ companyId,
72684
+ dateRange.endKey,
72685
+ dateRange.startKey,
72686
+ lineIdsKey,
72687
+ scopedLineIds,
72688
+ supabase,
72689
+ trendMode
72690
+ ]);
72691
+ React141__default.useEffect(() => {
72692
+ if (!supabase || !companyId) return void 0;
72693
+ if (scopedLineIds.length === 0) {
72694
+ setImprovements([]);
72695
+ setIsImprovementsLoading(false);
72696
+ return void 0;
72697
+ }
72698
+ let cancelled = false;
72699
+ setIsImprovementsLoading(true);
72700
+ const fetchImprovements = async () => {
72701
+ const params = new URLSearchParams({
72702
+ company_id: companyId,
72703
+ status: "open",
72704
+ limit: "200",
72705
+ line_ids: scopedLineIds.join(",")
72706
+ });
72707
+ const response = await fetchBackendJson(
72708
+ supabase,
72709
+ `/api/improvement-center/recommendations?${params.toString()}`
72710
+ );
72711
+ if (cancelled) return;
72712
+ const allowedLineIds = new Set(scopedLineIds);
72713
+ const scopedRecommendations = (response.recommendations || []).filter((recommendation) => {
72714
+ return !recommendation.line_id || allowedLineIds.has(recommendation.line_id);
72715
+ });
72716
+ const nextImprovements = shuffle(scopedRecommendations).slice(0, 3).map((recommendation) => ({
72717
+ id: recommendation.id,
72718
+ title: recommendation.title?.trim() || "Untitled issue",
72719
+ impact: buildImprovementImpact(recommendation),
72720
+ metric: buildImprovementMetric(recommendation)
72721
+ }));
72722
+ setImprovements(nextImprovements);
72723
+ };
72724
+ fetchImprovements().catch((error) => {
72725
+ console.error("[PlantHeadView] Failed to fetch improvements", error);
72726
+ if (!cancelled) {
72727
+ setImprovements([]);
72728
+ }
72729
+ }).finally(() => {
72730
+ if (!cancelled) {
72731
+ setIsImprovementsLoading(false);
72732
+ }
72733
+ });
72734
+ return () => {
72735
+ cancelled = true;
72736
+ };
72737
+ }, [companyId, lineIdsKey, scopedLineIds, supabase]);
72738
+ const availableLineModes = overview.scope?.available_line_modes;
72739
+ React141__default.useEffect(() => {
72740
+ const hasOutput = !!availableLineModes?.has_output;
72741
+ const hasUptime = !!availableLineModes?.has_uptime;
72742
+ if (hasOutput && !hasUptime && poorestLineMode !== "output") {
72743
+ setPoorestLineMode("output");
72744
+ } else if (hasUptime && !hasOutput && poorestLineMode !== "uptime") {
72745
+ setPoorestLineMode("uptime");
72746
+ }
72747
+ }, [availableLineModes?.has_output, availableLineModes?.has_uptime, poorestLineMode]);
72748
+ const comparisonLabel = React141__default.useMemo(
72749
+ () => formatComparisonWindow(overview.scope?.current_range?.day_count ?? null),
72750
+ [overview.scope?.current_range?.day_count]
72751
+ );
72752
+ const plantEfficiencyBadge = React141__default.useMemo(() => {
72753
+ return buildDeltaBadge(overview.summary?.plant_efficiency?.delta_pp, {
72754
+ positiveIsGood: true,
72755
+ formatter: (value) => `${value >= 0 ? "+" : ""}${roundOne(value)}%`,
72756
+ comparisonLabel
72757
+ });
72758
+ }, [comparisonLabel, overview.summary?.plant_efficiency?.delta_pp]);
72759
+ const idleBadge = React141__default.useMemo(() => {
72760
+ return buildDeltaBadge(overview.summary?.avg_idle_per_workstation?.delta_seconds, {
72761
+ positiveIsGood: false,
72762
+ formatter: (value) => formatSignedIdleDuration(value),
72763
+ comparisonLabel
72764
+ });
72765
+ }, [comparisonLabel, overview.summary?.avg_idle_per_workstation?.delta_seconds]);
72766
+ const trendData = React141__default.useMemo(() => {
72767
+ return (overview.trend?.points || []).map((point) => ({
72768
+ name: point.date ? format(parseDateKeyToDate(point.date), "MMM d") : "",
72769
+ efficiency: (() => {
72770
+ const value = toNumber3(point.avg_efficiency);
72771
+ return value === null ? void 0 : value;
72772
+ })()
72773
+ }));
72774
+ }, [overview.trend?.points]);
72775
+ const trendPlayKey = React141__default.useMemo(() => {
72776
+ return `${trendViewOpenNonce}:${trendFetchNonce}`;
72777
+ }, [trendFetchNonce, trendViewOpenNonce]);
72778
+ const idleBreakdown = React141__default.useMemo(() => {
72779
+ return idleReasonBreakdown.map((item) => ({
72780
+ name: item.reason?.trim() || "Unknown",
72781
+ value: toNumber3(item.percentage) || 0,
72782
+ totalDurationSeconds: toNumber3(item.total_duration_seconds),
72783
+ efficiencyLossPercentage: toNumber3(item.efficiency_loss_percentage),
72784
+ contributors: (item.contributors || []).map((contributor) => ({
72785
+ workspaceId: contributor.workspace_id || "",
72786
+ workspaceName: contributor.workspace_name?.trim() || "Unknown",
72787
+ totalDurationSeconds: toNumber3(contributor.total_duration_seconds),
72788
+ percentageWithinReason: toNumber3(contributor.percentage_within_reason)
72789
+ }))
72790
+ })).filter((item) => item.value > 0);
72791
+ }, [idleReasonBreakdown]);
72792
+ const mergedPoorestLines = React141__default.useMemo(() => {
72793
+ const rows = overview.poorest_lines?.[poorestLineMode] || [];
72794
+ return rows.slice(0, 3).map((line) => {
72795
+ const lineId = line.line_id || "";
72796
+ const supervisors = supervisorsByLineId.get(lineId) || [];
72797
+ const supervisor = supervisors[0];
72798
+ return {
72799
+ id: lineId,
72800
+ name: line.line_name?.trim() || "Unknown Line",
72801
+ efficiency: roundOne(toNumber3(line.avg_efficiency) || 0),
72802
+ previousEfficiency: toNumber3(line.previous_avg_efficiency),
72803
+ delta: toNumber3(line.delta_pp),
72804
+ supervisor: supervisor?.displayName || "Unassigned",
72805
+ supervisorImage: supervisor?.profilePhotoUrl ?? null
72806
+ };
72807
+ });
72808
+ }, [overview.poorest_lines, poorestLineMode, supervisorsByLineId]);
72809
+ const showPoorestModeToggle = !!availableLineModes?.has_output && !!availableLineModes?.has_uptime;
72810
+ availableLineModes?.has_uptime && !availableLineModes?.has_output ? "Uptime" : "Output";
72811
+ const poorestMetricLabel = poorestLineMode === "uptime" ? "Uptime" : "Efficiency";
72812
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-h-screen bg-slate-50 w-full font-sans", children: [
72813
+ /* @__PURE__ */ jsx("header", { className: "sticky top-0 z-10 bg-white border-b flex-shrink-0 shadow-sm", children: /* @__PURE__ */ jsxs("div", { className: "px-3 sm:px-4 md:px-6 py-2 sm:py-3 relative", children: [
72814
+ /* @__PURE__ */ jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
72815
+ mobileMenuContext ? /* @__PURE__ */ jsx(
72816
+ HamburgerButton,
72817
+ {
72818
+ onClick: mobileMenuContext.onMobileMenuOpen,
72819
+ className: "flex-shrink-0 -ml-1"
72820
+ }
72821
+ ) : /* @__PURE__ */ jsx("div", { className: "w-8 flex-shrink-0" }),
72822
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center", children: [
72823
+ /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-gray-900 text-center px-1 truncate max-w-[200px]", children: "Operations Overview" }),
72824
+ /* @__PURE__ */ jsxs("span", { className: "text-[10px] font-medium text-slate-500 text-center mt-0.5", children: [
72825
+ format(parseDateKeyToDate(dateRange.startKey), "do MMM"),
72826
+ " - ",
72827
+ format(parseDateKeyToDate(dateRange.endKey), "do MMM, yyyy")
72828
+ ] })
72829
+ ] }),
72830
+ /* @__PURE__ */ jsxs("div", { className: "flex-shrink-0 flex items-center gap-1.5", children: [
72831
+ /* @__PURE__ */ jsx(
72832
+ MonthlyRangeFilter_default,
72833
+ {
72834
+ month: parseDateKeyToDate(dateRange.startKey).getMonth(),
72835
+ year: parseDateKeyToDate(dateRange.startKey).getFullYear(),
72836
+ timezone: appTimezone,
72837
+ value: dateRange,
72838
+ onChange: setDateRange,
72839
+ showLabel: false
72840
+ }
72841
+ ),
72842
+ /* @__PURE__ */ jsxs(
72843
+ "button",
72844
+ {
72845
+ ref: mobileFilterButtonRef,
72846
+ onClick: () => setIsFilterOpen(!isFilterOpen),
72847
+ className: `p-2 rounded-full transition-colors relative ${isFilterOpen || trendMode !== "all" ? "bg-blue-50" : "active:bg-gray-100"}`,
72848
+ "aria-label": "Open filters",
72849
+ children: [
72850
+ /* @__PURE__ */ jsx(Filter, { className: `w-5 h-5 ${trendMode !== "all" ? "text-blue-600" : "text-gray-700"}` }),
72851
+ trendMode !== "all" && /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1 flex items-center justify-center w-4 h-4 bg-blue-600 text-white text-[10px] rounded-full font-bold", children: "1" })
72852
+ ]
72853
+ }
72854
+ )
72855
+ ] })
72856
+ ] }) }),
72857
+ /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center relative min-h-[56px]", children: [
72858
+ /* @__PURE__ */ jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center pointer-events-none", children: [
72859
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight text-center pointer-events-auto leading-tight mb-0.5", children: "Operations Overview" }),
72860
+ /* @__PURE__ */ jsxs("span", { className: "text-xs sm:text-sm font-medium text-slate-500 text-center pointer-events-auto", children: [
72861
+ format(parseDateKeyToDate(dateRange.startKey), "do MMMM, yyyy"),
72862
+ " - ",
72863
+ format(parseDateKeyToDate(dateRange.endKey), "do MMMM, yyyy")
72864
+ ] })
72865
+ ] }),
72866
+ /* @__PURE__ */ jsxs("div", { className: "absolute right-0 flex items-center gap-3", children: [
72867
+ /* @__PURE__ */ jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsx(
72868
+ MonthlyRangeFilter_default,
72869
+ {
72870
+ month: parseDateKeyToDate(dateRange.startKey).getMonth(),
72871
+ year: parseDateKeyToDate(dateRange.startKey).getFullYear(),
72872
+ timezone: appTimezone,
72873
+ value: dateRange,
72874
+ onChange: setDateRange,
72875
+ showLabel: false
72876
+ }
72877
+ ) }),
72878
+ /* @__PURE__ */ jsxs(
72879
+ "button",
72880
+ {
72881
+ ref: filterButtonRef,
72882
+ onClick: () => setIsFilterOpen(!isFilterOpen),
72883
+ className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || trendMode !== "all" ? "border-blue-500 bg-blue-50 text-blue-700 ring-1 ring-blue-500" : "border-slate-200 bg-white text-slate-700 hover:bg-slate-50"}`,
72884
+ "aria-label": "Open filters",
72885
+ children: [
72886
+ /* @__PURE__ */ jsx(Filter, { className: `w-[18px] h-[18px] ${trendMode !== "all" ? "text-blue-600" : "text-slate-500"}` }),
72887
+ "Filters",
72888
+ /* @__PURE__ */ jsx(ChevronDown, { className: `w-4 h-4 ml-0.5 transition-transform duration-200 ${isFilterOpen ? "rotate-180" : ""}` })
72889
+ ]
72890
+ }
72891
+ )
72892
+ ] })
72893
+ ] }) }),
72894
+ isFilterOpen && /* @__PURE__ */ jsxs("div", { ref: filterRef, className: "absolute right-3 sm:right-4 md:right-5 lg:right-6 top-full mt-2 w-72 bg-white rounded-xl shadow-xl border border-gray-100 p-4 z-50", children: [
72895
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
72896
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Filter View" }),
72897
+ trendMode !== "all" && /* @__PURE__ */ jsx(
72898
+ "button",
72899
+ {
72900
+ onClick: () => {
72901
+ setTrendMode("all");
72902
+ setIsFilterOpen(false);
72903
+ },
72904
+ className: "text-xs text-red-600 hover:text-red-700 font-medium",
72905
+ children: "Clear all"
72906
+ }
72907
+ )
72908
+ ] }),
72909
+ /* @__PURE__ */ jsx("div", { className: "space-y-3", children: /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
72910
+ /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: "Shift" }),
72911
+ /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
72912
+ "select",
72913
+ {
72914
+ value: trendMode,
72915
+ onChange: (e) => setTrendMode(e.target.value),
72916
+ className: "w-full appearance-none pl-3 pr-8 py-2 text-sm bg-gray-50 border border-gray-200 hover:border-gray-300 rounded-lg text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-white transition-all cursor-pointer",
72917
+ 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` },
72918
+ children: [
72919
+ /* @__PURE__ */ jsx("option", { value: "all", children: "All Shifts" }),
72920
+ /* @__PURE__ */ jsx("option", { value: "day", children: "Day Shift" }),
72921
+ /* @__PURE__ */ jsx("option", { value: "night", children: "Night Shift" })
72922
+ ]
72923
+ }
72924
+ ) })
72925
+ ] }) })
72926
+ ] })
72927
+ ] }) }),
72928
+ /* @__PURE__ */ jsxs("div", { className: "p-4 sm:p-6 pb-6 max-w-[1800px] mx-auto w-full flex-1 min-h-0 overflow-y-auto flex flex-col gap-5", children: [
72929
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-5", children: [
72930
+ /* @__PURE__ */ jsxs(
72931
+ "div",
72932
+ {
72933
+ 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",
72934
+ children: [
72935
+ /* @__PURE__ */ jsx("div", { className: "flex justify-between items-center mb-1", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Overall Efficiency" }) }),
72936
+ isSnapshotLoading ? /* @__PURE__ */ jsx(OverviewMetricCardSkeleton, {}) : overview.summary?.plant_efficiency?.current !== null && overview.summary?.plant_efficiency?.current !== void 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:gap-3 mt-1", children: [
72937
+ /* @__PURE__ */ jsxs("span", { className: "text-2xl sm:text-3xl font-bold text-slate-800 tracking-tight", children: [
72938
+ roundOne(overview.summary.plant_efficiency.current),
72939
+ "%"
72940
+ ] }),
72941
+ /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${plantEfficiencyBadge.className}`, children: [
72942
+ plantEfficiencyBadge.icon === "up" ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : plantEfficiencyBadge.icon === "down" ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
72943
+ /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: plantEfficiencyBadge.text })
72944
+ ] })
72945
+ ] }) : /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No efficiency data available" })
72946
+ ]
72947
+ }
72948
+ ),
72949
+ /* @__PURE__ */ jsxs(
72950
+ "div",
72951
+ {
72952
+ 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",
72953
+ children: [
72954
+ /* @__PURE__ */ jsx("div", { className: "flex justify-between items-center mb-1", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Idle Time per Workstation" }) }),
72955
+ isSnapshotLoading ? /* @__PURE__ */ jsx(OverviewMetricCardSkeleton, {}) : overview.summary?.avg_idle_per_workstation?.current_seconds !== null && overview.summary?.avg_idle_per_workstation?.current_seconds !== void 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:gap-3 mt-1", children: [
72956
+ /* @__PURE__ */ 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) }),
72957
+ /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${idleBadge.className}`, children: [
72958
+ idleBadge.icon === "up" ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : idleBadge.icon === "down" ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
72959
+ /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: idleBadge.text })
72960
+ ] })
72961
+ ] }) : /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No idle time data available" })
72962
+ ]
72963
+ }
72964
+ )
72965
+ ] }),
72966
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-h-0 grid grid-cols-1 xl:grid-cols-2 gap-5 auto-rows-fr", children: [
72967
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-rows-1 xl:grid-rows-2 gap-5 min-h-0", children: [
72968
+ /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-slate-100 flex flex-col overflow-hidden", children: [
72969
+ /* @__PURE__ */ jsxs("div", { className: "px-5 py-4 border-b border-slate-50 flex justify-between items-center gap-3 flex-wrap", children: [
72970
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 flex-wrap", children: [
72971
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Poorest Performers" }),
72972
+ showPoorestModeToggle && /* @__PURE__ */ jsxs("div", { className: "flex bg-slate-100 p-0.5 rounded-lg", children: [
72973
+ /* @__PURE__ */ jsx(
72974
+ "button",
72975
+ {
72976
+ type: "button",
72977
+ onClick: () => setPoorestLineMode("output"),
72978
+ className: `px-3 py-1 text-[11px] font-bold rounded-md ${poorestLineMode === "output" ? "bg-white text-slate-800 shadow-sm" : "text-slate-500 hover:text-slate-800"}`,
72979
+ children: "Output"
72980
+ }
72981
+ ),
72982
+ /* @__PURE__ */ jsx(
72983
+ "button",
72984
+ {
72985
+ type: "button",
72986
+ onClick: () => setPoorestLineMode("uptime"),
72987
+ className: `px-3 py-1 text-[11px] font-bold rounded-md ${poorestLineMode === "uptime" ? "bg-white text-slate-800 shadow-sm" : "text-slate-500 hover:text-slate-800"}`,
72988
+ children: "Uptime"
72989
+ }
72990
+ )
72991
+ ] })
72992
+ ] }),
72993
+ /* @__PURE__ */ jsx(
72994
+ "button",
72995
+ {
72996
+ type: "button",
72997
+ onClick: () => navigate("/kpis"),
72998
+ className: "text-[11px] font-bold text-slate-500 hover:text-slate-800 transition-colors",
72999
+ children: "View All"
73000
+ }
73001
+ )
73002
+ ] }),
73003
+ /* @__PURE__ */ jsx("div", { className: "flex-1 flex flex-col p-0 overflow-auto", children: /* @__PURE__ */ jsxs("div", { className: "divide-y divide-slate-50 flex-1 px-5", children: [
73004
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2", children: [
73005
+ /* @__PURE__ */ jsx("div", { className: "font-semibold text-slate-400 text-[10px] uppercase tracking-wider min-w-[120px]", children: "Line" }),
73006
+ /* @__PURE__ */ jsx("div", { className: "font-semibold text-slate-400 text-[10px] uppercase tracking-wider text-left shrink-0 min-w-[110px] flex items-center gap-2", children: poorestMetricLabel })
73007
+ ] }),
73008
+ isSnapshotLoading ? /* @__PURE__ */ jsx(OverviewListSkeleton, {}) : mergedPoorestLines.length > 0 ? mergedPoorestLines.map((line) => {
73009
+ const lineDelta = buildLineDeltaTone(line.delta, comparisonLabel);
73010
+ return /* @__PURE__ */ jsx(
73011
+ "div",
73012
+ {
73013
+ onClick: () => navigate(`/kpis/${line.id}`),
73014
+ className: "block py-3 hover:bg-slate-50/50 transition-colors cursor-pointer group relative",
73015
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
73016
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
73017
+ /* @__PURE__ */ jsx("div", { className: "w-8 h-8 rounded-full bg-slate-100 border border-slate-200 overflow-hidden flex-shrink-0", children: line.supervisorImage ? /* @__PURE__ */ jsx(
73018
+ "img",
73019
+ {
73020
+ src: line.supervisorImage,
73021
+ alt: line.supervisor,
73022
+ className: "w-full h-full object-cover"
73023
+ }
73024
+ ) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center text-[10px] font-bold text-slate-500", children: line.supervisor.split(" ").map((part) => part[0]).join("").slice(0, 2) }) }),
73025
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
73026
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
73027
+ /* @__PURE__ */ jsx("div", { className: "font-bold text-slate-800 text-[13px] truncate group-hover:text-indigo-600 transition-colors", children: line.name }),
73028
+ /* @__PURE__ */ jsxs(
73029
+ "button",
73030
+ {
73031
+ type: "button",
73032
+ onClick: (event) => {
73033
+ event.stopPropagation();
73034
+ console.log(`Notify ${line.supervisor}`);
73035
+ },
73036
+ className: "flex items-center gap-1 text-[9px] font-bold text-slate-500 bg-slate-100 px-1.5 py-0.5 rounded transition-colors hover:bg-slate-200 hover:text-slate-700",
73037
+ children: [
73038
+ /* @__PURE__ */ jsx(Bell, { className: "w-2.5 h-2.5" }),
73039
+ "Notify"
73040
+ ]
73041
+ }
73042
+ )
73043
+ ] }),
73044
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 mt-0.5 flex-wrap", children: /* @__PURE__ */ jsx("span", { className: "text-[10px] text-slate-400 font-medium", children: line.supervisor }) })
73045
+ ] })
73046
+ ] }),
73047
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 shrink-0 justify-start min-w-[110px]", children: [
73048
+ /* @__PURE__ */ jsxs("div", { className: "text-[15px] font-bold text-slate-800", children: [
73049
+ line.efficiency,
73050
+ "%"
73051
+ ] }),
73052
+ line.delta !== null && line.delta !== void 0 && Number.isFinite(line.delta) ? /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-0.5 px-2 py-0.5 rounded-full ${line.delta >= 0 ? "bg-[#ecfdf5] text-[#059669]" : "bg-[#FEF2F2] text-[#DC2626]"}`, children: [
73053
+ line.delta >= 0 ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3", strokeWidth: 2.5 }) : /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3", strokeWidth: 2.5 }),
73054
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold", children: lineDelta.text.split(" vs ")[0].replace("+", "") })
73055
+ ] }) : /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0.5 px-2 py-0.5 rounded-full bg-slate-50 text-slate-400", children: /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold", children: "\u2014" }) })
73056
+ ] })
73057
+ ] })
73058
+ },
73059
+ line.id
73060
+ );
73061
+ }) : /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-slate-400", children: `No ${poorestLineMode} line data available` })
73062
+ ] }) })
73063
+ ] }),
73064
+ /* @__PURE__ */ jsxs(
73065
+ "div",
73066
+ {
73067
+ className: "bg-white rounded-xl shadow-sm border border-slate-100 flex flex-col overflow-hidden text-left",
73068
+ children: [
73069
+ /* @__PURE__ */ jsx("div", { className: "px-5 py-4 flex-none flex justify-between items-center border-b border-slate-50/50 relative", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Idle Time Breakdown" }) }),
73070
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 p-4 pt-2 relative", children: isIdleReasonBreakdownLoading ? /* @__PURE__ */ jsx(OverviewIdleBreakdownSkeleton, {}) : /* @__PURE__ */ jsx(
73071
+ IdleTimeReasonChart,
73072
+ {
73073
+ data: idleBreakdown,
73074
+ isLoading: false,
73075
+ hideTotalDuration: true
73076
+ }
73077
+ ) })
73078
+ ]
73079
+ }
73080
+ )
73081
+ ] }),
73082
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-rows-1 xl:grid-rows-2 gap-5 min-h-0", children: [
73083
+ /* @__PURE__ */ jsxs(
73084
+ "div",
73085
+ {
73086
+ className: "bg-white rounded-xl shadow-[0_2px_10px_-3px_rgba(6,81,237,0.1)] border border-slate-100 flex flex-col overflow-hidden text-left",
73087
+ children: [
73088
+ /* @__PURE__ */ jsx("div", { className: "px-6 py-5 flex-none flex justify-between items-center border-b border-slate-50/50", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Efficiency Trend" }) }),
73089
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 w-full p-4 pt-4 relative", children: isTrendLoading ? /* @__PURE__ */ jsx(OverviewChartSkeleton, {}) : /* @__PURE__ */ jsx("div", { className: "absolute inset-0 pb-2 pr-4 pl-1", children: /* @__PURE__ */ jsx(
73090
+ LineChart,
73091
+ {
73092
+ data: trendData,
73093
+ lines: efficiencyLineConfig,
73094
+ xAxisDataKey: "name",
73095
+ yAxisUnit: "%",
73096
+ yAxisDomain: [0, 100],
73097
+ showLegend: false,
73098
+ showGrid: true,
73099
+ fillContainer: true
73100
+ },
73101
+ trendPlayKey
73102
+ ) }) })
73103
+ ]
73104
+ }
73105
+ ),
73106
+ /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-slate-100 flex flex-col overflow-hidden", children: [
73107
+ /* @__PURE__ */ jsxs("div", { className: "px-5 py-4 flex-none flex justify-between items-center border-b border-slate-50/50", children: [
73108
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Improvements" }),
73109
+ /* @__PURE__ */ jsx(
73110
+ "button",
73111
+ {
73112
+ type: "button",
73113
+ onClick: () => navigate("/improvement-center"),
73114
+ className: "text-[11px] font-bold text-slate-500 hover:text-slate-800 transition-colors",
73115
+ children: "View All"
73116
+ }
73117
+ )
73118
+ ] }),
73119
+ /* @__PURE__ */ jsx("div", { className: "flex-1 p-0 flex flex-col px-5 py-2 justify-start overflow-auto", children: isImprovementsLoading ? /* @__PURE__ */ jsx(OverviewImprovementsSkeleton, {}) : improvements.length > 0 ? improvements.map((item) => /* @__PURE__ */ jsx(
73120
+ "div",
73121
+ {
73122
+ onClick: () => navigate("/improvement-center"),
73123
+ className: "flex items-center justify-between py-3 border-b border-slate-50 last:border-0 group cursor-pointer",
73124
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0 pr-4", children: [
73125
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsx(ArrowUpRight, { className: "w-4 h-4 text-slate-400 group-hover:text-indigo-500 transition-colors" }) }),
73126
+ /* @__PURE__ */ jsxs("div", { children: [
73127
+ /* @__PURE__ */ jsx("h4", { className: "text-[13px] font-semibold text-slate-800 truncate transition-colors group-hover:text-indigo-600 mb-0.5", children: item.title }),
73128
+ /* @__PURE__ */ jsxs("p", { className: "text-[10px] font-medium text-slate-400", children: [
73129
+ "Impact: ",
73130
+ /* @__PURE__ */ jsx("span", { className: "text-slate-500 font-semibold", children: item.impact })
73131
+ ] })
73132
+ ] })
73133
+ ] })
73134
+ },
73135
+ item.id
73136
+ )) : /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-slate-400", children: "No open improvement issues" }) })
73137
+ ] })
73138
+ ] })
73139
+ ] })
73140
+ ] })
73141
+ ] });
73142
+ };
73143
+ var PlantHeadView_default = PlantHeadView;
71588
73144
  var S3Service = class {
71589
73145
  constructor(config) {
71590
73146
  this.s3Client = null;
@@ -72061,4 +73617,4 @@ var streamProxyConfig = {
72061
73617
  }
72062
73618
  };
72063
73619
 
72064
- export { ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getReasonColor, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFullMonthRange, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeDateKeyRange, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
73620
+ export { ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getReasonColor, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFullMonthRange, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeDateKeyRange, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };