CI / Generate TypeScript types (push) Successful in 15s
CI / Server unit tests (push) Successful in 23s
CI / Build server (push) Successful in 29s
CI / Build client (push) Successful in 1m2s
CI / Playwright E2E tests (push) Successful in 1m33s
CI / Build and push Docker image (push) Successful in 49s
CI / Notify (push) Successful in 1s
- obchod s pomůckami a trvalými vylepšeními (větší síťka, strašák, zpevněná síťka) – mince mají trvalý smysl - černé můry se míchají mezi motýly; chycení (i magnetem) ubere hodně úlovků - ptáci silnější, plašič dražší a kratší, zloději chodí častěji podle bohatství - denní úkol s odměnou + achievementy/odznaky - netopýr v noci loví motýly, pavouk zamotá síťku pavučinou – oba na zaklikání - nákupní hlášky rozlišují nedostatek mincí od jiné chyby; herní smyčka se pozastaví při skryté záložce Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
112 lines
5.6 KiB
TypeScript
112 lines
5.6 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { Modal } from "react-bootstrap";
|
|
import {
|
|
ButterflyLeaderboardEntry, ButterflyStats, ButterflyAchievement,
|
|
getButterflyLeaderboard, getButterflyAchievements,
|
|
} from "../../../../types";
|
|
import { useAuth } from "../../context/auth";
|
|
import "./ButterflyLeaderboardModal.scss";
|
|
|
|
type Props = {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
myStats?: ButterflyStats;
|
|
};
|
|
|
|
const MEDALS = ['🥇', '🥈', '🥉'];
|
|
|
|
/** Modální dialog s osobními statistikami, achievementy a týmovým žebříčkem. */
|
|
export default function ButterflyLeaderboardModal({ isOpen, onClose, myStats }: Readonly<Props>) {
|
|
const auth = useAuth();
|
|
const [entries, setEntries] = useState<ButterflyLeaderboardEntry[]>();
|
|
const [achievements, setAchievements] = useState<ButterflyAchievement[]>();
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (!isOpen) return;
|
|
let cancelled = false;
|
|
setLoading(true);
|
|
Promise.all([
|
|
getButterflyLeaderboard({ query: { limit: 20 } }).then(r => r.data ?? []).catch(() => []),
|
|
getButterflyAchievements().then(r => r.data ?? []).catch(() => []),
|
|
]).then(([lb, ach]) => {
|
|
if (cancelled) return;
|
|
setEntries(lb);
|
|
setAchievements(ach);
|
|
}).finally(() => { if (!cancelled) setLoading(false); });
|
|
return () => { cancelled = true; };
|
|
}, [isOpen]);
|
|
|
|
return (
|
|
<Modal show={isOpen} onHide={onClose} centered>
|
|
<Modal.Header closeButton>
|
|
<Modal.Title>🦋 Chytání motýlků</Modal.Title>
|
|
</Modal.Header>
|
|
<Modal.Body>
|
|
{myStats && (
|
|
<div className="butterfly-mystats">
|
|
<div className="butterfly-mystats-title">
|
|
{myStats.level}. {myStats.title}
|
|
</div>
|
|
<div className="butterfly-mystats-grid">
|
|
<div><span className="v">{myStats.caught}</span><span className="l">🦋 chyceno</span></div>
|
|
<div><span className="v gold">{myStats.goldenCaught}</span><span className="l">✨ zlatých</span></div>
|
|
<div><span className="v">{myStats.coins}</span><span className="l">🪙 mincí</span></div>
|
|
<div><span className="v">{myStats.waspsKilled}</span><span className="l">🪰 vos zabito</span></div>
|
|
<div><span className="v">{myStats.birdsScared}</span><span className="l">🦅 vyplašeno</span></div>
|
|
<div><span className="v">{myStats.thievesDefeated}</span><span className="l">🦹 zlodějů</span></div>
|
|
<div><span className="v">{myStats.caterpillarsDefeated}</span><span className="l">🐛 housenek</span></div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{achievements && achievements.length > 0 && (
|
|
<>
|
|
<h6 className="butterfly-leaderboard-heading">Odznaky</h6>
|
|
<div className="butterfly-achievements">
|
|
{achievements.map(a => (
|
|
<div
|
|
key={a.id}
|
|
className={a.unlocked ? 'butterfly-achievement unlocked' : 'butterfly-achievement'}
|
|
title={a.description}
|
|
>
|
|
<span className="ach-icon">{a.unlocked ? '🏅' : '🔒'}</span>
|
|
<span className="ach-title">{a.title}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
<h6 className="butterfly-leaderboard-heading">Žebříček týmu</h6>
|
|
{loading && <p className="text-center text-muted mb-0">Načítám žebříček…</p>}
|
|
{!loading && entries && entries.length === 0 && (
|
|
<p className="text-center text-muted mb-0">Zatím nikdo nic nechytil. Buď první!</p>
|
|
)}
|
|
{!loading && entries && entries.length > 0 && (
|
|
<ol className="butterfly-leaderboard">
|
|
{entries.map((e, i) => (
|
|
<li
|
|
key={e.login}
|
|
className={e.login === auth?.login ? 'butterfly-leaderboard-row me' : 'butterfly-leaderboard-row'}
|
|
>
|
|
<span className="butterfly-leaderboard-rank">{MEDALS[i] ?? `${i + 1}.`}</span>
|
|
<span className="butterfly-leaderboard-name" title={e.title}>
|
|
{e.login}
|
|
<span className="butterfly-leaderboard-title">{e.level}. {e.title}</span>
|
|
</span>
|
|
<span className="butterfly-leaderboard-stats">
|
|
<span className="butterfly-leaderboard-caught">{e.caught} 🦋</span>
|
|
{e.goldenCaught > 0 && (
|
|
<span className="butterfly-leaderboard-golden">{e.goldenCaught} ✨</span>
|
|
)}
|
|
</span>
|
|
</li>
|
|
))}
|
|
</ol>
|
|
)}
|
|
</Modal.Body>
|
|
</Modal>
|
|
);
|
|
}
|