Add dedicated home page with game list and welcome screen, replacing auto-selection behavior
Implemented HomePage component with centered welcome message, create/join button, and list of user's games with name/code display. Modified App.jsx to show HomePage when no game is selected instead of auto-selecting first game. Added `goHome` handler to reset all game state and return to home screen. Added home button (🏠) to GamePickerCard header next to help button with bilingual tooltip. Removed automatic
This commit is contained in:
+22
-2
@@ -27,6 +27,7 @@ import NewGameModal from "./components/NewGameModal";
|
|||||||
import StatsModal from "./components/StatsModal";
|
import StatsModal from "./components/StatsModal";
|
||||||
import AdminSettingsModal from "./components/AdminSettingsModal";
|
import AdminSettingsModal from "./components/AdminSettingsModal";
|
||||||
import InvitePage from "./components/InvitePage";
|
import InvitePage from "./components/InvitePage";
|
||||||
|
import HomePage from "./components/HomePage";
|
||||||
import { useLanguage } from "./i18n";
|
import { useLanguage } from "./i18n";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
@@ -134,7 +135,7 @@ export default function App() {
|
|||||||
const gs = await api("/games");
|
const gs = await api("/games");
|
||||||
setGames(gs);
|
setGames(gs);
|
||||||
|
|
||||||
if (gs[0] && !gameId) setGameId(gs[0].id);
|
// Always open on the start page; the user explicitly chooses a game.
|
||||||
};
|
};
|
||||||
|
|
||||||
const reloadSheet = async () => {
|
const reloadSheet = async () => {
|
||||||
@@ -528,7 +529,7 @@ export default function App() {
|
|||||||
await api(`/games/${gameId}`, { method: "DELETE" });
|
await api(`/games/${gameId}`, { method: "DELETE" });
|
||||||
const nextGames = await api("/games");
|
const nextGames = await api("/games");
|
||||||
setGames(nextGames);
|
setGames(nextGames);
|
||||||
setGameId(nextGames[0]?.id || null);
|
setGameId(null);
|
||||||
setSheet(null);
|
setSheet(null);
|
||||||
setGameMeta(null);
|
setGameMeta(null);
|
||||||
setMembers([]);
|
setMembers([]);
|
||||||
@@ -539,6 +540,20 @@ export default function App() {
|
|||||||
showSnack(language === "en" ? "Game cancelled." : "Spiel abgebrochen.");
|
showSnack(language === "en" ? "Game cancelled." : "Spiel abgebrochen.");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const goHome = () => {
|
||||||
|
setGameId(null);
|
||||||
|
setSheet(null);
|
||||||
|
setGameMeta(null);
|
||||||
|
setMembers([]);
|
||||||
|
setGameChips([]);
|
||||||
|
setWinnerUserId("");
|
||||||
|
setChipOpen(false);
|
||||||
|
setChipEntry(null);
|
||||||
|
setCelebrateOpen(false);
|
||||||
|
setCelebrateName("");
|
||||||
|
setStartCelebrateOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
// ===== Winner =====
|
// ===== Winner =====
|
||||||
const saveWinner = async () => {
|
const saveWinner = async () => {
|
||||||
if (!gameId) return;
|
if (!gameId) return;
|
||||||
@@ -735,6 +750,9 @@ export default function App() {
|
|||||||
<AdminSettingsModal open={adminSettingsOpen} onClose={() => setAdminSettingsOpen(false)} />
|
<AdminSettingsModal open={adminSettingsOpen} onClose={() => setAdminSettingsOpen(false)} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{!gameId ? (
|
||||||
|
<HomePage games={games} onOpenNewGame={() => setNewGameOpen(true)} onOpenGame={setGameId} />
|
||||||
|
) : <>
|
||||||
<GamePickerCard
|
<GamePickerCard
|
||||||
games={games}
|
games={games}
|
||||||
gameId={gameId}
|
gameId={gameId}
|
||||||
@@ -750,6 +768,7 @@ export default function App() {
|
|||||||
chipCount={gameChips.length}
|
chipCount={gameChips.length}
|
||||||
onStartGame={startGame}
|
onStartGame={startGame}
|
||||||
onCancelGame={cancelGame}
|
onCancelGame={cancelGame}
|
||||||
|
onGoHome={goHome}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{gameStarted && (
|
{gameStarted && (
|
||||||
@@ -760,6 +779,7 @@ export default function App() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
</>}
|
||||||
|
|
||||||
<HelpModal open={helpOpen} onClose={() => setHelpOpen(false)} />
|
<HelpModal open={helpOpen} onClose={() => setHelpOpen(false)} />
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export default function GamePickerCard({
|
|||||||
chipCount = 0,
|
chipCount = 0,
|
||||||
onStartGame,
|
onStartGame,
|
||||||
onCancelGame,
|
onCancelGame,
|
||||||
|
onGoHome,
|
||||||
}) {
|
}) {
|
||||||
const { language, t } = useLanguage();
|
const { language, t } = useLanguage();
|
||||||
const cur = games.find((x) => x.id === gameId);
|
const cur = games.find((x) => x.id === gameId);
|
||||||
@@ -102,8 +103,11 @@ export default function GamePickerCard({
|
|||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<button onClick={onOpenHelp} style={styles.helpBtn} title={t("help")}>
|
<button onClick={onGoHome} style={styles.helpBtn} title={language === "en" ? "Home" : "Startseite"} aria-label={language === "en" ? "Home" : "Startseite"}>
|
||||||
{t("help")}
|
🏠
|
||||||
|
</button>
|
||||||
|
<button onClick={onOpenHelp} style={styles.helpBtn} title={t("help")} aria-label={t("help")}>
|
||||||
|
❔
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { styles } from "../styles/styles";
|
||||||
|
import { stylesTokens } from "../styles/theme";
|
||||||
|
import { useLanguage } from "../i18n";
|
||||||
|
|
||||||
|
export default function HomePage({ games = [], onOpenNewGame, onOpenGame }) {
|
||||||
|
const { language, t } = useLanguage();
|
||||||
|
return (
|
||||||
|
<main className="hp-home-page" style={{ marginTop: 14, display: "grid", gap: 14 }}>
|
||||||
|
<div style={styles.card}>
|
||||||
|
<div style={{ padding: "26px 20px 22px", textAlign: "center" }}>
|
||||||
|
<div style={{ fontSize: 34, color: stylesTokens.textGold }}>✦</div>
|
||||||
|
<h1 style={{ margin: "8px 0 0", color: stylesTokens.textGold, fontSize: 24 }}>{language === "en" ? "Welcome to Notizbogen" : "Willkommen beim Notizbogen"}</h1>
|
||||||
|
<p style={{ margin: "9px auto 0", maxWidth: 430, color: stylesTokens.textDim, lineHeight: 1.5 }}>{language === "en" ? "Create a new investigation or join an existing game to get started." : "Erstelle eine neue Ermittlung oder tritt einem bestehenden Spiel bei, um zu beginnen."}</p>
|
||||||
|
<button onClick={onOpenNewGame} style={{ ...styles.primaryBtn, marginTop: 18 }}>{language === "en" ? "✦ Create or join game" : "✦ Spiel erstellen oder beitreten"}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{games.length > 0 && <div style={styles.card}>
|
||||||
|
<div style={styles.sectionHeader}>{language === "en" ? "Your games" : "Deine Spiele"}</div>
|
||||||
|
<div style={{ display: "grid", gap: 8, padding: 12 }}>
|
||||||
|
{games.map((game) => <button key={game.id} onClick={() => onOpenGame(game.id)} style={{ ...styles.secondaryBtn, display: "flex", justifyContent: "space-between", alignItems: "center", textAlign: "left" }}>
|
||||||
|
<span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{game.name}</span><span style={{ color: stylesTokens.textGold, marginLeft: 10 }}>{game.code}</span>
|
||||||
|
</button>)}
|
||||||
|
</div>
|
||||||
|
</div>}
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user