175 lines
7.3 KiB
TypeScript
175 lines
7.3 KiB
TypeScript
import React, { useEffect } from 'react';
|
|
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 });
|
|
};
|
|
|
|
return (
|
|
<div
|
|
role="alertdialog"
|
|
aria-modal="true"
|
|
aria-labelledby="partner-denied-title"
|
|
aria-describedby="partner-denied-description"
|
|
className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/85 backdrop-blur-md animate-in fade-in duration-200"
|
|
>
|
|
<div className="relative w-full max-w-lg overflow-hidden rounded-2xl bg-[#0e1424] border border-rose-900/60 shadow-2xl shadow-rose-950/50">
|
|
{/* Glow Header Accent */}
|
|
<div className="h-2 w-full bg-linear-to-r from-rose-600 via-red-500 to-amber-500" />
|
|
|
|
<div className="p-6 sm:p-8 space-y-6">
|
|
{/* Header */}
|
|
<div className="flex items-start gap-4">
|
|
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-rose-500/15 border border-rose-500/30 text-rose-400">
|
|
<Ban className="h-6 w-6 text-rose-400" />
|
|
</div>
|
|
<div className="space-y-1">
|
|
<div className="flex items-center gap-2">
|
|
<span className="inline-flex items-center gap-1 text-[11px] font-semibold text-rose-400 bg-rose-950/60 px-2 py-0.5 rounded-md border border-rose-800/60">
|
|
<Lock className="w-3 h-3" />
|
|
Restricted Role
|
|
</span>
|
|
<span className="text-xs text-slate-500">Security Policy</span>
|
|
</div>
|
|
<h2 id="partner-denied-title" className="text-lg font-bold text-white tracking-tight">
|
|
Access Denied: Partner Role
|
|
</h2>
|
|
<p id="partner-denied-description" className="text-xs text-slate-400 leading-relaxed">
|
|
Users assigned the <strong className="text-rose-300">Partner</strong> role by security are not permitted to access the PFM Backoffice Console.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* User & Identity Summary Card */}
|
|
<div className="rounded-xl bg-slate-900/80 border border-slate-800 p-4 space-y-3 text-xs">
|
|
<div className="flex items-center justify-between pb-2 border-b border-slate-800/80">
|
|
<span className="text-slate-400 font-medium">Account Name</span>
|
|
<span className="text-white font-semibold">{displayName}</span>
|
|
</div>
|
|
|
|
{displayEmail && (
|
|
<div className="flex items-center justify-between pb-2 border-b border-slate-800/80">
|
|
<span className="text-slate-400 font-medium flex items-center gap-1.5">
|
|
<Mail className="w-3.5 h-3.5 text-slate-500" />
|
|
Email
|
|
</span>
|
|
<span className="text-slate-200 font-mono">{displayEmail}</span>
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex items-center justify-between pb-2 border-b border-slate-800/80">
|
|
<span className="text-slate-400 font-medium flex items-center gap-1.5">
|
|
<Building2 className="w-3.5 h-3.5 text-slate-500" />
|
|
Assigned Role
|
|
</span>
|
|
<span className="text-rose-400 font-semibold bg-rose-950/60 px-2 py-0.5 rounded border border-rose-800/50">
|
|
{role}
|
|
</span>
|
|
</div>
|
|
|
|
{tenant && (
|
|
<div className="flex items-center justify-between pb-2 border-b border-slate-800/80">
|
|
<span className="text-slate-400 font-medium flex items-center gap-1.5">
|
|
<Building2 className="w-3.5 h-3.5 text-slate-500" />
|
|
Tenant Context
|
|
</span>
|
|
<span className="text-slate-200 font-medium truncate max-w-[220px]">{tenant}</span>
|
|
</div>
|
|
)}
|
|
|
|
{sub && (
|
|
<div className="flex items-center justify-between text-[11px] text-slate-500">
|
|
<span className="flex items-center gap-1">
|
|
<Fingerprint className="w-3 h-3" />
|
|
Subject Key
|
|
</span>
|
|
<span className="font-mono text-slate-400 truncate max-w-[200px]">{sub}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Security Policy Information */}
|
|
<div className="p-4 rounded-xl bg-rose-950/20 border border-rose-900/40 text-xs text-rose-200 leading-relaxed space-y-1.5">
|
|
<p className="font-semibold text-rose-300 flex items-center gap-1.5">
|
|
<ShieldAlert className="w-4 h-4 text-rose-400" />
|
|
Administrative Boundary Notice
|
|
</p>
|
|
<p className="text-[11px] text-rose-300/90">
|
|
The PFM Console is reserved for statutory administrators, sponsors, programme managers, and governance officers. Partner credentials cannot access this environment. If you require backoffice administrative access, please request an updated role assignment from your system administrator.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Actions */}
|
|
<div className="pt-2">
|
|
<button
|
|
onClick={handleLogoutClick}
|
|
className="w-full flex items-center justify-center gap-2 py-2.5 px-4 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-200 hover:text-white text-xs font-semibold border border-slate-700 transition cursor-pointer shadow-sm"
|
|
>
|
|
<LogOut className="w-4 h-4 text-rose-400" />
|
|
<span>Sign Out & Return to Home</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Footer Brand watermark */}
|
|
<div className="px-6 py-3 bg-[#0a0f1d] border-t border-slate-800/80 flex items-center justify-between text-[11px] text-slate-500">
|
|
<div className="flex items-center gap-2">
|
|
<BrandLogo size={16} showGlow={false} animateOnHover={false} />
|
|
<span>Post Fund Management (PFM)</span>
|
|
</div>
|
|
<span>National Security Gateway</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|