mirror of
https://github.com/ceratic/project_vollidioten_website.git
synced 2026-05-14 00:16:47 +02:00
feat: Add DatabaseManager and LinkPlayer components, implement authentication and linking logic
- Created DatabaseManager component for managing database access via phpMyAdmin. - Developed LinkPlayer component to link Discord accounts with game characters, including user authentication and error handling. - Added mock data files for players, organizations, and projects to handle backend unavailability. - Implemented AuthService for managing user authentication and session checks. - Created DatabaseService to fetch and manage player, organization, and project data with fallback to mock data. - Added HTML page for handling authentication unavailability. - Developed a test script for validating Docker setup and required files.
This commit is contained in:
85
App.tsx
85
App.tsx
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Layout from './components/Layout';
|
||||
import Dashboard from './pages/Dashboard';
|
||||
import PlayerProfile from './pages/PlayerProfile';
|
||||
@@ -9,7 +9,12 @@ import Cities from './pages/Cities';
|
||||
import CityProfile from './pages/CityProfile';
|
||||
import ProjectProfile from './pages/ProjectProfile';
|
||||
import DatapackGenerator from './pages/DatapackGenerator';
|
||||
import { MOCK_PLAYERS, MOCK_ORGS, MOCK_PROJECTS } from './constants';
|
||||
import DatabaseManager from './pages/DatabaseManager'; // Ensure this file exists or remove import if not
|
||||
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() {
|
||||
@@ -19,6 +24,44 @@ function App() {
|
||||
const [selectedProjectId, setSelectedProjectId] = useState<string | null>(null);
|
||||
const [selectedOrgId, setSelectedOrgId] = useState<string | null>(null);
|
||||
|
||||
// Auth state
|
||||
const [user, setUser] = useState<DiscordUser | null>(null);
|
||||
const [authChecked, setAuthChecked] = useState(false);
|
||||
|
||||
// State for data from DB (Async)
|
||||
const [players, setPlayers] = useState(dbService.getPlayers());
|
||||
const [orgs, setOrgs] = useState(dbService.getOrgs());
|
||||
const [projects, setProjects] = useState(dbService.getProjects());
|
||||
|
||||
// Subscribe to DB updates (when fetch completes or edits happen)
|
||||
useEffect(() => {
|
||||
const unsub = dbService.subscribe(() => {
|
||||
setPlayers([...dbService.getPlayers()]);
|
||||
setOrgs([...dbService.getOrgs()]);
|
||||
setProjects([...dbService.getProjects()]);
|
||||
});
|
||||
return unsub;
|
||||
}, []);
|
||||
|
||||
// Subscribe to auth updates
|
||||
useEffect(() => {
|
||||
const unsub = authService.subscribe((currentUser) => {
|
||||
setUser(currentUser);
|
||||
setAuthChecked(true);
|
||||
|
||||
// If user is logged in but not linked, redirect to link page
|
||||
if (currentUser && !currentUser.linkedPlayerUuid) {
|
||||
setActiveTab('link-player');
|
||||
} else if (currentUser && currentUser.linkedPlayerUuid) {
|
||||
// User is fully authenticated, redirect to dashboard if on link page
|
||||
if (activeTab === 'link-player') {
|
||||
setActiveTab('dashboard');
|
||||
}
|
||||
}
|
||||
});
|
||||
return unsub;
|
||||
}, [activeTab]);
|
||||
|
||||
const handleNavigate = (tab: string) => {
|
||||
setActiveTab(tab);
|
||||
if (tab !== 'players') setSelectedPlayerId(null);
|
||||
@@ -27,21 +70,18 @@ function App() {
|
||||
if (tab !== 'organizations') setSelectedOrgId(null);
|
||||
};
|
||||
|
||||
// Helper to jump to a player from another view
|
||||
const navigateToPlayer = (id: string) => {
|
||||
setSelectedPlayerId(id);
|
||||
setActiveTab('players');
|
||||
};
|
||||
|
||||
// Helper to jump to a project from another view
|
||||
const navigateToProject = (id: string) => {
|
||||
setSelectedProjectId(id);
|
||||
setActiveTab('projects');
|
||||
};
|
||||
|
||||
// Helper to jump to an org/city
|
||||
const navigateToOrg = (id: string) => {
|
||||
const org = MOCK_ORGS.find(o => o.id === id);
|
||||
const org = orgs.find(o => o.id === id);
|
||||
if (org?.type === 'City') {
|
||||
setSelectedCityId(id);
|
||||
setActiveTab('cities');
|
||||
@@ -52,11 +92,16 @@ function App() {
|
||||
};
|
||||
|
||||
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 = MOCK_PROJECTS.find(p => p.id === selectedProjectId);
|
||||
const project = projects.find(p => p.id === selectedProjectId);
|
||||
if (project) return (
|
||||
<ProjectProfile
|
||||
project={project}
|
||||
@@ -66,12 +111,12 @@ function App() {
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <Projects onSelectProject={setSelectedProjectId} />;
|
||||
return <Projects onSelectProject={setSelectedProjectId} />;
|
||||
}
|
||||
|
||||
if (activeTab === 'organizations') {
|
||||
if (selectedOrgId) {
|
||||
const org = MOCK_ORGS.find(o => o.id === selectedOrgId);
|
||||
const org = orgs.find(o => o.id === selectedOrgId);
|
||||
if (org) return (
|
||||
<CityProfile
|
||||
city={org}
|
||||
@@ -88,10 +133,10 @@ function App() {
|
||||
if (activeTab === 'setup') return <SetupGuide />;
|
||||
|
||||
if (activeTab === 'datapack') return <DatapackGenerator />;
|
||||
|
||||
|
||||
if (activeTab === 'cities') {
|
||||
if (selectedCityId) {
|
||||
const city = MOCK_ORGS.find(o => o.id === selectedCityId);
|
||||
const city = orgs.find(o => o.id === selectedCityId);
|
||||
if (city) return (
|
||||
<CityProfile
|
||||
city={city}
|
||||
@@ -107,7 +152,7 @@ function App() {
|
||||
|
||||
if (activeTab === 'players') {
|
||||
if (selectedPlayerId) {
|
||||
const player = MOCK_PLAYERS.find(p => p.uuid === selectedPlayerId);
|
||||
const player = players.find(p => p.uuid === selectedPlayerId);
|
||||
if (player) return <PlayerProfile player={player} onBack={() => setSelectedPlayerId(null)} />;
|
||||
}
|
||||
|
||||
@@ -126,7 +171,7 @@ function App() {
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||
{MOCK_PLAYERS.map(player => (
|
||||
{players.map(player => (
|
||||
<div
|
||||
key={player.uuid}
|
||||
onClick={() => setSelectedPlayerId(player.uuid)}
|
||||
@@ -149,6 +194,16 @@ function App() {
|
||||
</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">
|
||||
@@ -165,4 +220,4 @@ function App() {
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
export default App;
|
||||
|
||||
Reference in New Issue
Block a user