From d6af9543fda3db4becf3631af6de5eb408901b6c Mon Sep 17 00:00:00 2001 From: "vluk@2fi-solutions.com.hk" Date: Tue, 6 Jan 2026 18:39:41 +0800 Subject: [PATCH] no message --- src/components/Require2FA.js | 52 ++++++++++++++++++++++++++++++ src/routes/ClientRoutes.js | 44 ++++++++++++++++--------- src/routes/SettingRoutes.js | 62 ++++++++++++++++++++++++------------ 3 files changed, 122 insertions(+), 36 deletions(-) create mode 100644 src/components/Require2FA.js diff --git a/src/components/Require2FA.js b/src/components/Require2FA.js new file mode 100644 index 0000000..19f266e --- /dev/null +++ b/src/components/Require2FA.js @@ -0,0 +1,52 @@ +// src/components/Require2FA.jsx +import React, { useState, useEffect } from 'react'; +import { Navigate } from 'react-router-dom'; +import { Box, CircularProgress, Typography } from '@mui/material'; +import axios from 'axios'; +import { apiPath } from '../auth/utils'; + +const Require2FA = ({ children }) => { + const [is2FAEnabled, setIs2FAEnabled] = useState(null); // null = loading + const [error, setError] = useState(false); + + useEffect(() => { + const check2FA = async () => { + try { + const response = await axios.get(`${apiPath}/2fa/status`, { + headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` } + }); + setIs2FAEnabled(response.data.enabled); + } catch (err) { + // Fallback to localStorage (same logic as in Profile page) + try { + const userData = JSON.parse(localStorage.getItem('userData') || '{}'); + setIs2FAEnabled(!!userData.twoFactorEnabled); + } catch { + setError(true); + } + } + }; + + check2FA(); + }, []); + + if (is2FAEnabled === null) { + // Still loading + return ( + + + Checking security settings... + + ); + } + + if (!is2FAEnabled || error) { + // Redirect to profile page with a clear message + return ; + } + + // 2FA is enabled → allow access + return children; +}; + +export default Require2FA; \ No newline at end of file diff --git a/src/routes/ClientRoutes.js b/src/routes/ClientRoutes.js index e8efc48..4c093d0 100644 --- a/src/routes/ClientRoutes.js +++ b/src/routes/ClientRoutes.js @@ -1,6 +1,6 @@ import {lazy, useContext} from 'react'; -// project import +import Require2FA from '../components/Require2FA'; import Loadable from 'components/Loadable'; import MainLayout from "../layout/MainLayout"; import {handleRouteAbility} from "../utils/CommonFunction"; @@ -26,64 +26,78 @@ const ClientRoutes =() => { path: '/', element: , children: [ + { path: 'client', element: ( - handleRouteAbility( + + {handleRouteAbility( ability.can('VIEW', 'CLIENT'), , - ) + )} + ), }, { path: 'client/maintain/:id', element: ( + + { handleRouteAbility( ability.can('VIEW', 'CLIENT'), , - ) + )} + ), }, { path: '/pdf/:id', element: ( - handleRouteAbility( - ability.can('VIEW', 'CLIENT'), - , - - ) + + {handleRouteAbility( + ability.can('VIEW', 'CLIENT'), + , + + )} + ), }, { path: '/pdf/maintain/:id', element: ( - handleRouteAbility( + + {handleRouteAbility( ability.can('VIEW', 'CLIENT'), , - ) + )} + ), }, { path: '/template/', element: ( - handleRouteAbility( + + {handleRouteAbility( ability.can('VIEW', 'TEMPLATE'), , - ) + )} + ), }, { path: '/pdf/form-up-down/:id', element: ( - handleRouteAbility( + + {handleRouteAbility( ability.can('VIEW', 'CLIENT'), , - ) + )} + ), }, { diff --git a/src/routes/SettingRoutes.js b/src/routes/SettingRoutes.js index c47179b..0314e19 100644 --- a/src/routes/SettingRoutes.js +++ b/src/routes/SettingRoutes.js @@ -1,6 +1,6 @@ import {lazy, useContext} from 'react'; -// project import +import Require2FA from '../components/Require2FA'; import Loadable from 'components/Loadable'; import MainLayout from "../layout/MainLayout"; import AbilityContext from "../components/AbilityProvider"; @@ -102,102 +102,122 @@ const SettingRoutes = () => { { path: 'usergroupSearchview', element: ( - handleRouteAbility( + + {handleRouteAbility( ability.can('MAINTAIN', 'USER_GROUP'), , - ) + )} + ), }, { path: 'userGroup/:id', element:( - handleRouteAbility( + + {handleRouteAbility( ability.can('MAINTAIN', 'USER_GROUP'), , - ) + )} + ), }, { path: 'user/:id', element: ( - handleRouteAbility( + + {handleRouteAbility( ability.can('VIEW', 'USER'), , - ) + )} + ), }, { path: 'userSearchview', element:( - handleRouteAbility( + + {handleRouteAbility( ability.can('VIEW', 'USER'), , - ) + )} + ), }, { path: 'consultant', element: ( - handleRouteAbility( + + {handleRouteAbility( ability.can('VIEW', 'USER'), , - ) + )} + ), }, { path: 'consultant/:id', element: ( - handleRouteAbility( + + {handleRouteAbility( ability.can('VIEW', 'USER'), , - ) + )} + ), }, { path: 'setting', element: ( - handleRouteAbility( + + {handleRouteAbility( ability.can('MANAGE', 'SYSTEM_CONFIGURATION'), , - ) + )} + ), }, { path: 'auditLog', element:( - handleRouteAbility( + + {handleRouteAbility( ability.can('VIEW', 'AUDIT_LOG'), , - ) + )} + ), }, { path: 'userActionLog', element: ( - handleRouteAbility( + + {handleRouteAbility( ability.can('VIEW', 'USER'), , - ) + )} + ), }, { path: 'loginLog', element: ( - handleRouteAbility( + + {handleRouteAbility( ability.can('VIEW', 'LOGIN_LOG'), , - ) + )} + ), }, {