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:
Lars Behrends
2025-12-28 16:46:04 +01:00
parent 6abdffe22a
commit d3d7ec46e6
40 changed files with 5967 additions and 102 deletions

View File

@@ -1,5 +1,7 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { Icons } from './IconSet';
import { authService } from '../services/AuthService';
import { DiscordUser } from '../types';
interface LayoutProps {
children: React.ReactNode;
@@ -30,6 +32,13 @@ const NavItem = ({
const Layout: React.FC<LayoutProps> = ({ children, activeTab, onNavigate }) => {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const [user, setUser] = useState<DiscordUser | null>(null);
useEffect(() => {
// Subscribe to auth changes
const unsubscribe = authService.subscribe(setUser);
return unsubscribe;
}, []);
return (
<div className="min-h-screen flex flex-col font-sans">
@@ -55,6 +64,9 @@ const Layout: React.FC<LayoutProps> = ({ children, activeTab, onNavigate }) => {
<NavItem active={activeTab === 'players'} label="Bürger" onClick={() => onNavigate('players')} />
{/* <NavItem active={activeTab === 'organizations'} label="Organisationen" onClick={() => onNavigate('organizations')} />*/}
<NavItem active={activeTab === 'projects'} label="Unternehmen" onClick={() => onNavigate('projects')} />
{user?.isAdmin && (
<NavItem active={activeTab === 'admin'} label="Admin" onClick={() => onNavigate('admin')} />
)}
</nav>
</div>
@@ -92,8 +104,11 @@ const Layout: React.FC<LayoutProps> = ({ children, activeTab, onNavigate }) => {
<div onClick={() => { onNavigate('players'); setMobileMenuOpen(false); }} className="block py-2 text-textMuted hover:text-textMain">Bürger</div>
<div onClick={() => { onNavigate('organizations'); setMobileMenuOpen(false); }} className="block py-2 text-textMuted hover:text-textMain">Organisationen</div>
<div onClick={() => { onNavigate('projects'); setMobileMenuOpen(false); }} className="block py-2 text-textMuted hover:text-textMain">Unternehmen</div>
{user?.isAdmin && (
<div onClick={() => { onNavigate('admin'); setMobileMenuOpen(false); }} className="block py-2 text-red-400 hover:text-red-300">Admin</div>
)}
<div onClick={() => { onNavigate('datapack'); setMobileMenuOpen(false); }} className="block py-2 text-textMain">Datapack holen</div>
<div onClick={() => { onNavigate('setup'); setMobileMenuOpen(false); }} className="block py-2 text-accentInfo font-mono text-sm border-t border-white/5 pt-4">Admin Setup >_</div>
<div onClick={() => { onNavigate('setup'); setMobileMenuOpen(false); }} className="block py-2 text-accentInfo font-mono text-sm border-t border-white/5 pt-4">{"Admin Setup >_"}</div>
</div>
)}
</header>
@@ -112,10 +127,43 @@ const Layout: React.FC<LayoutProps> = ({ children, activeTab, onNavigate }) => {
<div className="w-4 h-4 bg-textMuted rounded-full"></div>
<p>© 2024 Obsidian Platform</p>
</div>
<div className="flex gap-8">
<span className="cursor-pointer hover:text-textMain transition-colors">Dokumentation</span>
<span className="cursor-pointer hover:text-textMain transition-colors">Server Status</span>
<span className="cursor-pointer hover:text-textMain transition-colors">Datenschutz</span>
<div className="flex flex-col md:flex-row items-center gap-8">
{/* Auth Section */}
<div className="flex items-center gap-4 mb-4 md:mb-0">
{user ? (
<div className="flex items-center gap-3">
<div className="flex items-center gap-2">
<img
src={user.avatarUrl}
alt={user.username}
className="w-6 h-6 rounded-full"
/>
<span className="text-textMain font-medium">{user.username}</span>
</div>
<button
onClick={() => authService.logout()}
className="text-xs text-textMuted hover:text-accentInfo transition-colors"
>
Logout
</button>
</div>
) : (
<button
onClick={() => authService.login()}
className="flex items-center gap-2 text-textMain hover:text-accentInfo transition-colors font-medium"
>
<Icons.Users className="w-4 h-4" />
<span>Discord Login</span>
</button>
)}
</div>
{/* Links */}
<div className="flex gap-8">
<span className="cursor-pointer hover:text-textMain transition-colors">Dokumentation</span>
<span className="cursor-pointer hover:text-textMain transition-colors">Server Status</span>
<span className="cursor-pointer hover:text-textMain transition-colors">Datenschutz</span>
</div>
</div>
</div>
</footer>
@@ -123,4 +171,4 @@ const Layout: React.FC<LayoutProps> = ({ children, activeTab, onNavigate }) => {
);
};
export default Layout;
export default Layout;