// Root app — chooser ←→ product page with horizontal slide animation. // Click Recruit (right side) → page slides LEFT, Recruit comes in from right. // Click Anytime (left side) → page slides RIGHT, Anytime comes in from left. // No "spinning up" interstitial — just a clean 480ms slide. // // Centralized routing: same React bundle is served at /, /recruiters, // /recruiters.html, /anytime. QR codes pointing at /recruiters land // directly on the recruit view (no chooser flash). The "switch sides" // button + browser back/forward all update the URL via pushState so the // page is refresh-safe. const SLIDE_MS = 480; function getInitialView() { if (typeof window === 'undefined') return 'chooser'; const p = window.location.pathname.toLowerCase().replace(/\.html?$/, ''); if (p === '/recruiters' || p === '/recruiter' || p.startsWith('/recruit')) return 'recruit'; if (p === '/anytime' || p.startsWith('/anytime')) return 'anytime'; return 'chooser'; } function urlFor(view) { // Canonical paths: /recruit and /anytime. /recruiters still resolves (legacy // QR code traffic) — handled in getInitialView via startsWith('/recruit'). if (view === 'recruit') return '/recruit'; if (view === 'anytime') return '/anytime'; return '/'; } function pushUrl(view) { if (typeof window === 'undefined' || !window.history) return; const target = urlFor(view); if (window.location.pathname !== target) { window.history.pushState({ view }, '', target); } } function LandingApp() { const [view, setView] = React.useState(getInitialView()); // 'chooser' | 'recruit' | 'anytime' const [slidingTo, setSlidingTo] = React.useState(null); // 'recruit' | 'anytime' | null const [isSliding, setIsSliding] = React.useState(false); // toggles after first paint to start the transition const handleChoose = (which) => { if (slidingTo) return; if (typeof window !== 'undefined' && window.tkTrack) window.tkTrack('side_chosen', { side: which }); setSlidingTo(which); setIsSliding(false); // double-RAF to ensure the initial (pre-slide) transform has painted // before we toggle to the final transform — otherwise the browser // skips the transition. requestAnimationFrame(() => requestAnimationFrame(() => setIsSliding(true))); setTimeout(() => { setView(which); setSlidingTo(null); setIsSliding(false); pushUrl(which); }, SLIDE_MS + 20); }; const handleSwitch = () => { if (typeof window !== 'undefined' && window.tkTrack) window.tkTrack('side_switched_back', { from: view }); setView('chooser'); pushUrl('chooser'); }; // Browser back/forward → re-derive view from URL React.useEffect(() => { const onPop = () => setView(getInitialView()); window.addEventListener('popstate', onPop); return () => window.removeEventListener('popstate', onPop); }, []); React.useEffect(() => { if (!slidingTo) window.scrollTo({ top: 0, behavior: 'instant' }); }, [view, slidingTo]); if (slidingTo) { // Recruit lives to the RIGHT of chooser; Anytime lives to the LEFT. const dir = slidingTo === 'recruit' ? 'left' : 'right'; const Product = slidingTo === 'recruit' ? RecruitLanding : AnytimeLanding; return (
{}} />
); } return ( <> {view === 'chooser' && } {view === 'recruit' && } {view === 'anytime' && } ); } ReactDOM.createRoot(document.getElementById('root')).render();