feat: admin panel with user table and stats (Task 12)

- AdminPage: password gate (sessionStorage), user table, stats banner
- Auto-login using stored sessionStorage password on mount
- App.tsx: route to admin when pathname === '/admin'
- Fix: remove redundant setPassword in auto-login effect (useState already seeds from sessionStorage)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-30 02:23:15 +00:00
parent 10afc2bbb0
commit c9c12a4c2c
2 changed files with 170 additions and 6 deletions
+9 -6
View File
@@ -3,6 +3,7 @@ import { useAuth } from './hooks/useAuth'
import { LoginPage } from './pages/LoginPage'
import { OnboardingPage } from './pages/OnboardingPage'
import { GamePage } from './pages/GamePage'
import { AdminPage } from './pages/AdminPage'
import './index.css'
type AppRoute = 'login' | 'sent' | 'onboarding' | 'game' | 'admin'
@@ -12,6 +13,13 @@ export default function App() {
const [route, setRoute] = useState<AppRoute>('login')
const [checkingOnboarding, setCheckingOnboarding] = useState(false)
// Check for /admin path
useEffect(() => {
if (window.location.pathname === '/admin') {
setRoute('admin')
}
}, [])
// After auth resolves, check onboarding status
useEffect(() => {
if (!profile || !token) return
@@ -55,12 +63,7 @@ export default function App() {
{route === 'game' && token && (
<GamePage token={token} onLogout={() => { logout(); setRoute('login') }} />
)}
{route === 'admin' && (
<div>
<h1 style={{ fontFamily: 'var(--font-header)' }}>Admin</h1>
<p>Admin panel coming in Task 12.</p>
</div>
)}
{route === 'admin' && <AdminPage />}
</div>
)
}