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,7 +1,7 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { Organization, Project, Player } from '../types';
import { MOCK_PLAYERS, MOCK_PROJECTS } from '../constants';
import { Icons } from '../components/IconSet';
import { dbService } from '../services/DatabaseService';
interface CityProfileProps {
city: Organization;
@@ -11,17 +11,52 @@ interface CityProfileProps {
onSelectProject: (id: string) => void;
}
const CityProfile: React.FC<CityProfileProps> = ({
city,
onBack,
const CityProfile: React.FC<CityProfileProps> = ({
city,
onBack,
backLabel = 'Zurück',
onSelectPlayer,
onSelectProject
}) => {
const [activeTab, setActiveTab] = useState<'overview' | 'residents' | 'ventures'>('overview');
const residents = MOCK_PLAYERS.filter(p => p.stats.organizationId === city.id);
const ventures = MOCK_PROJECTS.filter(p => p.associatedOrgId === city.id);
const [residents, setResidents] = useState<Player[]>([]);
const [ventures, setVentures] = useState<Project[]>([]);
const [cityStats, setCityStats] = useState<any>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const loadCityData = () => {
// Load residents (players in this city)
const allPlayers = dbService.getPlayers();
const cityResidents = allPlayers.filter(p => p.stats.organizationId === city.id);
setResidents(cityResidents);
// Load ventures (projects in this city)
const allProjects = dbService.getProjects();
const cityVentures = allProjects.filter(p => p.associatedOrgId === city.id);
setVentures(cityVentures);
// Calculate dynamic city statistics
const stats = {
citizens: cityResidents.length,
businesses: cityVentures.length,
activeBusinesses: cityVentures.filter(p => p.status === 'active').length,
recruitingBusinesses: cityVentures.filter(p => p.hiring).length,
// Merge with existing static stats
...city.cityStats
};
setCityStats(stats);
setLoading(false);
};
// Initial load
loadCityData();
// Subscribe to updates
const unsub = dbService.subscribe(loadCityData);
return unsub;
}, [city.id]);
return (
<div className="animate-in slide-in-from-right-4 duration-300">
@@ -244,4 +279,4 @@ const CityProfile: React.FC<CityProfileProps> = ({
);
};
export default CityProfile;
export default CityProfile;