Files
pfm/PostFundManagement.ConsoleUI/src/components/auth/PartnerAccessDeniedModal.tsx
T
2026-10-24 17:36:30 +02:00

123 lines
4.5 KiB
TypeScript

import React, { useEffect } from 'react';
import { createPortal } from 'react-dom';
import { useNavigate } from 'react-router-dom';
import {
ShieldAlert,
LogOut,
Ban,
Mail,
Building2,
Fingerprint,
Lock,
} from 'lucide-react';
import { BrandLogo } from '../ui/BrandLogo';
import { AuthUserProfile, UserClaims } from '../../auth/AuthProvider';
import { cancelSessionExpiration, dismissSubordinateModals } from '../../services/sessionExpiration';
interface PartnerAccessDeniedModalProps {
user: AuthUserProfile | null;
claims: UserClaims;
sub: string;
onLogout: () => Promise<void>;
}
export const PartnerAccessDeniedModal: React.FC<PartnerAccessDeniedModalProps> = ({
user,
claims,
sub,
onLogout,
}) => {
const navigate = useNavigate();
// Clear any existing session prompt and close background dialogs
useEffect(() => {
cancelSessionExpiration();
dismissSubordinateModals();
}, []);
const displayName =
user?.name ||
(claims.name as string) ||
(claims.preferred_username as string) ||
'Authenticated User';
const displayEmail =
user?.email ||
(claims.email as string) ||
(claims['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'] as string) ||
'';
const tenant = user?.tenant || (claims.tenant as string) || (claims.org as string) || 'Statutory Enterprise';
const role = user?.role || (claims.role as string) || 'Partner';
const handleLogoutClick = async () => {
await onLogout();
navigate('/', { replace: true });
};
const modalContent = (
<div
role="alertdialog"
aria-modal="true"
aria-labelledby="partner-denied-title"
aria-describedby="partner-denied-description"
className="fixed inset-0 z-[9999] flex items-center justify-center p-4 bg-black/80 backdrop-blur-md animate-in fade-in duration-150 overflow-y-auto"
>
<div className="relative w-full max-w-md overflow-hidden rounded-2xl bg-[#0d1322] border border-slate-800 shadow-2xl my-auto text-slate-100">
<div className="h-1 w-full bg-rose-600" />
<div className="p-5 space-y-4">
<div className="flex items-start gap-3">
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-rose-500/10 border border-rose-500/20 text-rose-400">
<Ban className="h-5 w-5" />
</div>
<div>
<h2 id="partner-denied-title" className="text-base font-bold text-white tracking-tight">
Partner Portal Required
</h2>
<p id="partner-denied-description" className="text-xs text-slate-400 mt-0.5">
Accounts with the Partner role must access the Partner Portal.
</p>
</div>
</div>
<div className="rounded-xl bg-slate-900/60 border border-slate-800 p-3.5 space-y-2 text-xs">
<div className="flex items-center justify-between">
<span className="text-slate-500 text-[11px] uppercase font-semibold">User</span>
<span className="text-white font-medium">{displayName}</span>
</div>
{displayEmail && (
<div className="flex items-center justify-between border-t border-slate-800/60 pt-2">
<span className="text-slate-500 text-[11px] uppercase font-semibold">Email</span>
<span className="text-slate-300 font-mono text-[11px]">{displayEmail}</span>
</div>
)}
<div className="flex items-center justify-between border-t border-slate-800/60 pt-2">
<span className="text-slate-500 text-[11px] uppercase font-semibold">Role</span>
<span className="text-rose-400 font-medium">{role}</span>
</div>
</div>
<p className="text-[11px] text-slate-400 text-center leading-relaxed">
The Console is reserved for statutory administrators and programme managers.
</p>
<div className="pt-1">
<button
onClick={handleLogoutClick}
className="w-full flex items-center justify-center gap-2 py-2.5 px-4 rounded-xl bg-blue-600 hover:bg-blue-500 text-white text-xs font-semibold shadow-md transition cursor-pointer"
>
<LogOut className="w-4 h-4" />
<span>Sign Out & Return Home</span>
</button>
</div>
</div>
</div>
</div>
);
return typeof document !== 'undefined'
? createPortal(modalContent, document.body)
: modalContent;
};