v0.1 - макет интерфейса, аутентификация через логин, аккаунт админа, создание партии в 2 этапа, базовые настройки профиля и группы, переключение между группами, статистика

This commit is contained in:
2026-06-16 17:41:06 +03:00
parent 6ab74f01aa
commit 56b5d09a4d
123 changed files with 13572 additions and 21 deletions
+65
View File
@@ -0,0 +1,65 @@
import { useNavigate } from "react-router-dom";
import { CreateGroupForm } from "../components/CreateGroupForm";
import { GroupSwitcher } from "../components/GroupSwitcher";
import { Leaderboard } from "../components/Leaderboard";
import { MatchListView } from "../components/MatchList";
import { Spinner } from "../components/Spinner";
import { useMe } from "../hooks/auth";
import { useGroup, useGroupMatches, useGroupStats } from "../hooks/groups";
export function GroupPage() {
const { data: me, isLoading } = useMe();
const navigate = useNavigate();
const groupId = me?.active_group_id ?? null;
const { data: group } = useGroup(groupId);
const { data: stats } = useGroupStats(groupId);
const { data: matches } = useGroupMatches(groupId);
if (isLoading) return <Spinner />;
if (!groupId) {
return (
<div>
<div className="card">
<h3>Активная группа не выбрана</h3>
<p className="muted small">
Создайте группу или выберите существующую, чтобы вести учёт партий.
</p>
</div>
<GroupSwitcher />
<CreateGroupForm />
</div>
);
}
return (
<div>
<div className="card">
<div className="row-between">
<h2 style={{ margin: 0 }}>{group?.name ?? "Группа"}</h2>
{group && (
<button className="btn btn-ghost small" onClick={() => navigate("/group/settings")}>
Настройки
</button>
)}
</div>
<p className="muted small">
Партий: {stats?.total_matches ?? 0}
{stats?.last_match_at ? ` · последняя: ${stats.last_match_at}` : ""}
</p>
</div>
<div className="card">
<h3>Топ в группе</h3>
{stats && <Leaderboard entries={stats.leaderboard} provisional={stats.provisional} />}
</div>
<GroupSwitcher />
<h3 style={{ marginTop: 8 }}>Партии</h3>
{matches && <MatchListView items={matches.items} />}
</div>
);
}