'use client'; import { useEffect, useRef, useState } from 'react'; import { useSession } from 'next-auth/react'; interface ResponsiveIframeProps { src: string; className?: string; allow?: string; style?: React.CSSProperties; token?: string; } export function ResponsiveIframe({ src, className = '', allow, style, token }: ResponsiveIframeProps) { const iframeRef = useRef(null); const { data: session } = useSession(); const [authError, setAuthError] = useState(null); // Add token parameter only if token is provided const fullSrc = token ? `${src}${src.includes('?') ? '&' : '?'}token=${encodeURIComponent(token)}` : src; // Handle silent authentication refresh useEffect(() => { let silentRefreshTimer: NodeJS.Timeout; // Set up periodic silent refresh (every 15 minutes) const startSilentRefresh = () => { silentRefreshTimer = setInterval(() => { console.log('Performing silent authentication check for iframes'); // Create a hidden iframe for silent authentication const refreshFrame = document.createElement('iframe'); refreshFrame.style.display = 'none'; refreshFrame.src = '/silent-refresh'; document.body.appendChild(refreshFrame); // Remove iframe after it has loaded (5 seconds timeout) setTimeout(() => { if (refreshFrame && refreshFrame.parentNode) { refreshFrame.parentNode.removeChild(refreshFrame); } }, 5000); }, 15 * 60 * 1000); // 15 minutes }; if (session) { startSilentRefresh(); } return () => { if (silentRefreshTimer) { clearInterval(silentRefreshTimer); } }; }, [session]); useEffect(() => { const iframe = iframeRef.current; if (!iframe) return; const calculateHeight = () => { const pageY = (elem: HTMLElement): number => { return elem.offsetParent ? (elem.offsetTop + pageY(elem.offsetParent as HTMLElement)) : elem.offsetTop; }; const height = document.documentElement.clientHeight; const iframeY = pageY(iframe); const newHeight = Math.max(0, height - iframeY); iframe.style.height = `${newHeight}px`; }; const handleHashChange = () => { if (window.location.hash && window.location.hash.length) { const iframeURL = new URL(iframe.src); iframeURL.hash = window.location.hash; iframe.src = iframeURL.toString(); } }; // Handle authentication messages from iframe const handleMessage = (event: MessageEvent) => { // Accept messages from our iframe or from silent auth iframe if (event.source !== iframe.contentWindow && !event.data?.type?.startsWith('SILENT_AUTH_')) return; const { type, data, error } = event.data || {}; // Handle auth-related messages if (type === 'AUTH_ERROR' || type === 'SESSION_EXPIRED') { console.log('Auth error in iframe:', data || error); setAuthError(error || 'Authentication error'); } else if (type === 'SILENT_AUTH_SUCCESS') { console.log('Silent authentication successful'); setAuthError(null); } else if (type === 'SILENT_AUTH_FAILURE') { console.log('Silent authentication failed:', error); // Only set error if it's persistent if (error !== 'loading') { setAuthError('Session expired'); } } }; // Initial setup calculateHeight(); handleHashChange(); // Event listeners window.addEventListener('resize', calculateHeight); window.addEventListener('hashchange', handleHashChange); window.addEventListener('message', handleMessage); iframe.addEventListener('load', calculateHeight); // Cleanup return () => { window.removeEventListener('resize', calculateHeight); window.removeEventListener('hashchange', handleHashChange); window.removeEventListener('message', handleMessage); iframe.removeEventListener('load', calculateHeight); }; }, []); return ( <> {authError && (
Authentication error: {authError}. The service might not work correctly.
)}