UI: приглашение игрока перенесено из настроек в «Список игроков»

Карточка «Статистика игроков» на странице группы переименована в
«Список игроков», под списком — поле приглашения по нику (с проверкой
максимума участников и отправкой по Enter). В настройках группы остался
только состав с удалением участников.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 17:17:47 +03:00
co-authored by Claude Fable 5
parent 49864db87e
commit 378094c366
2 changed files with 52 additions and 33 deletions
+3 -31
View File
@@ -1,4 +1,4 @@
import { Trash2, UserPlus } from "lucide-react";
import { Trash2 } from "lucide-react";
import { useEffect, useState } from "react";
import { ApiError } from "../api/client";
@@ -9,7 +9,7 @@ import { Switch } from "../components/Switch";
import { MAX_GROUP_SIZE } from "../domain/constants";
import { useToast } from "../context/ToastContext";
import { useMe } from "../hooks/auth";
import { useGroup, useGroupMembers, useInviteMember, useRemoveMember, useSetGroupExpansions } from "../hooks/groups";
import { useGroup, useGroupMembers, useRemoveMember, useSetGroupExpansions } from "../hooks/groups";
import { useExpansions } from "../hooks/reference";
export function GroupSettingsPage() {
@@ -19,12 +19,10 @@ export function GroupSettingsPage() {
const { data: expansions } = useExpansions();
const { data: members } = useGroupMembers(groupId);
const setExpansions = useSetGroupExpansions(groupId ?? 0);
const inviteMember = useInviteMember();
const removeMember = useRemoveMember(groupId ?? 0);
const toast = useToast();
const [selected, setSelected] = useState<Set<number>>(new Set());
const [newNick, setNewNick] = useState("");
const [removeTarget, setRemoveTarget] = useState<{ userId: number; nickname: string } | null>(null);
useEffect(() => {
@@ -51,18 +49,6 @@ export function GroupSettingsPage() {
}
};
const add = async () => {
const nick = newNick.trim();
if (!nick) return;
try {
await inviteMember.mutateAsync({ groupId: group.id, nickname: nick });
setNewNick("");
toast.show("Приглашение отправлено");
} catch (e) {
toast.show(e instanceof ApiError ? e.message : "Ошибка");
}
};
const remove = async (userId: number) => {
try {
await removeMember.mutateAsync(userId);
@@ -99,22 +85,8 @@ export function GroupSettingsPage() {
</div>
<div className="card">
{/* Приглашение нового игрока — на странице группы («Список игроков»). */}
<h3>Участники ({(members ?? []).length}/{MAX_GROUP_SIZE})</h3>
{isOwner && (members ?? []).length >= MAX_GROUP_SIZE && (
<p className="muted small">Достигнут максимум участников ({MAX_GROUP_SIZE}).</p>
)}
{isOwner && (members ?? []).length < MAX_GROUP_SIZE && (
<div className="row" style={{ marginBottom: 10 }}>
<input
placeholder="Ник игрока — отправить приглашение"
value={newNick}
onChange={(e) => setNewNick(e.target.value)}
/>
<button className="btn btn-primary" onClick={add} disabled={inviteMember.isPending}>
<UserPlus size={18} />
</button>
</div>
)}
<div className="stack">
{(members ?? []).map((m) => (
<div key={m.user_id} className="row-between">