mirror of
https://github.com/ceratic/project_vollidioten_website.git
synced 2026-05-14 00:16:47 +02:00
Refactor CityProfile and PlayerProfile components for improved data fetching and error handling; add NPC management modals for banner, gallery, and logo with enhanced user experience and error feedback.
This commit is contained in:
139
pages/Admin.tsx
139
pages/Admin.tsx
@@ -1,6 +1,9 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Icons } from '../components/IconSet';
|
||||
import { authService } from '../services/AuthService';
|
||||
import NpcBannerManagementModal from '../components/NpcBannerManagementModal';
|
||||
import NpcLogoManagementModal from '../components/NpcLogoManagementModal';
|
||||
import NpcGalleryManagementModal from '../components/NpcGalleryManagementModal';
|
||||
|
||||
interface AdminPageProps {
|
||||
onBack: () => void;
|
||||
@@ -453,6 +456,9 @@ const EditNpcCompanyCard: React.FC<{ company: any; npcCitizens: any[]; onUpdate:
|
||||
const [isEditingShop, setIsEditingShop] = useState(false);
|
||||
const [isManaging, setIsManaging] = useState(false);
|
||||
const [shopItems, setShopItems] = useState<any[]>(company.shopCatalog || []);
|
||||
const [bannerModalOpen, setBannerModalOpen] = useState(false);
|
||||
const [logoModalOpen, setLogoModalOpen] = useState(false);
|
||||
const [galleryModalOpen, setGalleryModalOpen] = useState(false);
|
||||
const [formData, setFormData] = useState({
|
||||
title: company.title,
|
||||
description: company.description || '',
|
||||
@@ -606,42 +612,89 @@ const EditNpcCompanyCard: React.FC<{ company: any; npcCitizens: any[]; onUpdate:
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-surfaceHighlight/30 border border-border rounded-lg p-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 bg-purple-500/20 rounded flex items-center justify-center text-xs font-bold text-purple-400">
|
||||
NPC
|
||||
<>
|
||||
<div className="bg-surfaceHighlight/30 border border-border rounded-lg p-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 bg-purple-500/20 rounded flex items-center justify-center text-xs font-bold text-purple-400">
|
||||
NPC
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-medium text-white">{company.title}</h4>
|
||||
<p className="text-xs text-textMuted">{company.category}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-medium text-white">{company.title}</h4>
|
||||
<p className="text-xs text-textMuted">{company.category}</p>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => setBannerModalOpen(true)}
|
||||
className="text-blue-400 hover:text-blue-300 text-sm"
|
||||
title="Banner bearbeiten"
|
||||
>
|
||||
<Icons.Layers className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setLogoModalOpen(true)}
|
||||
className="text-green-400 hover:text-green-300 text-sm"
|
||||
title="Logo bearbeiten"
|
||||
>
|
||||
<Icons.Shield className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setGalleryModalOpen(true)}
|
||||
className="text-orange-400 hover:text-orange-300 text-sm"
|
||||
title="Portfolio verwalten"
|
||||
>
|
||||
<Icons.Box className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => onOpenShopModal(company.id, company.shopCatalog || [])}
|
||||
className="text-accentInfo hover:text-accentInfo/80 text-sm"
|
||||
title="Shop verwalten"
|
||||
>
|
||||
<Icons.ShoppingBag className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setIsEditing(true)}
|
||||
className="text-purple-400 hover:text-purple-300 text-sm"
|
||||
>
|
||||
<Icons.Edit className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => onOpenShopModal(company.id, company.shopCatalog || [])}
|
||||
className="text-accentInfo hover:text-accentInfo/80 text-sm"
|
||||
title="Shop verwalten"
|
||||
>
|
||||
<Icons.ShoppingBag className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setIsEditing(true)}
|
||||
className="text-purple-400 hover:text-purple-300 text-sm"
|
||||
>
|
||||
<Icons.Edit className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="text-xs text-textMuted">
|
||||
Eigentümer: {company.owner}
|
||||
</div>
|
||||
<div className="text-xs text-textMuted">
|
||||
Eigentümer: {company.owner}
|
||||
{company.shopCatalog && company.shopCatalog.length > 0 && (
|
||||
<div className="text-xs text-accentInfo mt-1">
|
||||
Shop: {company.shopCatalog.length} Artikel
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{company.shopCatalog && company.shopCatalog.length > 0 && (
|
||||
<div className="text-xs text-accentInfo mt-1">
|
||||
Shop: {company.shopCatalog.length} Artikel
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Image Management Modals */}
|
||||
<NpcBannerManagementModal
|
||||
isOpen={bannerModalOpen}
|
||||
onClose={() => setBannerModalOpen(false)}
|
||||
projectId={company.id}
|
||||
currentBannerUrl={company.bannerUrl}
|
||||
onUpdate={() => onUpdate()}
|
||||
/>
|
||||
|
||||
<NpcLogoManagementModal
|
||||
isOpen={logoModalOpen}
|
||||
onClose={() => setLogoModalOpen(false)}
|
||||
projectId={company.id}
|
||||
currentLogoUrl={company.logoUrl}
|
||||
onUpdate={() => onUpdate()}
|
||||
/>
|
||||
|
||||
<NpcGalleryManagementModal
|
||||
isOpen={galleryModalOpen}
|
||||
onClose={() => setGalleryModalOpen(false)}
|
||||
projectId={company.id}
|
||||
onUpdate={() => onUpdate()}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -666,13 +719,24 @@ const AdminPage: React.FC<AdminPageProps> = ({ onBack }) => {
|
||||
return unsub;
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeTab === 'npcs' && isAdmin) {
|
||||
useEffect(() => {
|
||||
loadNpcs();
|
||||
}
|
||||
if (activeTab === 'cities' && isAdmin) {
|
||||
loadCities();
|
||||
}
|
||||
}, [isAdmin]);
|
||||
|
||||
// Auto-refresh data every 30 seconds when on relevant tabs
|
||||
useEffect(() => {
|
||||
if (!isAdmin) return;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
if (activeTab === 'edit-npcs' || activeTab === 'create-npc') {
|
||||
loadNpcs();
|
||||
} else if (activeTab === 'cities' || activeTab === 'create-city') {
|
||||
loadCities();
|
||||
}
|
||||
}, 30000); // 30 seconds
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [activeTab, isAdmin]);
|
||||
|
||||
const loadNpcs = async () => {
|
||||
@@ -1677,7 +1741,6 @@ const AdminPage: React.FC<AdminPageProps> = ({ onBack }) => {
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
alert('Banner erfolgreich aktualisiert!');
|
||||
loadCities(); // Reload to show updated image
|
||||
} else {
|
||||
setError('Fehler beim Hochladen des Banners');
|
||||
@@ -1727,7 +1790,6 @@ const AdminPage: React.FC<AdminPageProps> = ({ onBack }) => {
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
alert('Logo erfolgreich aktualisiert!');
|
||||
loadCities(); // Reload to show updated image
|
||||
} else {
|
||||
setError('Fehler beim Hochladen des Logos');
|
||||
@@ -1781,7 +1843,6 @@ const AdminPage: React.FC<AdminPageProps> = ({ onBack }) => {
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
alert('Stadt erfolgreich aktualisiert!');
|
||||
setEditingCity(null);
|
||||
loadCities();
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user