feat: implement Players component with data fetching and loading state; remove mock data and enhance error handling in database service

This commit is contained in:
Lars Behrends
2025-12-30 15:58:07 +01:00
parent c6ad8a92ec
commit ea2b803534
12 changed files with 184 additions and 341 deletions

View File

@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import { MOCK_ORGS } from '../constants';
import React, { useState, useEffect } from 'react';
import { Organization } from '../types';
import { Icons } from '../components/IconSet';
import { dbService } from '../services/DatabaseService';
const OrgCard = ({ org, onClick }: { org: Organization; onClick: () => void }) => (
<div
@@ -43,8 +43,35 @@ const OrgCard = ({ org, onClick }: { org: Organization; onClick: () => void }) =
const Organizations: React.FC<{ onSelectOrg: (id: string) => void }> = ({ onSelectOrg }) => {
const [filter, setFilter] = useState<'all' | Organization['type']>('all');
const [orgs, setOrgs] = useState<Organization[]>([]);
const [loading, setLoading] = useState(true);
const filteredOrgs = MOCK_ORGS.filter(org =>
useEffect(() => {
const loadData = async () => {
setLoading(true);
try {
await dbService.fetchAll();
} catch (error) {
console.warn('Failed to fetch fresh data:', error);
// Continue with cached data
}
setLoading(false);
};
const loadOrgs = () => {
const allOrgs = dbService.getOrgs();
setOrgs(allOrgs);
};
// Load fresh data on mount
loadData();
// Subscribe to updates
const unsub = dbService.subscribe(loadOrgs);
return unsub;
}, []);
const filteredOrgs = orgs.filter(org =>
filter === 'all' ? true : org.type === filter
);
@@ -73,8 +100,8 @@ const Organizations: React.FC<{ onSelectOrg: (id: string) => void }> = ({ onSele
key={tab.id}
onClick={() => setFilter(tab.id as any)}
className={`px-4 py-2 text-sm font-medium rounded-t-lg transition-colors relative top-[1px] ${
filter === tab.id
? 'text-textMain border-b-2 border-accentInfo bg-surfaceHighlight/20'
filter === tab.id
? 'text-textMain border-b-2 border-accentInfo bg-surfaceHighlight/20'
: 'text-textMuted hover:text-textMain hover:bg-white/5'
}`}
>
@@ -83,19 +110,29 @@ const Organizations: React.FC<{ onSelectOrg: (id: string) => void }> = ({ onSele
))}
</div>
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
{filteredOrgs.map(org => (
<OrgCard key={org.id} org={org} onClick={() => onSelectOrg(org.id)} />
))}
</div>
{filteredOrgs.length === 0 && (
<div className="text-center py-20 text-textMuted">
<p>Keine Organisationen gefunden.</p>
{loading ? (
<div className="flex justify-center py-20">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-accentInfo"></div>
</div>
) : (
<>
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
{filteredOrgs.map(org => (
<div key={org.id}>
<OrgCard org={org} onClick={() => onSelectOrg(org.id)} />
</div>
))}
</div>
{filteredOrgs.length === 0 && (
<div className="text-center py-20 text-textMuted">
<p>Keine Organisationen gefunden.</p>
</div>
)}
</>
)}
</div>
);
};
export default Organizations;
export default Organizations;