@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.css +29 -31
- package/dist/index.d.mts +179 -14
- package/dist/index.d.ts +179 -14
- package/dist/index.js +1852 -893
- package/dist/index.mjs +1846 -895
- package/package.json +1 -1
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://
|
|
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
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
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
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
"
|
|
2842
|
-
|
|
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
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
10619
|
-
|
|
10620
|
-
"
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
|
|
10627
|
-
|
|
10628
|
-
"
|
|
10629
|
-
|
|
10630
|
-
|
|
10631
|
-
|
|
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
|
|
10635
|
-
|
|
11032
|
+
if (!userRole) return [];
|
|
11033
|
+
return roleAccessMap[userRole] || [];
|
|
11034
|
+
}, [userRole]);
|
|
10636
11035
|
const hasAccess = React23.useMemo(() => {
|
|
10637
11036
|
return (path) => {
|
|
10638
|
-
return
|
|
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
|
|
11054
|
+
return hasAccess(path);
|
|
10644
11055
|
};
|
|
10645
|
-
}, []);
|
|
11056
|
+
}, [hasAccess]);
|
|
10646
11057
|
const canAccessPage = React23.useMemo(() => {
|
|
10647
11058
|
return (path) => {
|
|
10648
|
-
return
|
|
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
|
-
|
|
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
|
|
10841
|
-
|
|
10842
|
-
|
|
10843
|
-
|
|
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
|
-
|
|
11271
|
+
setSupervisors([]);
|
|
10854
11272
|
setSupervisor(null);
|
|
10855
11273
|
}
|
|
10856
11274
|
} catch (err) {
|
|
10857
|
-
console.error("[useLineSupervisor] Error fetching
|
|
10858
|
-
setError(err instanceof Error ? err : new Error("Failed to fetch
|
|
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
|
|
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
|
-
|
|
21783
|
+
Logo,
|
|
21308
21784
|
{
|
|
21309
|
-
|
|
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
|
-
|
|
21326
|
-
|
|
21327
|
-
|
|
21328
|
-
|
|
21329
|
-
|
|
21330
|
-
|
|
21331
|
-
|
|
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:", {
|
|
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("
|
|
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
|
-
|
|
21381
|
-
|
|
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
|
|
21384
|
-
|
|
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 =
|
|
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.
|
|
29256
|
-
|
|
29257
|
-
|
|
29258
|
-
|
|
29259
|
-
e
|
|
29260
|
-
|
|
29261
|
-
|
|
29262
|
-
|
|
29263
|
-
|
|
29264
|
-
|
|
29265
|
-
|
|
29266
|
-
|
|
29267
|
-
|
|
29268
|
-
|
|
29269
|
-
|
|
29270
|
-
|
|
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:
|
|
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(
|
|
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
|
|
37901
|
-
|
|
37902
|
-
|
|
37903
|
-
|
|
37904
|
-
|
|
37905
|
-
|
|
37906
|
-
|
|
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
|
|
37915
|
-
|
|
37916
|
-
|
|
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://
|
|
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 <
|
|
38101
|
-
setTypedText(
|
|
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",
|
|
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 <
|
|
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 =
|
|
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
|
|
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.
|
|
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("
|
|
46456
|
-
/* @__PURE__ */ jsxRuntime.
|
|
46457
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
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
|
-
|
|
47385
|
+
WorkspaceHealthStatusBadge,
|
|
46460
47386
|
{
|
|
46461
|
-
|
|
46462
|
-
|
|
46463
|
-
|
|
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
|
-
|
|
46468
|
-
|
|
46469
|
-
|
|
46470
|
-
|
|
46471
|
-
|
|
46472
|
-
|
|
46473
|
-
|
|
46474
|
-
|
|
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
|
-
|
|
47421
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
|
|
46479
47422
|
] }),
|
|
46480
|
-
/* @__PURE__ */ jsxRuntime.
|
|
46481
|
-
|
|
46482
|
-
|
|
46483
|
-
|
|
46484
|
-
|
|
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:
|
|
46487
|
-
|
|
46488
|
-
|
|
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
|
-
|
|
46493
|
-
|
|
46494
|
-
|
|
46495
|
-
|
|
46496
|
-
|
|
46497
|
-
|
|
46498
|
-
|
|
46499
|
-
|
|
46500
|
-
|
|
46501
|
-
|
|
46502
|
-
|
|
46503
|
-
|
|
46504
|
-
|
|
46505
|
-
|
|
46506
|
-
|
|
46507
|
-
|
|
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
|
-
|
|
46512
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
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: `
|
|
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: `
|
|
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: `
|
|
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.
|
|
46576
|
-
|
|
46577
|
-
|
|
46578
|
-
|
|
46579
|
-
|
|
46580
|
-
|
|
46581
|
-
|
|
46582
|
-
|
|
46583
|
-
|
|
46584
|
-
|
|
46585
|
-
|
|
46586
|
-
|
|
46587
|
-
|
|
46588
|
-
|
|
46589
|
-
|
|
46590
|
-
|
|
46591
|
-
|
|
46592
|
-
|
|
46593
|
-
|
|
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: () =>
|
|
46597
|
-
className: `
|
|
46598
|
-
|
|
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
|
-
|
|
46603
|
-
|
|
46604
|
-
WorkspaceMonthlyPdfGenerator,
|
|
47561
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
47562
|
+
"div",
|
|
46605
47563
|
{
|
|
46606
|
-
|
|
46607
|
-
|
|
46608
|
-
|
|
46609
|
-
|
|
46610
|
-
|
|
46611
|
-
|
|
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
|
-
|
|
46618
|
-
|
|
46619
|
-
|
|
46620
|
-
|
|
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:
|
|
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
|
-
|
|
46666
|
-
|
|
46667
|
-
|
|
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-[
|
|
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: "
|
|
46738
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
46739
|
-
|
|
46740
|
-
|
|
46741
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
46742
|
-
|
|
46743
|
-
|
|
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
|
-
|
|
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
|
-
|
|
46824
|
-
/* @__PURE__ */ jsxRuntime.
|
|
46825
|
-
|
|
46826
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
46827
|
-
|
|
46828
|
-
|
|
46829
|
-
|
|
46830
|
-
|
|
46831
|
-
|
|
46832
|
-
|
|
46833
|
-
|
|
46834
|
-
|
|
46835
|
-
|
|
46836
|
-
|
|
46837
|
-
|
|
46838
|
-
|
|
46839
|
-
|
|
46840
|
-
|
|
46841
|
-
|
|
46842
|
-
|
|
46843
|
-
|
|
46844
|
-
|
|
46845
|
-
|
|
46846
|
-
|
|
46847
|
-
|
|
46848
|
-
|
|
46849
|
-
|
|
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
|
-
|
|
46910
|
-
|
|
46911
|
-
|
|
46912
|
-
|
|
46913
|
-
className: "h-[calc(100vh-10rem)]"
|
|
47747
|
+
selectedMonth,
|
|
47748
|
+
selectedYear,
|
|
47749
|
+
onDataLoaded: handleMonthlyDataLoaded,
|
|
47750
|
+
onLoadingChange: setMonthlyDataLoading
|
|
46914
47751
|
}
|
|
46915
|
-
)
|
|
46916
|
-
|
|
46917
|
-
|
|
46918
|
-
|
|
46919
|
-
|
|
46920
|
-
|
|
46921
|
-
|
|
46922
|
-
|
|
46923
|
-
|
|
46924
|
-
|
|
46925
|
-
|
|
46926
|
-
|
|
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
|
-
|
|
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
|
-
|
|
48064
|
-
|
|
48065
|
-
|
|
48066
|
-
|
|
48067
|
-
|
|
48068
|
-
|
|
48069
|
-
|
|
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(
|
|
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-
|
|
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 &&
|
|
48157
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
48158
|
-
/* @__PURE__ */ jsxRuntime.
|
|
48159
|
-
|
|
48160
|
-
|
|
48161
|
-
|
|
48162
|
-
|
|
48163
|
-
|
|
48164
|
-
|
|
48165
|
-
|
|
48166
|
-
|
|
48167
|
-
|
|
48168
|
-
|
|
48169
|
-
|
|
48170
|
-
|
|
48171
|
-
|
|
48172
|
-
|
|
48173
|
-
|
|
48174
|
-
|
|
48175
|
-
|
|
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
|
-
|
|
48220
|
-
|
|
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(
|
|
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-
|
|
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 &&
|
|
48329
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
48330
|
-
/* @__PURE__ */ jsxRuntime.
|
|
48331
|
-
|
|
48332
|
-
|
|
48333
|
-
|
|
48334
|
-
|
|
48335
|
-
|
|
48336
|
-
|
|
48337
|
-
|
|
48338
|
-
|
|
48339
|
-
|
|
48340
|
-
|
|
48341
|
-
|
|
48342
|
-
|
|
48343
|
-
|
|
48344
|
-
|
|
48345
|
-
|
|
48346
|
-
|
|
48347
|
-
|
|
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
|
-
|
|
48389
|
-
|
|
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
|
|
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
|
|
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
|
|
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://
|
|
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;
|