mirror of
https://github.com/ceratic/project_vollidioten_website.git
synced 2026-05-14 00:16:47 +02:00
routing
This commit is contained in:
262
App.tsx
262
App.tsx
@@ -1,4 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Routes, Route, useNavigate, useLocation } from 'react-router-dom';
|
||||
import Layout from './components/Layout';
|
||||
import Dashboard from './pages/Dashboard';
|
||||
import PlayerProfile from './pages/PlayerProfile';
|
||||
@@ -9,20 +10,16 @@ import Cities from './pages/Cities';
|
||||
import CityProfile from './pages/CityProfile';
|
||||
import ProjectProfile from './pages/ProjectProfile';
|
||||
import DatapackGenerator from './pages/DatapackGenerator';
|
||||
import DatabaseManager from './pages/DatabaseManager'; // Ensure this file exists or remove import if not
|
||||
import DatabaseManager from './pages/DatabaseManager';
|
||||
import LinkPlayer from './pages/LinkPlayer';
|
||||
import AdminPage from './pages/Admin';
|
||||
import { dbService } from './services/DatabaseService';
|
||||
import { authService } from './services/AuthService';
|
||||
import { DiscordUser } from './types';
|
||||
import { Icons } from './components/IconSet';
|
||||
|
||||
function App() {
|
||||
const [activeTab, setActiveTab] = useState('dashboard');
|
||||
const [selectedPlayerId, setSelectedPlayerId] = useState<string | null>(null);
|
||||
const [selectedCityId, setSelectedCityId] = useState<string | null>(null);
|
||||
const [selectedProjectId, setSelectedProjectId] = useState<string | null>(null);
|
||||
const [selectedOrgId, setSelectedOrgId] = useState<string | null>(null);
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
// Auth state
|
||||
const [user, setUser] = useState<DiscordUser | null>(null);
|
||||
@@ -51,171 +48,138 @@ function App() {
|
||||
|
||||
// If user is logged in but not linked, redirect to link page
|
||||
if (currentUser && !currentUser.linkedPlayerUuid) {
|
||||
setActiveTab('link-player');
|
||||
navigate('/link-player');
|
||||
} else if (currentUser && currentUser.linkedPlayerUuid) {
|
||||
// User is fully authenticated, redirect to dashboard if on link page
|
||||
if (activeTab === 'link-player') {
|
||||
setActiveTab('dashboard');
|
||||
// User is fully authenticated, redirect from link page if needed
|
||||
if (location.pathname === '/link-player') {
|
||||
navigate('/');
|
||||
}
|
||||
}
|
||||
});
|
||||
return unsub;
|
||||
}, [activeTab]);
|
||||
|
||||
const handleNavigate = (tab: string) => {
|
||||
setActiveTab(tab);
|
||||
if (tab !== 'players') setSelectedPlayerId(null);
|
||||
if (tab !== 'cities') setSelectedCityId(null);
|
||||
if (tab !== 'projects') setSelectedProjectId(null);
|
||||
if (tab !== 'organizations') setSelectedOrgId(null);
|
||||
};
|
||||
}, [navigate, location.pathname]);
|
||||
|
||||
const navigateToPlayer = (id: string) => {
|
||||
setSelectedPlayerId(id);
|
||||
setActiveTab('players');
|
||||
navigate(`/players/${id}`);
|
||||
};
|
||||
|
||||
const navigateToProject = (id: string) => {
|
||||
setSelectedProjectId(id);
|
||||
setActiveTab('projects');
|
||||
navigate(`/projects/${id}`);
|
||||
};
|
||||
|
||||
const navigateToOrg = (id: string) => {
|
||||
const org = orgs.find(o => o.id === id);
|
||||
if (org?.type === 'City') {
|
||||
setSelectedCityId(id);
|
||||
setActiveTab('cities');
|
||||
navigate(`/cities/${id}`);
|
||||
} else {
|
||||
setSelectedOrgId(id);
|
||||
setActiveTab('organizations');
|
||||
navigate(`/organizations/${id}`);
|
||||
}
|
||||
};
|
||||
|
||||
const renderContent = () => {
|
||||
// Show link player page if user is logged in but not linked
|
||||
if (activeTab === 'link-player') {
|
||||
return <LinkPlayer />;
|
||||
}
|
||||
|
||||
if (activeTab === 'dashboard') return <Dashboard />;
|
||||
|
||||
if (activeTab === 'projects') {
|
||||
if (selectedProjectId) {
|
||||
const project = projects.find(p => p.id === selectedProjectId);
|
||||
if (project) return (
|
||||
<ProjectProfile
|
||||
project={project}
|
||||
onBack={() => setSelectedProjectId(null)}
|
||||
onSelectPlayer={navigateToPlayer}
|
||||
onSelectOrg={navigateToOrg}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <Projects onSelectProject={setSelectedProjectId} />;
|
||||
}
|
||||
|
||||
if (activeTab === 'organizations') {
|
||||
if (selectedOrgId) {
|
||||
const org = orgs.find(o => o.id === selectedOrgId);
|
||||
if (org) return (
|
||||
<CityProfile
|
||||
city={org}
|
||||
onBack={() => setSelectedOrgId(null)}
|
||||
backLabel="Zurück zum Verzeichnis"
|
||||
onSelectPlayer={navigateToPlayer}
|
||||
onSelectProject={navigateToProject}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <Organizations onSelectOrg={setSelectedOrgId} />;
|
||||
}
|
||||
|
||||
if (activeTab === 'setup') return <SetupGuide />;
|
||||
|
||||
if (activeTab === 'datapack') return <DatapackGenerator />;
|
||||
|
||||
if (activeTab === 'cities') {
|
||||
if (selectedCityId) {
|
||||
const city = orgs.find(o => o.id === selectedCityId);
|
||||
if (city) return (
|
||||
<CityProfile
|
||||
city={city}
|
||||
onBack={() => setSelectedCityId(null)}
|
||||
backLabel="Zurück zu Städte"
|
||||
onSelectPlayer={navigateToPlayer}
|
||||
onSelectProject={navigateToProject}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <Cities onSelectCity={setSelectedCityId} />;
|
||||
}
|
||||
|
||||
if (activeTab === 'players') {
|
||||
if (selectedPlayerId) {
|
||||
const player = players.find(p => p.uuid === selectedPlayerId);
|
||||
if (player) return <PlayerProfile player={player} onBack={() => setSelectedPlayerId(null)} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="animate-in fade-in">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h2 className="text-2xl font-bold">Bürgerverzeichnis</h2>
|
||||
<div className="relative">
|
||||
<Icons.Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-textMuted" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Filtern nach Tag oder Name..."
|
||||
className="bg-surfaceHighlight border border-border rounded-lg pl-10 pr-4 py-2 text-sm text-textMain focus:border-accentInfo focus:outline-none w-64 transition-colors"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||
{players.map(player => (
|
||||
<div
|
||||
key={player.uuid}
|
||||
onClick={() => setSelectedPlayerId(player.uuid)}
|
||||
className="group bg-surface border border-border p-4 rounded-xl cursor-pointer hover:border-accentInfo/50 transition-all duration-200 hover:shadow-card"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-12 h-12 rounded-md flex items-center justify-center font-bold text-lg text-textMuted group-hover:text-textMain transition-colors">
|
||||
<img src={"https://minotar.net/armor/bust/"+player.username+"/500.png"}></img>
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-semibold text-textMain group-hover:text-accentInfo transition-colors">{player.username}</div>
|
||||
<div className="text-xs text-textMuted mt-1 flex gap-2">
|
||||
{player.tags.slice(0, 2).map(t => <span key={t}>{t}</span>)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Admin panel (only for admins)
|
||||
if (activeTab === 'admin') {
|
||||
return <AdminPage onBack={() => setActiveTab('dashboard')} />;
|
||||
}
|
||||
|
||||
// Placeholder for database manager if user navigates there (needs explicit page or component)
|
||||
if (activeTab === 'database') {
|
||||
return <div className="p-10 text-center text-textMuted">Datenbank wird jetzt über das Backend (SQLite) verwaltet.</div>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-[50vh] text-textMuted">
|
||||
<Icons.Box className="w-12 h-12 mb-4 opacity-20" />
|
||||
<p>Modul <strong>{activeTab}</strong> wird derzeit gewartet.</p>
|
||||
</div>
|
||||
);
|
||||
const handleNavigate = (path: string) => {
|
||||
navigate(path);
|
||||
};
|
||||
|
||||
// Determine active tab from current path
|
||||
const getActiveTab = () => {
|
||||
const path = location.pathname;
|
||||
if (path === '/') return 'dashboard';
|
||||
if (path.startsWith('/players')) return 'players';
|
||||
if (path.startsWith('/cities')) return 'cities';
|
||||
if (path.startsWith('/projects')) return 'projects';
|
||||
if (path.startsWith('/organizations')) return 'organizations';
|
||||
if (path.startsWith('/admin')) return 'admin';
|
||||
if (path === '/setup') return 'setup';
|
||||
if (path === '/datapack') return 'datapack';
|
||||
if (path === '/link-player') return 'link-player';
|
||||
return 'dashboard';
|
||||
};
|
||||
|
||||
const activeTab = getActiveTab();
|
||||
|
||||
return (
|
||||
<Layout activeTab={activeTab} onNavigate={handleNavigate}>
|
||||
{renderContent()}
|
||||
<Routes>
|
||||
{/* Auth Route */}
|
||||
<Route path="/link-player" element={<LinkPlayer />} />
|
||||
|
||||
{/* Main Routes */}
|
||||
<Route path="/" element={<Dashboard />} />
|
||||
<Route path="/setup" element={<SetupGuide />} />
|
||||
<Route path="/datapack" element={<DatapackGenerator />} />
|
||||
|
||||
{/* Player Routes */}
|
||||
<Route path="/players" element={
|
||||
<div className="animate-in fade-in">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h2 className="text-2xl font-bold">Bürgerverzeichnis</h2>
|
||||
<div className="relative">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Filtern nach Tag oder Name..."
|
||||
className="bg-surfaceHighlight border border-border rounded-lg pl-10 pr-4 py-2 text-sm text-textMain focus:border-accentInfo focus:outline-none w-64 transition-colors"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||
{players.map(player => (
|
||||
<div
|
||||
key={player.uuid}
|
||||
onClick={() => navigateToPlayer(player.uuid)}
|
||||
className="group bg-surface border border-border p-4 rounded-xl cursor-pointer hover:border-accentInfo/50 transition-all duration-200 hover:shadow-card"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-12 h-12 rounded-md flex items-center justify-center font-bold text-lg text-textMuted group-hover:text-textMain transition-colors">
|
||||
<img src={"https://minotar.net/armor/bust/"+player.username+"/500.png"}></img>
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-semibold text-textMain group-hover:text-accentInfo transition-colors">{player.username}</div>
|
||||
<div className="text-xs text-textMuted mt-1 flex gap-2">
|
||||
{player.tags.slice(0, 2).map(t => <span key={t}>{t}</span>)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
} />
|
||||
<Route path="/players/:id" element={<PlayerProfile />} />
|
||||
|
||||
{/* City Routes */}
|
||||
<Route path="/cities" element={<Cities onSelectCity={(id) => navigateToOrg(id)} />} />
|
||||
<Route path="/cities/:id" element={<CityProfile />} />
|
||||
|
||||
{/* Organization Routes */}
|
||||
<Route path="/organizations" element={<Organizations onSelectOrg={(id) => navigateToOrg(id)} />} />
|
||||
<Route path="/organizations/:id" element={<CityProfile />} />
|
||||
|
||||
{/* Project Routes */}
|
||||
<Route path="/projects" element={<Projects onSelectProject={(id) => navigateToProject(id)} />} />
|
||||
<Route path="/projects/:id" element={<ProjectProfile
|
||||
onBack={() => navigate('/projects')}
|
||||
onSelectPlayer={navigateToPlayer}
|
||||
onSelectOrg={navigateToOrg}
|
||||
/>} />
|
||||
|
||||
{/* Admin Routes */}
|
||||
<Route path="/admin" element={<AdminPage onBack={() => navigate('/')} />} />
|
||||
|
||||
{/* Fallback */}
|
||||
<Route path="*" element={
|
||||
<div className="flex flex-col items-center justify-center h-[50vh] text-textMuted">
|
||||
<div className="text-6xl mb-4">404</div>
|
||||
<p>Seite nicht gefunden</p>
|
||||
<button
|
||||
onClick={() => navigate('/')}
|
||||
className="mt-4 text-accentInfo hover:underline"
|
||||
>
|
||||
Zurück zur Startseite
|
||||
</button>
|
||||
</div>
|
||||
} />
|
||||
</Routes>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user