From 56fb9acfea17eb2383b68d91b5d783f13b32c287 Mon Sep 17 00:00:00 2001 From: mansur-codes Date: Wed, 26 Aug 2026 15:27:12 +0100 Subject: [PATCH 1/3] feat(dashboard): add practice vs on-chain mode chip (#410) --- src/pages/Dashboard.tsx | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index ecb19b6..6572076 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -23,6 +23,7 @@ import { useRoundStore } from "../store/useRoundStore"; import type { Round, UserPrediction, UserStats } from "../lib/api-client"; import { educationApi, statsApi, predictionsApi } from "../lib/api-client"; import { useWalletStore, selectIsWalletConnected } from "../store/useWalletStore"; +import StatusChip from "../components/hud/StatusChip"; import { TipCard } from "../components/education/TipCard"; import type { Tip } from "../types/education"; import EmptyState from '../components/EmptyState'; @@ -192,6 +193,27 @@ const activeRoundId = useRoundStore((state) => state.activeRound?.id ?? null); const [inspector, setInspector] = useState(null); const [isInspectorLoading, setIsInspectorLoading] = useState(false); const [roundSoundEnabled, setRoundSoundEnabled] = useState(() => localStorage.getItem("xelma_round_sound") === "1"); + const [practiceMode, setPracticeMode] = useState(() => localStorage.getItem("xelma_practice_mode") !== "false"); + + const prevWalletConnectedRef = useRef(isWalletConnected); + useEffect(() => { + if (!isWalletConnected) { + if (prevWalletConnectedRef.current) { + setPracticeMode(true); + localStorage.setItem("xelma_practice_mode", "true"); + } + } + prevWalletConnectedRef.current = isWalletConnected; + }, [isWalletConnected]); + + const effectivePracticeMode = !isWalletConnected || practiceMode; + + const handlePracticeModeToggle = () => { + if (!isWalletConnected) return; + const nextMode = !practiceMode; + setPracticeMode(nextMode); + localStorage.setItem("xelma_practice_mode", String(nextMode)); + }; // Asset tab state from URL query param const [searchParams] = useSearchParams(); @@ -383,6 +405,18 @@ const activeRoundId = useRoundStore((state) => state.activeRound?.id ?? null); {!isLoading && (
+
diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index aa5c32a..776afc2 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -182,7 +182,9 @@ const activeRoundId = useRoundStore((state) => state.activeRound?.id ?? null); // Clear the entry marker whenever the active round changes. useEffect(() => { - setEntryPrice(null); + Promise.resolve().then(() => { + setEntryPrice(null); + }); }, [activeRoundId]); const [stats, setStats] = useState(null); @@ -305,8 +307,10 @@ const activeRoundId = useRoundStore((state) => state.activeRound?.id ?? null); }, [isWalletConnected, publicKey]); useEffect(() => { - void fetchStats(); - void fetchActivities(); + Promise.resolve().then(() => { + void fetchStats(); + void fetchActivities(); + }); }, [fetchStats, fetchActivities]); const refreshInspector = useCallback(async () => { @@ -331,7 +335,9 @@ const activeRoundId = useRoundStore((state) => state.activeRound?.id ?? null); }, [isWalletConnected, publicKey]); useEffect(() => { - void refreshInspector(); + Promise.resolve().then(() => { + void refreshInspector(); + }); }, [refreshInspector]); const handleRoundSoundToggle = (enabled: boolean) => { diff --git a/src/pages/Learn.tsx b/src/pages/Learn.tsx index 6def81f..3154cf9 100644 --- a/src/pages/Learn.tsx +++ b/src/pages/Learn.tsx @@ -52,7 +52,9 @@ const LearnPage = () => { }, []); useEffect(() => { - fetchData(); + Promise.resolve().then(() => { + fetchData(); + }); }, [fetchData]); if (loading) {