update
This commit is contained in:
102
Frontend/src/shared/components/MfaRequiredBanner.tsx
Normal file
102
Frontend/src/shared/components/MfaRequiredBanner.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import React from 'react';
|
||||
import { AlertTriangle, Shield, ArrowRight } from 'lucide-react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import useAuthStore from '../../store/useAuthStore';
|
||||
|
||||
interface MfaRequiredBannerProps {
|
||||
/**
|
||||
* Role-specific security page path
|
||||
* e.g., '/accountant/security' or '/admin/security'
|
||||
*/
|
||||
securityPagePath: string;
|
||||
/**
|
||||
* Optional custom message
|
||||
*/
|
||||
message?: string;
|
||||
/**
|
||||
* Optional callback when banner is dismissed
|
||||
*/
|
||||
onDismiss?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* MFA Required Banner Component
|
||||
*
|
||||
* Displays a warning banner when MFA is required but not enabled.
|
||||
* Used on dashboards for roles that require MFA for financial access.
|
||||
*/
|
||||
const MfaRequiredBanner: React.FC<MfaRequiredBannerProps> = ({
|
||||
securityPagePath,
|
||||
message,
|
||||
onDismiss,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const { userInfo } = useAuthStore();
|
||||
const [dismissed, setDismissed] = React.useState(false);
|
||||
|
||||
// Check if MFA is required for this role
|
||||
const isFinancialRole = userInfo?.role === 'accountant' || userInfo?.role === 'admin';
|
||||
|
||||
if (!isFinancialRole || dismissed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleSetupMfa = () => {
|
||||
navigate(`${securityPagePath}?setup_mfa=true`);
|
||||
};
|
||||
|
||||
const handleDismiss = () => {
|
||||
setDismissed(true);
|
||||
if (onDismiss) {
|
||||
onDismiss();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-gradient-to-r from-amber-50 via-yellow-50 to-amber-50 border-l-4 border-amber-500 rounded-lg shadow-md mb-6 p-4 sm:p-5">
|
||||
<div className="flex items-start gap-3 sm:gap-4">
|
||||
<div className="flex-shrink-0">
|
||||
<div className="w-10 h-10 sm:w-12 sm:h-12 rounded-full bg-amber-100 flex items-center justify-center">
|
||||
<AlertTriangle className="w-5 h-5 sm:w-6 sm:h-6 text-amber-600" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="flex-1">
|
||||
<h3 className="text-base sm:text-lg font-semibold text-amber-900 mb-1 flex items-center gap-2">
|
||||
<Shield className="w-4 h-4 sm:w-5 sm:h-5" />
|
||||
Multi-Factor Authentication Required
|
||||
</h3>
|
||||
<p className="text-sm sm:text-base text-amber-800 mb-3">
|
||||
{message ||
|
||||
'Multi-factor authentication is required for financial access. Please enable MFA to continue using financial features.'}
|
||||
</p>
|
||||
|
||||
<button
|
||||
onClick={handleSetupMfa}
|
||||
className="inline-flex items-center gap-2 px-4 py-2 bg-amber-600 hover:bg-amber-700 text-white font-medium rounded-lg transition-colors duration-200 shadow-sm hover:shadow-md"
|
||||
>
|
||||
<Shield className="w-4 h-4" />
|
||||
Enable MFA Now
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleDismiss}
|
||||
className="flex-shrink-0 text-amber-600 hover:text-amber-800 transition-colors p-1"
|
||||
aria-label="Dismiss banner"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MfaRequiredBanner;
|
||||
Reference in New Issue
Block a user