diff --git a/README.md b/README.md index c6ab06b..d58a33a 100644 --- a/README.md +++ b/README.md @@ -277,6 +277,20 @@ src/ └── utils/ # Pure utility functions ``` +### Dashboard routes + +`/dashboard` is the single primary prediction terminal. It now includes the +high-value panels that previously lived only on the legacy `/play` view: the +price chart, the round lifecycle timeline, round-update connection status, the +end-round modal, and opt-in community chat (toggled from the dashboard header so +the default terminal stays uncluttered). + +`/play` is **deprecated** and permanently redirects to `/dashboard`. The +`LegacyDashboard` component is retained only for reference and is no longer +routed. Chat and notifications are available via the in-dashboard toggle; further +social/notification consolidation is tracked in issue +[#130](https://github.com/TevaLabs/Xelma-Frontend/issues/130). + --- ## Testing diff --git a/src/App.tsx b/src/App.tsx index 3ab4074..9c817ae 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,5 @@ import { lazy, Suspense } from 'react'; -import { Routes, Route, useLocation } from 'react-router-dom'; +import { Routes, Route, Navigate, useLocation } from 'react-router-dom'; import { Toaster } from 'sonner'; import Navbar from './components/Navbar'; import PageSkeleton from './components/PageSkeleton'; @@ -14,7 +14,6 @@ import { Trophy } from 'lucide-react'; import { ENTER } from './utils/motion'; const Dashboard = lazy(() => import(/* webpackChunkName: "dashboard" */ './pages/Dashboard')); -const LegacyDashboard = lazy(() => import(/* webpackChunkName: "legacy-dashboard" */ './pages/LegacyDashboard')); const Leaderboard = lazy(() => import(/* webpackChunkName: "leaderboard" */ './components/Leaderboard')); const LearnPage = lazy(() => import(/* webpackChunkName: "learn" */ './pages/Learn')); const Connect = lazy(() => import('./pages/Connect')); @@ -40,28 +39,28 @@ function App() { }> -
- - } /> - }>} /> - }>} /> - }>} /> - }>} /> - } /> - } /> - - } - /> - } /> - -
+ + } /> + }>
} /> + {/* /play is deprecated: its high-value panels (price chart, round + timeline, chat, end-round modal) now live in /dashboard. */} + } /> + }>} /> + }>} /> + } /> + } /> + + } + /> + } /> +
diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index a12997f..462fcf9 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -5,6 +5,10 @@ import PredictionHistory from "../components/PredictionHistory"; import type { PredictionData } from "../components/PredictionControls"; import BetModal from "../components/BetModal"; import EndRoundModal from "../components/EndRoundModal"; +import RoundTimeline from "../components/RoundTimeline"; +import { ChatSidebar } from "../components/ChatSidebar"; +import { ConnectionStatus } from "../components/ConnectionStatus"; +import { useConnectionStatus } from "../hooks/useConnectionStatus"; import { useRoundStore } from "../store/useRoundStore"; import type { Round } from "../lib/api-client"; import { educationApi } from "../lib/api-client"; @@ -90,6 +94,7 @@ const DailyTip = () => { const Dashboard = () => { const isRoundActive = useRoundStore((state) => state.isRoundActive); const isLoading = useRoundStore((state) => state.isLoading); + const sseConnection = useRoundStore((state) => state.sseConnection); const isWalletConnected = useWalletStore(selectIsWalletConnected); const isWalletConnecting = useWalletStore( (s) => s.status === "connecting" || s.status === "checking" @@ -97,9 +102,12 @@ const Dashboard = () => { const resolvedRound = useRoundStore((state) => state.resolvedRound); const dismissResolvedRound = useRoundStore((state) => state.dismissResolvedRound); const publicKey = useWalletStore((s) => s.publicKey); - const balance = useWalletStore((s) => s.balance); + const { isConnected: isSocketConnected } = useConnectionStatus(); const [isBetModalOpen, setIsBetModalOpen] = useState(false); const [pendingPrediction, setPendingPrediction] = useState(null); + // Community chat is opt-in so the default terminal stays uncluttered. + const [isChatOpen, setIsChatOpen] = useState(false); + const timeoutRef = useRef(null); useEffect(() => { const { fetchActiveRound, subscribeToRoundEvents } = useRoundStore.getState(); @@ -151,9 +159,51 @@ const Dashboard = () => { return (
+ {/* Opt-in community chat (ported from the legacy /play view). Self-positions + as a fixed slide-over, so mounting it does not shift the terminal layout. */} + {isChatOpen && } +
{isLoading && } + {!isLoading && ( +
+ +
+ )} + + {/* Round-update connectivity, ported from /play so users see SSE/socket health. */} + {!isLoading && + (!isSocketConnected || + (sseConnection && sseConnection.status !== "connected")) && ( +
+ + {sseConnection && + sseConnection.status !== "connected" && + sseConnection.error && ( +
+

+ Round updates: {sseConnection.error} +

+
+ )} +
+ )} + + {/* Round lifecycle timeline, ported from /play. */} + {!isLoading && ( +
+ +
+ )} + {!isLoading && !isWalletConnected && (