'use client'; import { useEffect, useRef, useState } from 'react'; import { useSession } from 'next-auth/react'; export interface ResponsiveIframeProps { src: string; title?: string; token?: string; className?: string; style?: React.CSSProperties; hideUntilLoad?: boolean; allowFullScreen?: boolean; scrolling?: boolean; heightOffset?: number; } // Map of service prefixes to their base URLs - keep in sync with proxy route.ts const SERVICE_URLS: Record = { 'parole': process.env.NEXT_PUBLIC_IFRAME_PAROLE_URL || '', 'alma': process.env.NEXT_PUBLIC_IFRAME_AI_ASSISTANT_URL || '', 'crm': process.env.NEXT_PUBLIC_IFRAME_MEDIATIONS_URL || '', 'vision': process.env.NEXT_PUBLIC_IFRAME_CONFERENCE_URL || '', 'showcase': process.env.NEXT_PUBLIC_IFRAME_SHOWCASE_URL || '', 'agilite': process.env.NEXT_PUBLIC_IFRAME_AGILITY_URL || '', 'dossiers': process.env.NEXT_PUBLIC_IFRAME_DRIVE_URL || '', 'the-message': process.env.NEXT_PUBLIC_IFRAME_THEMESSAGE_URL || '', 'qg': process.env.NEXT_PUBLIC_IFRAME_MISSIONVIEW_URL || '', 'design': process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || '', 'artlab': process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || '' }; export default function ResponsiveIframe({ src, title = 'Embedded content', token, className = '', style = {}, hideUntilLoad = false, allowFullScreen = false, scrolling = true, heightOffset = 0, }: ResponsiveIframeProps) { const [height, setHeight] = useState(0); const [loaded, setLoaded] = useState(false); const [authError, setAuthError] = useState(false); const iframeRef = useRef(null); const silentAuthRef = useRef(null); const silentAuthTimerRef = useRef(null); const { data: session } = useSession(); // Convert proxy URLs to direct URLs to avoid double proxying const processedSrc = (() => { if (src.startsWith('/api/proxy/')) { // Extract the service name and path const parts = src.replace('/api/proxy/', '').split('/'); const serviceName = parts[0]; const path = parts.slice(1).join('/'); // Look up the base URL for this service const baseUrl = SERVICE_URLS[serviceName]; if (baseUrl) { console.log(`Converting proxy URL to direct URL: ${src} -> ${baseUrl}/${path}`); return `${baseUrl}/${path}`; } } return src; })(); // Append token to src if provided const fullSrc = token ? `${processedSrc}${processedSrc.includes('?') ? '&' : '?'}token=${token}` : processedSrc; // Handle silent authentication refresh useEffect(() => { // Setup silent authentication check every 15 minutes const setupSilentAuth = () => { if (silentAuthTimerRef.current) { clearTimeout(silentAuthTimerRef.current); } // Create a hidden iframe to check authentication status silentAuthTimerRef.current = setTimeout(() => { console.log('Running silent authentication check'); // Create the silent auth iframe if it doesn't exist if (silentAuthRef.current && !silentAuthRef.current.src) { silentAuthRef.current.src = '/silent-refresh'; } // Setup next check setupSilentAuth(); }, 15 * 60 * 1000); // 15 minutes }; // Handle messages from the silent auth iframe const handleAuthMessage = (event: MessageEvent) => { if (event.data && event.data.type === 'AUTH_STATUS') { console.log('Received auth status:', event.data); if (event.data.status === 'UNAUTHENTICATED') { console.error('Silent authentication failed - user is not authenticated'); setAuthError(true); // Force immediate refresh if (silentAuthRef.current) { silentAuthRef.current.src = '/silent-refresh'; } } else if (event.data.status === 'AUTHENTICATED') { console.log('Silent authentication successful'); setAuthError(false); } } }; window.addEventListener('message', handleAuthMessage); setupSilentAuth(); // Cleanup return () => { window.removeEventListener('message', handleAuthMessage); if (silentAuthTimerRef.current) { clearTimeout(silentAuthTimerRef.current); } }; }, []); // Adjust iframe height based on window size useEffect(() => { const updateHeight = () => { const viewportHeight = window.innerHeight; const newHeight = viewportHeight - heightOffset; setHeight(newHeight > 0 ? newHeight : 0); }; updateHeight(); window.addEventListener('resize', updateHeight); return () => { window.removeEventListener('resize', updateHeight); }; }, [heightOffset]); // Handle hash changes by updating iframe source useEffect(() => { const handleHashChange = () => { const iframe = iframeRef.current; if (iframe && iframe.src) { const url = new URL(iframe.src); // If there's a hash in the parent window's URL if (window.location.hash) { url.hash = window.location.hash; iframe.src = url.toString(); } } }; window.addEventListener('hashchange', handleHashChange); return () => { window.removeEventListener('hashchange', handleHashChange); }; }, []); return ( <> {/* Hidden iframe for silent authentication */}