This commit is contained in:
Iliyan Angelov
2025-12-05 22:12:32 +02:00
parent 13c91f95f4
commit 7667eb5eda
53 changed files with 3065 additions and 9257 deletions

View 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;