diff --git a/web/maplefile-frontend/src/components/UIX/GDPRFooter/GDPRFooter.jsx b/web/maplefile-frontend/src/components/UIX/GDPRFooter/GDPRFooter.jsx index 03fedfa..054fa52 100644 --- a/web/maplefile-frontend/src/components/UIX/GDPRFooter/GDPRFooter.jsx +++ b/web/maplefile-frontend/src/components/UIX/GDPRFooter/GDPRFooter.jsx @@ -16,10 +16,12 @@ import { * * @param {string} className - Additional CSS classes * @param {string} containerClassName - Additional classes for the outer container + * @param {boolean} showSecurityFeatures - Whether to show the security features section (default: true) */ const GDPRFooter = memo(function GDPRFooter({ className = "", - containerClassName = "" + containerClassName = "", + showSecurityFeatures = true, }) { const { getThemeClasses } = useUIXTheme(); @@ -36,29 +38,31 @@ const GDPRFooter = memo(function GDPRFooter({
Data Controller: Maple Open Tech Inc. |{" "}
Location: Canada (Adequate protection under GDPR Art. 45)
diff --git a/web/maplefile-frontend/src/components/UIX/themes/index.js b/web/maplefile-frontend/src/components/UIX/themes/index.js
index 0e9b766..cc83427 100644
--- a/web/maplefile-frontend/src/components/UIX/themes/index.js
+++ b/web/maplefile-frontend/src/components/UIX/themes/index.js
@@ -227,6 +227,45 @@ const getThemeConfigs = () => {
"success-bg": "bg-green-50",
"success-border": "border-green-200",
"success-text": "text-green-800",
+
+ // Help page section colors
+ "help-section-blue-text": "text-blue-600",
+ "help-section-blue-bg": "bg-blue-50",
+ "help-section-green-text": "text-green-600",
+ "help-section-green-bg": "bg-green-50",
+ "help-section-purple-text": "text-purple-600",
+ "help-section-purple-bg": "bg-purple-50",
+ "help-section-pink-text": "text-pink-600",
+ "help-section-pink-bg": "bg-pink-50",
+ "help-section-red-text": "text-red-600",
+ "help-section-red-bg": "bg-red-50",
+
+ // Export page section colors - Success (green)
+ "export-section-success-bg": "bg-green-50",
+ "export-section-success-border": "border-green-200",
+ "export-section-success-icon": "text-green-600",
+ "export-section-success-title": "text-green-900",
+ "export-section-success-text": "text-green-800",
+ "export-section-success-muted": "text-green-700",
+
+ // Export page section colors - Info (blue)
+ "export-section-info-bg": "bg-blue-50",
+ "export-section-info-border": "border-blue-200",
+ "export-section-info-icon": "text-blue-600",
+ "export-section-info-title": "text-blue-900",
+ "export-section-info-text": "text-blue-800",
+
+ // Export page section colors - Warning (yellow)
+ "export-section-warning-bg": "bg-yellow-50",
+ "export-section-warning-border": "border-yellow-200",
+ "export-section-warning-icon": "text-yellow-600",
+ "export-section-warning-title": "text-yellow-900",
+ "export-section-warning-text": "text-yellow-800",
+ "export-section-warning-muted": "text-yellow-700",
+ "export-section-warning-code": "bg-yellow-100",
+
+ // Muted background
+ "bg-muted": "bg-gray-50",
},
},
@@ -434,6 +473,45 @@ const getThemeConfigs = () => {
"success-bg": "bg-green-50",
"success-border": "border-green-200",
"success-text": "text-green-800",
+
+ // Help page section colors
+ "help-section-blue-text": "text-blue-600",
+ "help-section-blue-bg": "bg-blue-50",
+ "help-section-green-text": "text-green-600",
+ "help-section-green-bg": "bg-green-50",
+ "help-section-purple-text": "text-purple-600",
+ "help-section-purple-bg": "bg-purple-50",
+ "help-section-pink-text": "text-pink-600",
+ "help-section-pink-bg": "bg-pink-50",
+ "help-section-red-text": "text-red-600",
+ "help-section-red-bg": "bg-red-50",
+
+ // Export page section colors - Success (green)
+ "export-section-success-bg": "bg-green-50",
+ "export-section-success-border": "border-green-200",
+ "export-section-success-icon": "text-green-600",
+ "export-section-success-title": "text-green-900",
+ "export-section-success-text": "text-green-800",
+ "export-section-success-muted": "text-green-700",
+
+ // Export page section colors - Info (blue)
+ "export-section-info-bg": "bg-blue-50",
+ "export-section-info-border": "border-blue-200",
+ "export-section-info-icon": "text-blue-600",
+ "export-section-info-title": "text-blue-900",
+ "export-section-info-text": "text-blue-800",
+
+ // Export page section colors - Warning (yellow)
+ "export-section-warning-bg": "bg-yellow-50",
+ "export-section-warning-border": "border-yellow-200",
+ "export-section-warning-icon": "text-yellow-600",
+ "export-section-warning-title": "text-yellow-900",
+ "export-section-warning-text": "text-yellow-800",
+ "export-section-warning-muted": "text-yellow-700",
+ "export-section-warning-code": "bg-yellow-100",
+
+ // Muted background
+ "bg-muted": "bg-gray-50",
},
},
@@ -642,6 +720,45 @@ const getThemeConfigs = () => {
"success-bg": "bg-green-50",
"success-border": "border-green-200",
"success-text": "text-green-800",
+
+ // Help page section colors
+ "help-section-blue-text": "text-blue-600",
+ "help-section-blue-bg": "bg-blue-50",
+ "help-section-green-text": "text-green-600",
+ "help-section-green-bg": "bg-green-50",
+ "help-section-purple-text": "text-purple-600",
+ "help-section-purple-bg": "bg-purple-50",
+ "help-section-pink-text": "text-pink-600",
+ "help-section-pink-bg": "bg-pink-50",
+ "help-section-red-text": "text-red-600",
+ "help-section-red-bg": "bg-red-50",
+
+ // Export page section colors - Success (green)
+ "export-section-success-bg": "bg-green-50",
+ "export-section-success-border": "border-green-200",
+ "export-section-success-icon": "text-green-600",
+ "export-section-success-title": "text-green-900",
+ "export-section-success-text": "text-green-800",
+ "export-section-success-muted": "text-green-700",
+
+ // Export page section colors - Info (blue)
+ "export-section-info-bg": "bg-blue-50",
+ "export-section-info-border": "border-blue-200",
+ "export-section-info-icon": "text-blue-600",
+ "export-section-info-title": "text-blue-900",
+ "export-section-info-text": "text-blue-800",
+
+ // Export page section colors - Warning (yellow)
+ "export-section-warning-bg": "bg-yellow-50",
+ "export-section-warning-border": "border-yellow-200",
+ "export-section-warning-icon": "text-yellow-600",
+ "export-section-warning-title": "text-yellow-900",
+ "export-section-warning-text": "text-yellow-800",
+ "export-section-warning-muted": "text-yellow-700",
+ "export-section-warning-code": "bg-yellow-100",
+
+ // Muted background
+ "bg-muted": "bg-gray-50",
},
},
@@ -849,6 +966,45 @@ const getThemeConfigs = () => {
"success-bg": "bg-green-50",
"success-border": "border-green-200",
"success-text": "text-green-800",
+
+ // Help page section colors
+ "help-section-blue-text": "text-blue-600",
+ "help-section-blue-bg": "bg-blue-50",
+ "help-section-green-text": "text-green-600",
+ "help-section-green-bg": "bg-green-50",
+ "help-section-purple-text": "text-purple-600",
+ "help-section-purple-bg": "bg-purple-50",
+ "help-section-pink-text": "text-pink-600",
+ "help-section-pink-bg": "bg-pink-50",
+ "help-section-red-text": "text-red-600",
+ "help-section-red-bg": "bg-red-50",
+
+ // Export page section colors - Success (green)
+ "export-section-success-bg": "bg-green-50",
+ "export-section-success-border": "border-green-200",
+ "export-section-success-icon": "text-green-600",
+ "export-section-success-title": "text-green-900",
+ "export-section-success-text": "text-green-800",
+ "export-section-success-muted": "text-green-700",
+
+ // Export page section colors - Info (blue)
+ "export-section-info-bg": "bg-blue-50",
+ "export-section-info-border": "border-blue-200",
+ "export-section-info-icon": "text-blue-600",
+ "export-section-info-title": "text-blue-900",
+ "export-section-info-text": "text-blue-800",
+
+ // Export page section colors - Warning (yellow)
+ "export-section-warning-bg": "bg-yellow-50",
+ "export-section-warning-border": "border-yellow-200",
+ "export-section-warning-icon": "text-yellow-600",
+ "export-section-warning-title": "text-yellow-900",
+ "export-section-warning-text": "text-yellow-800",
+ "export-section-warning-muted": "text-yellow-700",
+ "export-section-warning-code": "bg-yellow-100",
+
+ // Muted background
+ "bg-muted": "bg-gray-50",
},
},
@@ -1056,6 +1212,45 @@ const getThemeConfigs = () => {
"success-bg": "bg-green-50",
"success-border": "border-green-200",
"success-text": "text-green-800",
+
+ // Help page section colors
+ "help-section-blue-text": "text-blue-600",
+ "help-section-blue-bg": "bg-blue-50",
+ "help-section-green-text": "text-green-600",
+ "help-section-green-bg": "bg-green-50",
+ "help-section-purple-text": "text-purple-600",
+ "help-section-purple-bg": "bg-purple-50",
+ "help-section-pink-text": "text-pink-600",
+ "help-section-pink-bg": "bg-pink-50",
+ "help-section-red-text": "text-red-600",
+ "help-section-red-bg": "bg-red-50",
+
+ // Export page section colors - Success (green)
+ "export-section-success-bg": "bg-green-50",
+ "export-section-success-border": "border-green-200",
+ "export-section-success-icon": "text-green-600",
+ "export-section-success-title": "text-green-900",
+ "export-section-success-text": "text-green-800",
+ "export-section-success-muted": "text-green-700",
+
+ // Export page section colors - Info (blue)
+ "export-section-info-bg": "bg-blue-50",
+ "export-section-info-border": "border-blue-200",
+ "export-section-info-icon": "text-blue-600",
+ "export-section-info-title": "text-blue-900",
+ "export-section-info-text": "text-blue-800",
+
+ // Export page section colors - Warning (yellow)
+ "export-section-warning-bg": "bg-yellow-50",
+ "export-section-warning-border": "border-yellow-200",
+ "export-section-warning-icon": "text-yellow-600",
+ "export-section-warning-title": "text-yellow-900",
+ "export-section-warning-text": "text-yellow-800",
+ "export-section-warning-muted": "text-yellow-700",
+ "export-section-warning-code": "bg-yellow-100",
+
+ // Muted background
+ "bg-muted": "bg-gray-50",
},
},
};
diff --git a/web/maplefile-frontend/src/components/pages/Anonymous/Login/LoginPageUIX.jsx b/web/maplefile-frontend/src/components/pages/Anonymous/Login/LoginPageUIX.jsx
index 85165a8..87d0e62 100644
--- a/web/maplefile-frontend/src/components/pages/Anonymous/Login/LoginPageUIX.jsx
+++ b/web/maplefile-frontend/src/components/pages/Anonymous/Login/LoginPageUIX.jsx
@@ -33,6 +33,7 @@ function LoginPageUIX() {
const authManager = useAuthManager();
const navigate = useNavigate();
const emailInputRef = useRef(null);
+ const isMountedRef = useRef(true);
// UIX Theme support - defaults to blue theme
const { getThemeClasses } = useUIXTheme();
@@ -47,6 +48,14 @@ function LoginPageUIX() {
const [showPassword, setShowPassword] = useState(false);
const [hasInitialized, setHasInitialized] = useState(false);
+ // Cleanup on unmount - prevents state updates after unmount
+ useEffect(() => {
+ isMountedRef.current = true;
+ return () => {
+ isMountedRef.current = false;
+ };
+ }, []);
+
// Split useEffect 1: Basic initialization
useEffect(() => {
if (hasInitialized) return;
@@ -145,9 +154,12 @@ function LoginPageUIX() {
return newErrors;
};
- const handleSubmit = async (e) => {
+ const handleSubmit = useCallback(async (e) => {
e.preventDefault();
+ // Prevent state updates if component is unmounted
+ if (!isMountedRef.current) return;
+
const validationErrors = validateForm();
if (Object.keys(validationErrors).length > 0) {
setErrors(validationErrors);
@@ -177,6 +189,8 @@ function LoginPageUIX() {
password: formData.password,
});
+ if (!isMountedRef.current) return;
+
if (import.meta.env.DEV) {
console.log("LoginPage: Login successful");
}
@@ -203,6 +217,8 @@ function LoginPageUIX() {
navigate("/login/2fa");
}
} catch (error) {
+ if (!isMountedRef.current) return;
+
if (import.meta.env.DEV) {
console.error("LoginPage: Login failed", error);
}
@@ -215,16 +231,18 @@ function LoginPageUIX() {
form?.classList.add("animate-shake");
setTimeout(() => form?.classList.remove("animate-shake"), 500);
} finally {
- setLoading(false);
+ if (isMountedRef.current) {
+ setLoading(false);
+ }
}
- };
+ }, [formData, rememberMe, authManager, navigate, validateForm]);
// Handle Enter key submission - memoized to prevent Input component re-renders
const handleKeyDown = useCallback((e) => {
if (e.key === "Enter" && !loading) {
handleSubmit(e);
}
- }, [loading]); // Depends on loading state to disable during submission
+ }, [loading, handleSubmit]); // Depends on loading state and handleSubmit
// Memoized password toggle button - prevents Input re-renders
const passwordSuffix = useMemo(() => (
@@ -350,7 +368,7 @@ function LoginPageUIX() {
- © 2024 Flashpoint Training + © 2025 Flashpoint Training