'use client' import { useEffect, useMemo, useRef, useState } from 'react' import Link from 'next/link' import { ArrowLeft, Check, Copy, Heart } from 'lucide-react' import { usePostHog } from 'posthog-js/react' import { isValidInviteCode, normalizeInviteCode } from '../../../lib/inviteCode' import { APP_STORE_URL, PLAY_STORE_URL, buildInviteSchemeUrl } from '../../../lib/appLinks' type Platform = 'ios' | 'android' | 'desktop' | 'other' function getPlatform(): Platform { if (typeof navigator === 'undefined') return 'other' const userAgent = navigator.userAgent if (/iPad|iPhone|iPod/i.test(userAgent)) return 'ios' if (/Android/i.test(userAgent)) return 'android' if (/Macintosh|Windows|Linux/i.test(userAgent)) return 'desktop' return 'other' } export function JoinClient({ code }: { code: string }) { const posthog = usePostHog() const [copied, setCopied] = useState(false) const [isOnline, setIsOnline] = useState(true) const [openAppFallbackVisible, setOpenAppFallbackVisible] = useState(false) const [platform, setPlatform] = useState('other') const fallbackTimer = useRef | null>(null) const hasCopiedCode = useRef(false) const isValid = isValidInviteCode(code) const normalizedCode = useMemo(() => (isValid ? normalizeInviteCode(code) : ''), [isValid, code]) useEffect(() => { const detectedPlatform = getPlatform() setPlatform(detectedPlatform) posthog?.capture('join_page_viewed', { code_valid: isValid, platform: detectedPlatform }) // eslint-disable-next-line react-hooks/exhaustive-deps }, []) useEffect(() => { const updateOnlineStatus = () => setIsOnline(navigator.onLine) updateOnlineStatus() window.addEventListener('online', updateOnlineStatus) window.addEventListener('offline', updateOnlineStatus) return () => { window.removeEventListener('online', updateOnlineStatus) window.removeEventListener('offline', updateOnlineStatus) } }, []) useEffect(() => { if (!isOnline) posthog?.capture('join_page_offline_shown') }, [isOnline, posthog]) useEffect(() => () => { if (fallbackTimer.current) clearTimeout(fallbackTimer.current) }, []) const handleCopy = async (trigger: 'code_block' | 'fallback_note') => { try { await navigator.clipboard.writeText(normalizedCode) hasCopiedCode.current = true setCopied(true) posthog?.capture('join_page_code_copied', { trigger }) setTimeout(() => setCopied(false), 2000) } catch (err) { console.error('Failed to copy invite code:', err) } } const handleStoreClick = (store: 'app_store' | 'play_store') => { if (!isOnline) return posthog?.capture('join_page_store_button_clicked', { store, code_copied_first: hasCopiedCode.current }) } const handleOpenInApp = () => { setOpenAppFallbackVisible(false) posthog?.capture('join_page_open_app_clicked', { platform }) window.location.href = buildInviteSchemeUrl(normalizedCode) if (fallbackTimer.current) clearTimeout(fallbackTimer.current) fallbackTimer.current = setTimeout(() => { if (document.visibilityState === 'visible') { setOpenAppFallbackVisible(true) posthog?.capture('join_page_open_app_fallback_shown', { platform }) } }, 1500) } if (!isValid) { const malformedStoreUrl = platform === 'android' ? PLAY_STORE_URL : APP_STORE_URL return (

Invite link not recognized

This invite link looks incomplete. Ask your partner to send a new one from the Sauci app.

Back to Home Get Sauci
) } const copyAnnouncement = copied ? 'Invite code copied.' : '' const storeUnavailableTitle = isOnline ? undefined : 'Reconnect to open the app store.' const desktopCopy = platform === 'desktop' ? 'Sauci is a phone app. Copy your code, then open this link on your phone or install from the store there.' : 'They have already answered questions about you two. When you join, you will both see only the things you agree on. Neither of you sees the other’s individual answers.' return (
Back to Home
{!isOnline && (

You're offline. Your code is below, and it still works.

)}

You've been invited to compare answers

{desktopCopy}

Your invite code

{normalizedCode}

Copy this before you install. You'll enter it in the app.

{copyAnnouncement}

Already installed? This opens the app with your code.

{openAppFallbackVisible && (

Nothing opened? You probably don't have Sauci yet.{' '} , then install below.

)}

Get Sauci

) }