@optifye/dashboard-core 6.9.0 → 6.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -228,7 +228,7 @@ var DEFAULT_DATE_TIME_CONFIG = {
228
228
  };
229
229
  var DEFAULT_ENDPOINTS_CONFIG = {
230
230
  whatsapp: "/api/send-whatsapp-direct",
231
- agnoApiUrl: process.env.NEXT_PUBLIC_AGNO_URL || "https://optifye-agent-production.up.railway.app",
231
+ agnoApiUrl: process.env.NEXT_PUBLIC_AGNO_URL || "https://fastapi-production-111f9.up.railway.app",
232
232
  // Default AGNO API URL
233
233
  // Use environment variable for Slack webhook URL for privacy/security
234
234
  // Note: SLACK_WEBHOOK_URL is server-side only, NEXT_PUBLIC_SLACK_WEBHOOK_URL works client-side but is less secure
@@ -2793,60 +2793,135 @@ var authCoreService = {
2793
2793
  }
2794
2794
  };
2795
2795
 
2796
+ // src/lib/utils/apiClient.ts
2797
+ var ApiClient = class {
2798
+ // 5 minutes
2799
+ /**
2800
+ * Fetch with timeout, retry, and error handling
2801
+ *
2802
+ * @param url - URL to fetch
2803
+ * @param options - Fetch options plus ApiClient options
2804
+ * @returns Promise resolving to parsed JSON data
2805
+ */
2806
+ static async fetch(url, options = {}) {
2807
+ const {
2808
+ timeout = this.DEFAULT_TIMEOUT,
2809
+ retries = 1,
2810
+ retryDelay = 1e3,
2811
+ silentErrors = true,
2812
+ fallbackData = null,
2813
+ ...fetchOptions
2814
+ } = options;
2815
+ let lastError = null;
2816
+ for (let attempt = 0; attempt <= retries; attempt++) {
2817
+ const controller = new AbortController();
2818
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
2819
+ try {
2820
+ console.log(`[ApiClient] Request ${attempt > 0 ? `(retry ${attempt})` : ""}: ${url}`);
2821
+ const response = await fetch(url, {
2822
+ ...fetchOptions,
2823
+ signal: controller.signal
2824
+ });
2825
+ clearTimeout(timeoutId);
2826
+ if (!response.ok) {
2827
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
2828
+ }
2829
+ const data = await response.json();
2830
+ console.log(`[ApiClient] Success: ${url}`);
2831
+ return data;
2832
+ } catch (error) {
2833
+ clearTimeout(timeoutId);
2834
+ lastError = error;
2835
+ console.error(`[ApiClient] Error (attempt ${attempt + 1}/${retries + 1}):`, {
2836
+ url,
2837
+ error: error.message,
2838
+ isTimeout: error.name === "AbortError",
2839
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2840
+ });
2841
+ if (attempt < retries) {
2842
+ console.log(`[ApiClient] Retrying in ${retryDelay}ms...`);
2843
+ await new Promise((resolve) => setTimeout(resolve, retryDelay));
2844
+ continue;
2845
+ }
2846
+ if (silentErrors) {
2847
+ console.warn("[ApiClient] All retries exhausted, returning fallback data");
2848
+ return fallbackData;
2849
+ } else {
2850
+ throw lastError;
2851
+ }
2852
+ }
2853
+ }
2854
+ return fallbackData;
2855
+ }
2856
+ };
2857
+ ApiClient.DEFAULT_TIMEOUT = 3e5;
2858
+
2796
2859
  // src/lib/services/authService.ts
2797
2860
  var AuthService = class {
2798
2861
  /**
2799
- * Fetch enriched user session from backend
2862
+ * Fetch enriched user session from backend with 5-minute timeout
2800
2863
  * This is your SINGLE call to get ALL auth data
2801
- *
2864
+ *
2802
2865
  * @param accessToken - JWT token from Supabase
2803
2866
  * @returns Complete user session with profile, permissions, and assignments
2804
2867
  */
2805
2868
  static async getSession(accessToken) {
2806
2869
  console.log("[AuthService] Fetching session from backend...");
2807
- const response = await fetch(`${this.backendUrl}/api/auth/session`, {
2808
- headers: {
2809
- "Authorization": `Bearer ${accessToken}`,
2810
- "Content-Type": "application/json"
2811
- }
2812
- });
2813
- if (!response.ok) {
2814
- const errorText = await response.text();
2815
- console.error("[AuthService] Session fetch failed:", response.status, errorText);
2816
- throw new Error(`Failed to fetch session: ${response.statusText}`);
2870
+ try {
2871
+ const data = await ApiClient.fetch(
2872
+ `${this.backendUrl}/api/auth/session`,
2873
+ {
2874
+ headers: {
2875
+ "Authorization": `Bearer ${accessToken}`,
2876
+ "Content-Type": "application/json"
2877
+ },
2878
+ timeout: 3e5,
2879
+ // 5 minutes
2880
+ retries: 1,
2881
+ silentErrors: false
2882
+ // We want to know about auth errors
2883
+ }
2884
+ );
2885
+ console.log("[AuthService] Session loaded:", {
2886
+ user_id: data.user_id,
2887
+ role: data.role,
2888
+ company_id: data.company_id,
2889
+ has_profile: !!data.profile,
2890
+ has_permissions: !!data.permissions
2891
+ });
2892
+ return data;
2893
+ } catch (error) {
2894
+ console.error("[AuthService] Session fetch failed:", error);
2895
+ throw error;
2817
2896
  }
2818
- const data = await response.json();
2819
- console.log("[AuthService] Session loaded:", {
2820
- user_id: data.user_id,
2821
- role: data.role,
2822
- company_id: data.company_id,
2823
- has_profile: !!data.profile,
2824
- has_permissions: !!data.permissions
2825
- });
2826
- return data;
2827
2897
  }
2828
2898
  /**
2829
- * Quick validation check without full profile fetch
2899
+ * Quick validation check without full profile fetch with timeout
2830
2900
  * Use this for lightweight auth checks
2831
- *
2901
+ *
2832
2902
  * @param accessToken - JWT token from Supabase
2833
2903
  * @returns Boolean indicating if session is valid
2834
2904
  */
2835
2905
  static async validateSession(accessToken) {
2836
2906
  try {
2837
2907
  console.log("[AuthService] Validating session...");
2838
- const response = await fetch(`${this.backendUrl}/api/auth/validate`, {
2839
- method: "POST",
2840
- headers: {
2841
- "Authorization": `Bearer ${accessToken}`,
2842
- "Content-Type": "application/json"
2908
+ const data = await ApiClient.fetch(
2909
+ `${this.backendUrl}/api/auth/validate`,
2910
+ {
2911
+ method: "POST",
2912
+ headers: {
2913
+ "Authorization": `Bearer ${accessToken}`,
2914
+ "Content-Type": "application/json"
2915
+ },
2916
+ timeout: 3e5,
2917
+ // 5 minutes
2918
+ retries: 2,
2919
+ // More retries for validation
2920
+ silentErrors: true,
2921
+ fallbackData: { valid: false, user_id: "", email: "" }
2922
+ // Safe default
2843
2923
  }
2844
- });
2845
- if (!response.ok) {
2846
- console.log("[AuthService] Session validation failed:", response.status);
2847
- return false;
2848
- }
2849
- const data = await response.json();
2924
+ );
2850
2925
  const isValid3 = data.valid === true;
2851
2926
  console.log("[AuthService] Session validation result:", isValid3);
2852
2927
  return isValid3;
@@ -2856,26 +2931,27 @@ var AuthService = class {
2856
2931
  }
2857
2932
  }
2858
2933
  /**
2859
- * Get just permissions (lightweight call)
2934
+ * Get just permissions (lightweight call) with timeout
2860
2935
  * Faster than full session fetch
2861
- *
2936
+ *
2862
2937
  * @param accessToken - JWT token from Supabase
2863
2938
  * @returns User permissions and role
2864
2939
  */
2865
2940
  static async getPermissions(accessToken) {
2866
2941
  console.log("[AuthService] Fetching permissions...");
2867
- const response = await fetch(`${this.backendUrl}/api/auth/permissions`, {
2868
- headers: {
2869
- "Authorization": `Bearer ${accessToken}`,
2870
- "Content-Type": "application/json"
2942
+ const data = await ApiClient.fetch(
2943
+ `${this.backendUrl}/api/auth/permissions`,
2944
+ {
2945
+ headers: {
2946
+ "Authorization": `Bearer ${accessToken}`,
2947
+ "Content-Type": "application/json"
2948
+ },
2949
+ timeout: 3e5,
2950
+ // 5 minutes
2951
+ retries: 1,
2952
+ silentErrors: false
2871
2953
  }
2872
- });
2873
- if (!response.ok) {
2874
- const errorText = await response.text();
2875
- console.error("[AuthService] Permissions fetch failed:", response.status, errorText);
2876
- throw new Error(`Failed to fetch permissions: ${response.statusText}`);
2877
- }
2878
- const data = await response.json();
2954
+ );
2879
2955
  console.log("[AuthService] Permissions loaded for role:", data.role);
2880
2956
  return data;
2881
2957
  }
@@ -3170,7 +3246,7 @@ var SSEChatClient = class {
3170
3246
  user_id: userId,
3171
3247
  context
3172
3248
  });
3173
- const agnoApiUrl = this.baseUrl || "https://fastapi-production-111f9.up.railway.app";
3249
+ const agnoApiUrl = this.baseUrl || (process.env.NEXT_PUBLIC_AGNO_URL || "https://fastapi-production-111f9.up.railway.app");
3174
3250
  const endpoint = `${agnoApiUrl}/api/v2/chat`;
3175
3251
  console.log("[SSEClient] Posting directly to AGNO:", endpoint);
3176
3252
  const response = await fetch(endpoint, {
@@ -5807,6 +5883,67 @@ var UserManagementService = class {
5807
5883
  var createUserManagementService = (supabase) => {
5808
5884
  return new UserManagementService(supabase);
5809
5885
  };
5886
+ var SupabaseContext = React23.createContext(void 0);
5887
+ var SupabaseProvider = ({ client, children }) => {
5888
+ _setSupabaseInstance(client);
5889
+ React23.useEffect(() => {
5890
+ _setSupabaseInstance(client);
5891
+ }, [client]);
5892
+ const contextValue = React23.useMemo(() => ({ supabase: client }), [client]);
5893
+ return /* @__PURE__ */ jsxRuntime.jsx(SupabaseContext.Provider, { value: contextValue, children });
5894
+ };
5895
+ var useSupabase = () => {
5896
+ const context = React23.useContext(SupabaseContext);
5897
+ if (context === void 0) {
5898
+ throw new Error("useSupabase must be used within a SupabaseProvider.");
5899
+ }
5900
+ return context.supabase;
5901
+ };
5902
+
5903
+ // src/lib/hooks/useSessionKeepAlive.ts
5904
+ var useSessionKeepAlive = (options = {}) => {
5905
+ const {
5906
+ enabled = true,
5907
+ intervalMs = 3e5
5908
+ // 5 minutes
5909
+ } = options;
5910
+ const supabase = useSupabase();
5911
+ const intervalRef = React23.useRef(null);
5912
+ React23.useEffect(() => {
5913
+ if (!enabled || !supabase) {
5914
+ return;
5915
+ }
5916
+ const keepAlive = async () => {
5917
+ try {
5918
+ const {
5919
+ data: { session }
5920
+ } = await supabase.auth.getSession();
5921
+ if (!session) {
5922
+ console.log("[SessionKeepAlive] No session, skipping keep-alive");
5923
+ return;
5924
+ }
5925
+ console.log("[SessionKeepAlive] Pinging backend to keep session alive");
5926
+ const isValid3 = await AuthService.validateSession(session.access_token);
5927
+ if (!isValid3) {
5928
+ console.warn("[SessionKeepAlive] Session validation failed");
5929
+ } else {
5930
+ console.log("[SessionKeepAlive] Session still valid");
5931
+ }
5932
+ } catch (error) {
5933
+ console.error("[SessionKeepAlive] Error during keep-alive:", error);
5934
+ }
5935
+ };
5936
+ const initialTimeout = setTimeout(keepAlive, 1e3);
5937
+ intervalRef.current = setInterval(keepAlive, intervalMs);
5938
+ return () => {
5939
+ clearTimeout(initialTimeout);
5940
+ if (intervalRef.current) {
5941
+ clearInterval(intervalRef.current);
5942
+ intervalRef.current = null;
5943
+ }
5944
+ };
5945
+ }, [enabled, intervalMs, supabase]);
5946
+ };
5810
5947
  var AuthContext = React23.createContext({
5811
5948
  session: null,
5812
5949
  user: null,
@@ -5833,14 +5970,17 @@ var AuthProvider = ({ children }) => {
5833
5970
  const router$1 = router.useRouter();
5834
5971
  const isFetchingRef = React23.useRef(false);
5835
5972
  const lastProcessedSessionRef = React23.useRef(null);
5836
- const fetchSession = React23.useCallback(async (supabaseSession) => {
5973
+ const hasAuthenticatedRef = React23.useRef(false);
5974
+ const fetchSession = React23.useCallback(async (supabaseSession, isReauth = false) => {
5837
5975
  if (isFetchingRef.current) {
5838
5976
  console.log("[AuthContext] Already fetching, skipping duplicate request");
5839
5977
  return;
5840
5978
  }
5841
- console.log("[AuthContext] Fetching session from backend");
5979
+ console.log("[AuthContext] Fetching session from backend", { isReauth });
5842
5980
  isFetchingRef.current = true;
5843
- setLoading(true);
5981
+ if (!isReauth) {
5982
+ setLoading(true);
5983
+ }
5844
5984
  try {
5845
5985
  const enrichedUser = await AuthService.getSession(supabaseSession.access_token);
5846
5986
  const authUser = AuthService.toAuthUser(enrichedUser);
@@ -5848,6 +5988,7 @@ var AuthProvider = ({ children }) => {
5848
5988
  setSession(supabaseSession);
5849
5989
  setError(null);
5850
5990
  lastProcessedSessionRef.current = supabaseSession.access_token.substring(0, 20);
5991
+ hasAuthenticatedRef.current = true;
5851
5992
  if (!authUser.first_login_completed) {
5852
5993
  setShowOnboarding(true);
5853
5994
  }
@@ -5867,6 +6008,15 @@ var AuthProvider = ({ children }) => {
5867
6008
  });
5868
6009
  } catch (err) {
5869
6010
  console.error("[AuthContext] Failed to fetch session:", err);
6011
+ if (err.message?.includes("JWT expired") || err.message?.includes("invalid token") || err.message?.includes("token") || err.message?.includes("401")) {
6012
+ console.log("[AuthContext] Token expired or invalid, clearing session and redirecting to login");
6013
+ setUser(null);
6014
+ setSession(null);
6015
+ setError(new Error("Your session has expired. Please log in again."));
6016
+ await supabase.auth.signOut();
6017
+ router$1.replace("/login");
6018
+ return;
6019
+ }
5870
6020
  setError(err);
5871
6021
  setUser(null);
5872
6022
  if (err.message?.includes("profile")) {
@@ -5877,11 +6027,13 @@ var AuthProvider = ({ children }) => {
5877
6027
  setUser(basicUser);
5878
6028
  }
5879
6029
  } finally {
5880
- setLoading(false);
6030
+ if (!isReauth) {
6031
+ setLoading(false);
6032
+ }
5881
6033
  isFetchingRef.current = false;
5882
- console.log("[AuthContext] Loading set to false");
6034
+ console.log("[AuthContext] Loading set to false", { isReauth });
5883
6035
  }
5884
- }, []);
6036
+ }, [supabase, router$1]);
5885
6037
  const markFirstLoginCompleted = React23.useCallback(async () => {
5886
6038
  if (!user?.id || !supabase) return false;
5887
6039
  try {
@@ -5913,6 +6065,7 @@ var AuthProvider = ({ children }) => {
5913
6065
  setSession(null);
5914
6066
  setError(null);
5915
6067
  setShowOnboarding(false);
6068
+ hasAuthenticatedRef.current = false;
5916
6069
  router$1.push("/login");
5917
6070
  } catch (err) {
5918
6071
  console.error("[AuthContext] Sign out error:", err);
@@ -5921,6 +6074,48 @@ var AuthProvider = ({ children }) => {
5921
6074
  setLoading(false);
5922
6075
  }
5923
6076
  }, [supabase, router$1, authConfig]);
6077
+ useSessionKeepAlive({
6078
+ enabled: !!session,
6079
+ // Only when logged in
6080
+ intervalMs: 3e5
6081
+ // 5 minutes
6082
+ });
6083
+ React23.useEffect(() => {
6084
+ if (!session || !supabase) {
6085
+ return;
6086
+ }
6087
+ const monitorTokenExpiry = () => {
6088
+ const expiresAt = session.expires_at;
6089
+ if (!expiresAt) {
6090
+ console.warn("[AuthContext] Session has no expiry time");
6091
+ return;
6092
+ }
6093
+ const expiryTime = expiresAt * 1e3;
6094
+ const now2 = Date.now();
6095
+ const timeUntilExpiry = expiryTime - now2;
6096
+ const minutesUntilExpiry = Math.floor(timeUntilExpiry / 6e4);
6097
+ console.log(`[AuthContext] Token expires in ${minutesUntilExpiry} minutes`);
6098
+ if (minutesUntilExpiry < 5 && minutesUntilExpiry > 0) {
6099
+ console.warn("[AuthContext] Token expiring soon, attempting refresh...");
6100
+ supabase.auth.refreshSession().then(({ data, error: error2 }) => {
6101
+ if (error2) {
6102
+ console.error("[AuthContext] Token refresh failed:", error2);
6103
+ } else {
6104
+ console.log("[AuthContext] Token refreshed successfully");
6105
+ }
6106
+ });
6107
+ }
6108
+ if (timeUntilExpiry < 0) {
6109
+ console.error("[AuthContext] Token has expired, logging out");
6110
+ signOut();
6111
+ }
6112
+ };
6113
+ monitorTokenExpiry();
6114
+ const intervalId = setInterval(monitorTokenExpiry, 6e4);
6115
+ return () => {
6116
+ clearInterval(intervalId);
6117
+ };
6118
+ }, [session, supabase, signOut]);
5924
6119
  React23.useEffect(() => {
5925
6120
  if (!supabase) {
5926
6121
  console.log("[AuthContext] No Supabase client, skipping auth initialization");
@@ -5941,7 +6136,8 @@ var AuthProvider = ({ children }) => {
5941
6136
  }
5942
6137
  if (currentSession) {
5943
6138
  console.log("[AuthContext] Found existing session, fetching user data");
5944
- await fetchSession(currentSession);
6139
+ const isReauth = hasAuthenticatedRef.current;
6140
+ await fetchSession(currentSession, isReauth);
5945
6141
  } else {
5946
6142
  console.log("[AuthContext] No session found");
5947
6143
  setLoading(false);
@@ -5973,20 +6169,27 @@ var AuthProvider = ({ children }) => {
5973
6169
  }
5974
6170
  console.log("[AuthContext] Processing auth event, fetching session");
5975
6171
  lastProcessedSessionRef.current = sessionId;
5976
- await fetchSession(currentSession);
6172
+ const isReauth = hasAuthenticatedRef.current;
6173
+ await fetchSession(currentSession, isReauth);
5977
6174
  }
5978
6175
  } else if (event === "SIGNED_OUT") {
5979
6176
  console.log("[AuthContext] User signed out");
5980
6177
  lastProcessedSessionRef.current = null;
6178
+ hasAuthenticatedRef.current = false;
5981
6179
  setUser(null);
5982
6180
  setSession(null);
5983
6181
  setError(null);
5984
6182
  setShowOnboarding(false);
5985
6183
  setLoading(false);
5986
6184
  } else if (event === "TOKEN_REFRESHED") {
5987
- console.log("[AuthContext] Token refreshed");
6185
+ console.log("[AuthContext] Token refreshed automatically");
5988
6186
  if (currentSession) {
5989
6187
  setSession(currentSession);
6188
+ const expiresAt = currentSession.expires_at;
6189
+ if (expiresAt) {
6190
+ const minutesUntilExpiry = Math.floor((expiresAt * 1e3 - Date.now()) / 6e4);
6191
+ console.log(`[AuthContext] New token expires in ${minutesUntilExpiry} minutes`);
6192
+ }
5990
6193
  }
5991
6194
  }
5992
6195
  });
@@ -5994,7 +6197,7 @@ var AuthProvider = ({ children }) => {
5994
6197
  mounted = false;
5995
6198
  subscription?.unsubscribe();
5996
6199
  };
5997
- }, [supabase, fetchSession]);
6200
+ }, [supabase]);
5998
6201
  const value = {
5999
6202
  session,
6000
6203
  user,
@@ -6042,22 +6245,6 @@ function usePageOverride(key, Default) {
6042
6245
  function useOverrides() {
6043
6246
  return React23.useContext(DashboardOverridesContext);
6044
6247
  }
6045
- var SupabaseContext = React23.createContext(void 0);
6046
- var SupabaseProvider = ({ client, children }) => {
6047
- _setSupabaseInstance(client);
6048
- React23.useEffect(() => {
6049
- _setSupabaseInstance(client);
6050
- }, [client]);
6051
- const contextValue = React23.useMemo(() => ({ supabase: client }), [client]);
6052
- return /* @__PURE__ */ jsxRuntime.jsx(SupabaseContext.Provider, { value: contextValue, children });
6053
- };
6054
- var useSupabase = () => {
6055
- const context = React23.useContext(SupabaseContext);
6056
- if (context === void 0) {
6057
- throw new Error("useSupabase must be used within a SupabaseProvider.");
6058
- }
6059
- return context.supabase;
6060
- };
6061
6248
  var SubscriptionManagerContext = React23.createContext({
6062
6249
  subscriptionManager: null
6063
6250
  });
@@ -10537,6 +10724,153 @@ var useWorkspaceHealthById = (workspaceId, options) => {
10537
10724
  refetch: fetchWorkspaceHealth
10538
10725
  };
10539
10726
  };
10727
+
10728
+ // src/lib/utils/relativeTime.ts
10729
+ function formatRelativeTime(timestamp) {
10730
+ if (!timestamp) return "Never";
10731
+ try {
10732
+ const now2 = /* @__PURE__ */ new Date();
10733
+ const date = typeof timestamp === "string" ? new Date(timestamp) : timestamp;
10734
+ if (isNaN(date.getTime())) return "Invalid date";
10735
+ if (date > now2) return "Just now";
10736
+ const diffMs = now2.getTime() - date.getTime();
10737
+ const diffSeconds = Math.floor(diffMs / 1e3);
10738
+ const diffMinutes = Math.floor(diffSeconds / 60);
10739
+ const diffHours = Math.floor(diffMinutes / 60);
10740
+ const diffDays = Math.floor(diffHours / 24);
10741
+ if (diffSeconds < 60) {
10742
+ return "Less than a minute ago";
10743
+ }
10744
+ if (diffMinutes < 60) {
10745
+ const minuteLabel = diffMinutes === 1 ? "minute" : "minutes";
10746
+ return `${diffMinutes} ${minuteLabel} ago`;
10747
+ }
10748
+ if (diffHours < 24) {
10749
+ const hourLabel = diffHours === 1 ? "hour" : "hours";
10750
+ return `${diffHours} ${hourLabel} ago`;
10751
+ }
10752
+ const dayLabel = diffDays === 1 ? "day" : "days";
10753
+ return `${diffDays} ${dayLabel} ago`;
10754
+ } catch (error) {
10755
+ console.error("[formatRelativeTime] Error formatting timestamp:", error);
10756
+ return "Unknown";
10757
+ }
10758
+ }
10759
+ function getNextUpdateInterval(timestamp) {
10760
+ if (!timestamp) return 6e4;
10761
+ try {
10762
+ const now2 = /* @__PURE__ */ new Date();
10763
+ const date = typeof timestamp === "string" ? new Date(timestamp) : timestamp;
10764
+ if (isNaN(date.getTime())) return 6e4;
10765
+ const diffMs = now2.getTime() - date.getTime();
10766
+ const diffSeconds = Math.floor(diffMs / 1e3);
10767
+ const diffMinutes = Math.floor(diffSeconds / 60);
10768
+ const diffHours = Math.floor(diffMinutes / 60);
10769
+ if (diffSeconds < 60) return 1e4;
10770
+ if (diffMinutes < 60) return 6e4;
10771
+ if (diffHours < 24) return 6e4;
10772
+ return 36e5;
10773
+ } catch (error) {
10774
+ return 6e4;
10775
+ }
10776
+ }
10777
+
10778
+ // src/lib/hooks/useWorkspaceHealthStatus.ts
10779
+ var useWorkspaceHealthStatus = (workspaceId) => {
10780
+ const supabase = useSupabase();
10781
+ const [healthData, setHealthData] = React23.useState(null);
10782
+ const [loading, setLoading] = React23.useState(true);
10783
+ const [error, setError] = React23.useState(null);
10784
+ const [timeSinceUpdate, setTimeSinceUpdate] = React23.useState("Never");
10785
+ const isFetchingRef = React23.useRef(false);
10786
+ const updateIntervalRef = React23.useRef(null);
10787
+ const fetchHealthStatus = React23.useCallback(async () => {
10788
+ if (!supabase || !workspaceId || isFetchingRef.current) return;
10789
+ try {
10790
+ isFetchingRef.current = true;
10791
+ setLoading(true);
10792
+ setError(null);
10793
+ const { data, error: fetchError } = await supabase.from("workspace_health_status").select("*").eq("workspace_id", workspaceId).maybeSingle();
10794
+ if (fetchError) throw fetchError;
10795
+ if (data) {
10796
+ setHealthData(data);
10797
+ setTimeSinceUpdate(formatRelativeTime(data.last_heartbeat));
10798
+ } else {
10799
+ setHealthData(null);
10800
+ setTimeSinceUpdate("Never");
10801
+ }
10802
+ } catch (err) {
10803
+ console.error("[useWorkspaceHealthStatus] Error fetching health status:", err);
10804
+ setError({ message: err.message, code: err.code || "FETCH_ERROR" });
10805
+ setHealthData(null);
10806
+ setTimeSinceUpdate("Unknown");
10807
+ } finally {
10808
+ setLoading(false);
10809
+ isFetchingRef.current = false;
10810
+ }
10811
+ }, [supabase, workspaceId]);
10812
+ const updateDisplayTime = React23.useCallback(() => {
10813
+ if (healthData?.last_heartbeat) {
10814
+ setTimeSinceUpdate(formatRelativeTime(healthData.last_heartbeat));
10815
+ }
10816
+ }, [healthData?.last_heartbeat]);
10817
+ React23.useEffect(() => {
10818
+ fetchHealthStatus();
10819
+ }, [fetchHealthStatus]);
10820
+ React23.useEffect(() => {
10821
+ if (!supabase || !workspaceId) return;
10822
+ console.log("[useWorkspaceHealthStatus] Setting up real-time subscription for workspace:", workspaceId);
10823
+ const channel = supabase.channel(`workspace-health-status-${workspaceId}`).on(
10824
+ "postgres_changes",
10825
+ {
10826
+ event: "*",
10827
+ // Listen to all events (INSERT, UPDATE, DELETE)
10828
+ schema: "public",
10829
+ table: "workspace_health_status",
10830
+ filter: `workspace_id=eq.${workspaceId}`
10831
+ },
10832
+ (payload) => {
10833
+ console.log("[useWorkspaceHealthStatus] Real-time update received:", payload);
10834
+ if (payload.new && "last_heartbeat" in payload.new) {
10835
+ const newData = payload.new;
10836
+ setHealthData(newData);
10837
+ setTimeSinceUpdate(formatRelativeTime(newData.last_heartbeat));
10838
+ } else if (payload.eventType === "DELETE") {
10839
+ setHealthData(null);
10840
+ setTimeSinceUpdate("Never");
10841
+ }
10842
+ }
10843
+ ).subscribe((status) => {
10844
+ console.log("[useWorkspaceHealthStatus] Subscription status:", status);
10845
+ });
10846
+ return () => {
10847
+ console.log("[useWorkspaceHealthStatus] Cleaning up subscription");
10848
+ supabase.removeChannel(channel);
10849
+ };
10850
+ }, [supabase, workspaceId]);
10851
+ React23.useEffect(() => {
10852
+ if (updateIntervalRef.current) {
10853
+ clearInterval(updateIntervalRef.current);
10854
+ }
10855
+ if (!healthData?.last_heartbeat) return;
10856
+ const intervalMs = getNextUpdateInterval(healthData.last_heartbeat);
10857
+ updateIntervalRef.current = setInterval(updateDisplayTime, intervalMs);
10858
+ return () => {
10859
+ if (updateIntervalRef.current) {
10860
+ clearInterval(updateIntervalRef.current);
10861
+ }
10862
+ };
10863
+ }, [healthData?.last_heartbeat, updateDisplayTime]);
10864
+ return {
10865
+ lastHeartbeat: healthData?.last_heartbeat || null,
10866
+ timeSinceUpdate,
10867
+ isHealthy: healthData?.is_healthy ?? false,
10868
+ healthData,
10869
+ loading,
10870
+ error,
10871
+ refetch: fetchHealthStatus
10872
+ };
10873
+ };
10540
10874
  function useDateFormatter() {
10541
10875
  const { defaultTimezone, defaultLocale, dateFormatOptions, timeFormatOptions, dateTimeFormatOptions } = useDateTimeConfig();
10542
10876
  const formatDate = React23.useCallback(
@@ -10610,50 +10944,129 @@ function useAccessControl() {
10610
10944
  const userRole = React23.useMemo(() => {
10611
10945
  if (!user?.role_level) return null;
10612
10946
  const roleLevel = user.role_level;
10613
- if (roleLevel === "owner" || roleLevel === "plant_head" || roleLevel === "supervisor") {
10947
+ if (roleLevel === "owner" || roleLevel === "plant_head" || roleLevel === "supervisor" || roleLevel === "optifye") {
10614
10948
  return roleLevel;
10615
10949
  }
10616
10950
  return "supervisor";
10617
10951
  }, [user?.role_level]);
10618
- const allPages = [
10619
- "/",
10620
- "/leaderboard",
10621
- "/kpis",
10622
- "/targets",
10623
- "/shifts",
10624
- "/supervisor-management",
10625
- "/skus",
10626
- "/ai-agent",
10627
- "/help",
10628
- "/health",
10629
- "/profile",
10630
- "/workspace",
10631
- "/factory-view"
10632
- ];
10952
+ const assignedLineIds = React23.useMemo(() => {
10953
+ if (!user) return [];
10954
+ if (user.role_level === "supervisor") {
10955
+ const lines = user.properties?.line_id || user.properties?.line_ids || [];
10956
+ return Array.isArray(lines) ? lines : [];
10957
+ }
10958
+ return [];
10959
+ }, [user]);
10960
+ const assignedFactoryIds = React23.useMemo(() => {
10961
+ if (!user) return [];
10962
+ if (user.role_level === "plant_head") {
10963
+ const factories = user.properties?.factory_id || user.properties?.factory_ids || [];
10964
+ return Array.isArray(factories) ? factories : [];
10965
+ }
10966
+ return [];
10967
+ }, [user]);
10968
+ const roleAccessMap = {
10969
+ optifye: [
10970
+ "/",
10971
+ "/leaderboard",
10972
+ "/kpis",
10973
+ "/targets",
10974
+ "/shifts",
10975
+ "/supervisor-management",
10976
+ "/skus",
10977
+ "/ai-agent",
10978
+ "/help",
10979
+ "/health",
10980
+ "/profile",
10981
+ "/workspace",
10982
+ "/factory-view",
10983
+ "/team-management"
10984
+ ],
10985
+ owner: [
10986
+ "/",
10987
+ "/leaderboard",
10988
+ "/kpis",
10989
+ "/targets",
10990
+ "/shifts",
10991
+ "/supervisor-management",
10992
+ "/skus",
10993
+ "/ai-agent",
10994
+ "/help",
10995
+ "/health",
10996
+ "/profile",
10997
+ "/workspace",
10998
+ "/factory-view",
10999
+ "/team-management"
11000
+ ],
11001
+ plant_head: [
11002
+ "/",
11003
+ "/leaderboard",
11004
+ "/kpis",
11005
+ "/targets",
11006
+ "/shifts",
11007
+ "/supervisor-management",
11008
+ "/skus",
11009
+ "/ai-agent",
11010
+ "/help",
11011
+ "/health",
11012
+ "/profile",
11013
+ "/workspace",
11014
+ "/factory-view",
11015
+ "/team-management"
11016
+ ],
11017
+ supervisor: [
11018
+ "/",
11019
+ "/leaderboard",
11020
+ "/kpis",
11021
+ "/targets",
11022
+ "/shifts",
11023
+ "/skus",
11024
+ "/ai-agent",
11025
+ "/help",
11026
+ "/health",
11027
+ "/profile",
11028
+ "/workspace"
11029
+ ]
11030
+ };
10633
11031
  const accessiblePages = React23.useMemo(() => {
10634
- return allPages;
10635
- }, []);
11032
+ if (!userRole) return [];
11033
+ return roleAccessMap[userRole] || [];
11034
+ }, [userRole]);
10636
11035
  const hasAccess = React23.useMemo(() => {
10637
11036
  return (path) => {
10638
- return true;
11037
+ if (!userRole) return false;
11038
+ const basePath = path.split("?")[0].split("/").slice(0, 2).join("/");
11039
+ const hasBaseAccess = accessiblePages.includes(basePath) || accessiblePages.includes("/");
11040
+ if (userRole === "supervisor" && assignedLineIds.length > 0) {
11041
+ if (path.includes("/kpis/") || path.includes("/workspace/")) {
11042
+ const lineIdMatch = path.match(/\/kpis\/([^/?]+)/);
11043
+ if (lineIdMatch) {
11044
+ const pathLineId = lineIdMatch[1];
11045
+ return assignedLineIds.includes(pathLineId);
11046
+ }
11047
+ }
11048
+ }
11049
+ return hasBaseAccess;
10639
11050
  };
10640
- }, []);
11051
+ }, [userRole, accessiblePages, assignedLineIds]);
10641
11052
  const isPageVisible = React23.useMemo(() => {
10642
11053
  return (path) => {
10643
- return true;
11054
+ return hasAccess(path);
10644
11055
  };
10645
- }, []);
11056
+ }, [hasAccess]);
10646
11057
  const canAccessPage = React23.useMemo(() => {
10647
11058
  return (path) => {
10648
- return true;
11059
+ return hasAccess(path);
10649
11060
  };
10650
- }, []);
11061
+ }, [hasAccess]);
10651
11062
  return {
10652
11063
  userRole,
10653
11064
  hasAccess,
10654
11065
  accessiblePages,
10655
11066
  isPageVisible,
10656
- canAccessPage
11067
+ canAccessPage,
11068
+ assignedLineIds,
11069
+ assignedFactoryIds
10657
11070
  };
10658
11071
  }
10659
11072
 
@@ -10817,45 +11230,51 @@ function useHasLineAccess(lineId, configLineIds) {
10817
11230
  function useLineSupervisor(lineId) {
10818
11231
  const supabase = useSupabase();
10819
11232
  const [supervisor, setSupervisor] = React23.useState(null);
11233
+ const [supervisors, setSupervisors] = React23.useState([]);
10820
11234
  const [isLoading, setIsLoading] = React23.useState(true);
10821
11235
  const [error, setError] = React23.useState(null);
10822
- console.log("[useLineSupervisor] Hook initialized for lineId:", lineId);
10823
11236
  const fetchSupervisor = React23.useCallback(async () => {
10824
11237
  if (!lineId || !supabase) {
10825
- console.log("[useLineSupervisor] Skipping fetch - lineId or supabase missing:", { lineId, hasSupabase: !!supabase });
10826
11238
  setIsLoading(false);
10827
11239
  return;
10828
11240
  }
10829
11241
  try {
10830
11242
  setIsLoading(true);
10831
11243
  setError(null);
10832
- console.log("[useLineSupervisor] Fetching supervisor for lineId:", lineId);
10833
- const { data, error: fetchError } = await supabase.from("user_roles").select("user_id, email, properties").eq("role_level", "supervisor").filter("properties->line_id", "@>", `["${lineId}"]`).limit(1);
10834
- console.log("[useLineSupervisor] Query result:", { data, error: fetchError, lineId });
11244
+ const { data, error: fetchError } = await supabase.from("user_roles").select("user_id, email, properties").eq("role_level", "supervisor");
10835
11245
  if (fetchError) {
10836
11246
  console.error("[useLineSupervisor] Query error:", fetchError);
10837
11247
  throw fetchError;
10838
11248
  }
10839
11249
  if (data && data.length > 0) {
10840
- const supervisorData = data[0];
10841
- console.log("[useLineSupervisor] Found supervisor:", {
10842
- email: supervisorData.email,
10843
- properties: supervisorData.properties,
10844
- line_id_in_properties: supervisorData.properties?.line_id
10845
- });
10846
- const displayName = supervisorData.email.split("@")[0] || supervisorData.email;
10847
- setSupervisor({
10848
- userId: supervisorData.user_id,
10849
- email: supervisorData.email,
10850
- displayName
11250
+ const supervisorsForLine = data.filter((supervisorData) => {
11251
+ const lineIds = supervisorData.properties?.line_id || supervisorData.properties?.line_ids || [];
11252
+ const isAssigned = Array.isArray(lineIds) && lineIds.includes(lineId);
11253
+ return isAssigned;
10851
11254
  });
11255
+ if (supervisorsForLine.length > 0) {
11256
+ const allSupervisors = supervisorsForLine.map((supervisorData) => {
11257
+ const displayName = supervisorData.email.split("@")[0] || supervisorData.email;
11258
+ return {
11259
+ userId: supervisorData.user_id,
11260
+ email: supervisorData.email,
11261
+ displayName
11262
+ };
11263
+ });
11264
+ setSupervisors(allSupervisors);
11265
+ setSupervisor(allSupervisors[0]);
11266
+ } else {
11267
+ setSupervisors([]);
11268
+ setSupervisor(null);
11269
+ }
10852
11270
  } else {
10853
- console.log("[useLineSupervisor] No supervisor found for line:", lineId);
11271
+ setSupervisors([]);
10854
11272
  setSupervisor(null);
10855
11273
  }
10856
11274
  } catch (err) {
10857
- console.error("[useLineSupervisor] Error fetching supervisor:", err);
10858
- setError(err instanceof Error ? err : new Error("Failed to fetch supervisor"));
11275
+ console.error("[useLineSupervisor] Error fetching supervisors:", err);
11276
+ setError(err instanceof Error ? err : new Error("Failed to fetch supervisors"));
11277
+ setSupervisors([]);
10859
11278
  setSupervisor(null);
10860
11279
  } finally {
10861
11280
  setIsLoading(false);
@@ -10880,7 +11299,6 @@ function useLineSupervisor(lineId) {
10880
11299
  filter: `role_level=eq.supervisor`
10881
11300
  },
10882
11301
  (payload) => {
10883
- console.log("[useLineSupervisor] Real-time update received:", payload);
10884
11302
  fetchSupervisor();
10885
11303
  }
10886
11304
  ).subscribe();
@@ -10892,9 +11310,11 @@ function useLineSupervisor(lineId) {
10892
11310
  }
10893
11311
  };
10894
11312
  }, [lineId, supabase, fetchSupervisor]);
11313
+ const supervisorName = supervisors.length > 0 ? supervisors.map((s) => s.displayName).join(", ") : null;
10895
11314
  return {
10896
- supervisorName: supervisor?.displayName || null,
11315
+ supervisorName,
10897
11316
  supervisor,
11317
+ supervisors,
10898
11318
  isLoading,
10899
11319
  error
10900
11320
  };
@@ -13896,7 +14316,9 @@ var createSupabaseClient = (url, key) => supabaseJs.createClient(url, key, {
13896
14316
  autoRefreshToken: true,
13897
14317
  persistSession: true,
13898
14318
  detectSessionInUrl: true,
13899
- flowType: "pkce"
14319
+ flowType: "pkce",
14320
+ // Enable debug logging in development
14321
+ debug: process.env.NODE_ENV === "development"
13900
14322
  },
13901
14323
  db: {
13902
14324
  schema: "public"
@@ -13905,6 +14327,22 @@ var createSupabaseClient = (url, key) => supabaseJs.createClient(url, key, {
13905
14327
  global: {
13906
14328
  headers: {
13907
14329
  "x-application-name": "optifye-dashboard"
14330
+ },
14331
+ // Add global fetch timeout (5 minutes)
14332
+ fetch: async (url2, options = {}) => {
14333
+ const controller = new AbortController();
14334
+ const timeoutId = setTimeout(() => controller.abort(), 3e5);
14335
+ try {
14336
+ const response = await fetch(url2, {
14337
+ ...options,
14338
+ signal: controller.signal
14339
+ });
14340
+ clearTimeout(timeoutId);
14341
+ return response;
14342
+ } catch (error) {
14343
+ clearTimeout(timeoutId);
14344
+ throw error;
14345
+ }
13908
14346
  }
13909
14347
  }
13910
14348
  });
@@ -13919,7 +14357,29 @@ var getAnonClient = () => {
13919
14357
  autoRefreshToken: true,
13920
14358
  persistSession: true,
13921
14359
  detectSessionInUrl: true,
13922
- flowType: "pkce"
14360
+ flowType: "pkce",
14361
+ debug: process.env.NODE_ENV === "development"
14362
+ },
14363
+ global: {
14364
+ headers: {
14365
+ "x-application-name": "optifye-dashboard"
14366
+ },
14367
+ // Add global fetch timeout (5 minutes)
14368
+ fetch: async (url2, options = {}) => {
14369
+ const controller = new AbortController();
14370
+ const timeoutId = setTimeout(() => controller.abort(), 3e5);
14371
+ try {
14372
+ const response = await fetch(url2, {
14373
+ ...options,
14374
+ signal: controller.signal
14375
+ });
14376
+ clearTimeout(timeoutId);
14377
+ return response;
14378
+ } catch (error) {
14379
+ clearTimeout(timeoutId);
14380
+ throw error;
14381
+ }
14382
+ }
13923
14383
  }
13924
14384
  });
13925
14385
  };
@@ -21283,17 +21743,33 @@ var createMotionComponent = /* @__PURE__ */ createMotionComponentFactory({
21283
21743
 
21284
21744
  // ../../node_modules/framer-motion/dist/es/render/components/motion/proxy.mjs
21285
21745
  var motion = /* @__PURE__ */ createDOMMotionComponentProxy(createMotionComponent);
21746
+
21747
+ // src/assets/optifye-logo.png
21748
+ var optifye_logo_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAACFIAAASwCAYAAADSLPxEAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEyGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSfvu78nIGlkPSdXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQnPz4KPHg6eG1wbWV0YSB4bWxuczp4PSdhZG9iZTpuczptZXRhLyc+CjxyZGY6UkRGIHhtbG5zOnJkZj0naHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyc+CgogPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9JycKICB4bWxuczpBdHRyaWI9J2h0dHA6Ly9ucy5hdHRyaWJ1dGlvbi5jb20vYWRzLzEuMC8nPgogIDxBdHRyaWI6QWRzPgogICA8cmRmOlNlcT4KICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0nUmVzb3VyY2UnPgogICAgIDxBdHRyaWI6Q3JlYXRlZD4yMDI1LTAyLTE5PC9BdHRyaWI6Q3JlYXRlZD4KICAgICA8QXR0cmliOkV4dElkPmEwNzgwZWVmLWUxNjItNGE4MS1iY2I0LTgxODU3M2VkMmI5YjwvQXR0cmliOkV4dElkPgogICAgIDxBdHRyaWI6RmJJZD41MjUyNjU5MTQxNzk1ODA8L0F0dHJpYjpGYklkPgogICAgIDxBdHRyaWI6VG91Y2hUeXBlPjI8L0F0dHJpYjpUb3VjaFR5cGU+CiAgICA8L3JkZjpsaT4KICAgPC9yZGY6U2VxPgogIDwvQXR0cmliOkFkcz4KIDwvcmRmOkRlc2NyaXB0aW9uPgoKIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PScnCiAgeG1sbnM6ZGM9J2h0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvJz4KICA8ZGM6dGl0bGU+CiAgIDxyZGY6QWx0PgogICAgPHJkZjpsaSB4bWw6bGFuZz0neC1kZWZhdWx0Jz5vcHRpZnllIGxvZ28gc2V4eSAoMjEzMCB4IDEyMDAgcHgpIC0gMTwvcmRmOmxpPgogICA8L3JkZjpBbHQ+CiAgPC9kYzp0aXRsZT4KIDwvcmRmOkRlc2NyaXB0aW9u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";
21749
+ var Logo = ({
21750
+ className = "",
21751
+ alt = "Optifye"
21752
+ }) => {
21753
+ return /* @__PURE__ */ jsxRuntime.jsx(
21754
+ "img",
21755
+ {
21756
+ src: optifye_logo_default,
21757
+ alt,
21758
+ className
21759
+ }
21760
+ );
21761
+ };
21286
21762
  var OptifyeLogoLoader = ({
21287
21763
  size = "md",
21288
21764
  message,
21289
21765
  className
21290
21766
  }) => {
21291
21767
  const sizeClasses = {
21292
- sm: "w-10",
21768
+ sm: "w-10 h-10",
21293
21769
  // 40px
21294
- md: "w-16",
21770
+ md: "w-16 h-16",
21295
21771
  // 64px
21296
- lg: "w-24"
21772
+ lg: "w-24 h-24"
21297
21773
  // 96px
21298
21774
  };
21299
21775
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -21304,11 +21780,10 @@ var OptifyeLogoLoader = ({
21304
21780
  className: `flex flex-col items-center justify-center p-4 ${className || ""}`.trim(),
21305
21781
  children: [
21306
21782
  /* @__PURE__ */ jsxRuntime.jsx(
21307
- "img",
21783
+ Logo,
21308
21784
  {
21309
- src: "/optifye-logo.png",
21310
- alt: "Optifye Logo",
21311
- className: `${sizeClasses[size]} h-auto animate-pulse select-none pointer-events-none`
21785
+ className: `${sizeClasses[size]} object-contain animate-pulse select-none pointer-events-none`,
21786
+ alt: "Optifye Logo"
21312
21787
  }
21313
21788
  ),
21314
21789
  message && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 text-gray-600 text-base sm:text-sm font-medium text-center", children: message })
@@ -21320,15 +21795,65 @@ var OptifyeLogoLoader_default = OptifyeLogoLoader;
21320
21795
  var LoadingPage = ({
21321
21796
  message = "Loading Dashboard...",
21322
21797
  subMessage = "Please wait while we prepare your data",
21323
- className
21798
+ className,
21799
+ onTimeout,
21800
+ timeoutMs = 3e5
21801
+ // 5 minutes default
21324
21802
  }) => {
21325
- React23__namespace.default.useEffect(() => {
21326
- console.log("LoadingPage rendered with message:", message);
21327
- const timeout = setTimeout(() => {
21328
- console.warn("LoadingPage has been visible for more than 8 seconds. This might indicate an issue.");
21329
- }, 8e3);
21330
- return () => clearTimeout(timeout);
21331
- }, [message]);
21803
+ const [showTimeoutWarning, setShowTimeoutWarning] = React23.useState(false);
21804
+ const [timeoutReached, setTimeoutReached] = React23.useState(false);
21805
+ const warningTime = timeoutMs * 0.8;
21806
+ React23.useEffect(() => {
21807
+ console.log("[LoadingPage] Rendered with message:", message);
21808
+ const warningTimer = setTimeout(() => {
21809
+ console.warn("[LoadingPage] Loading taking longer than expected");
21810
+ setShowTimeoutWarning(true);
21811
+ }, warningTime);
21812
+ const timeoutTimer = setTimeout(() => {
21813
+ console.error("[LoadingPage] Loading timeout reached after", timeoutMs, "ms");
21814
+ setTimeoutReached(true);
21815
+ if (onTimeout) {
21816
+ onTimeout();
21817
+ }
21818
+ }, timeoutMs);
21819
+ return () => {
21820
+ clearTimeout(warningTimer);
21821
+ clearTimeout(timeoutTimer);
21822
+ };
21823
+ }, [message, timeoutMs, warningTime, onTimeout]);
21824
+ const handleResetAndTryAgain = React23.useCallback(() => {
21825
+ console.log("[LoadingPage] User initiated reset");
21826
+ const hasLocalStorage = typeof window !== "undefined" && window.localStorage;
21827
+ const hasCachedData = hasLocalStorage && localStorage.getItem("sb-zmzewpwerpaupoaoeqhh-auth-token");
21828
+ if (hasCachedData) {
21829
+ console.log("[LoadingPage] Found cached session, attempting to use it");
21830
+ window.location.reload();
21831
+ } else {
21832
+ console.log("[LoadingPage] No cached session, redirecting to login");
21833
+ if (hasLocalStorage) {
21834
+ localStorage.clear();
21835
+ sessionStorage.clear();
21836
+ }
21837
+ window.location.href = "/login";
21838
+ }
21839
+ }, []);
21840
+ if (timeoutReached) {
21841
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex h-full w-full items-center justify-center bg-slate-50 ${className || ""}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center space-y-6 text-center max-w-md", children: [
21842
+ /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "lg", message: "Loading Dashboard..." }),
21843
+ /* @__PURE__ */ jsxRuntime.jsxs(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, className: "space-y-2", children: [
21844
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base text-gray-600", children: "This is taking longer than usual" }),
21845
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Your session might have timed out" })
21846
+ ] }),
21847
+ /* @__PURE__ */ jsxRuntime.jsx(
21848
+ "button",
21849
+ {
21850
+ onClick: handleResetAndTryAgain,
21851
+ className: "mt-4 px-4 py-2 text-sm text-gray-600 hover:text-gray-900 underline transition-colors",
21852
+ children: "Reset and try again"
21853
+ }
21854
+ )
21855
+ ] }) });
21856
+ }
21332
21857
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex h-full w-full items-center justify-center bg-slate-50 ${className || ""}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center space-y-6 text-center", children: [
21333
21858
  /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "lg", message }),
21334
21859
  subMessage && /* @__PURE__ */ jsxRuntime.jsx(
@@ -21340,23 +21865,19 @@ var LoadingPage = ({
21340
21865
  transition: { delay: 0.2, duration: 0.3 },
21341
21866
  children: subMessage
21342
21867
  }
21868
+ ),
21869
+ showTimeoutWarning && !timeoutReached && /* @__PURE__ */ jsxRuntime.jsx(
21870
+ motion.p,
21871
+ {
21872
+ initial: { opacity: 0 },
21873
+ animate: { opacity: 1 },
21874
+ className: "text-sm text-gray-500 italic",
21875
+ children: "Still loading, please wait..."
21876
+ }
21343
21877
  )
21344
21878
  ] }) });
21345
21879
  };
21346
21880
  var LoadingPage_default = LoadingPage;
21347
- var AccessDeniedPage = () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen flex items-center justify-center bg-gray-50", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-md w-full bg-white shadow-lg rounded-lg p-6 text-center", children: [
21348
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "mx-auto h-12 w-12 text-red-500", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.962-.833-2.732 0L4.082 15.5c-.77.833.192 2.5 1.732 2.5z" }) }) }),
21349
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Access Denied" }),
21350
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-600 mb-4", children: "You do not have access to this dashboard. Please contact your administrator for assistance." }),
21351
- /* @__PURE__ */ jsxRuntime.jsx(
21352
- "button",
21353
- {
21354
- onClick: () => window.location.href = "/login",
21355
- className: "bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-md transition-colors",
21356
- children: "Return to Login"
21357
- }
21358
- )
21359
- ] }) });
21360
21881
  var withAuth = (WrappedComponent2, options) => {
21361
21882
  const defaultOptions = {
21362
21883
  redirectTo: "/login",
@@ -21366,22 +21887,64 @@ var withAuth = (WrappedComponent2, options) => {
21366
21887
  const WithAuthComponent = React23__namespace.memo(function WithAuthComponent2(props) {
21367
21888
  const { session, loading, error } = useAuth();
21368
21889
  const router$1 = router.useRouter();
21890
+ const [localLoading, setLocalLoading] = React23__namespace.useState(loading);
21891
+ const [loadingTimeoutReached, setLoadingTimeoutReached] = React23__namespace.useState(false);
21369
21892
  React23__namespace.useEffect(() => {
21370
21893
  if (process.env.NODE_ENV === "development" && process.env.DEBUG_AUTH === "true") {
21371
- console.log("withAuth state:", { loading, hasSession: !!session, requireAuth: defaultOptions.requireAuth });
21894
+ console.log("withAuth state:", {
21895
+ loading,
21896
+ hasSession: !!session,
21897
+ requireAuth: defaultOptions.requireAuth,
21898
+ hasError: !!error
21899
+ });
21372
21900
  }
21373
- }, [session, loading]);
21901
+ }, [session, loading, error]);
21902
+ const handleLoadingTimeout = React23__namespace.useCallback(() => {
21903
+ console.warn("[withAuth] Loading timeout reached");
21904
+ setLoadingTimeoutReached(true);
21905
+ if (typeof window !== "undefined" && localStorage.getItem("sb-zmzewpwerpaupoaoeqhh-auth-token")) {
21906
+ console.log("[withAuth] Found cached session, attempting to continue");
21907
+ setLocalLoading(false);
21908
+ } else {
21909
+ console.log("[withAuth] No cached session, redirecting to login");
21910
+ router$1.replace(defaultOptions.redirectTo);
21911
+ }
21912
+ }, [router$1]);
21374
21913
  React23__namespace.useEffect(() => {
21375
21914
  if (!loading && defaultOptions.requireAuth && !session && !error) {
21376
- console.log("Redirecting to login from withAuth");
21915
+ console.log("[withAuth] No session found, redirecting to login");
21377
21916
  router$1.replace(defaultOptions.redirectTo);
21378
21917
  }
21379
21918
  }, [session, loading, router$1, error]);
21380
- if (loading) {
21381
- return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage, { message: "Authenticating..." });
21919
+ React23__namespace.useEffect(() => {
21920
+ setLocalLoading(loading);
21921
+ }, [loading]);
21922
+ if (loading || localLoading) {
21923
+ return /* @__PURE__ */ jsxRuntime.jsx(
21924
+ LoadingPage,
21925
+ {
21926
+ message: "Authenticating...",
21927
+ timeoutMs: 3e5,
21928
+ onTimeout: handleLoadingTimeout
21929
+ }
21930
+ );
21382
21931
  }
21383
- if (error && error.message.includes("You do not have access to this dashboard")) {
21384
- return /* @__PURE__ */ jsxRuntime.jsx(AccessDeniedPage, {});
21932
+ if (error) {
21933
+ console.error("[withAuth] Auth error:", {
21934
+ message: error.message,
21935
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
21936
+ });
21937
+ if (error.message.includes("You do not have access to this dashboard")) {
21938
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen flex items-center justify-center bg-slate-50", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-md text-center space-y-4", children: [
21939
+ /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "lg", message: "Checking Access..." }),
21940
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Verifying your permissions" }),
21941
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/login", className: "text-xs text-gray-400 hover:text-gray-600 underline", children: "Return to login" })
21942
+ ] }) });
21943
+ }
21944
+ if (defaultOptions.requireAuth) {
21945
+ router$1.replace(defaultOptions.redirectTo);
21946
+ return null;
21947
+ }
21385
21948
  }
21386
21949
  if (defaultOptions.requireAuth && !session) {
21387
21950
  return null;
@@ -21418,7 +21981,7 @@ function withAccessControl(WrappedComponent2, options = {}) {
21418
21981
  }
21419
21982
  var LoginPage = ({
21420
21983
  onRateLimitCheck,
21421
- logoSrc = "/optifye-logo.png",
21984
+ logoSrc = optifye_logo_default,
21422
21985
  logoAlt = "Optifye",
21423
21986
  brandName = "Optifye"
21424
21987
  }) => {
@@ -25027,13 +25590,37 @@ var WhatsAppShareButton = ({
25027
25590
  }
25028
25591
  );
25029
25592
  };
25593
+ var AxelOrb = ({
25594
+ className = "",
25595
+ size = "md",
25596
+ animate = false
25597
+ }) => {
25598
+ const sizeClasses = {
25599
+ sm: "w-8 h-8",
25600
+ md: "w-10 h-10",
25601
+ lg: "w-12 h-12",
25602
+ xl: "w-16 h-16",
25603
+ "2xl": "w-20 h-20"
25604
+ };
25605
+ return /* @__PURE__ */ jsxRuntime.jsx(
25606
+ "div",
25607
+ {
25608
+ className: `${sizeClasses[size]} rounded-full ${animate ? "animate-float" : ""} ${className}`,
25609
+ style: {
25610
+ background: "linear-gradient(to top, #078DDB 0%, #65ADD6 33%, #A3D0E6 66%, #C7E2EC 100%)",
25611
+ boxShadow: "0 4px 12px rgba(7, 141, 219, 0.4), 0 0 20px rgba(7, 141, 219, 0.2)"
25612
+ },
25613
+ "aria-label": "Axel AI",
25614
+ role: "img"
25615
+ }
25616
+ );
25617
+ };
25030
25618
  var BreakNotificationPopup = ({
25031
25619
  activeBreaks,
25032
25620
  onDismiss,
25033
25621
  isVisible = true,
25034
25622
  className = "",
25035
- lineNames = {},
25036
- axelImagePath = "/axel-profile.png"
25623
+ lineNames = {}
25037
25624
  }) => {
25038
25625
  const [isDismissed, setIsDismissed] = React23.useState(false);
25039
25626
  const [currentTime, setCurrentTime] = React23.useState(/* @__PURE__ */ new Date());
@@ -25069,22 +25656,7 @@ var BreakNotificationPopup = ({
25069
25656
  style: { top: `${6 + index * 12}rem` },
25070
25657
  children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white text-gray-900 rounded-lg border border-gray-200 shadow-lg overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between", children: [
25071
25658
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start space-x-3 flex-1", children: [
25072
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
25073
- "img",
25074
- {
25075
- src: axelImagePath,
25076
- alt: "Axel AI",
25077
- className: "w-10 h-10 rounded-full object-cover border-2 border-gray-200 shadow-sm",
25078
- onError: (e) => {
25079
- const target = e.currentTarget;
25080
- target.style.display = "none";
25081
- const fallback = document.createElement("div");
25082
- fallback.className = "w-10 h-10 rounded-full bg-blue-500 flex items-center justify-center text-white font-bold text-base shadow-sm border-2 border-gray-200";
25083
- fallback.textContent = "A";
25084
- target.parentElement?.appendChild(fallback);
25085
- }
25086
- }
25087
- ) }),
25659
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(AxelOrb, { size: "md" }) }),
25088
25660
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
25089
25661
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1.5", children: [
25090
25662
  /* @__PURE__ */ jsxRuntime.jsxs("h4", { className: "font-semibold text-sm text-gray-900", children: [
@@ -25284,8 +25856,7 @@ var AxelNotificationPopup = ({
25284
25856
  suggestion,
25285
25857
  isVisible = true,
25286
25858
  onDismiss,
25287
- className = "",
25288
- axelImagePath = "/axel-profile.png"
25859
+ className = ""
25289
25860
  }) => {
25290
25861
  const [isDismissed, setIsDismissed] = React23.useState(false);
25291
25862
  React23.useEffect(() => {
@@ -25331,22 +25902,7 @@ var AxelNotificationPopup = ({
25331
25902
  className: "p-3",
25332
25903
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between", children: [
25333
25904
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start space-x-3 flex-1", children: [
25334
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
25335
- "img",
25336
- {
25337
- src: axelImagePath,
25338
- alt: "Axel AI",
25339
- className: "w-10 h-10 rounded-full object-cover border-2 border-gray-200 shadow-sm",
25340
- onError: (e) => {
25341
- const target = e.currentTarget;
25342
- target.style.display = "none";
25343
- const fallback = document.createElement("div");
25344
- fallback.className = "w-10 h-10 rounded-full bg-blue-500 flex items-center justify-center text-white font-bold text-base shadow-sm border-2 border-gray-200";
25345
- fallback.textContent = "A";
25346
- target.parentElement?.appendChild(fallback);
25347
- }
25348
- }
25349
- ) }),
25905
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(AxelOrb, { size: "md" }) }),
25350
25906
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
25351
25907
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1.5", children: [
25352
25908
  /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "font-semibold text-sm text-gray-900", children: suggestion.title }),
@@ -25797,6 +26353,140 @@ var TimePickerDropdown = ({
25797
26353
  ] })
25798
26354
  ] });
25799
26355
  };
26356
+ var SilentErrorBoundary = class extends React23__namespace.default.Component {
26357
+ constructor(props) {
26358
+ super(props);
26359
+ this.handleClearAndReload = () => {
26360
+ console.log("[ErrorBoundary] User initiated reset");
26361
+ if (typeof window !== "undefined") {
26362
+ try {
26363
+ localStorage.clear();
26364
+ sessionStorage.clear();
26365
+ console.log("[ErrorBoundary] Cleared all storage");
26366
+ } catch (error) {
26367
+ console.error("[ErrorBoundary] Failed to clear storage:", error);
26368
+ }
26369
+ }
26370
+ window.location.href = "/login";
26371
+ };
26372
+ this.state = {
26373
+ hasError: false,
26374
+ errorCount: 0,
26375
+ lastError: null,
26376
+ errorInfo: null
26377
+ };
26378
+ }
26379
+ static getDerivedStateFromError(error) {
26380
+ return { hasError: true };
26381
+ }
26382
+ componentDidCatch(error, errorInfo) {
26383
+ console.error("[ErrorBoundary] Caught render error:", {
26384
+ error: error.message,
26385
+ stack: error.stack,
26386
+ componentStack: errorInfo.componentStack,
26387
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
26388
+ });
26389
+ this.setState((prev) => ({
26390
+ errorCount: prev.errorCount + 1,
26391
+ lastError: error,
26392
+ errorInfo
26393
+ }));
26394
+ try {
26395
+ if (typeof window !== "undefined" && window.mixpanel) {
26396
+ window.mixpanel.track("React Render Error", {
26397
+ error: error.message,
26398
+ component: errorInfo.componentStack?.split("\n")[1] || "unknown",
26399
+ errorCount: this.state.errorCount + 1
26400
+ });
26401
+ }
26402
+ } catch (analyticsError) {
26403
+ console.warn("[ErrorBoundary] Analytics tracking failed:", analyticsError);
26404
+ }
26405
+ }
26406
+ render() {
26407
+ if (!this.state.hasError) {
26408
+ return this.props.children;
26409
+ }
26410
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-screen w-screen items-center justify-center bg-slate-50", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center space-y-6 text-center", children: [
26411
+ /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "lg", message: "Loading Dashboard..." }),
26412
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Taking longer than usual..." }),
26413
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-4", children: /* @__PURE__ */ jsxRuntime.jsx(
26414
+ "a",
26415
+ {
26416
+ href: "#",
26417
+ onClick: (e) => {
26418
+ e.preventDefault();
26419
+ this.handleClearAndReload();
26420
+ },
26421
+ className: "text-xs text-gray-400 hover:text-gray-600 underline transition-colors",
26422
+ children: "Reset and try again"
26423
+ }
26424
+ ) }),
26425
+ process.env.NODE_ENV === "development" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-400 italic mt-4", children: "Check console for error details" })
26426
+ ] }) });
26427
+ }
26428
+ };
26429
+ var PlayPauseIndicator = ({
26430
+ show,
26431
+ isPlaying,
26432
+ duration = 600
26433
+ }) => {
26434
+ const [isVisible, setIsVisible] = React23.useState(false);
26435
+ const [isFading, setIsFading] = React23.useState(false);
26436
+ React23.useEffect(() => {
26437
+ if (show) {
26438
+ setIsVisible(true);
26439
+ setIsFading(false);
26440
+ const fadeTimer = setTimeout(() => {
26441
+ setIsFading(true);
26442
+ }, 100);
26443
+ const hideTimer = setTimeout(() => {
26444
+ setIsVisible(false);
26445
+ setIsFading(false);
26446
+ }, duration);
26447
+ return () => {
26448
+ clearTimeout(fadeTimer);
26449
+ clearTimeout(hideTimer);
26450
+ };
26451
+ }
26452
+ }, [show, duration]);
26453
+ if (!isVisible) return null;
26454
+ return /* @__PURE__ */ jsxRuntime.jsx(
26455
+ "div",
26456
+ {
26457
+ className: "absolute inset-0 flex items-center justify-center pointer-events-none z-10",
26458
+ style: {
26459
+ opacity: isFading ? 0 : 1,
26460
+ transition: `opacity ${duration - 100}ms ease-out`
26461
+ },
26462
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-black/70 rounded-full p-6", children: isPlaying ? (
26463
+ // Play icon (triangle)
26464
+ /* @__PURE__ */ jsxRuntime.jsx(
26465
+ "svg",
26466
+ {
26467
+ xmlns: "http://www.w3.org/2000/svg",
26468
+ viewBox: "0 0 24 24",
26469
+ fill: "white",
26470
+ className: "w-16 h-16",
26471
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 5v14l11-7z" })
26472
+ }
26473
+ )
26474
+ ) : (
26475
+ // Pause icon (two bars)
26476
+ /* @__PURE__ */ jsxRuntime.jsx(
26477
+ "svg",
26478
+ {
26479
+ xmlns: "http://www.w3.org/2000/svg",
26480
+ viewBox: "0 0 24 24",
26481
+ fill: "white",
26482
+ className: "w-16 h-16",
26483
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" })
26484
+ }
26485
+ )
26486
+ ) })
26487
+ }
26488
+ );
26489
+ };
25800
26490
  var ERROR_MAPPING = {
25801
26491
  1: {
25802
26492
  // MEDIA_ERR_ABORTED
@@ -25902,12 +26592,16 @@ var VideoPlayer = React23__namespace.default.forwardRef(({
25902
26592
  onLoadedMetadata,
25903
26593
  onLoadedData,
25904
26594
  onSeeking,
25905
- onSeeked
26595
+ onSeeked,
26596
+ onClick
25906
26597
  }, ref) => {
25907
26598
  const videoRef = React23.useRef(null);
25908
26599
  const playerRef = React23.useRef(null);
25909
26600
  const [isReady, setIsReady] = React23.useState(false);
25910
26601
  const [isLoading, setIsLoading] = React23.useState(true);
26602
+ const [showIndicator, setShowIndicator] = React23.useState(false);
26603
+ const [indicatorIsPlaying, setIndicatorIsPlaying] = React23.useState(false);
26604
+ const indicatorKeyRef = React23.useRef(0);
25911
26605
  const defaultOptions = {
25912
26606
  controls: false,
25913
26607
  // Always disable Video.js controls - we use custom controls
@@ -26223,6 +26917,18 @@ var VideoPlayer = React23__namespace.default.forwardRef(({
26223
26917
  dispose,
26224
26918
  isReady
26225
26919
  }));
26920
+ const handleClickWithIndicator = React23.useCallback(() => {
26921
+ if (!onClick || !playerRef.current) return;
26922
+ const player = playerRef.current;
26923
+ const willBePlaying = player.paused();
26924
+ setIndicatorIsPlaying(willBePlaying);
26925
+ setShowIndicator(false);
26926
+ setTimeout(() => {
26927
+ indicatorKeyRef.current += 1;
26928
+ setShowIndicator(true);
26929
+ }, 0);
26930
+ onClick();
26931
+ }, [onClick]);
26226
26932
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `video-player-wrapper ${className}`, style: { position: "relative", width: "100%", height: "100%" }, children: [
26227
26933
  /* @__PURE__ */ jsxRuntime.jsx(
26228
26934
  "div",
@@ -26232,7 +26938,31 @@ var VideoPlayer = React23__namespace.default.forwardRef(({
26232
26938
  "data-vjs-player": true
26233
26939
  }
26234
26940
  ),
26235
- isLoading && !externalLoadingControl && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "video-player-loading", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) })
26941
+ isLoading && !externalLoadingControl && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "video-player-loading", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
26942
+ onClick && /* @__PURE__ */ jsxRuntime.jsx(
26943
+ "div",
26944
+ {
26945
+ onClick: handleClickWithIndicator,
26946
+ style: {
26947
+ position: "absolute",
26948
+ top: 0,
26949
+ left: 0,
26950
+ right: 0,
26951
+ bottom: 0,
26952
+ zIndex: 1,
26953
+ cursor: "pointer"
26954
+ },
26955
+ "aria-label": "Click to play/pause"
26956
+ }
26957
+ ),
26958
+ onClick && /* @__PURE__ */ jsxRuntime.jsx(
26959
+ PlayPauseIndicator,
26960
+ {
26961
+ show: showIndicator,
26962
+ isPlaying: indicatorIsPlaying
26963
+ },
26964
+ indicatorKeyRef.current
26965
+ )
26236
26966
  ] });
26237
26967
  });
26238
26968
  VideoPlayer.displayName = "VideoPlayer";
@@ -26250,6 +26980,9 @@ var CroppedVideoPlayer = React23.forwardRef(({
26250
26980
  const [isVideoReady, setIsVideoReady] = React23.useState(false);
26251
26981
  const [canvasDimensions, setCanvasDimensions] = React23.useState({ width: 0, height: 0 });
26252
26982
  const [isProcessing, setIsProcessing] = React23.useState(false);
26983
+ const [showIndicator, setShowIndicator] = React23.useState(false);
26984
+ const [indicatorIsPlaying, setIndicatorIsPlaying] = React23.useState(false);
26985
+ const indicatorKeyRef = React23.useRef(0);
26253
26986
  const stopCanvasRendering = React23.useCallback(() => {
26254
26987
  if (animationFrameRef.current) {
26255
26988
  cancelAnimationFrame(animationFrameRef.current);
@@ -26428,14 +27161,26 @@ var CroppedVideoPlayer = React23.forwardRef(({
26428
27161
  };
26429
27162
  }, [stopCanvasRendering]);
26430
27163
  if (!crop) {
26431
- return /* @__PURE__ */ jsxRuntime.jsx(VideoPlayer, { ref, ...videoProps });
26432
- }
27164
+ return /* @__PURE__ */ jsxRuntime.jsx(VideoPlayer, { ref, ...videoProps, onClick });
27165
+ }
27166
+ const handleClickWithIndicator = () => {
27167
+ if (!onClick || !hiddenVideoRef.current?.player) return;
27168
+ const player = hiddenVideoRef.current.player;
27169
+ const willBePlaying = player.paused();
27170
+ setIndicatorIsPlaying(willBePlaying);
27171
+ setShowIndicator(false);
27172
+ setTimeout(() => {
27173
+ indicatorKeyRef.current += 1;
27174
+ setShowIndicator(true);
27175
+ }, 0);
27176
+ onClick();
27177
+ };
26433
27178
  return /* @__PURE__ */ jsxRuntime.jsxs(
26434
27179
  "div",
26435
27180
  {
26436
27181
  ref: videoContainerRef,
26437
27182
  className: `relative w-full h-full flex items-center justify-center bg-black ${onClick ? "cursor-pointer" : ""} ${videoProps.className || ""}`,
26438
- onClick,
27183
+ onClick: handleClickWithIndicator,
26439
27184
  children: [
26440
27185
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
26441
27186
  VideoPlayer,
@@ -26492,7 +27237,15 @@ var CroppedVideoPlayer = React23.forwardRef(({
26492
27237
  "Processing: ",
26493
27238
  isProcessing ? "Yes" : "No"
26494
27239
  ] })
26495
- ] })
27240
+ ] }),
27241
+ onClick && /* @__PURE__ */ jsxRuntime.jsx(
27242
+ PlayPauseIndicator,
27243
+ {
27244
+ show: showIndicator,
27245
+ isPlaying: indicatorIsPlaying
27246
+ },
27247
+ indicatorKeyRef.current
27248
+ )
26496
27249
  ]
26497
27250
  }
26498
27251
  );
@@ -28147,6 +28900,7 @@ var BottlenecksContent = ({
28147
28900
  const [metadataCache, setMetadataCache] = React23.useState({});
28148
28901
  const [triageClips, setTriageClips] = React23.useState([]);
28149
28902
  const [isLoadingTriageClips, setIsLoadingTriageClips] = React23.useState(false);
28903
+ const [isFullscreen, setIsFullscreen] = React23.useState(false);
28150
28904
  const categoryMetadataRef = React23.useRef([]);
28151
28905
  const currentMetadataIndexRef = React23.useRef(0);
28152
28906
  const {
@@ -29040,6 +29794,24 @@ var BottlenecksContent = ({
29040
29794
  player.pause();
29041
29795
  }
29042
29796
  };
29797
+ const toggleFullscreen = React23.useCallback((e) => {
29798
+ e.stopPropagation();
29799
+ setIsFullscreen((prev) => !prev);
29800
+ }, []);
29801
+ const exitFullscreen = React23.useCallback(() => {
29802
+ setIsFullscreen(false);
29803
+ }, []);
29804
+ React23.useEffect(() => {
29805
+ const handleEscape = (e) => {
29806
+ if (e.key === "Escape" && isFullscreen) {
29807
+ exitFullscreen();
29808
+ }
29809
+ };
29810
+ if (isFullscreen) {
29811
+ window.addEventListener("keydown", handleEscape);
29812
+ return () => window.removeEventListener("keydown", handleEscape);
29813
+ }
29814
+ }, [isFullscreen, exitFullscreen]);
29043
29815
  const getClipTypeLabel = (video) => {
29044
29816
  if (!video) return "";
29045
29817
  const currentFilter = activeFilterRef.current;
@@ -29152,7 +29924,7 @@ var BottlenecksContent = ({
29152
29924
  )
29153
29925
  ] }) })
29154
29926
  ] }) }),
29155
- filteredVideos.length > 0 && currentVideo ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: `p-4 ${triageMode ? "h-full" : "h-[calc(100%-4rem)]"}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-full group", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full h-full overflow-hidden rounded-md shadow-inner bg-gray-900", children: [
29927
+ filteredVideos.length > 0 && currentVideo && !isFullscreen ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: `p-4 ${triageMode ? "h-full" : "h-[calc(100%-4rem)]"}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-full group", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full h-full overflow-hidden rounded-md shadow-inner bg-gray-900", children: [
29156
29928
  /* @__PURE__ */ jsxRuntime.jsx(
29157
29929
  "div",
29158
29930
  {
@@ -29252,22 +30024,24 @@ var BottlenecksContent = ({
29252
30024
  ] }) })
29253
30025
  ),
29254
30026
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 p-3 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 z-10", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-white", children: [
29255
- /* @__PURE__ */ jsxRuntime.jsx(
29256
- "button",
29257
- {
29258
- onClick: (e) => {
29259
- e.stopPropagation();
29260
- togglePlayback();
29261
- },
29262
- className: "p-1.5 hover:bg-white/20 rounded-full focus:outline-none focus:ring-2 focus:ring-white/50",
29263
- "aria-label": isPlaying ? "Pause" : "Play",
29264
- children: isPlaying ? /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 00-1 1v2a1 1 0 102 0V9a1 1 0 00-1-1zm5 0a1 1 0 00-1 1v2a1 1 0 102 0V9a1 1 0 00-1-1z", clipRule: "evenodd" }) }) : /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8.118l-.001 3.764a1 1 0 001.555.832l3.196-1.882a1 1 0 000-1.664l-3.196-1.882z", clipRule: "evenodd" }) })
29265
- }
29266
- ),
29267
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-mono px-2", children: [
29268
- formatTime2(currentTime),
29269
- " / ",
29270
- formatTime2(duration)
30027
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
30028
+ /* @__PURE__ */ jsxRuntime.jsx(
30029
+ "button",
30030
+ {
30031
+ onClick: (e) => {
30032
+ e.stopPropagation();
30033
+ togglePlayback();
30034
+ },
30035
+ className: "p-1.5 hover:bg-white/20 rounded-full focus:outline-none focus:ring-2 focus:ring-white/50",
30036
+ "aria-label": isPlaying ? "Pause" : "Play",
30037
+ children: isPlaying ? /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 00-1 1v2a1 1 0 102 0V9a1 1 0 00-1-1zm5 0a1 1 0 00-1 1v2a1 1 0 102 0V9a1 1 0 00-1-1z", clipRule: "evenodd" }) }) : /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8.118l-.001 3.764a1 1 0 001.555.832l3.196-1.882a1 1 0 000-1.664l-3.196-1.882z", clipRule: "evenodd" }) })
30038
+ }
30039
+ ),
30040
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-mono px-2", children: [
30041
+ formatTime2(currentTime),
30042
+ " / ",
30043
+ formatTime2(duration)
30044
+ ] })
29271
30045
  ] }),
29272
30046
  /* @__PURE__ */ jsxRuntime.jsx(
29273
30047
  "input",
@@ -29288,6 +30062,16 @@ var BottlenecksContent = ({
29288
30062
  },
29289
30063
  "aria-label": "Seek slider"
29290
30064
  }
30065
+ ),
30066
+ /* @__PURE__ */ jsxRuntime.jsx(
30067
+ "button",
30068
+ {
30069
+ onClick: toggleFullscreen,
30070
+ className: "p-1.5 hover:bg-white/20 rounded-full focus:outline-none focus:ring-2 focus:ring-white/50",
30071
+ "aria-label": "Fullscreen",
30072
+ title: "Expand to fullscreen",
30073
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { className: "h-5 w-5" })
30074
+ }
29291
30075
  )
29292
30076
  ] }) })
29293
30077
  ] }) }) }) : (
@@ -29424,6 +30208,147 @@ var BottlenecksContent = ({
29424
30208
  )
29425
30209
  ) })
29426
30210
  ] }),
30211
+ isFullscreen && currentVideo && /* @__PURE__ */ jsxRuntime.jsxs(
30212
+ "div",
30213
+ {
30214
+ className: "fixed inset-0 z-50 bg-black flex items-center justify-center",
30215
+ style: { margin: 0 },
30216
+ children: [
30217
+ /* @__PURE__ */ jsxRuntime.jsx(
30218
+ "button",
30219
+ {
30220
+ onClick: exitFullscreen,
30221
+ className: "absolute top-4 right-4 z-50 p-2 bg-black/60 hover:bg-black/80 rounded-full text-white transition-colors focus:outline-none focus:ring-2 focus:ring-white/50",
30222
+ "aria-label": "Exit fullscreen",
30223
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-6 w-6" })
30224
+ }
30225
+ ),
30226
+ (currentVideo.type === "cycle_completion" || currentVideo.type === "bottleneck" && currentVideo.description.toLowerCase().includes("cycle time")) && currentVideo.cycle_time_seconds || currentVideo.type === "idle_time" || currentVideo.type === "low_value" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-4 left-4 z-50 bg-black/60 backdrop-blur-sm px-4 py-2 rounded-lg text-white shadow-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
30227
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-shrink-0 h-3 w-3 rounded-full ${currentVideo.type === "low_value" || currentVideo.type === "idle_time" ? "bg-purple-400" : isPercentileCategory(activeFilterRef.current) ? activeFilterRef.current === "fast-cycles" ? "bg-green-600" : activeFilterRef.current === "slow-cycles" ? "bg-red-700" : "bg-orange-500" : currentVideo.type === "cycle_completion" ? "bg-blue-600" : "bg-gray-500"} mr-2 animate-pulse` }),
30228
+ (currentVideo.type === "cycle_completion" || currentVideo.type === "bottleneck" && currentVideo.description.toLowerCase().includes("cycle time")) && currentVideo.cycle_time_seconds ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "opacity-90 font-mono bg-black/30 px-2 py-1 rounded", children: [
30229
+ "Cycle time: ",
30230
+ currentVideo.cycle_time_seconds.toFixed(1),
30231
+ "s"
30232
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
30233
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium mr-2", children: getClipTypeLabel(currentVideo) }),
30234
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-80", children: currentVideo.description })
30235
+ ] })
30236
+ ] }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-4 right-20 z-50 bg-black/60 backdrop-blur-sm px-4 py-2 rounded-lg text-white shadow-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
30237
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-shrink-0 h-3 w-3 rounded-full ${getSeverityColor(currentVideo.severity)} mr-2 animate-pulse` }),
30238
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium mr-2", children: getClipTypeLabel(currentVideo) }),
30239
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-80", children: currentVideo.description })
30240
+ ] }) }),
30241
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center p-8", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full h-full max-w-7xl group", children: [
30242
+ /* @__PURE__ */ jsxRuntime.jsx(
30243
+ "div",
30244
+ {
30245
+ className: "w-full h-full",
30246
+ style: {
30247
+ opacity: isTransitioning ? 0 : 1,
30248
+ transition: "opacity 0.1s ease-in-out"
30249
+ },
30250
+ children: /* @__PURE__ */ jsxRuntime.jsx(
30251
+ CroppedVideoPlayer,
30252
+ {
30253
+ ref: videoRef,
30254
+ src: currentVideo.src,
30255
+ poster: "",
30256
+ className: "w-full h-full",
30257
+ crop: workspaceCrop?.crop,
30258
+ onClick: togglePlayback,
30259
+ autoplay: true,
30260
+ playsInline: true,
30261
+ loop: false,
30262
+ externalLoadingControl: true,
30263
+ onReady: handleVideoReady,
30264
+ onPlay: handleVideoPlay,
30265
+ onPause: handleVideoPause,
30266
+ onTimeUpdate: handleTimeUpdate,
30267
+ onDurationChange: handleDurationChange,
30268
+ onEnded: handleVideoEnded,
30269
+ onError: handleVideoError,
30270
+ onLoadedData: handleLoadedData,
30271
+ onPlaying: handleVideoPlaying,
30272
+ onLoadingChange: handleVideoLoadingChange,
30273
+ options: {
30274
+ fluid: false,
30275
+ responsive: false,
30276
+ fill: false
30277
+ }
30278
+ }
30279
+ )
30280
+ }
30281
+ ),
30282
+ (isTransitioning || isVideoBuffering && isInitialLoading) && !error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-black", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
30283
+ !isTransitioning && isVideoBuffering && !isInitialLoading && !error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
30284
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 p-4 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 z-10", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-white", children: [
30285
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
30286
+ /* @__PURE__ */ jsxRuntime.jsx(
30287
+ "button",
30288
+ {
30289
+ onClick: (e) => {
30290
+ e.stopPropagation();
30291
+ togglePlayback();
30292
+ },
30293
+ className: "p-2 hover:bg-white/20 rounded-full focus:outline-none focus:ring-2 focus:ring-white/50",
30294
+ "aria-label": isPlaying ? "Pause" : "Play",
30295
+ children: isPlaying ? /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-6 w-6", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 00-1 1v2a1 1 0 102 0V9a1 1 0 00-1-1zm5 0a1 1 0 00-1 1v2a1 1 0 102 0V9a1 1 0 00-1-1z", clipRule: "evenodd" }) }) : /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-6 w-6", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8.118l-.001 3.764a1 1 0 001.555.832l3.196-1.882a1 1 0 000-1.664l-3.196-1.882z", clipRule: "evenodd" }) })
30296
+ }
30297
+ ),
30298
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-mono px-2", children: [
30299
+ formatTime2(currentTime),
30300
+ " / ",
30301
+ formatTime2(duration)
30302
+ ] })
30303
+ ] }),
30304
+ /* @__PURE__ */ jsxRuntime.jsx(
30305
+ "input",
30306
+ {
30307
+ type: "range",
30308
+ min: "0",
30309
+ max: duration || 0,
30310
+ value: currentTime,
30311
+ onChange: (e) => {
30312
+ if (videoRef.current) {
30313
+ videoRef.current.currentTime(Number(e.target.value));
30314
+ }
30315
+ },
30316
+ className: "flex-grow mx-4 h-2.5 bg-white/30 rounded-full appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-white/50 touch-manipulation",
30317
+ style: {
30318
+ WebkitAppearance: "none",
30319
+ appearance: "none"
30320
+ },
30321
+ "aria-label": "Seek slider"
30322
+ }
30323
+ ),
30324
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
30325
+ /* @__PURE__ */ jsxRuntime.jsx(
30326
+ "button",
30327
+ {
30328
+ onClick: handlePrevious,
30329
+ disabled: currentMetadataIndex <= 0,
30330
+ className: `p-2 rounded-full transition-colors ${currentMetadataIndex <= 0 ? "text-gray-500 cursor-not-allowed" : "text-white hover:bg-white/20"}`,
30331
+ "aria-label": "Previous clip",
30332
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-5 w-5" })
30333
+ }
30334
+ ),
30335
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm px-3 py-1 bg-blue-600 text-white rounded-full font-medium tabular-nums", children: categoryMetadata.length > 0 ? `${currentMetadataIndex + 1} / ${categoryMetadata.length}` : "0 / 0" }),
30336
+ /* @__PURE__ */ jsxRuntime.jsx(
30337
+ "button",
30338
+ {
30339
+ onClick: handleNext,
30340
+ disabled: currentMetadataIndex >= categoryMetadata.length - 1,
30341
+ className: `p-2 rounded-full transition-colors ${currentMetadataIndex >= categoryMetadata.length - 1 ? "text-gray-500 cursor-not-allowed" : "text-white hover:bg-white/20"}`,
30342
+ "aria-label": "Next clip",
30343
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-5 w-5" })
30344
+ }
30345
+ )
30346
+ ] })
30347
+ ] }) })
30348
+ ] }) })
30349
+ ]
30350
+ }
30351
+ ),
29427
30352
  !triageMode && /* @__PURE__ */ jsxRuntime.jsx(
29428
30353
  AdvancedFilterDialog,
29429
30354
  {
@@ -33260,14 +34185,16 @@ var WorkspaceWhatsAppShareButton = ({
33260
34185
  };
33261
34186
  var WorkspacePdfGenerator = ({ workspace, className }) => {
33262
34187
  const [isGenerating, setIsGenerating] = React23.useState(false);
34188
+ const entityConfig = useEntityConfig();
33263
34189
  const generatePDF = async () => {
33264
34190
  setIsGenerating(true);
33265
34191
  try {
34192
+ const lineName = workspace.line_name || getLineDisplayName(entityConfig, workspace.line_id);
33266
34193
  trackCoreEvent("Workspace PDF Export Clicked", {
33267
34194
  workspace_id: workspace.workspace_id,
33268
34195
  line_id: workspace.line_id,
33269
34196
  workspace_name: workspace.workspace_name,
33270
- line_name: workspace.line_name
34197
+ line_name: lineName
33271
34198
  });
33272
34199
  const doc = new jsPDF.jsPDF();
33273
34200
  doc.setFontSize(14);
@@ -33288,7 +34215,7 @@ var WorkspacePdfGenerator = ({ workspace, className }) => {
33288
34215
  doc.setFontSize(32);
33289
34216
  doc.setFont("helvetica", "bold");
33290
34217
  doc.setTextColor(0, 0, 0);
33291
- doc.text("Line 1", 20, 40);
34218
+ doc.text(lineName, 20, 40);
33292
34219
  doc.setFontSize(22);
33293
34220
  doc.setFont("helvetica", "normal");
33294
34221
  doc.setTextColor(40, 40, 40);
@@ -35761,20 +36688,7 @@ var SideNavBar = React23.memo(({
35761
36688
  onClick: handleLogoClick,
35762
36689
  className: "mx-auto flex items-center justify-center w-full hover:opacity-80 transition-opacity focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 rounded-lg",
35763
36690
  "aria-label": "Go to home page",
35764
- children: /* @__PURE__ */ jsxRuntime.jsx(
35765
- "img",
35766
- {
35767
- src: "/optifye-logo.png",
35768
- alt: "Optifye",
35769
- className: "w-12 h-12 object-contain cursor-pointer",
35770
- onError: (e) => {
35771
- e.currentTarget.style.display = "none";
35772
- if (e.currentTarget.parentElement) {
35773
- e.currentTarget.parentElement.innerHTML = '<span class="text-blue-600 font-bold text-lg cursor-pointer">OP</span>';
35774
- }
35775
- }
35776
- }
35777
- )
36691
+ children: /* @__PURE__ */ jsxRuntime.jsx(Logo, { className: "w-12 h-12 object-contain cursor-pointer" })
35778
36692
  }
35779
36693
  ) }),
35780
36694
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 w-full py-6 px-4 overflow-y-auto", children: [
@@ -36152,20 +37066,7 @@ var SideNavBar = React23.memo(({
36152
37066
  ),
36153
37067
  /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: `md:hidden fixed inset-y-0 left-0 w-72 xs:w-80 bg-white shadow-2xl flex flex-col z-50 transform transition-transform duration-300 ease-in-out ${isMobileMenuOpen ? "translate-x-0" : "-translate-x-full"}`, children: [
36154
37068
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-5 py-4 border-b border-gray-200 bg-gradient-to-r from-blue-50 to-white", children: [
36155
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
36156
- "img",
36157
- {
36158
- src: "/optifye-logo.png",
36159
- alt: "Optifye",
36160
- className: "w-11 h-11 object-contain",
36161
- onError: (e) => {
36162
- e.currentTarget.style.display = "none";
36163
- if (e.currentTarget.parentElement) {
36164
- e.currentTarget.parentElement.innerHTML = '<span class="text-blue-600 font-bold text-xl">Optifye</span>';
36165
- }
36166
- }
36167
- }
36168
- ) }),
37069
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(Logo, { className: "w-11 h-11 object-contain" }) }),
36169
37070
  /* @__PURE__ */ jsxRuntime.jsx(
36170
37071
  "button",
36171
37072
  {
@@ -36274,20 +37175,7 @@ var MainLayout = ({
36274
37175
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen ${className}`, children: [
36275
37176
  /* @__PURE__ */ jsxRuntime.jsx("header", { className: "md:hidden bg-white border-b border-gray-200 shadow-sm px-5 py-3.5 flex items-center justify-between sticky top-0 z-40", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
36276
37177
  /* @__PURE__ */ jsxRuntime.jsx(HamburgerButton, { onClick: handleMobileMenuOpen }),
36277
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
36278
- "img",
36279
- {
36280
- src: "/optifye-logo.png",
36281
- alt: "Optifye",
36282
- className: "h-9 w-9 object-contain",
36283
- onError: (e) => {
36284
- e.currentTarget.style.display = "none";
36285
- if (e.currentTarget.parentElement) {
36286
- e.currentTarget.parentElement.innerHTML = '<span class="text-blue-600 font-bold text-lg">Optifye</span>';
36287
- }
36288
- }
36289
- }
36290
- ) })
37178
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(Logo, { className: "h-9 w-9 object-contain" }) })
36291
37179
  ] }) }),
36292
37180
  /* @__PURE__ */ jsxRuntime.jsx(
36293
37181
  SideNavBar,
@@ -37897,23 +38785,29 @@ var ThreadSidebar = ({
37897
38785
  ] }) })
37898
38786
  ] });
37899
38787
  };
37900
- var axelProfilePng = "/axel-profile.png";
37901
- var ProfilePicture = React23__namespace.default.memo(({ alt = "Axel", className = "w-8 h-8 sm:w-10 sm:h-10 md:w-12 md:h-12" }) => {
37902
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${className} rounded-xl overflow-hidden shadow-sm`, children: /* @__PURE__ */ jsxRuntime.jsx(
37903
- "img",
37904
- {
37905
- src: axelProfilePng,
37906
- alt,
37907
- className: "w-full h-full object-cover",
37908
- loading: "eager",
37909
- decoding: "async"
37910
- }
37911
- ) }) });
38788
+ var ProfilePicture = React23__namespace.default.memo(({
38789
+ alt = "Axel",
38790
+ className = "",
38791
+ size = "md",
38792
+ animate = false
38793
+ }) => {
38794
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(AxelOrb, { size, animate }) });
37912
38795
  });
37913
38796
  ProfilePicture.displayName = "ProfilePicture";
37914
- var preloadImage = (src) => {
37915
- const img = new Image();
37916
- img.src = src;
38797
+ var GREETING_MESSAGES = [
38798
+ "How can I help you today?",
38799
+ "What would you like to know?",
38800
+ "Ready to optimize your operations?",
38801
+ "How can I assist you today?"
38802
+ ];
38803
+ var getDailyGreeting = () => {
38804
+ const now2 = /* @__PURE__ */ new Date();
38805
+ const startOfYear = new Date(now2.getFullYear(), 0, 0);
38806
+ const diff = now2.getTime() - startOfYear.getTime();
38807
+ const oneDay = 1e3 * 60 * 60 * 24;
38808
+ const dayOfYear = Math.floor(diff / oneDay);
38809
+ const index = dayOfYear % GREETING_MESSAGES.length;
38810
+ return GREETING_MESSAGES[index];
37917
38811
  };
37918
38812
  var AIAgentView = () => {
37919
38813
  const { navigate, pathname } = useNavigation();
@@ -37940,6 +38834,7 @@ var AIAgentView = () => {
37940
38834
  const [lastTypingTime, setLastTypingTime] = React23.useState(null);
37941
38835
  const [characterCount, setCharacterCount] = React23.useState(0);
37942
38836
  const typingTimeoutRef = React23.useRef(null);
38837
+ const currentGreeting = React23.useMemo(() => getDailyGreeting(), [greetingReset]);
37943
38838
  const isThreadLoading = (threadId) => {
37944
38839
  return threadId ? loadingThreads.has(threadId) : false;
37945
38840
  };
@@ -38020,7 +38915,7 @@ var AIAgentView = () => {
38020
38915
  const renderedContentCache = React23.useRef(/* @__PURE__ */ new Map());
38021
38916
  const { createThread, mutate: mutateThreads } = useThreads();
38022
38917
  const { messages, addMessage, setMessages } = useMessages(activeThreadId);
38023
- const agnoApiUrl = config.endpoints?.agnoApiUrl || "https://optifye-agent-production.up.railway.app";
38918
+ const agnoApiUrl = config.endpoints?.agnoApiUrl || "https://fastapi-production-111f9.up.railway.app";
38024
38919
  const sseClient = React23.useMemo(() => {
38025
38920
  console.log("[AIAgentView] Using AGNO API URL:", agnoApiUrl);
38026
38921
  return new SSEChatClient(agnoApiUrl);
@@ -38093,12 +38988,11 @@ var AIAgentView = () => {
38093
38988
  }, [activeThreadId]);
38094
38989
  React23.useEffect(() => {
38095
38990
  if (messages.length === 0 && !isTransitioning) {
38096
- const fullText = "Hi, I'm Axel - Your AI Supervisor";
38097
38991
  let index = 0;
38098
38992
  setTypedText("");
38099
38993
  const typeInterval = setInterval(() => {
38100
- if (index < fullText.length) {
38101
- setTypedText(fullText.substring(0, index + 1));
38994
+ if (index < currentGreeting.length) {
38995
+ setTypedText(currentGreeting.substring(0, index + 1));
38102
38996
  index++;
38103
38997
  } else {
38104
38998
  clearInterval(typeInterval);
@@ -38106,7 +39000,7 @@ var AIAgentView = () => {
38106
39000
  }, 50);
38107
39001
  return () => clearInterval(typeInterval);
38108
39002
  }
38109
- }, [messages.length, isTransitioning, greetingReset]);
39003
+ }, [messages.length, isTransitioning, greetingReset, currentGreeting]);
38110
39004
  React23.useEffect(() => {
38111
39005
  if (isSidebarOpen) {
38112
39006
  setNewChatCount(0);
@@ -38132,9 +39026,6 @@ var AIAgentView = () => {
38132
39026
  localStorage.removeItem(ACTIVE_THREAD_STORAGE_KEY);
38133
39027
  textareaRef.current?.focus();
38134
39028
  };
38135
- React23.useEffect(() => {
38136
- preloadImage(axelProfilePng);
38137
- }, []);
38138
39029
  React23.useEffect(() => {
38139
39030
  return () => {
38140
39031
  if (typingTimeoutRef.current) {
@@ -39609,10 +40500,10 @@ var AIAgentView = () => {
39609
40500
  /* Centered welcome and input for new chat */
39610
40501
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-3xl mx-auto px-3 sm:px-4 md:px-6 flex flex-col items-center justify-center space-y-8 sm:space-y-12 -mt-8 sm:-mt-16", children: [
39611
40502
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
39612
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center mb-4 sm:mb-6 md:mb-8", children: /* @__PURE__ */ jsxRuntime.jsx(ProfilePicture, { alt: "Axel - AI Manufacturing Expert", className: "w-16 h-16 sm:w-20 sm:h-20 md:w-24 md:h-24" }) }),
40503
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center mb-4 sm:mb-6 md:mb-8", children: /* @__PURE__ */ jsxRuntime.jsx(ProfilePicture, { alt: "Axel - AI Manufacturing Expert", size: "2xl", animate: true }) }),
39613
40504
  /* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "text-lg sm:text-xl md:text-2xl lg:text-3xl font-semibold text-gray-900 px-2 sm:px-4", children: [
39614
40505
  typedText,
39615
- typedText.length < "Hi, I'm Axel - Your AI Supervisor".length && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-pulse", children: "|" })
40506
+ typedText.length < currentGreeting.length && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-pulse", children: "|" })
39616
40507
  ] })
39617
40508
  ] }),
39618
40509
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, children: [
@@ -42979,7 +43870,7 @@ LeaderboardDetailView.displayName = "LeaderboardDetailView";
42979
43870
  var LeaderboardDetailViewWithDisplayNames = withAllWorkspaceDisplayNames(LeaderboardDetailView);
42980
43871
  var LeaderboardDetailView_default = LeaderboardDetailViewWithDisplayNames;
42981
43872
  function LoginView({
42982
- logoSrc = "/optifye-logo.png",
43873
+ logoSrc = optifye_logo_default,
42983
43874
  logoAlt = "Optifye",
42984
43875
  brandName = "Optifye",
42985
43876
  onRateLimitCheck
@@ -46059,6 +46950,26 @@ var getInitialTab = (sourceType, defaultTab, fromMonthly, urlDate) => {
46059
46950
  }
46060
46951
  return "overview";
46061
46952
  };
46953
+ var WorkspaceHealthStatusBadge = ({
46954
+ workspaceId,
46955
+ mode = "full",
46956
+ className = "",
46957
+ showHealthDot = false
46958
+ }) => {
46959
+ const { timeSinceUpdate, isHealthy, loading, error } = useWorkspaceHealthStatus(workspaceId);
46960
+ if (loading || error) {
46961
+ return null;
46962
+ }
46963
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-2 ${className}`, children: [
46964
+ showHealthDot && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
46965
+ "div",
46966
+ {
46967
+ className: `h-2 w-2 rounded-full ${isHealthy ? "bg-green-500 animate-pulse" : "bg-red-500"}`
46968
+ }
46969
+ ) }),
46970
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-500", children: mode === "full" ? `Last updated: ${timeSinceUpdate}` : timeSinceUpdate })
46971
+ ] });
46972
+ };
46062
46973
  var WorkspaceDetailView = ({
46063
46974
  workspaceId,
46064
46975
  date,
@@ -46110,6 +47021,7 @@ var WorkspaceDetailView = ({
46110
47021
  const [showIdleTime, setShowIdleTime] = React23.useState(false);
46111
47022
  const dashboardConfig = useDashboardConfig();
46112
47023
  const isClipsEnabled = dashboardConfig?.clipsConfig?.enabled ?? true;
47024
+ dashboardConfig?.supervisorConfig?.enabled || false;
46113
47025
  const {
46114
47026
  workspace: workspaceHealth,
46115
47027
  loading: healthLoading,
@@ -46118,6 +47030,36 @@ var WorkspaceDetailView = ({
46118
47030
  enableRealtime: true,
46119
47031
  refreshInterval: 3e4
46120
47032
  });
47033
+ const {
47034
+ isHealthy: isWorkspaceHealthy,
47035
+ timeSinceUpdate,
47036
+ lastHeartbeat,
47037
+ loading: healthStatusLoading,
47038
+ error: healthStatusError
47039
+ } = useWorkspaceHealthStatus(workspaceId);
47040
+ const isLive = React23.useMemo(() => {
47041
+ if (!lastHeartbeat) return false;
47042
+ const now2 = /* @__PURE__ */ new Date();
47043
+ const heartbeat = new Date(lastHeartbeat);
47044
+ const minutesSince = (now2.getTime() - heartbeat.getTime()) / 6e4;
47045
+ return minutesSince < 5;
47046
+ }, [lastHeartbeat]);
47047
+ React23.useEffect(() => {
47048
+ console.log("[WorkspaceDetailView] Workspace Health Status:", {
47049
+ workspaceId,
47050
+ // Old workspace_health table
47051
+ oldStatus: workspaceHealth?.status,
47052
+ oldLastHeartbeat: workspaceHealth?.last_heartbeat,
47053
+ oldTimeSinceLastUpdate: workspaceHealth?.timeSinceLastUpdate,
47054
+ // New workspace_health_status table
47055
+ isHealthy: isWorkspaceHealthy,
47056
+ isLive,
47057
+ lastHeartbeat,
47058
+ timeSinceUpdate,
47059
+ loading: healthLoading || healthStatusLoading,
47060
+ error: healthError || healthStatusError
47061
+ });
47062
+ }, [workspaceId, workspaceHealth, isWorkspaceHealthy, isLive, lastHeartbeat, timeSinceUpdate, healthLoading, healthStatusLoading, healthError, healthStatusError]);
46121
47063
  const {
46122
47064
  status: prefetchStatus,
46123
47065
  data: prefetchData,
@@ -46154,82 +47096,7 @@ var WorkspaceDetailView = ({
46154
47096
  const workspace = isHistoricView ? historicMetrics : liveMetrics;
46155
47097
  const loading = isHistoricView ? historicLoading : liveLoading;
46156
47098
  const error = isHistoricView ? historicError : liveError;
46157
- const audioService = useAudioService();
46158
- const { latestAchievement, hasNewAchievements } = useHourlyTargetAchievements({
46159
- hourlyData: workspace?.hourly_action_counts || [],
46160
- targetThreshold: workspace?.pph_threshold || 0,
46161
- shiftStart: workspace?.shift_start || "06:00",
46162
- enabled: !isHistoricView && Boolean(workspace)
46163
- // Only for live data
46164
- });
46165
- const { latestMiss, hasNewMiss } = useHourlyTargetMisses({
46166
- hourlyData: workspace?.hourly_action_counts || [],
46167
- targetThreshold: workspace?.pph_threshold || 0,
46168
- shiftStart: workspace?.shift_start || "06:00",
46169
- enabled: !isHistoricView && Boolean(workspace)
46170
- // Only for live data
46171
- });
46172
- const [showCongratulations, setShowCongratulations] = React23.useState(false);
46173
- const [currentAchievement, setCurrentAchievement] = React23.useState(null);
46174
- const [showEncouragement, setShowEncouragement] = React23.useState(false);
46175
- const [currentMiss, setCurrentMiss] = React23.useState(null);
46176
- const [audioReady, setAudioReady] = React23.useState(false);
46177
- React23.useEffect(() => {
46178
- if (hasNewAchievements && latestAchievement && !isHistoricView) {
46179
- console.log("[\u{1F389} ACHIEVEMENT UNLOCKED! \u{1F389}] Target reached!", latestAchievement);
46180
- const startCelebration = async () => {
46181
- setCurrentAchievement(latestAchievement);
46182
- setShowCongratulations(true);
46183
- setTimeout(async () => {
46184
- try {
46185
- console.log("[\u{1F3B5} CELEBRATION FANFARE] Playing victory audio...");
46186
- await audioService.playCongratsSound();
46187
- console.log("[\u2705 AUDIO SUCCESS] Celebration fanfare completed!");
46188
- } catch (err) {
46189
- console.warn("[\u274C AUDIO ERROR] Failed to play congratulations sound:", err);
46190
- }
46191
- }, 300);
46192
- console.log(`[\u{1F4CA} ACHIEVEMENT ANALYTICS] Worker hit target: ${latestAchievement.currentValue}/${latestAchievement.targetValue} during ${latestAchievement.timeRange}`);
46193
- };
46194
- startCelebration();
46195
- }
46196
- }, [hasNewAchievements, latestAchievement, isHistoricView, audioService]);
46197
- React23.useEffect(() => {
46198
- if (hasNewMiss && latestMiss && !isHistoricView) {
46199
- console.log("[\u{1F499} ENCOURAGEMENT NEEDED] Target not reached, showing support", latestMiss);
46200
- const startEncouragement = async () => {
46201
- setCurrentMiss(latestMiss);
46202
- setShowEncouragement(true);
46203
- setTimeout(async () => {
46204
- try {
46205
- console.log("[\u{1F3B5} GENTLE ENCOURAGEMENT] Playing supportive audio...");
46206
- await audioService.playEncouragementSound();
46207
- console.log("[\u2705 AUDIO SUCCESS] Encouragement audio completed!");
46208
- } catch (err) {
46209
- console.warn("[\u274C AUDIO ERROR] Failed to play encouragement sound:", err);
46210
- }
46211
- }, 300);
46212
- console.log(`[\u{1F4CA} ENCOURAGEMENT ANALYTICS] Target missed: ${latestMiss.actualValue}/${latestMiss.targetValue} (${Math.round(latestMiss.actualValue / latestMiss.targetValue * 100)}% achieved)`);
46213
- };
46214
- startEncouragement();
46215
- }
46216
- }, [hasNewMiss, latestMiss, isHistoricView, audioService]);
46217
- React23.useEffect(() => {
46218
- const handleUserInteraction = () => {
46219
- console.log("[\u{1F50A} AUDIO ENABLED] User interaction detected - celebration sounds ready!");
46220
- audioService.markUserInteraction();
46221
- setAudioReady(true);
46222
- };
46223
- console.log("[\u{1F3A7} AUDIO SETUP] Setting up celebration audio listeners...");
46224
- document.addEventListener("click", handleUserInteraction);
46225
- document.addEventListener("touchstart", handleUserInteraction);
46226
- document.addEventListener("keydown", handleUserInteraction);
46227
- return () => {
46228
- document.removeEventListener("click", handleUserInteraction);
46229
- document.removeEventListener("touchstart", handleUserInteraction);
46230
- document.removeEventListener("keydown", handleUserInteraction);
46231
- };
46232
- }, [audioService]);
47099
+ const { supervisorName } = useLineSupervisor(workspace?.line_id || lineId);
46233
47100
  React23.useEffect(() => {
46234
47101
  if (onTabChange) {
46235
47102
  onTabChange(activeTab);
@@ -46445,113 +47312,157 @@ var WorkspaceDetailView = ({
46445
47312
  )
46446
47313
  ] });
46447
47314
  }
46448
- return /* @__PURE__ */ jsxRuntime.jsxs(
47315
+ return /* @__PURE__ */ jsxRuntime.jsx(
46449
47316
  motion.div,
46450
47317
  {
46451
47318
  className: `min-h-screen bg-slate-50 ${className}`,
46452
47319
  initial: { opacity: 1 },
46453
47320
  animate: { opacity: 1 },
46454
- children: [
46455
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen w-full flex flex-col bg-slate-50", children: [
46456
- /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "sticky top-0 z-10 px-3 sm:px-4 md:px-5 lg:px-6 py-2 sm:py-2.5 lg:py-3 flex flex-col shadow-sm bg-white", children: [
46457
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
47321
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen w-full flex flex-col bg-slate-50", children: [
47322
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "sticky top-0 z-10 px-3 sm:px-4 md:px-5 lg:px-6 py-3 sm:py-3 lg:py-3.5 flex flex-col shadow-sm bg-white", children: [
47323
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
47324
+ /* @__PURE__ */ jsxRuntime.jsx(
47325
+ "button",
47326
+ {
47327
+ onClick: handleBackNavigation,
47328
+ className: "p-2 -ml-2 rounded-full active:bg-gray-100 transition-colors",
47329
+ "aria-label": "Navigate back",
47330
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "w-5 h-5 text-gray-700" })
47331
+ }
47332
+ ),
47333
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center", children: [
47334
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
47335
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-base font-semibold text-gray-900 truncate max-w-[220px]", children: formattedWorkspaceName }),
47336
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex h-2 w-2", children: [
47337
+ isLive && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" }),
47338
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
47339
+ "relative inline-flex rounded-full h-2 w-2",
47340
+ isLive ? "bg-green-500" : "bg-red-500"
47341
+ ) })
47342
+ ] }) })
47343
+ ] }),
47344
+ activeTab !== "monthly_history" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5 mt-1", children: [
47345
+ workspaceHealth && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-gray-500", children: workspaceHealth.timeSinceLastUpdate }),
47346
+ /* @__PURE__ */ jsxRuntime.jsx(
47347
+ WorkspaceHealthStatusBadge,
47348
+ {
47349
+ workspaceId,
47350
+ mode: "compact",
47351
+ showHealthDot: false,
47352
+ className: "text-[10px]"
47353
+ }
47354
+ )
47355
+ ] })
47356
+ ] }),
47357
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-9" })
47358
+ ] }) }),
47359
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center", children: [
47360
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(
47361
+ BackButtonMinimal,
47362
+ {
47363
+ onClick: handleBackNavigation,
47364
+ text: previousView === "line_monthly_history" ? "Back to Line History" : returnUrl && returnUrl.includes("monthly_history") ? "Back to Line History" : returnUrl && returnUrl.includes("/kpis/") ? "Back to KPIs" : returnUrl && returnUrl.includes("/leaderboard/") ? "Back to Leaderboard" : (date || shift) && activeTab !== "monthly_history" ? "Back to Monthly History" : "Back",
47365
+ size: "default",
47366
+ "aria-label": "Navigate back to previous page"
47367
+ }
47368
+ ) }),
47369
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-1/2 transform -translate-x-1/2 max-w-[calc(100%-200px)]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
47370
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg md:text-xl lg:text-2xl xl:text-3xl font-semibold text-gray-900 truncate", children: formattedWorkspaceName }),
47371
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex h-2.5 w-2.5", children: [
47372
+ isLive && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" }),
47373
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
47374
+ "relative inline-flex rounded-full h-2.5 w-2.5",
47375
+ isLive ? "bg-green-500" : "bg-red-500"
47376
+ ) })
47377
+ ] })
47378
+ ] }) }),
47379
+ activeTab !== "monthly_history" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 top-0 flex flex-col items-end gap-1", children: [
47380
+ workspaceHealth && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-500", children: [
47381
+ "Last update: ",
47382
+ workspaceHealth.timeSinceLastUpdate
47383
+ ] }),
46458
47384
  /* @__PURE__ */ jsxRuntime.jsx(
46459
- "button",
47385
+ WorkspaceHealthStatusBadge,
46460
47386
  {
46461
- onClick: handleBackNavigation,
46462
- className: "p-2 -ml-2 rounded-full active:bg-gray-100 transition-colors",
46463
- "aria-label": "Navigate back",
46464
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "w-5 h-5 text-gray-700" })
47387
+ workspaceId,
47388
+ mode: "full",
47389
+ showHealthDot: false
46465
47390
  }
46466
- ),
46467
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center", children: [
46468
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
46469
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-base font-semibold text-gray-900 truncate max-w-[220px]", children: formattedWorkspaceName }),
46470
- workspaceHealth && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex h-2 w-2", children: [
46471
- workspaceHealth.status === "healthy" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" }),
46472
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
46473
- "relative inline-flex rounded-full h-2 w-2",
46474
- workspaceHealth.status === "healthy" ? "bg-green-500" : "bg-red-500"
46475
- ) })
46476
- ] }) })
47391
+ )
47392
+ ] }),
47393
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-8" })
47394
+ ] }) }),
47395
+ activeTab !== "monthly_history" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
47396
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
47397
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: formatISTDate2(new Date(workspace.date)) }) }),
47398
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
47399
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(workspace.shift_type) }),
47400
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: workspace.shift_type })
47401
+ ] }),
47402
+ !date && !shift && !usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(LiveTimer, {}) }) }) : date ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-amber-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-amber-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : null
47403
+ ] }),
47404
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block mt-3 bg-blue-50 px-3 py-2 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3 md:gap-4", children: [
47405
+ !date && !shift && !usingFallbackData && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
47406
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base md:text-lg font-medium text-blue-600", children: /* @__PURE__ */ jsxRuntime.jsx(LiveTimer, {}) }),
47407
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
47408
+ ] }),
47409
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: formatISTDate2(new Date(workspace.date)) }),
47410
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" }),
47411
+ date && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
47412
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs font-medium bg-blue-200 text-blue-800 rounded-md", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }),
47413
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
47414
+ ] }),
47415
+ !date && !shift && usingFallbackData && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
47416
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-2 py-1 text-xs font-medium bg-amber-100 text-amber-700 rounded-md", children: [
47417
+ "Latest available data (",
47418
+ getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00"),
47419
+ ")"
46477
47420
  ] }),
46478
- workspaceHealth && activeTab !== "monthly_history" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-gray-500 mt-0.5", children: workspaceHealth.timeSinceLastUpdate })
47421
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
46479
47422
  ] }),
46480
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-9" })
46481
- ] }) }),
46482
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center", children: [
46483
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(
46484
- BackButtonMinimal,
47423
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
47424
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon(workspace.shift_type) }),
47425
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
47426
+ workspace.shift_type,
47427
+ " Shift"
47428
+ ] })
47429
+ ] })
47430
+ ] }) })
47431
+ ] }),
47432
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 sm:mt-1.5 lg:mt-2", children: [
47433
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex bg-gray-100 rounded-lg p-0.5", children: [
47434
+ /* @__PURE__ */ jsxRuntime.jsx(
47435
+ "button",
46485
47436
  {
46486
- onClick: handleBackNavigation,
46487
- text: previousView === "line_monthly_history" ? "Back to Line History" : returnUrl && returnUrl.includes("monthly_history") ? "Back to Line History" : returnUrl && returnUrl.includes("/kpis/") ? "Back to KPIs" : returnUrl && returnUrl.includes("/leaderboard/") ? "Back to Leaderboard" : (date || shift) && activeTab !== "monthly_history" ? "Back to Monthly History" : "Back",
46488
- size: "default",
46489
- "aria-label": "Navigate back to previous page"
47437
+ onClick: () => setActiveTab("overview"),
47438
+ className: `flex-1 px-2 py-1.5 text-xs font-medium rounded-md transition-all duration-200 ${activeTab === "overview" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600"}`,
47439
+ children: "Efficiency"
46490
47440
  }
46491
- ) }),
46492
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-1/2 transform -translate-x-1/2 max-w-[calc(100%-200px)]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
46493
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg md:text-xl lg:text-2xl xl:text-3xl font-semibold text-gray-900 truncate", children: formattedWorkspaceName }),
46494
- workspaceHealth && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex h-2.5 w-2.5", children: [
46495
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
46496
- "animate-ping absolute inline-flex h-full w-full rounded-full opacity-75",
46497
- workspaceHealth.status === "healthy" ? "bg-green-400" : "bg-red-400"
46498
- ) }),
46499
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
46500
- "relative inline-flex rounded-full h-2.5 w-2.5",
46501
- workspaceHealth.status === "healthy" ? "bg-green-500" : "bg-red-500"
46502
- ) })
46503
- ] })
46504
- ] }) }),
46505
- workspaceHealth && activeTab !== "monthly_history" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-0 top-0 flex items-center h-8", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-500", children: [
46506
- "Last update: ",
46507
- workspaceHealth.timeSinceLastUpdate
46508
- ] }) }),
46509
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-8" })
47441
+ ),
47442
+ isClipsEnabled && /* @__PURE__ */ jsxRuntime.jsx(
47443
+ "button",
47444
+ {
47445
+ onClick: () => setActiveTab("bottlenecks"),
47446
+ className: `flex-1 px-2 py-1.5 text-xs font-medium rounded-md transition-all duration-200 ${activeTab === "bottlenecks" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600"}`,
47447
+ children: "Clips"
47448
+ }
47449
+ ),
47450
+ /* @__PURE__ */ jsxRuntime.jsx(
47451
+ "button",
47452
+ {
47453
+ onClick: () => setActiveTab("monthly_history"),
47454
+ className: `flex-1 px-2 py-1.5 text-xs font-medium rounded-md transition-all duration-200 ${activeTab === "monthly_history" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600"}`,
47455
+ children: "History"
47456
+ }
47457
+ )
46510
47458
  ] }) }),
46511
- activeTab !== "monthly_history" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
46512
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
46513
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: formatISTDate2(new Date(workspace.date)) }) }),
46514
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
46515
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(workspace.shift_type) }),
46516
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: workspace.shift_type })
46517
- ] }),
46518
- !date && !shift && !usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(LiveTimer, {}) }) }) : date ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-amber-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-amber-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : null
46519
- ] }),
46520
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block mt-3 bg-blue-50 px-3 py-2 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3 md:gap-4", children: [
46521
- !date && !shift && !usingFallbackData && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
46522
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base md:text-lg font-medium text-blue-600", children: /* @__PURE__ */ jsxRuntime.jsx(LiveTimer, {}) }),
46523
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
46524
- ] }),
46525
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: formatISTDate2(new Date(workspace.date)) }),
46526
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" }),
46527
- date && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
46528
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs font-medium bg-blue-200 text-blue-800 rounded-md", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }),
46529
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
46530
- ] }),
46531
- !date && !shift && usingFallbackData && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
46532
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-2 py-1 text-xs font-medium bg-amber-100 text-amber-700 rounded-md", children: [
46533
- "Latest available data (",
46534
- getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00"),
46535
- ")"
46536
- ] }),
46537
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
46538
- ] }),
46539
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
46540
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon(workspace.shift_type) }),
46541
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
46542
- workspace.shift_type,
46543
- " Shift"
46544
- ] })
46545
- ] })
46546
- ] }) })
46547
- ] }),
46548
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 sm:mt-1.5 lg:mt-2", children: [
46549
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex bg-gray-100 rounded-lg p-0.5", children: [
47459
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden sm:flex items-center justify-between", children: [
47460
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1.5 lg:gap-2", children: [
46550
47461
  /* @__PURE__ */ jsxRuntime.jsx(
46551
47462
  "button",
46552
47463
  {
46553
47464
  onClick: () => setActiveTab("overview"),
46554
- className: `flex-1 px-2 py-1.5 text-xs font-medium rounded-md transition-all duration-200 ${activeTab === "overview" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600"}`,
47465
+ className: `px-2 lg:px-3 py-1 lg:py-1.5 text-sm lg:text-base font-medium rounded-lg transition-colors whitespace-nowrap ${activeTab === "overview" ? "bg-blue-50 text-blue-600" : "text-gray-600 hover:bg-gray-50"}`,
46555
47466
  children: "Efficiency"
46556
47467
  }
46557
47468
  ),
@@ -46559,7 +47470,7 @@ var WorkspaceDetailView = ({
46559
47470
  "button",
46560
47471
  {
46561
47472
  onClick: () => setActiveTab("bottlenecks"),
46562
- className: `flex-1 px-2 py-1.5 text-xs font-medium rounded-md transition-all duration-200 ${activeTab === "bottlenecks" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600"}`,
47473
+ className: `px-2 lg:px-3 py-1 lg:py-1.5 text-sm lg:text-base font-medium rounded-lg transition-colors whitespace-nowrap ${activeTab === "bottlenecks" ? "bg-blue-50 text-blue-600" : "text-gray-600 hover:bg-gray-50"}`,
46563
47474
  children: "Clips"
46564
47475
  }
46565
47476
  ),
@@ -46567,59 +47478,151 @@ var WorkspaceDetailView = ({
46567
47478
  "button",
46568
47479
  {
46569
47480
  onClick: () => setActiveTab("monthly_history"),
46570
- className: `flex-1 px-2 py-1.5 text-xs font-medium rounded-md transition-all duration-200 ${activeTab === "monthly_history" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600"}`,
46571
- children: "History"
47481
+ className: `px-2 lg:px-3 py-1 lg:py-1.5 text-sm lg:text-base font-medium rounded-lg transition-colors whitespace-nowrap ${activeTab === "monthly_history" ? "bg-blue-50 text-blue-600" : "text-gray-600 hover:bg-gray-50"}`,
47482
+ children: "Monthly History"
46572
47483
  }
46573
47484
  )
46574
- ] }) }),
46575
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden sm:flex items-center justify-between", children: [
46576
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1.5 lg:gap-2", children: [
46577
- /* @__PURE__ */ jsxRuntime.jsx(
46578
- "button",
46579
- {
46580
- onClick: () => setActiveTab("overview"),
46581
- className: `px-2 lg:px-3 py-1 lg:py-1.5 text-sm lg:text-base font-medium rounded-lg transition-colors whitespace-nowrap ${activeTab === "overview" ? "bg-blue-50 text-blue-600" : "text-gray-600 hover:bg-gray-50"}`,
46582
- children: "Efficiency"
46583
- }
46584
- ),
46585
- isClipsEnabled && /* @__PURE__ */ jsxRuntime.jsx(
46586
- "button",
46587
- {
46588
- onClick: () => setActiveTab("bottlenecks"),
46589
- className: `px-2 lg:px-3 py-1 lg:py-1.5 text-sm lg:text-base font-medium rounded-lg transition-colors whitespace-nowrap ${activeTab === "bottlenecks" ? "bg-blue-50 text-blue-600" : "text-gray-600 hover:bg-gray-50"}`,
46590
- children: "Clips"
46591
- }
46592
- ),
46593
- /* @__PURE__ */ jsxRuntime.jsx(
47485
+ ] }),
47486
+ activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5 lg:gap-2", children: renderHeaderActions ? renderHeaderActions(workspace) : /* @__PURE__ */ jsxRuntime.jsx(WorkspacePdfGenerator, { workspace }) }),
47487
+ activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5 lg:gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
47488
+ WorkspaceMonthlyPdfGenerator,
47489
+ {
47490
+ workspaceId,
47491
+ workspaceName: workspace?.workspace_name || "",
47492
+ monthlyData,
47493
+ selectedMonth,
47494
+ selectedYear,
47495
+ selectedShift
47496
+ }
47497
+ ) })
47498
+ ] })
47499
+ ] })
47500
+ ] }),
47501
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4", children: [
47502
+ activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full lg:h-[calc(100vh-10rem)] overflow-y-auto lg:overflow-hidden", children: [
47503
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "block lg:hidden space-y-6 pb-6", children: [
47504
+ !shouldShowCycleTimeChart && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm p-6", children: [
47505
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-700 mb-8", children: "Daily Progress" }),
47506
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center space-y-8", children: [
47507
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center space-y-1", children: [
47508
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-7xl font-bold tracking-tight", children: [
47509
+ (workspace.total_actions / workspace.target_output * 100).toFixed(1),
47510
+ "%"
47511
+ ] }),
47512
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center gap-2 text-gray-500", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium", children: "of today's target" }) })
47513
+ ] }),
47514
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
47515
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [
47516
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-600", children: "Overall Progress" }),
47517
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-lg font-semibold text-gray-700", children: [
47518
+ workspace.total_actions,
47519
+ " / ",
47520
+ workspace.target_output
47521
+ ] })
47522
+ ] }),
47523
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full bg-gray-100 rounded-full h-2.5", children: /* @__PURE__ */ jsxRuntime.jsx(
47524
+ motion.div,
47525
+ {
47526
+ initial: { width: 0 },
47527
+ animate: {
47528
+ width: `${Math.min(100, workspace.total_actions / workspace.target_output * 100)}%`
47529
+ },
47530
+ transition: {
47531
+ duration: 1,
47532
+ ease: "easeOut",
47533
+ delay: 0.2
47534
+ },
47535
+ className: "bg-green-500 h-2.5 rounded-full"
47536
+ }
47537
+ ) })
47538
+ ] }) })
47539
+ ] })
47540
+ ] }),
47541
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm p-4", children: [
47542
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center mb-4", children: [
47543
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-700", children: shouldShowCycleTimeChart ? "Cycle Time (last 60 minutes)" : "Hourly Output" }),
47544
+ !shouldShowCycleTimeChart && /* @__PURE__ */ jsxRuntime.jsxs(
46594
47545
  "button",
46595
47546
  {
46596
- onClick: () => setActiveTab("monthly_history"),
46597
- className: `px-2 lg:px-3 py-1 lg:py-1.5 text-sm lg:text-base font-medium rounded-lg transition-colors whitespace-nowrap ${activeTab === "monthly_history" ? "bg-blue-50 text-blue-600" : "text-gray-600 hover:bg-gray-50"}`,
46598
- children: "Monthly History"
47547
+ onClick: () => setShowIdleTime(!showIdleTime),
47548
+ className: `
47549
+ flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded
47550
+ transition-all duration-200 border
47551
+ ${showIdleTime ? "bg-gray-100 text-gray-700 border-gray-300 hover:bg-gray-200" : "bg-white text-gray-500 border-gray-200 hover:bg-gray-50 hover:text-gray-700"}
47552
+ `,
47553
+ "aria-label": showIdleTime ? "Hide idle time bars from chart" : "Show idle time bars on chart",
47554
+ children: [
47555
+ showIdleTime ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeOff, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: "w-3.5 h-3.5" }),
47556
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: showIdleTime ? "Hide Idle Time" : "Show Idle Time" })
47557
+ ]
46599
47558
  }
46600
47559
  )
46601
47560
  ] }),
46602
- activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5 lg:gap-2", children: renderHeaderActions ? renderHeaderActions(workspace) : /* @__PURE__ */ jsxRuntime.jsx(WorkspacePdfGenerator, { workspace }) }),
46603
- activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5 lg:gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
46604
- WorkspaceMonthlyPdfGenerator,
47561
+ /* @__PURE__ */ jsxRuntime.jsx(
47562
+ "div",
46605
47563
  {
46606
- workspaceId,
46607
- workspaceName: workspace?.workspace_name || "",
46608
- monthlyData,
46609
- selectedMonth,
46610
- selectedYear,
46611
- selectedShift
47564
+ className: "h-[300px]",
47565
+ style: { minHeight: "200px", minWidth: "300px" },
47566
+ children: shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
47567
+ CycleTimeOverTimeChart,
47568
+ {
47569
+ data: workspace.hourly_action_counts || [],
47570
+ idealCycleTime: workspace.ideal_cycle_time || 0,
47571
+ shiftStart: workspace.shift_start || ""
47572
+ }
47573
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
47574
+ HourlyOutputChart2,
47575
+ {
47576
+ data: workspace.hourly_action_counts || [],
47577
+ pphThreshold: workspace.pph_threshold || 0,
47578
+ shiftStart: workspace.shift_start || "",
47579
+ shiftEnd: workspace.shift_end,
47580
+ showIdleTime,
47581
+ idleTimeHourly: workspace.idle_time_hourly
47582
+ }
47583
+ )
46612
47584
  }
46613
- ) })
46614
- ] })
46615
- ] })
46616
- ] }),
46617
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4", children: [
46618
- activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full lg:h-[calc(100vh-10rem)] overflow-y-auto lg:overflow-hidden", children: [
46619
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "block lg:hidden space-y-6 pb-6", children: [
46620
- !shouldShowCycleTimeChart && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm p-6", children: [
47585
+ )
47586
+ ] }),
47587
+ shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
47588
+ /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
47589
+ /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg text-center", children: "Efficiency" }) }),
47590
+ /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
47591
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: `text-5xl font-bold ${(workspace.avg_efficiency || 0) >= 80 ? "text-green-500" : "text-red-500"}`, children: [
47592
+ (workspace.avg_efficiency || 0).toFixed(1),
47593
+ "%"
47594
+ ] }),
47595
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-2", children: "Target: 80%" })
47596
+ ] }) })
47597
+ ] }),
47598
+ /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
47599
+ /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg text-center", children: "Cycle Time (s)" }) }),
47600
+ /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
47601
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-5xl font-bold ${workspace.avg_cycle_time > (workspace.ideal_cycle_time || 0) ? "text-red-500" : "text-green-500"}`, children: workspace.avg_cycle_time.toFixed(1) }),
47602
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-gray-500 mt-2", children: [
47603
+ "Standard: ",
47604
+ workspace.ideal_cycle_time?.toFixed(1) || 0,
47605
+ "s"
47606
+ ] })
47607
+ ] }) })
47608
+ ] }),
47609
+ /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
47610
+ /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg text-center", children: "Idle Time" }) }),
47611
+ /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
47612
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-4xl font-bold ${!workspace.idle_time || workspace.idle_time <= 0 ? "text-green-500" : workspace.idle_time <= 300 ? "text-yellow-500" : (
47613
+ // 5 minutes or less
47614
+ "text-red-500"
47615
+ )}`, children: formatIdleTime(workspace.idle_time) }),
47616
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-2", children: "Total idle time" })
47617
+ ] }) })
47618
+ ] })
47619
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(WorkspaceMetricCards, { workspace, className: "flex-1" }) })
47620
+ ] }),
47621
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden lg:flex lg:flex-col lg:h-full", children: [
47622
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-[60%] grid grid-cols-1 lg:grid-cols-5 gap-3 mb-3", children: [
47623
+ !shouldShowCycleTimeChart && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm p-6 lg:col-span-2", children: [
46621
47624
  /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-700 mb-8", children: "Daily Progress" }),
46622
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center space-y-8", children: [
47625
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-[calc(100%-6rem)] justify-center space-y-8", children: [
46623
47626
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center space-y-1", children: [
46624
47627
  /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-7xl font-bold tracking-tight", children: [
46625
47628
  (workspace.total_actions / workspace.target_output * 100).toFixed(1),
@@ -46654,7 +47657,7 @@ var WorkspaceDetailView = ({
46654
47657
  ] }) })
46655
47658
  ] })
46656
47659
  ] }),
46657
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm p-4", children: [
47660
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `bg-white rounded-lg shadow-sm p-4 ${shouldShowCycleTimeChart ? "lg:col-span-5" : "lg:col-span-3"}`, children: [
46658
47661
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center mb-4", children: [
46659
47662
  /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-700", children: shouldShowCycleTimeChart ? "Cycle Time (last 60 minutes)" : "Hourly Output" }),
46660
47663
  !shouldShowCycleTimeChart && /* @__PURE__ */ jsxRuntime.jsxs(
@@ -46662,10 +47665,10 @@ var WorkspaceDetailView = ({
46662
47665
  {
46663
47666
  onClick: () => setShowIdleTime(!showIdleTime),
46664
47667
  className: `
46665
- flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded
46666
- transition-all duration-200 border
46667
- ${showIdleTime ? "bg-gray-100 text-gray-700 border-gray-300 hover:bg-gray-200" : "bg-white text-gray-500 border-gray-200 hover:bg-gray-50 hover:text-gray-700"}
46668
- `,
47668
+ flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded
47669
+ transition-all duration-200 border
47670
+ ${showIdleTime ? "bg-gray-100 text-gray-700 border-gray-300 hover:bg-gray-200" : "bg-white text-gray-500 border-gray-200 hover:bg-gray-50 hover:text-gray-700"}
47671
+ `,
46669
47672
  "aria-label": showIdleTime ? "Hide idle time bars from chart" : "Show idle time bars on chart",
46670
47673
  children: [
46671
47674
  showIdleTime ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeOff, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: "w-3.5 h-3.5" }),
@@ -46677,7 +47680,7 @@ var WorkspaceDetailView = ({
46677
47680
  /* @__PURE__ */ jsxRuntime.jsx(
46678
47681
  "div",
46679
47682
  {
46680
- className: "h-[300px]",
47683
+ className: "h-[calc(100%-3rem)]",
46681
47684
  style: { minHeight: "200px", minWidth: "300px" },
46682
47685
  children: shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
46683
47686
  CycleTimeOverTimeChart,
@@ -46699,248 +47702,103 @@ var WorkspaceDetailView = ({
46699
47702
  )
46700
47703
  }
46701
47704
  )
46702
- ] }),
46703
- shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
46704
- /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
46705
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg text-center", children: "Efficiency" }) }),
46706
- /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
46707
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: `text-5xl font-bold ${(workspace.avg_efficiency || 0) >= 80 ? "text-green-500" : "text-red-500"}`, children: [
46708
- (workspace.avg_efficiency || 0).toFixed(1),
46709
- "%"
46710
- ] }),
46711
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-2", children: "Target: 80%" })
46712
- ] }) })
46713
- ] }),
46714
- /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
46715
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg text-center", children: "Cycle Time (s)" }) }),
46716
- /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
46717
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-5xl font-bold ${workspace.avg_cycle_time > (workspace.ideal_cycle_time || 0) ? "text-red-500" : "text-green-500"}`, children: workspace.avg_cycle_time.toFixed(1) }),
46718
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-gray-500 mt-2", children: [
46719
- "Standard: ",
46720
- workspace.ideal_cycle_time?.toFixed(1) || 0,
46721
- "s"
46722
- ] })
46723
- ] }) })
46724
- ] }),
46725
- /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
46726
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg text-center", children: "Idle Time" }) }),
46727
- /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
46728
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-4xl font-bold ${!workspace.idle_time || workspace.idle_time <= 0 ? "text-green-500" : workspace.idle_time <= 300 ? "text-yellow-500" : (
46729
- // 5 minutes or less
46730
- "text-red-500"
46731
- )}`, children: formatIdleTime(workspace.idle_time) }),
46732
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-2", children: "Total idle time" })
46733
- ] }) })
46734
- ] })
46735
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(WorkspaceMetricCards, { workspace, className: "flex-1" }) })
47705
+ ] })
46736
47706
  ] }),
46737
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden lg:flex lg:flex-col lg:h-full", children: [
46738
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-[60%] grid grid-cols-1 lg:grid-cols-5 gap-3 mb-3", children: [
46739
- !shouldShowCycleTimeChart && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm p-6 lg:col-span-2", children: [
46740
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-700 mb-8", children: "Daily Progress" }),
46741
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-[calc(100%-6rem)] justify-center space-y-8", children: [
46742
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center space-y-1", children: [
46743
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-7xl font-bold tracking-tight", children: [
46744
- (workspace.total_actions / workspace.target_output * 100).toFixed(1),
46745
- "%"
46746
- ] }),
46747
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center gap-2 text-gray-500", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium", children: "of today's target" }) })
46748
- ] }),
46749
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
46750
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [
46751
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-600", children: "Overall Progress" }),
46752
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-lg font-semibold text-gray-700", children: [
46753
- workspace.total_actions,
46754
- " / ",
46755
- workspace.target_output
46756
- ] })
46757
- ] }),
46758
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full bg-gray-100 rounded-full h-2.5", children: /* @__PURE__ */ jsxRuntime.jsx(
46759
- motion.div,
46760
- {
46761
- initial: { width: 0 },
46762
- animate: {
46763
- width: `${Math.min(100, workspace.total_actions / workspace.target_output * 100)}%`
46764
- },
46765
- transition: {
46766
- duration: 1,
46767
- ease: "easeOut",
46768
- delay: 0.2
46769
- },
46770
- className: "bg-green-500 h-2.5 rounded-full"
46771
- }
46772
- ) })
46773
- ] }) })
46774
- ] })
46775
- ] }),
46776
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `bg-white rounded-lg shadow-sm p-4 ${shouldShowCycleTimeChart ? "lg:col-span-5" : "lg:col-span-3"}`, children: [
46777
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center mb-4", children: [
46778
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-700", children: shouldShowCycleTimeChart ? "Cycle Time (last 60 minutes)" : "Hourly Output" }),
46779
- !shouldShowCycleTimeChart && /* @__PURE__ */ jsxRuntime.jsxs(
46780
- "button",
46781
- {
46782
- onClick: () => setShowIdleTime(!showIdleTime),
46783
- className: `
46784
- flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded
46785
- transition-all duration-200 border
46786
- ${showIdleTime ? "bg-gray-100 text-gray-700 border-gray-300 hover:bg-gray-200" : "bg-white text-gray-500 border-gray-200 hover:bg-gray-50 hover:text-gray-700"}
46787
- `,
46788
- "aria-label": showIdleTime ? "Hide idle time bars from chart" : "Show idle time bars on chart",
46789
- children: [
46790
- showIdleTime ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeOff, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: "w-3.5 h-3.5" }),
46791
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: showIdleTime ? "Hide Idle Time" : "Show Idle Time" })
46792
- ]
46793
- }
46794
- )
47707
+ shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-[40%] grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3", children: [
47708
+ /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
47709
+ /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg text-center", children: "Efficiency" }) }),
47710
+ /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
47711
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: `text-5xl font-bold ${(workspace.avg_efficiency || 0) >= 80 ? "text-green-500" : "text-red-500"}`, children: [
47712
+ (workspace.avg_efficiency || 0).toFixed(1),
47713
+ "%"
46795
47714
  ] }),
46796
- /* @__PURE__ */ jsxRuntime.jsx(
46797
- "div",
46798
- {
46799
- className: "h-[calc(100%-3rem)]",
46800
- style: { minHeight: "200px", minWidth: "300px" },
46801
- children: shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
46802
- CycleTimeOverTimeChart,
46803
- {
46804
- data: workspace.hourly_action_counts || [],
46805
- idealCycleTime: workspace.ideal_cycle_time || 0,
46806
- shiftStart: workspace.shift_start || ""
46807
- }
46808
- ) : /* @__PURE__ */ jsxRuntime.jsx(
46809
- HourlyOutputChart2,
46810
- {
46811
- data: workspace.hourly_action_counts || [],
46812
- pphThreshold: workspace.pph_threshold || 0,
46813
- shiftStart: workspace.shift_start || "",
46814
- shiftEnd: workspace.shift_end,
46815
- showIdleTime,
46816
- idleTimeHourly: workspace.idle_time_hourly
46817
- }
46818
- )
46819
- }
46820
- )
46821
- ] })
47715
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-2", children: "Target: 80%" })
47716
+ ] }) })
46822
47717
  ] }),
46823
- shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-[40%] grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3", children: [
46824
- /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
46825
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg text-center", children: "Efficiency" }) }),
46826
- /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
46827
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: `text-5xl font-bold ${(workspace.avg_efficiency || 0) >= 80 ? "text-green-500" : "text-red-500"}`, children: [
46828
- (workspace.avg_efficiency || 0).toFixed(1),
46829
- "%"
46830
- ] }),
46831
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-2", children: "Target: 80%" })
46832
- ] }) })
46833
- ] }),
46834
- /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
46835
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg text-center", children: "Cycle Time (s)" }) }),
46836
- /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
46837
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-5xl font-bold ${workspace.avg_cycle_time > (workspace.ideal_cycle_time || 0) ? "text-red-500" : "text-green-500"}`, children: workspace.avg_cycle_time.toFixed(1) }),
46838
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-gray-500 mt-2", children: [
46839
- "Standard: ",
46840
- workspace.ideal_cycle_time?.toFixed(1) || 0,
46841
- "s"
46842
- ] })
46843
- ] }) })
46844
- ] }),
46845
- /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
46846
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg text-center", children: "Idle Time" }) }),
46847
- /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
46848
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-4xl font-bold ${!workspace.idle_time || workspace.idle_time <= 0 ? "text-green-500" : workspace.idle_time <= 300 ? "text-yellow-500" : (
46849
- // 5 minutes or less
46850
- "text-red-500"
46851
- )}`, children: formatIdleTime(workspace.idle_time) }),
46852
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-2", children: "Total idle time" })
46853
- ] }) })
46854
- ] })
46855
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[40%] flex", children: /* @__PURE__ */ jsxRuntime.jsx(WorkspaceMetricCards, { workspace, className: "flex-1" }) })
46856
- ] })
46857
- ] }),
46858
- activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-[calc(100vh-10rem)] overflow-y-auto px-2 sm:px-4 lg:px-0", children: [
46859
- workspaceId && activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsx(
46860
- WorkspaceMonthlyDataFetcher,
46861
- {
46862
- workspaceId,
46863
- selectedMonth,
46864
- selectedYear,
46865
- onDataLoaded: handleMonthlyDataLoaded,
46866
- onLoadingChange: setMonthlyDataLoading
46867
- }
46868
- ),
46869
- usingFallbackData && !date && !shift && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-3 sm:mb-4 bg-amber-50 border border-amber-200 rounded-lg px-3 sm:px-4 py-2 sm:py-3 text-amber-800", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs sm:text-sm font-medium flex items-center", children: [
46870
- /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-4 w-4 sm:h-5 sm:w-5 mr-2", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) }),
46871
- "No current data available for today. Showing monthly history instead."
46872
- ] }) }),
46873
- /* @__PURE__ */ jsxRuntime.jsx(
46874
- WorkspaceMonthlyHistory,
46875
- {
46876
- data: monthlyData,
46877
- month: selectedMonth,
46878
- year: selectedYear,
46879
- workspaceId,
46880
- selectedShift,
46881
- monthlyDataLoading,
46882
- onDateSelect: (selectedDate, shift2) => {
46883
- if (onDateSelect) {
46884
- onDateSelect(selectedDate, shift2);
46885
- } else if (onNavigate) {
46886
- const params = new URLSearchParams();
46887
- params.set("date", selectedDate);
46888
- params.set("shift", shift2 === "day" ? "0" : "1");
46889
- params.set("fromMonthly", "true");
46890
- if (effectiveLineId) {
46891
- params.set("lineId", effectiveLineId);
46892
- }
46893
- onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
46894
- }
46895
- },
46896
- onMonthNavigate: (newMonth, newYear) => {
46897
- setSelectedMonth(newMonth);
46898
- setSelectedYear(newYear);
46899
- },
46900
- onShiftChange: setSelectedShift,
46901
- className: "w-full"
46902
- }
46903
- )
46904
- ] }),
46905
- activeTab === "bottlenecks" && /* @__PURE__ */ jsxRuntime.jsx(ClipFilterProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
46906
- BottlenecksContent,
47718
+ /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
47719
+ /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg text-center", children: "Cycle Time (s)" }) }),
47720
+ /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
47721
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-5xl font-bold ${workspace.avg_cycle_time > (workspace.ideal_cycle_time || 0) ? "text-red-500" : "text-green-500"}`, children: workspace.avg_cycle_time.toFixed(1) }),
47722
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-gray-500 mt-2", children: [
47723
+ "Standard: ",
47724
+ workspace.ideal_cycle_time?.toFixed(1) || 0,
47725
+ "s"
47726
+ ] })
47727
+ ] }) })
47728
+ ] }),
47729
+ /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
47730
+ /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg text-center", children: "Idle Time" }) }),
47731
+ /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
47732
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-4xl font-bold ${!workspace.idle_time || workspace.idle_time <= 0 ? "text-green-500" : workspace.idle_time <= 300 ? "text-yellow-500" : (
47733
+ // 5 minutes or less
47734
+ "text-red-500"
47735
+ )}`, children: formatIdleTime(workspace.idle_time) }),
47736
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-2", children: "Total idle time" })
47737
+ ] }) })
47738
+ ] })
47739
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[40%] flex", children: /* @__PURE__ */ jsxRuntime.jsx(WorkspaceMetricCards, { workspace, className: "flex-1" }) })
47740
+ ] })
47741
+ ] }),
47742
+ activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-[calc(100vh-10rem)] overflow-y-auto px-2 sm:px-4 lg:px-0", children: [
47743
+ workspaceId && activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsx(
47744
+ WorkspaceMonthlyDataFetcher,
46907
47745
  {
46908
47746
  workspaceId,
46909
- workspaceName: formattedWorkspaceName,
46910
- date,
46911
- shift,
46912
- totalOutput: workspace?.total_actions,
46913
- className: "h-[calc(100vh-10rem)]"
47747
+ selectedMonth,
47748
+ selectedYear,
47749
+ onDataLoaded: handleMonthlyDataLoaded,
47750
+ onLoadingChange: setMonthlyDataLoading
46914
47751
  }
46915
- ) })
46916
- ] })
46917
- ] }),
46918
- /* @__PURE__ */ jsxRuntime.jsx(
46919
- CongratulationsOverlay,
46920
- {
46921
- achievement: currentAchievement,
46922
- isVisible: showCongratulations,
46923
- duration: 6e4,
46924
- onDismiss: () => {
46925
- setShowCongratulations(false);
46926
- setCurrentAchievement(null);
47752
+ ),
47753
+ usingFallbackData && !date && !shift && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-3 sm:mb-4 bg-amber-50 border border-amber-200 rounded-lg px-3 sm:px-4 py-2 sm:py-3 text-amber-800", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs sm:text-sm font-medium flex items-center", children: [
47754
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-4 w-4 sm:h-5 sm:w-5 mr-2", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) }),
47755
+ "No current data available for today. Showing monthly history instead."
47756
+ ] }) }),
47757
+ /* @__PURE__ */ jsxRuntime.jsx(
47758
+ WorkspaceMonthlyHistory,
47759
+ {
47760
+ data: monthlyData,
47761
+ month: selectedMonth,
47762
+ year: selectedYear,
47763
+ workspaceId,
47764
+ selectedShift,
47765
+ monthlyDataLoading,
47766
+ onDateSelect: (selectedDate, shift2) => {
47767
+ if (onDateSelect) {
47768
+ onDateSelect(selectedDate, shift2);
47769
+ } else if (onNavigate) {
47770
+ const params = new URLSearchParams();
47771
+ params.set("date", selectedDate);
47772
+ params.set("shift", shift2 === "day" ? "0" : "1");
47773
+ params.set("fromMonthly", "true");
47774
+ if (effectiveLineId) {
47775
+ params.set("lineId", effectiveLineId);
47776
+ }
47777
+ onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
47778
+ }
47779
+ },
47780
+ onMonthNavigate: (newMonth, newYear) => {
47781
+ setSelectedMonth(newMonth);
47782
+ setSelectedYear(newYear);
47783
+ },
47784
+ onShiftChange: setSelectedShift,
47785
+ className: "w-full"
47786
+ }
47787
+ )
47788
+ ] }),
47789
+ activeTab === "bottlenecks" && /* @__PURE__ */ jsxRuntime.jsx(ClipFilterProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
47790
+ BottlenecksContent,
47791
+ {
47792
+ workspaceId,
47793
+ workspaceName: formattedWorkspaceName,
47794
+ date,
47795
+ shift,
47796
+ totalOutput: workspace?.total_actions,
47797
+ className: "h-[calc(100vh-10rem)]"
46927
47798
  }
46928
- }
46929
- ),
46930
- /* @__PURE__ */ jsxRuntime.jsx(
46931
- EncouragementOverlay,
46932
- {
46933
- isVisible: showEncouragement,
46934
- onClose: () => {
46935
- setShowEncouragement(false);
46936
- setCurrentMiss(null);
46937
- },
46938
- targetValue: currentMiss?.targetValue || 0,
46939
- actualValue: currentMiss?.actualValue || 0,
46940
- metricName: currentMiss?.metricName || "Target"
46941
- }
46942
- )
46943
- ]
47799
+ ) })
47800
+ ] })
47801
+ ] })
46944
47802
  }
46945
47803
  );
46946
47804
  };
@@ -48055,21 +48913,36 @@ var LineAssignmentDropdown = ({
48055
48913
  const [isOpen, setIsOpen] = React23.useState(false);
48056
48914
  const [selectedIds, setSelectedIds] = React23.useState(currentLineIds);
48057
48915
  const [isSaving, setIsSaving] = React23.useState(false);
48916
+ const [position, setPosition] = React23.useState({ top: 0, left: 0, width: 0 });
48917
+ const buttonRef = React23.useRef(null);
48058
48918
  const dropdownRef = React23.useRef(null);
48059
48919
  React23.useEffect(() => {
48060
48920
  setSelectedIds(currentLineIds);
48061
48921
  }, [currentLineIds]);
48062
48922
  React23.useEffect(() => {
48063
- console.log("[LineAssignmentDropdown] Available lines updated:", {
48064
- userId,
48065
- count: availableLines.length,
48066
- lines: availableLines,
48067
- hasCompanyId: availableLines.every((l) => l.company_id)
48068
- });
48069
- }, [availableLines, userId]);
48923
+ const updatePosition = () => {
48924
+ if (isOpen && buttonRef.current) {
48925
+ const rect = buttonRef.current.getBoundingClientRect();
48926
+ setPosition({
48927
+ top: rect.bottom,
48928
+ left: rect.left,
48929
+ width: rect.width
48930
+ });
48931
+ }
48932
+ };
48933
+ if (isOpen) {
48934
+ updatePosition();
48935
+ window.addEventListener("scroll", updatePosition, true);
48936
+ window.addEventListener("resize", updatePosition);
48937
+ }
48938
+ return () => {
48939
+ window.removeEventListener("scroll", updatePosition, true);
48940
+ window.removeEventListener("resize", updatePosition);
48941
+ };
48942
+ }, [isOpen]);
48070
48943
  React23.useEffect(() => {
48071
48944
  const handleClickOutside = (event) => {
48072
- if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
48945
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target) && buttonRef.current && !buttonRef.current.contains(event.target)) {
48073
48946
  setIsOpen(false);
48074
48947
  setSelectedIds(currentLineIds);
48075
48948
  }
@@ -48135,94 +49008,106 @@ var LineAssignmentDropdown = ({
48135
49008
  if (!canEdit) {
48136
49009
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm", children: getDisplayText() });
48137
49010
  }
48138
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref: dropdownRef, children: [
49011
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
48139
49012
  /* @__PURE__ */ jsxRuntime.jsxs(
48140
49013
  "button",
48141
49014
  {
49015
+ ref: buttonRef,
48142
49016
  onClick: () => setIsOpen(!isOpen),
48143
49017
  className: cn(
48144
- "flex items-center gap-2 px-3 py-1.5 text-sm border rounded-lg transition-colors",
49018
+ "flex items-center gap-2 px-3 py-2 text-sm border rounded-lg transition-colors min-w-[200px]",
48145
49019
  currentLineIds.length === 0 ? "border-blue-300 bg-blue-50 hover:bg-blue-100" : "border-gray-300 bg-white hover:bg-gray-50"
48146
49020
  ),
48147
49021
  children: [
48148
49022
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-left", children: getDisplayText() }),
48149
49023
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: cn(
48150
- "w-4 h-4 text-gray-400 transition-transform",
49024
+ "w-4 h-4 text-gray-400 transition-transform flex-shrink-0",
48151
49025
  isOpen && "rotate-180"
48152
49026
  ) })
48153
49027
  ]
48154
49028
  }
48155
49029
  ),
48156
- isOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute z-[10000] mt-2 w-72 bg-white rounded-lg shadow-lg border border-gray-200 left-0", children: [
48157
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3 border-b border-gray-200", children: [
48158
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
48159
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Assign Lines" }),
48160
- /* @__PURE__ */ jsxRuntime.jsx(
48161
- "button",
48162
- {
48163
- onClick: handleCancel,
48164
- className: "text-gray-400 hover:text-gray-600",
48165
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
48166
- }
48167
- )
48168
- ] }),
48169
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 mt-1", children: "Select one or more lines to assign" })
48170
- ] }),
48171
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-64 overflow-y-auto", children: availableLines.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-8 text-center", children: [
48172
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mb-2", children: "No lines available" }),
48173
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-400", children: "Check console (F12) for filtering details" })
48174
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-2", children: availableLines.map((line) => /* @__PURE__ */ jsxRuntime.jsxs(
48175
- "label",
48176
- {
48177
- className: "flex items-center gap-3 px-4 py-2.5 hover:bg-gray-50 cursor-pointer transition-colors",
48178
- children: [
48179
- /* @__PURE__ */ jsxRuntime.jsx(
48180
- "input",
48181
- {
48182
- type: "checkbox",
48183
- checked: selectedIds.includes(line.id),
48184
- onChange: () => handleToggleLine(line.id),
48185
- className: "h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
48186
- }
48187
- ),
48188
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900", children: line.line_name }) }),
48189
- selectedIds.includes(line.id) && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-4 h-4 text-blue-600" })
48190
- ]
48191
- },
48192
- line.id
48193
- )) }) }),
48194
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3 border-t border-gray-200 bg-gray-50 flex items-center justify-between", children: [
48195
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-600", children: [
48196
- selectedIds.length,
48197
- " selected"
48198
- ] }),
48199
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
48200
- /* @__PURE__ */ jsxRuntime.jsx(
48201
- "button",
48202
- {
48203
- onClick: handleCancel,
48204
- className: "px-3 py-1.5 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors",
48205
- children: "Cancel"
48206
- }
48207
- ),
48208
- /* @__PURE__ */ jsxRuntime.jsx(
48209
- "button",
48210
- {
48211
- onClick: handleSave,
48212
- disabled: !hasChanges || isSaving,
48213
- className: "px-3 py-1.5 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
48214
- children: isSaving ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
48215
- /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "animate-spin h-3 w-3", viewBox: "0 0 24 24", children: [
48216
- /* @__PURE__ */ jsxRuntime.jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4", fill: "none" }),
48217
- /* @__PURE__ */ jsxRuntime.jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
49030
+ isOpen && reactDom.createPortal(
49031
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
49032
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-[9998]" }),
49033
+ /* @__PURE__ */ jsxRuntime.jsxs(
49034
+ "div",
49035
+ {
49036
+ ref: dropdownRef,
49037
+ className: "fixed z-[9999] bg-white rounded-lg shadow-2xl border border-gray-200",
49038
+ style: {
49039
+ top: `${position.top + 4}px`,
49040
+ left: `${position.left}px`,
49041
+ minWidth: `${Math.max(position.width, 300)}px`,
49042
+ maxWidth: "400px",
49043
+ maxHeight: "calc(100vh - 100px)"
49044
+ },
49045
+ children: [
49046
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3 border-b border-gray-200 bg-gray-50", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
49047
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
49048
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Assign Lines" }),
49049
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 mt-0.5", children: "Select one or more lines" })
48218
49050
  ] }),
48219
- "Saving..."
48220
- ] }) : "Save"
48221
- }
48222
- )
48223
- ] })
48224
- ] })
48225
- ] })
49051
+ /* @__PURE__ */ jsxRuntime.jsx(
49052
+ "button",
49053
+ {
49054
+ onClick: handleCancel,
49055
+ className: "text-gray-400 hover:text-gray-600 transition-colors",
49056
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
49057
+ }
49058
+ )
49059
+ ] }) }),
49060
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-80 overflow-y-auto", children: availableLines.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-8 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "No lines available" }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-1", children: availableLines.map((line) => /* @__PURE__ */ jsxRuntime.jsxs(
49061
+ "label",
49062
+ {
49063
+ className: "flex items-center gap-3 px-4 py-2.5 hover:bg-gray-50 cursor-pointer transition-colors",
49064
+ children: [
49065
+ /* @__PURE__ */ jsxRuntime.jsx(
49066
+ "input",
49067
+ {
49068
+ type: "checkbox",
49069
+ checked: selectedIds.includes(line.id),
49070
+ onChange: () => handleToggleLine(line.id),
49071
+ className: "h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
49072
+ }
49073
+ ),
49074
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900 truncate", children: line.line_name }) }),
49075
+ selectedIds.includes(line.id) && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-4 h-4 text-blue-600 flex-shrink-0" })
49076
+ ]
49077
+ },
49078
+ line.id
49079
+ )) }) }),
49080
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3 border-t border-gray-200 bg-gray-50 flex items-center justify-between", children: [
49081
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-600", children: [
49082
+ selectedIds.length,
49083
+ " selected"
49084
+ ] }),
49085
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
49086
+ /* @__PURE__ */ jsxRuntime.jsx(
49087
+ "button",
49088
+ {
49089
+ onClick: handleCancel,
49090
+ className: "px-3 py-1.5 text-xs font-medium text-gray-700 bg-white border border-gray-300 rounded hover:bg-gray-50 transition-colors",
49091
+ children: "Cancel"
49092
+ }
49093
+ ),
49094
+ /* @__PURE__ */ jsxRuntime.jsx(
49095
+ "button",
49096
+ {
49097
+ onClick: handleSave,
49098
+ disabled: !hasChanges || isSaving,
49099
+ className: "px-3 py-1.5 text-xs font-medium text-white bg-blue-600 rounded hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
49100
+ children: isSaving ? "Saving..." : "Save"
49101
+ }
49102
+ )
49103
+ ] })
49104
+ ] })
49105
+ ]
49106
+ }
49107
+ )
49108
+ ] }),
49109
+ document.body
49110
+ )
48226
49111
  ] });
48227
49112
  };
48228
49113
  var FactoryAssignmentDropdown = ({
@@ -48235,13 +49120,36 @@ var FactoryAssignmentDropdown = ({
48235
49120
  const [isOpen, setIsOpen] = React23.useState(false);
48236
49121
  const [selectedIds, setSelectedIds] = React23.useState(currentFactoryIds);
48237
49122
  const [isSaving, setIsSaving] = React23.useState(false);
49123
+ const [position, setPosition] = React23.useState({ top: 0, left: 0, width: 0 });
49124
+ const buttonRef = React23.useRef(null);
48238
49125
  const dropdownRef = React23.useRef(null);
48239
49126
  React23.useEffect(() => {
48240
49127
  setSelectedIds(currentFactoryIds);
48241
49128
  }, [currentFactoryIds]);
49129
+ React23.useEffect(() => {
49130
+ const updatePosition = () => {
49131
+ if (isOpen && buttonRef.current) {
49132
+ const rect = buttonRef.current.getBoundingClientRect();
49133
+ setPosition({
49134
+ top: rect.bottom,
49135
+ left: rect.left,
49136
+ width: rect.width
49137
+ });
49138
+ }
49139
+ };
49140
+ if (isOpen) {
49141
+ updatePosition();
49142
+ window.addEventListener("scroll", updatePosition, true);
49143
+ window.addEventListener("resize", updatePosition);
49144
+ }
49145
+ return () => {
49146
+ window.removeEventListener("scroll", updatePosition, true);
49147
+ window.removeEventListener("resize", updatePosition);
49148
+ };
49149
+ }, [isOpen]);
48242
49150
  React23.useEffect(() => {
48243
49151
  const handleClickOutside = (event) => {
48244
- if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
49152
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target) && buttonRef.current && !buttonRef.current.contains(event.target)) {
48245
49153
  setIsOpen(false);
48246
49154
  setSelectedIds(currentFactoryIds);
48247
49155
  }
@@ -48307,91 +49215,106 @@ var FactoryAssignmentDropdown = ({
48307
49215
  if (!canEdit) {
48308
49216
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm", children: getDisplayText() });
48309
49217
  }
48310
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref: dropdownRef, children: [
49218
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
48311
49219
  /* @__PURE__ */ jsxRuntime.jsxs(
48312
49220
  "button",
48313
49221
  {
49222
+ ref: buttonRef,
48314
49223
  onClick: () => setIsOpen(!isOpen),
48315
49224
  className: cn(
48316
- "flex items-center gap-2 px-3 py-1.5 text-sm border rounded-lg transition-colors",
49225
+ "flex items-center gap-2 px-3 py-2 text-sm border rounded-lg transition-colors min-w-[200px]",
48317
49226
  currentFactoryIds.length === 0 ? "border-blue-300 bg-blue-50 hover:bg-blue-100" : "border-gray-300 bg-white hover:bg-gray-50"
48318
49227
  ),
48319
49228
  children: [
48320
49229
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-left", children: getDisplayText() }),
48321
49230
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: cn(
48322
- "w-4 h-4 text-gray-400 transition-transform",
49231
+ "w-4 h-4 text-gray-400 transition-transform flex-shrink-0",
48323
49232
  isOpen && "rotate-180"
48324
49233
  ) })
48325
49234
  ]
48326
49235
  }
48327
49236
  ),
48328
- isOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute z-[10000] mt-2 w-72 bg-white rounded-lg shadow-lg border border-gray-200 left-0", children: [
48329
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3 border-b border-gray-200", children: [
48330
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
48331
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Assign Factories" }),
48332
- /* @__PURE__ */ jsxRuntime.jsx(
48333
- "button",
48334
- {
48335
- onClick: handleCancel,
48336
- className: "text-gray-400 hover:text-gray-600",
48337
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
48338
- }
48339
- )
48340
- ] }),
48341
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 mt-1", children: "Select one or more factories to assign" })
48342
- ] }),
48343
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-64 overflow-y-auto", children: availableFactories.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-8 text-center text-sm text-gray-500", children: "No factories available" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-2", children: availableFactories.map((factory) => /* @__PURE__ */ jsxRuntime.jsxs(
48344
- "label",
48345
- {
48346
- className: "flex items-center gap-3 px-4 py-2.5 hover:bg-gray-50 cursor-pointer transition-colors",
48347
- children: [
48348
- /* @__PURE__ */ jsxRuntime.jsx(
48349
- "input",
48350
- {
48351
- type: "checkbox",
48352
- checked: selectedIds.includes(factory.id),
48353
- onChange: () => handleToggleFactory(factory.id),
48354
- className: "h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
48355
- }
48356
- ),
48357
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900", children: factory.factory_name }) }),
48358
- selectedIds.includes(factory.id) && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-4 h-4 text-blue-600" })
48359
- ]
48360
- },
48361
- factory.id
48362
- )) }) }),
48363
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3 border-t border-gray-200 bg-gray-50 flex items-center justify-between", children: [
48364
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-600", children: [
48365
- selectedIds.length,
48366
- " selected"
48367
- ] }),
48368
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
48369
- /* @__PURE__ */ jsxRuntime.jsx(
48370
- "button",
48371
- {
48372
- onClick: handleCancel,
48373
- className: "px-3 py-1.5 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors",
48374
- children: "Cancel"
48375
- }
48376
- ),
48377
- /* @__PURE__ */ jsxRuntime.jsx(
48378
- "button",
48379
- {
48380
- onClick: handleSave,
48381
- disabled: !hasChanges || isSaving,
48382
- className: "px-3 py-1.5 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
48383
- children: isSaving ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
48384
- /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "animate-spin h-3 w-3", viewBox: "0 0 24 24", children: [
48385
- /* @__PURE__ */ jsxRuntime.jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4", fill: "none" }),
48386
- /* @__PURE__ */ jsxRuntime.jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
49237
+ isOpen && reactDom.createPortal(
49238
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
49239
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-[9998]" }),
49240
+ /* @__PURE__ */ jsxRuntime.jsxs(
49241
+ "div",
49242
+ {
49243
+ ref: dropdownRef,
49244
+ className: "fixed z-[9999] bg-white rounded-lg shadow-2xl border border-gray-200",
49245
+ style: {
49246
+ top: `${position.top + 4}px`,
49247
+ left: `${position.left}px`,
49248
+ minWidth: `${Math.max(position.width, 300)}px`,
49249
+ maxWidth: "400px",
49250
+ maxHeight: "calc(100vh - 100px)"
49251
+ },
49252
+ children: [
49253
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3 border-b border-gray-200 bg-gray-50", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
49254
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
49255
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Assign Factories" }),
49256
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 mt-0.5", children: "Select one or more factories" })
48387
49257
  ] }),
48388
- "Saving..."
48389
- ] }) : "Save"
48390
- }
48391
- )
48392
- ] })
48393
- ] })
48394
- ] })
49258
+ /* @__PURE__ */ jsxRuntime.jsx(
49259
+ "button",
49260
+ {
49261
+ onClick: handleCancel,
49262
+ className: "text-gray-400 hover:text-gray-600 transition-colors",
49263
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
49264
+ }
49265
+ )
49266
+ ] }) }),
49267
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-80 overflow-y-auto", children: availableFactories.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-8 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "No factories available" }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-1", children: availableFactories.map((factory) => /* @__PURE__ */ jsxRuntime.jsxs(
49268
+ "label",
49269
+ {
49270
+ className: "flex items-center gap-3 px-4 py-2.5 hover:bg-gray-50 cursor-pointer transition-colors",
49271
+ children: [
49272
+ /* @__PURE__ */ jsxRuntime.jsx(
49273
+ "input",
49274
+ {
49275
+ type: "checkbox",
49276
+ checked: selectedIds.includes(factory.id),
49277
+ onChange: () => handleToggleFactory(factory.id),
49278
+ className: "h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
49279
+ }
49280
+ ),
49281
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900 truncate", children: factory.factory_name }) }),
49282
+ selectedIds.includes(factory.id) && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-4 h-4 text-blue-600 flex-shrink-0" })
49283
+ ]
49284
+ },
49285
+ factory.id
49286
+ )) }) }),
49287
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3 border-t border-gray-200 bg-gray-50 flex items-center justify-between", children: [
49288
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-600", children: [
49289
+ selectedIds.length,
49290
+ " selected"
49291
+ ] }),
49292
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
49293
+ /* @__PURE__ */ jsxRuntime.jsx(
49294
+ "button",
49295
+ {
49296
+ onClick: handleCancel,
49297
+ className: "px-3 py-1.5 text-xs font-medium text-gray-700 bg-white border border-gray-300 rounded hover:bg-gray-50 transition-colors",
49298
+ children: "Cancel"
49299
+ }
49300
+ ),
49301
+ /* @__PURE__ */ jsxRuntime.jsx(
49302
+ "button",
49303
+ {
49304
+ onClick: handleSave,
49305
+ disabled: !hasChanges || isSaving,
49306
+ className: "px-3 py-1.5 text-xs font-medium text-white bg-blue-600 rounded hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
49307
+ children: isSaving ? "Saving..." : "Save"
49308
+ }
49309
+ )
49310
+ ] })
49311
+ ] })
49312
+ ]
49313
+ }
49314
+ )
49315
+ ] }),
49316
+ document.body
49317
+ )
48395
49318
  ] });
48396
49319
  };
48397
49320
  var UserManagementTable = ({
@@ -48543,7 +49466,7 @@ var UserManagementTable = ({
48543
49466
  }
48544
49467
  )
48545
49468
  ] }),
48546
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white rounded-lg border border-gray-200 overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-visible relative", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full divide-y divide-gray-200", children: [
49469
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white rounded-lg border border-gray-200", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full divide-y divide-gray-200", children: [
48547
49470
  /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-gray-50", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
48548
49471
  /* @__PURE__ */ jsxRuntime.jsx(
48549
49472
  "th",
@@ -48612,7 +49535,7 @@ var UserManagementTable = ({
48612
49535
  ] })
48613
49536
  ] }) }),
48614
49537
  /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-4 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx(RoleBadge, { role: user.role_level, size: "sm" }) }),
48615
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-4 relative overflow-visible z-10", children: user.role_level === "supervisor" ? /* @__PURE__ */ jsxRuntime.jsx(
49538
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-4", children: user.role_level === "supervisor" ? /* @__PURE__ */ jsxRuntime.jsx(
48616
49539
  LineAssignmentDropdown,
48617
49540
  {
48618
49541
  userId: user.user_id,
@@ -48654,7 +49577,7 @@ var UserManagementTable = ({
48654
49577
  }
48655
49578
  ) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-900", children: formatAssignments(user) }) }),
48656
49579
  /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-4 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: formatDate(user.created_at) }) }),
48657
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-4 whitespace-nowrap text-right relative overflow-visible", children: hasActions && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative overflow-visible", children: [
49580
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-4 whitespace-nowrap text-right", children: hasActions && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
48658
49581
  /* @__PURE__ */ jsxRuntime.jsx(
48659
49582
  "button",
48660
49583
  {
@@ -48837,6 +49760,34 @@ var InviteUserDialog = ({
48837
49760
  throw new Error(data.error);
48838
49761
  }
48839
49762
  sonner.toast.success(data?.message || "User added successfully!");
49763
+ try {
49764
+ const dashboardUrl = typeof window !== "undefined" ? window.location.origin : "";
49765
+ if (dashboardUrl) {
49766
+ console.log("Sending welcome email to:", email.trim());
49767
+ const { data: emailData, error: emailError } = await supabase.functions.invoke("hyper-service", {
49768
+ body: {
49769
+ action: "send-welcome-email",
49770
+ email: email.trim(),
49771
+ company_id: companyId,
49772
+ dashboard_url: dashboardUrl
49773
+ }
49774
+ });
49775
+ if (emailError) {
49776
+ console.error("Failed to send welcome email:", emailError);
49777
+ sonner.toast.warning("User added successfully, but welcome email could not be sent");
49778
+ } else if (emailData?.success) {
49779
+ console.log("Welcome email sent successfully:", emailData);
49780
+ sonner.toast.success("User added and welcome email sent!");
49781
+ } else {
49782
+ console.log("Welcome email response:", emailData);
49783
+ }
49784
+ } else {
49785
+ console.warn("Dashboard URL not available, skipping welcome email");
49786
+ }
49787
+ } catch (emailErr) {
49788
+ console.error("Error sending welcome email:", emailErr);
49789
+ sonner.toast.info("User added successfully (email service unavailable)");
49790
+ }
48840
49791
  onInviteSent?.();
48841
49792
  onClose();
48842
49793
  } catch (err) {
@@ -50629,7 +51580,7 @@ var S3Service = class {
50629
51580
  };
50630
51581
 
50631
51582
  // src/lib/api/optifye-agent.ts
50632
- var OPTIFYE_API_URL = "https://optifye-agent-production.up.railway.app";
51583
+ var OPTIFYE_API_URL = process.env.NEXT_PUBLIC_AGNO_URL || "https://fastapi-production-111f9.up.railway.app";
50633
51584
  var OptifyeAgentClient = class {
50634
51585
  constructor(apiUrl = OPTIFYE_API_URL) {
50635
51586
  this.apiUrl = apiUrl;
@@ -51036,6 +51987,7 @@ exports.AuthenticatedTargetsView = AuthenticatedTargetsView;
51036
51987
  exports.AuthenticatedTicketsView = AuthenticatedTicketsView;
51037
51988
  exports.AuthenticatedWorkspaceHealthView = AuthenticatedWorkspaceHealthView;
51038
51989
  exports.AxelNotificationPopup = AxelNotificationPopup;
51990
+ exports.AxelOrb = AxelOrb;
51039
51991
  exports.BackButton = BackButton;
51040
51992
  exports.BackButtonMinimal = BackButtonMinimal;
51041
51993
  exports.BarChart = BarChart;
@@ -51127,6 +52079,7 @@ exports.LoadingSkeleton = LoadingSkeleton;
51127
52079
  exports.LoadingState = LoadingState;
51128
52080
  exports.LoginPage = LoginPage;
51129
52081
  exports.LoginView = LoginView_default;
52082
+ exports.Logo = Logo;
51130
52083
  exports.MainLayout = MainLayout;
51131
52084
  exports.MapGridView = MapGridView;
51132
52085
  exports.MetricCard = MetricCard_default;
@@ -51140,6 +52093,7 @@ exports.OptifyeLogoLoader = OptifyeLogoLoader_default;
51140
52093
  exports.OutputProgressChart = OutputProgressChart;
51141
52094
  exports.PageHeader = PageHeader;
51142
52095
  exports.PieChart = PieChart4;
52096
+ exports.PlayPauseIndicator = PlayPauseIndicator;
51143
52097
  exports.PrefetchConfigurationError = PrefetchConfigurationError;
51144
52098
  exports.PrefetchError = PrefetchError;
51145
52099
  exports.PrefetchEvents = PrefetchEvents;
@@ -51166,6 +52120,7 @@ exports.ShiftDisplay = ShiftDisplay_default;
51166
52120
  exports.ShiftsView = ShiftsView_default;
51167
52121
  exports.SideNavBar = SideNavBar;
51168
52122
  exports.SignupWithInvitation = SignupWithInvitation;
52123
+ exports.SilentErrorBoundary = SilentErrorBoundary;
51169
52124
  exports.SimpleOnboardingPopup = SimpleOnboardingPopup;
51170
52125
  exports.SingleVideoStream = SingleVideoStream_default;
51171
52126
  exports.Skeleton = Skeleton;
@@ -51238,6 +52193,7 @@ exports.formatDateInZone = formatDateInZone;
51238
52193
  exports.formatDateTimeInZone = formatDateTimeInZone;
51239
52194
  exports.formatISTDate = formatISTDate;
51240
52195
  exports.formatIdleTime = formatIdleTime;
52196
+ exports.formatRelativeTime = formatRelativeTime;
51241
52197
  exports.formatTimeInZone = formatTimeInZone;
51242
52198
  exports.fromUrlFriendlyName = fromUrlFriendlyName;
51243
52199
  exports.getAllLineDisplayNames = getAllLineDisplayNames;
@@ -51262,6 +52218,7 @@ exports.getDefaultTabForWorkspace = getDefaultTabForWorkspace;
51262
52218
  exports.getLineDisplayName = getLineDisplayName;
51263
52219
  exports.getManufacturingInsights = getManufacturingInsights;
51264
52220
  exports.getMetricsTablePrefix = getMetricsTablePrefix;
52221
+ exports.getNextUpdateInterval = getNextUpdateInterval;
51265
52222
  exports.getOperationalDate = getOperationalDate;
51266
52223
  exports.getS3SignedUrl = getS3SignedUrl;
51267
52224
  exports.getS3VideoSrc = getS3VideoSrc;
@@ -51373,6 +52330,7 @@ exports.usePrefetchClipCounts = usePrefetchClipCounts;
51373
52330
  exports.useRealtimeLineMetrics = useRealtimeLineMetrics;
51374
52331
  exports.useRegistry = useRegistry;
51375
52332
  exports.useSKUs = useSKUs;
52333
+ exports.useSessionKeepAlive = useSessionKeepAlive;
51376
52334
  exports.useShiftConfig = useShiftConfig;
51377
52335
  exports.useShifts = useShifts;
51378
52336
  exports.useSubscriptionManager = useSubscriptionManager;
@@ -51394,6 +52352,7 @@ exports.useWorkspaceDisplayName = useWorkspaceDisplayName;
51394
52352
  exports.useWorkspaceDisplayNames = useWorkspaceDisplayNames;
51395
52353
  exports.useWorkspaceDisplayNamesMap = useWorkspaceDisplayNamesMap;
51396
52354
  exports.useWorkspaceHealthById = useWorkspaceHealthById;
52355
+ exports.useWorkspaceHealthStatus = useWorkspaceHealthStatus;
51397
52356
  exports.useWorkspaceMetrics = useWorkspaceMetrics;
51398
52357
  exports.useWorkspaceNavigation = useWorkspaceNavigation;
51399
52358
  exports.useWorkspaceOperators = useWorkspaceOperators;