diff --git a/src/components/PredictionHistory.tsx b/src/components/PredictionHistory.tsx index b8a323b..54eef80 100644 --- a/src/components/PredictionHistory.tsx +++ b/src/components/PredictionHistory.tsx @@ -82,7 +82,9 @@ export default function PredictionHistory({ userId, optimisticPrediction }: Pred }, [history, userId]); useEffect(() => { - void loadHistory(); + Promise.resolve().then(() => { + void loadHistory(); + }); }, [loadHistory]); if (!userId) { @@ -174,12 +176,12 @@ export default function PredictionHistory({ userId, optimisticPrediction }: Pred

{(() => { - const raw = prediction.createdAt; - if (typeof raw !== "string") return "Unknown time"; - const date = new Date(raw); - if (Number.isNaN(date.getTime())) return "Unknown time"; - return formatRelativeTime(date); -})()} + const raw = prediction.createdAt; + if (typeof raw !== "string") return "Unknown time"; + const date = new Date(raw); + if (Number.isNaN(date.getTime())) return "Unknown time"; + return formatRelativeTime(date); + })()}

diff --git a/src/components/PriceChart.tsx b/src/components/PriceChart.tsx index 8f6cdc7..290eaab 100644 --- a/src/components/PriceChart.tsx +++ b/src/components/PriceChart.tsx @@ -487,20 +487,22 @@ const PriceChart = ({ height = 300, asset = "XLM", entryPrice, onPriceUpdate }: // Reload data when asset changes — reset and load mock/API data useEffect(() => { - setData([]); - setIsLoading(true); - setLoadError(null); - - // Use mock data directly for instant visual feedback per asset - const mockData = mockPriceData[asset]; - if (mockData && mockData.length > 0) { - setData(mockData); - setLastUpdatedAt(new Date()); - setIsLoading(false); - } + Promise.resolve().then(() => { + setData([]); + setIsLoading(true); + setLoadError(null); + + // Use mock data directly for instant visual feedback per asset + const mockData = mockPriceData[asset]; + if (mockData && mockData.length > 0) { + setData(mockData); + setLastUpdatedAt(new Date()); + setIsLoading(false); + } - // Also attempt to fetch live data from API - void loadInitialPrices(); + // Also attempt to fetch live data from API + void loadInitialPrices(); + }); }, [asset]); // eslint-disable-line react-hooks/exhaustive-deps // Update chart line color when asset changes diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index 7b3bcb4..776afc2 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'; @@ -181,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); @@ -194,6 +197,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(); @@ -283,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 () => { @@ -309,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) => { @@ -402,6 +430,18 @@ const activeRoundId = useRoundStore((state) => state.activeRound?.id ?? null); {!isLoading && (
+