Files
elysium/apps/web/src/components/game/LoginPage.tsx
T
hikari a3daed1683 feat: initial elysium idle game prototype
Sets up the full monorepo with pnpm workspaces. Includes shared types
package, Hono API with Discord OAuth/JWT auth, Prisma v6 + MongoDB
Atlas, and React + Vite frontend with game loop, five tabs, and
Discord-linked save/load.
2026-03-06 11:26:19 -08:00

88 lines
2.2 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useEffect, useState } from "react";
import { getAuthUrl, handleAuthCallback } from "../../api/client.js";
interface LoginPageProps {
onLogin: () => void;
}
export const LoginPage = ({ onLogin }: LoginPageProps): React.JSX.Element => {
const [authUrl, setAuthUrl] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
// Handle OAuth callback
const params = new URLSearchParams(window.location.search);
const code = params.get("code");
if (code) {
setIsLoading(true);
handleAuthCallback(code)
.then(() => {
window.history.replaceState({}, "", "/");
onLogin();
})
.catch((err: unknown) => {
setError(err instanceof Error ? err.message : "Authentication failed");
setIsLoading(false);
});
return;
}
// Fetch the Discord OAuth URL
getAuthUrl()
.then((url) => {
setAuthUrl(url);
setIsLoading(false);
})
.catch(() => {
setError("Failed to load authentication URL");
setIsLoading(false);
});
}, [onLogin]);
if (isLoading) {
return (
<div className="login-page">
<div className="login-card">
<p>Loading...</p>
</div>
</div>
);
}
if (error) {
return (
<div className="login-page">
<div className="login-card">
<p className="error">{error}</p>
<button
type="button"
onClick={() => { window.location.reload(); }}
>
Try Again
</button>
</div>
</div>
);
}
return (
<div className="login-page">
<div className="login-card">
<h1> Elysium</h1>
<p>An idle fantasy RPG. Hire adventurers, defeat bosses, and ascend to glory.</p>
<a
className="discord-login-button"
href={authUrl ?? "#"}
>
Login with Discord
</a>
<p className="login-note">
Your progress is saved to your Discord account and shareable with others!
</p>
</div>
</div>
);
};