Files
ForbiddenStarsApp/frontend/src/components/CreateGroupForm.tsx
T
NotBigGhostandClaude Fable 5 ca96073ccf UI: общие классы кнопок и бейджей вместо дублирующихся inline-стилей
- .btn-block в global.css заменяет 9 повторов style={{width:100%}};
- .badge-live — единый бейдж «идёт» (3 копии inline-стиля);
- незавершённые партии на главной используют стандартный .card,
  как список партий (была единственная карточка на самодельных стилях);
- в списке партий добавлен бейдж 🎲 случайной фракции — как на странице
  партии (раньше в списке он терялся);
- переключатель групп: кнопка «+» подписана «+ Создать группу»
  (по образцу «+ Добавить игрока»), убран пустой span.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 17:45:35 +03:00

67 lines
2.3 KiB
TypeScript

import { useState } from "react";
import { ApiError } from "../api/client";
import { useToast } from "../context/ToastContext";
import { useCreateGroup } from "../hooks/groups";
import { useExpansions } from "../hooks/reference";
import { Switch } from "./Switch";
export function CreateGroupForm({ onCreated }: { onCreated?: () => void }) {
const { data: expansions } = useExpansions();
const createGroup = useCreateGroup();
const toast = useToast();
const [name, setName] = useState("");
const [selected, setSelected] = useState<Set<number>>(new Set());
const [error, setError] = useState<string | null>(null);
const toggle = (id: number) =>
setSelected((s) => {
const next = new Set(s);
next.has(id) ? next.delete(id) : next.add(id);
return next;
});
const submit = async () => {
setError(null);
try {
await createGroup.mutateAsync({ name: name.trim(), expansion_ids: [...selected] });
toast.show("Группа создана");
onCreated?.();
} catch (e) {
setError(e instanceof ApiError ? e.message : "Не удалось создать группу");
}
};
return (
<div className="card">
<h3>Новая группа</h3>
<div className="field">
<label className="label">Название</label>
<input value={name} onChange={(e) => setName(e.target.value)} placeholder="Например: Вечер 40k" />
</div>
<div className="field">
<label className="label">Дополнения группы</label>
<div className="stack">
{(expansions ?? []).map((e) => (
<label key={e.id} className="row" style={{ justifyContent: "space-between" }}>
<span>
{e.name_ru}
{e.is_base && <span className="muted small"> (всегда включено)</span>}
</span>
<Switch
disabled={e.is_base}
checked={e.is_base || selected.has(e.id)}
onChange={() => toggle(e.id)}
/>
</label>
))}
</div>
</div>
{error && <p className="error-text">{error}</p>}
<button className="btn btn-primary btn-block" onClick={submit} disabled={createGroup.isPending}>
Создать
</button>
</div>
);
}