b273c6aa7e
Previous pipeline built images locally via Portainer Docker API, but Docker layer caching produced identical images. Now: - Build with nocache=1 - Push to Gitea registry (git.home.rm-warpstation.de) - Compose uses image: from registry instead of build: - Redeploy with pullImage: true forces fresh container Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
48 lines
4.2 KiB
JavaScript
48 lines
4.2 KiB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
import { useEffect, useState } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { api } from '../api/client';
|
|
import styles from './DashboardPage.module.css';
|
|
function formatStreak(streak) {
|
|
if (streak >= 20)
|
|
return `⚡${streak}`;
|
|
if (streak >= 10)
|
|
return `🔥🔥${streak}`;
|
|
if (streak >= 3)
|
|
return `🔥${streak}`;
|
|
if (streak > 0)
|
|
return String(streak);
|
|
return '0';
|
|
}
|
|
function formatCountdown(minutes) {
|
|
if (minutes < 60)
|
|
return `in ${minutes} Min`;
|
|
if (minutes < 60 * 24)
|
|
return `in ${Math.floor(minutes / 60)}h`;
|
|
return `in ${Math.floor(minutes / (60 * 24))} Tagen`;
|
|
}
|
|
export default function DashboardPage(_props) {
|
|
const [data, setData] = useState(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState(false);
|
|
const navigate = useNavigate();
|
|
useEffect(() => {
|
|
setLoading(true);
|
|
setError(false);
|
|
api.getDashboard()
|
|
.then(d => { setData(d); setLoading(false); })
|
|
.catch(() => { setError(true); setLoading(false); });
|
|
}, []);
|
|
if (loading)
|
|
return _jsx("div", { className: styles.loading, children: "Laden..." });
|
|
if (error || !data)
|
|
return _jsx("div", { className: styles.error, children: "Dashboard konnte nicht geladen werden." });
|
|
const { hero, stats, nudges } = data;
|
|
return (_jsxs("div", { className: styles.dashboard, children: [_jsxs("div", { className: `card ${styles.hero}`, onClick: () => navigate('/spiele'), children: [_jsxs("div", { className: styles.heroLabel, children: [_jsx("span", { children: "N\u00E4chstes Spiel" }), hero && (_jsx("span", { className: styles.heroCountdown, children: formatCountdown(hero.match.minutesUntilKickoff) }))] }), hero ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.heroTeams, children: [_jsxs("div", { className: styles.heroTeam, children: [hero.match.homeTeam.crest ? (_jsx("img", { src: hero.match.homeTeam.crest, alt: hero.match.homeTeam.name, className: styles.heroCrest })) : (_jsx("div", { className: styles.heroCrest })), _jsx("span", { children: hero.match.homeTeam.shortName })] }), _jsx("span", { className: styles.heroVs, children: "vs" }), _jsxs("div", { className: styles.heroTeam, children: [hero.match.awayTeam.crest ? (_jsx("img", { src: hero.match.awayTeam.crest, alt: hero.match.awayTeam.name, className: styles.heroCrest })) : (_jsx("div", { className: styles.heroCrest })), _jsx("span", { children: hero.match.awayTeam.shortName })] })] }), hero.userTip ? (_jsxs("div", { className: styles.heroTip, children: ["Dein Tipp: ", hero.userTip.home, ":", hero.userTip.away, " \u2713"] })) : hero.tippable ? (_jsx("button", { className: styles.heroTipBtn, onClick: e => { e.stopPropagation(); navigate('/spiele'); }, children: "Jetzt tippen" })) : null] })) : (_jsx("p", { style: { textAlign: 'center', color: 'var(--text-muted)', margin: '16px 0' }, children: "Keine anstehenden Spiele" }))] }), _jsxs("div", { className: styles.statsRow, children: [_jsxs("div", { className: `card ${styles.statTile}`, children: [_jsx("span", { className: styles.statValue, children: stats.rank !== null ? stats.rank : '—' }), _jsx("span", { className: styles.statLabel, children: "Dein Rang" })] }), _jsxs("div", { className: `card ${styles.statTile}`, children: [_jsx("span", { className: styles.statValue, children: stats.totalPoints }), _jsx("span", { className: styles.statLabel, children: "Punkte" })] }), _jsxs("div", { className: `card ${styles.statTile}`, children: [_jsx("span", { className: styles.statValue, children: formatStreak(stats.streak) }), _jsx("span", { className: styles.statLabel, children: "Streak" })] })] }), nudges.length > 0 && (_jsx("div", { className: styles.nudges, children: nudges.map((nudge, i) => (_jsx("div", { className: `card ${styles.nudge}`, onClick: () => {
|
|
if (nudge.type === 'untipped')
|
|
navigate('/spiele');
|
|
else if (nudge.type === 'leader')
|
|
navigate('/rangliste');
|
|
}, children: nudge.text }, i))) }))] }));
|
|
}
|