generated from nhcarrigan/template
feat: initial prototype — core game systems (#30)
## Summary This PR represents the full v1 prototype, implementing the core game systems for Elysium. - Full idle/clicker RPG loop: resource collection, crafting, boss fights, exploration, and quests - Adventurer hiring with batch size selector and progressive tier cost scaling - Prestige, transcendence, and apotheosis systems with auto-prestige support - Character sheet, titles, leaderboards, companion system, and daily login bonuses - Auto-quest and auto-boss toggles - Discord webhook notifications on prestige/transcendence/apotheosis - Discord role awarded on apotheosis - Responsive design and overarching story/lore system - In-game sound effects and browser notifications for key events - Support link button in the resource bar - Full test coverage (100% on `apps/api` and `packages/types`) - CI pipeline: lint → build → test ## Closes Closes #1 Closes #2 Closes #3 Closes #4 Closes #5 Closes #6 Closes #7 Closes #8 Closes #9 Closes #10 Closes #11 Closes #12 Closes #13 Closes #14 Closes #16 Closes #19 Closes #20 Closes #21 Closes #22 Closes #23 Closes #24 Closes #25 Closes #26 Closes #27 Closes #29 ✨ This issue was created with help from Hikari~ 🌸 Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com> Reviewed-on: #30 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
This commit was merged in pull request #30.
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @file Root application component that handles routing and authentication.
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
import { type JSX, useState } from "react";
|
||||
import { CharacterPage } from "./components/game/characterPage.js";
|
||||
import { GameLayout } from "./components/game/gameLayout.js";
|
||||
import { LeaderboardPage } from "./components/game/leaderboardPage.js";
|
||||
import { LoginPage } from "./components/game/loginPage.js";
|
||||
import { ProfilePage } from "./components/game/profilePage.js";
|
||||
import { GameProvider } from "./context/gameContext.js";
|
||||
|
||||
const getProfileDiscordId = (): string | null => {
|
||||
const match = /^\/profile\/(?<id>\d+)$/.exec(window.location.pathname);
|
||||
return match?.groups?.id ?? null;
|
||||
};
|
||||
|
||||
const getCharacterDiscordId = (): string | null => {
|
||||
const match = /^\/character\/(?<id>\d+)$/.exec(window.location.pathname);
|
||||
return match?.groups?.id ?? null;
|
||||
};
|
||||
|
||||
const handleAuthCallback = (): boolean => {
|
||||
if (window.location.pathname !== "/auth/callback") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const parameters = new URLSearchParams(window.location.search);
|
||||
const token = parameters.get("token");
|
||||
|
||||
if (token !== null && token.length > 0) {
|
||||
localStorage.setItem("elysium_token", token);
|
||||
}
|
||||
|
||||
window.history.replaceState(null, "", "/");
|
||||
return token !== null && token.length > 0;
|
||||
};
|
||||
|
||||
const isAuthenticated = (): boolean => {
|
||||
const fromCallback = handleAuthCallback();
|
||||
if (fromCallback) {
|
||||
return true;
|
||||
}
|
||||
const storedToken = localStorage.getItem("elysium_token");
|
||||
return storedToken !== null && storedToken.length > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the root application component, handling routing and authentication.
|
||||
* @returns The JSX element.
|
||||
*/
|
||||
const app = (): JSX.Element => {
|
||||
const [ loggedIn, setLoggedIn ] = useState(isAuthenticated);
|
||||
|
||||
const profileDiscordId = getProfileDiscordId();
|
||||
if (profileDiscordId !== null) {
|
||||
return <ProfilePage discordId={profileDiscordId} />;
|
||||
}
|
||||
|
||||
const characterDiscordId = getCharacterDiscordId();
|
||||
if (characterDiscordId !== null) {
|
||||
return <CharacterPage discordId={characterDiscordId} />;
|
||||
}
|
||||
|
||||
if (window.location.pathname === "/leaderboards") {
|
||||
return <LeaderboardPage />;
|
||||
}
|
||||
|
||||
function handleLogin(): void {
|
||||
setLoggedIn(true);
|
||||
}
|
||||
|
||||
if (!loggedIn) {
|
||||
return <LoginPage onLogin={handleLogin} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<GameProvider>
|
||||
<GameLayout />
|
||||
</GameProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export { app as App };
|
||||
Reference in New Issue
Block a user