import React, { useEffect, useState, useRef } from 'react'; import { createPortal } from 'react-dom'; import { Clock, LogOut, RefreshCw } from 'lucide-react'; import { PfmPartnerLogo } from '../common/PfmPartnerLogo'; import { clearSessionAndRedirectToLanding, dismissSubordinateModals } from '../../services/sessionExpiration'; interface SessionExpiredModalProps { isOpen: boolean; onDismiss?: () => void; reason?: string | null; countdownSeconds?: number; } export const SessionExpiredModal: React.FC = ({ isOpen, onDismiss, reason, countdownSeconds = 8, }) => { const [timeLeftMs, setTimeLeftMs] = useState(countdownSeconds * 1000); const [isPaused, setIsPaused] = useState(false); const totalDurationMs = countdownSeconds * 1000; const isClearingRef = useRef(false); useEffect(() => { if (isOpen) { dismissSubordinateModals(); } }, [isOpen]); useEffect(() => { const handleCancelled = () => { setTimeLeftMs(countdownSeconds * 1000); setIsPaused(false); isClearingRef.current = false; }; window.addEventListener('pfm:session-expired-cancelled', handleCancelled); return () => { window.removeEventListener('pfm:session-expired-cancelled', handleCancelled); }; }, [countdownSeconds]); useEffect(() => { if (!isOpen) { setTimeLeftMs(countdownSeconds * 1000); setIsPaused(false); isClearingRef.current = false; return; } const intervalMs = 50; const interval = setInterval(() => { setTimeLeftMs((prev) => { if (isPaused) return prev; const next = prev - intervalMs; if (next <= 0) { clearInterval(interval); handleAction(); return 0; } return next; }); }, intervalMs); return () => clearInterval(interval); }, [isOpen, isPaused, countdownSeconds]); const handleAction = () => { if (isClearingRef.current) return; isClearingRef.current = true; if (onDismiss) { onDismiss(); } else { clearSessionAndRedirectToLanding(); } }; if (!isOpen) return null; const secondsRemaining = Math.max(0, Math.ceil(timeLeftMs / 1000)); const progressPercent = Math.max(0, Math.min(100, (timeLeftMs / totalDurationMs) * 100)); const modalContent = (
setIsPaused(true)} onMouseLeave={() => setIsPaused(false)} role="dialog" aria-modal="true" aria-labelledby="session-expired-title" >
Session Expired

Security Session Ended

{reason ? reason.replace(/network\s*error/gi, 'Permission Check') : 'Your security credentials have expired for your protection. Please sign in again to continue.'}

{/* Smooth Countdown Bar */}
Redirecting in {secondsRemaining}s
); return typeof document !== 'undefined' ? createPortal(modalContent, document.body) : modalContent; };