feat: WM2026 Tippspiel - Initial Backend + Frontend
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { api, UserStats } from '../api/client';
|
||||
import styles from './ProfilePage.module.css';
|
||||
|
||||
export default function ProfilePage() {
|
||||
const [stats, setStats] = useState<UserStats | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
api.getMyStats().then(setStats).finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
if (loading) return <div className={styles.loading}><div className={styles.spinner} /></div>;
|
||||
if (!stats) return <div className={styles.empty}>Profil nicht verfügbar.</div>;
|
||||
|
||||
const evaluated = stats.exactCount + stats.tendencyCount + stats.wrongCount;
|
||||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<div className={`card ${styles.heroCard}`}>
|
||||
<div className={styles.avatar}>{stats.fullName.charAt(0).toUpperCase()}</div>
|
||||
<div className={styles.heroInfo}>
|
||||
<h1 className={`font-display ${styles.name}`}>{stats.fullName}</h1>
|
||||
{stats.rank && (
|
||||
<div className={styles.rankBadge}>🏆 Platz {stats.rank}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.heroPoints}>
|
||||
<span className={`font-display ${styles.pointsVal}`}>{stats.totalPoints}</span>
|
||||
<span className={styles.pointsLbl}>Punkte</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.statsGrid}>
|
||||
<div className={`card ${styles.statCard}`}>
|
||||
<span className={`font-display ${styles.statVal} text-gold`}>{stats.exactCount}</span>
|
||||
<span className={styles.statLbl}>🎯 Exakt</span>
|
||||
</div>
|
||||
<div className={`card ${styles.statCard}`}>
|
||||
<span className={`font-display ${styles.statVal} text-primary`}>{stats.tendencyCount}</span>
|
||||
<span className={styles.statLbl}>✓ Tendenz</span>
|
||||
</div>
|
||||
<div className={`card ${styles.statCard}`}>
|
||||
<span className={`font-display ${styles.statVal}`} style={{ color: 'var(--error)' }}>{stats.wrongCount}</span>
|
||||
<span className={styles.statLbl}>✗ Falsch</span>
|
||||
</div>
|
||||
<div className={`card ${styles.statCard}`}>
|
||||
<span className={`font-display ${styles.statVal}`}>{stats.tipsCount}</span>
|
||||
<span className={styles.statLbl}>Tipps gesamt</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{evaluated > 0 && (
|
||||
<div className={`card ${styles.accuracyCard}`}>
|
||||
<div className={styles.accuracyHeader}>
|
||||
<span className={styles.accuracyLabel}>Trefferquote</span>
|
||||
<span className={`font-display ${styles.accuracyVal}`}>{stats.accuracy}%</span>
|
||||
</div>
|
||||
<div className={styles.bar}>
|
||||
<div className={`${styles.barFill} ${styles.exact}`}
|
||||
style={{ width: `${(stats.exactCount / evaluated) * 100}%` }} />
|
||||
<div className={`${styles.barFill} ${styles.tendency}`}
|
||||
style={{ width: `${(stats.tendencyCount / evaluated) * 100}%` }} />
|
||||
</div>
|
||||
<div className={styles.barLegend}>
|
||||
<span><span className={styles.dot} style={{ background: 'var(--gold)' }} /> Exakt</span>
|
||||
<span><span className={styles.dot} style={{ background: 'var(--primary)' }} /> Tendenz</span>
|
||||
<span><span className={styles.dot} style={{ background: 'var(--surface-high)' }} /> Falsch</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user