import { useState, useEffect, useRef } from 'react' import { useParams, useNavigate } from 'react-router-dom' import { ChevronRight } from 'lucide-react' import { Sidebar } from '../components/Sidebar' import type { User } from '../types' export function AppFrame({ user }: { user: User }) { const { slug } = useParams<{ slug: string }>() const navigate = useNavigate() const app = user.apps.find(a => a.slug === slug) const [menuOpen, setMenuOpen] = useState(false) const iframeRef = useRef(null) // Capture hash once at mount — before iframe navigation overwrites it const [initialSrc] = useState(() => { if (!app) return '' const sub = window.location.hash.slice(1) return sub && sub !== '/' ? `${app.base_path}${sub}` : `${app.base_path}/` }) // Clear hash when switching apps useEffect(() => { return () => { history.replaceState(null, '', window.location.pathname) } }, [slug]) // Auto-close when user clicks into / navigates within the iframe useEffect(() => { if (!menuOpen) return const close = () => setMenuOpen(false) window.addEventListener('blur', close) return () => window.removeEventListener('blur', close) }, [menuOpen]) function handleIframeLoad() { try { const iframePath = iframeRef.current?.contentWindow?.location.pathname ?? '' const relative = iframePath.replace(app!.base_path, '') || '/' if (relative !== '/') { history.replaceState(null, '', `/app/${slug}#${relative}`) } } catch { // cross-origin guard — won't trigger in this same-origin stack } } if (!app) { return (

App not found or not permitted.

) } return (
{/* Collapsed sidebar strip */}
{/* Overlay sidebar + backdrop when open */} {menuOpen && ( <>
setMenuOpen(false)} style={{ position: 'fixed', inset: 0, zIndex: 19, background: 'rgba(0,0,0,0.35)' }} />
setMenuOpen(false)} />
)} {/* App iframe */}