From 4af93cae1ca54ad7c9bc7eb4b56c010f55c4c72d Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 20 Feb 2026 17:53:55 +0000 Subject: feat: allow viewing/spectating games without login Make watch, ranking, game list, and tournament endpoints accessible without authentication. Unauthenticated users can browse games and spectate from the index page, while play/submit/preview still require login. https://claude.ai/code/session_019j9tNcnLsLz15e1qtbmeqe --- frontend/app/App.tsx | 14 ++-------- frontend/app/pages/DashboardPage.tsx | 54 +++++++++++++++++++++++------------- frontend/app/pages/GolfWatchPage.tsx | 18 ++++++++---- frontend/app/pages/IndexPage.tsx | 3 +- 4 files changed, 51 insertions(+), 38 deletions(-) (limited to 'frontend') diff --git a/frontend/app/App.tsx b/frontend/app/App.tsx index 3f1333a..be608e4 100644 --- a/frontend/app/App.tsx +++ b/frontend/app/App.tsx @@ -26,9 +26,7 @@ export default function App() { - - - + {(params) => ( @@ -52,17 +50,11 @@ export default function App() { )} - {(params) => ( - - - - )} + {(params) => } {(params) => ( - - - + )} diff --git a/frontend/app/pages/DashboardPage.tsx b/frontend/app/pages/DashboardPage.tsx index 00db3f0..92c0f04 100644 --- a/frontend/app/pages/DashboardPage.tsx +++ b/frontend/app/pages/DashboardPage.tsx @@ -14,7 +14,7 @@ type Game = components["schemas"]["Game"]; export default function DashboardPage() { usePageTitle(`Dashboard | ${APP_NAME}`); - const { user, logout } = useAuth(); + const { user, isLoggedIn, isLoading: authLoading, logout } = useAuth(); const [, navigate] = useLocation(); const [games, setGames] = useState([]); @@ -33,7 +33,7 @@ export default function DashboardPage() { navigate("/"); } - if (loading) { + if (loading || authLoading) { return (

Loading...

@@ -43,18 +43,24 @@ export default function DashboardPage() { return (
- {user?.icon_path && ( + {isLoggedIn && user?.icon_path && ( )} -

{user?.display_name}

+ {isLoggedIn ? ( +

+ {user?.display_name} +

+ ) : ( +

試合一覧

+ )}
{games.length === 0 ? ( -

エントリーできる試合はありません

+

試合はありません

) : (
    {games.map((game) => ( @@ -68,20 +74,24 @@ export default function DashboardPage() {
- {game.started_at == null && ( + {isLoggedIn && game.started_at == null && ( 問題を見る )} - - 対戦 - + {isLoggedIn && ( + + 対戦 + + )} 観戦 - - 提出履歴 - + {isLoggedIn && ( + + 提出履歴 + + )}
))} @@ -89,14 +99,18 @@ export default function DashboardPage() { )}
- - {user?.is_admin && ( + {isLoggedIn ? ( + + ) : ( + ログイン + )} + {isLoggedIn && user?.is_admin && ( (null); const [ranking, setRanking] = useState([]); const [gameStates, setGameStates] = useState<{ [key: string]: LatestGameState; }>({}); const [loading, setLoading] = useState(true); + const [error, setError] = useState(false); const gameIdNum = Number(gameId); @@ -41,16 +39,16 @@ export default function GolfWatchPage({ gameId }: { gameId: string }) { setRanking(ranking); setGameStates(states); }) - .catch(() => navigate("/dashboard")) + .catch(() => setError(true)) .finally(() => setLoading(false)); - }, [gameIdNum, navigate]); + }, [gameIdNum]); const store = useMemo(() => { if (!game) return null; return createStore(); }, [game]); - if (loading || !game || !store) { + if (loading) { return (

Loading...

@@ -58,6 +56,14 @@ export default function GolfWatchPage({ gameId }: { gameId: string }) { ); } + if (error || !game || !store) { + return ( +
+

試合が見つかりませんでした

+
+ ); + } + return ( diff --git a/frontend/app/pages/IndexPage.tsx b/frontend/app/pages/IndexPage.tsx index 120720a..03e135b 100644 --- a/frontend/app/pages/IndexPage.tsx +++ b/frontend/app/pages/IndexPage.tsx @@ -31,7 +31,8 @@ export default function IndexPage() {

-
+
+ 観戦する ログイン
-- cgit v1.3.1