"use client"; import { useEffect } from "react"; import { MotionConfig } from "framer-motion"; import { HomeScreen } from "@/components/HomeScreen"; import { GameScreen } from "@/components/screens/GameScreen"; import { ProfileScreen } from "@/components/screens/ProfileScreen"; import { FriendsScreen } from "@/components/screens/FriendsScreen"; import { OnlineLobbyScreen } from "@/components/screens/OnlineLobbyScreen"; import { RoomScreen } from "@/components/screens/RoomScreen"; import { MatchmakingScreen } from "@/components/screens/MatchmakingScreen"; import { LeaderboardScreen } from "@/components/screens/LeaderboardScreen"; import { ShopScreen } from "@/components/screens/ShopScreen"; import { BuyCoinsScreen } from "@/components/screens/BuyCoinsScreen"; import { AchievementsScreen } from "@/components/screens/AchievementsScreen"; import { ChatScreen } from "@/components/screens/ChatScreen"; import { NotificationsScreen } from "@/components/screens/NotificationsScreen"; import { AuthScreen } from "@/components/screens/AuthScreen"; import { DailyRewardModal } from "@/components/online/DailyRewardModal"; import { NotificationToaster } from "@/components/online/NotificationToaster"; import { ResumeGameBar } from "@/components/online/ResumeGameBar"; import { CelebrationOverlay } from "@/components/online/CelebrationOverlay"; import { PublicProfileModal } from "@/components/online/PublicProfileModal"; import { CapacitorBack } from "@/components/CapacitorBack"; import { useSessionStore } from "@/lib/session-store"; import { useGameStore } from "@/lib/game-store"; import { useOnlineStore } from "@/lib/online-store"; import { useNotifStore, pushNotification } from "@/lib/notification-store"; import { getService } from "@/lib/online/service"; import { captureBazaarRedirect } from "@/lib/storeBilling"; import { screenFromHash, useUIStore, type Screen } from "@/lib/ui-store"; /** Transient screens can't be restored without their state — fall back to home. */ function resolveScreen(s: Screen): Screen { switch (s) { case "game": return useGameStore.getState().started ? s : "home"; case "room": return useOnlineStore.getState().room ? s : "home"; case "chat": return useOnlineStore.getState().activeChatFriend ? s : "home"; case "matchmaking": return useOnlineStore.getState().matchmaking.phase !== "idle" ? s : "home"; default: return s; } } export default function Page() { const screen = useUIStore((s) => s.screen); const init = useSessionStore((s) => s.init); const loading = useSessionStore((s) => s.loading); useEffect(() => { init(); // ZarinPal payment return (?pay=success&coins= / ?pay=failed) const params = new URLSearchParams(window.location.search); const pay = params.get("pay"); if (pay) { if (pay === "success") { const coins = params.get("coins"); pushNotification({ kind: "system", titleFa: "پرداخت موفق", titleEn: "Payment successful", bodyFa: coins ? `${coins} سکه به حساب شما اضافه شد` : undefined, bodyEn: coins ? `${coins} coins added` : undefined, icon: "💰", }); useSessionStore.getState().refreshProfile(); } else { pushNotification({ kind: "system", titleFa: "پرداخت ناموفق بود", titleEn: "Payment failed", icon: "⚠️" }); } window.history.replaceState({}, "", window.location.pathname); } // Cafe Bazaar in-app purchase return (?purchaseToken=...) → verify + credit. const iab = captureBazaarRedirect(); if (iab && iab.productId) { getService() .verifyIab(iab.store, iab.productId, iab.token) .then((v) => { if (v.ok) { if (v.profile) useSessionStore.setState({ profile: v.profile }); pushNotification({ kind: "system", titleFa: "پرداخت موفق", titleEn: "Payment successful", bodyFa: v.coins ? `${v.coins.toLocaleString()} سکه اضافه شد` : undefined, bodyEn: v.coins ? `${v.coins.toLocaleString()} coins added` : undefined, icon: "💰", }); } else { pushNotification({ kind: "system", titleFa: "پرداخت ناموفق بود", titleEn: "Payment failed", icon: "⚠️" }); } }) .finally(() => window.history.replaceState({}, "", window.location.pathname)); } useUIStore.getState().initHistory(); useNotifStore.getState().init(); // surface a daily-reward notification if it's available getService() .getDailyState() .then((d) => { if (d.available) pushNotification({ kind: "daily", titleFa: "پاداش روزانه آماده است", titleEn: "Daily reward is ready", icon: "🎁", }); }) .catch(() => {}); // Resume an in-progress server match after a full reload: the server // re-broadcasts state on (re)connect — if we're not already in a game and // not mid-matchmaking, re-enter live mode (minimized) so the resume pill shows. const svc = getService(); let resumeUnsub: (() => void) | undefined; let rewardUnsub: (() => void) | undefined; if (svc.live) { resumeUnsub = svc.onState((s) => { const gs = useGameStore.getState(); const scr = useUIStore.getState().screen; if ( !gs.started && scr !== "matchmaking" && scr !== "game" && s.matchWinner == null && s.phase !== "match-over" ) { gs.enterServerMatch(svc); gs.applyServerState(s); gs.minimize(); } }); // Nudge the player when a match they left finishes while they're away. rewardUnsub = svc.onReward(() => { if (useUIStore.getState().screen !== "game") pushNotification({ kind: "system", titleFa: "بازی به پایان رسید", titleEn: "Match ended", bodyFa: "نتیجه و جایزه را ببینید", bodyEn: "See the result and reward", icon: "🏆", }); }); } const onPop = (e: PopStateEvent) => { const raw = ((e.state?.screen as Screen) ?? screenFromHash()); useUIStore.getState().syncFromPop(resolveScreen(raw)); }; window.addEventListener("popstate", onPop); return () => { window.removeEventListener("popstate", onPop); resumeUnsub?.(); rewardUnsub?.(); }; }, [init]); return ( // reducedMotion="user" makes every Framer Motion animation honor the OS // "reduce motion" accessibility setting (coin rain, confetti, count-ups…). {renderScreen(screen)} {loading && null} ); } function renderScreen(screen: string) { switch (screen) { case "game": return ; case "auth": return ; case "profile": return ; case "friends": return ; case "online": return ; case "room": return ; case "matchmaking": return ; case "leaderboard": return ; case "shop": return ; case "buycoins": return ; case "achievements": return ; case "chat": return ; case "notifications": return ; default: return ; } }