Настройки группы: переименование группы
Новый хук useRenameGroup (PATCH /api/groups/{id} — эндпойнт уже был на
бэкенде) с инвалидацией всех мест, где видно имя группы (шапка группы,
переключатель групп, главная). В настройках — карточка «Название» с
полем и кнопкой «Сохранить» (по образцу смены ника в аккаунте).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -75,6 +75,26 @@ export function useCreateGroup() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useRenameGroup(groupId: number) {
|
||||||
|
const qc = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async (name: string) =>
|
||||||
|
unwrap(
|
||||||
|
await api.PATCH("/api/groups/{group_id}", {
|
||||||
|
params: { path: { group_id: groupId } },
|
||||||
|
body: { name },
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
onSuccess: () => {
|
||||||
|
// Имя группы видно в шапке группы, переключателе групп (me), на главной.
|
||||||
|
qc.invalidateQueries({ queryKey: qk.group(groupId) });
|
||||||
|
qc.invalidateQueries({ queryKey: qk.groups });
|
||||||
|
qc.invalidateQueries({ queryKey: qk.me });
|
||||||
|
qc.invalidateQueries({ queryKey: qk.home });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function useSetGroupExpansions(groupId: number) {
|
export function useSetGroupExpansions(groupId: number) {
|
||||||
const qc = useQueryClient();
|
const qc = useQueryClient();
|
||||||
return useMutation({
|
return useMutation({
|
||||||
|
|||||||
@@ -9,7 +9,13 @@ import { Switch } from "../components/Switch";
|
|||||||
import { MAX_GROUP_SIZE } from "../domain/constants";
|
import { MAX_GROUP_SIZE } from "../domain/constants";
|
||||||
import { useToast } from "../context/ToastContext";
|
import { useToast } from "../context/ToastContext";
|
||||||
import { useMe } from "../hooks/auth";
|
import { useMe } from "../hooks/auth";
|
||||||
import { useGroup, useGroupMembers, useRemoveMember, useSetGroupExpansions } from "../hooks/groups";
|
import {
|
||||||
|
useGroup,
|
||||||
|
useGroupMembers,
|
||||||
|
useRemoveMember,
|
||||||
|
useRenameGroup,
|
||||||
|
useSetGroupExpansions,
|
||||||
|
} from "../hooks/groups";
|
||||||
import { useExpansions } from "../hooks/reference";
|
import { useExpansions } from "../hooks/reference";
|
||||||
|
|
||||||
export function GroupSettingsPage() {
|
export function GroupSettingsPage() {
|
||||||
@@ -19,10 +25,13 @@ export function GroupSettingsPage() {
|
|||||||
const { data: expansions } = useExpansions();
|
const { data: expansions } = useExpansions();
|
||||||
const { data: members } = useGroupMembers(groupId);
|
const { data: members } = useGroupMembers(groupId);
|
||||||
const setExpansions = useSetGroupExpansions(groupId ?? 0);
|
const setExpansions = useSetGroupExpansions(groupId ?? 0);
|
||||||
|
const renameGroup = useRenameGroup(groupId ?? 0);
|
||||||
const removeMember = useRemoveMember(groupId ?? 0);
|
const removeMember = useRemoveMember(groupId ?? 0);
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
const [selected, setSelected] = useState<Set<number>>(new Set());
|
const [selected, setSelected] = useState<Set<number>>(new Set());
|
||||||
|
// Название редактируется локально; до первого ввода берём значение из группы.
|
||||||
|
const [name, setName] = useState<string | null>(null);
|
||||||
const [removeTarget, setRemoveTarget] = useState<{ userId: number; nickname: string } | null>(null);
|
const [removeTarget, setRemoveTarget] = useState<{ userId: number; nickname: string } | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -40,6 +49,20 @@ export function GroupSettingsPage() {
|
|||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const nameValue = name ?? group.name;
|
||||||
|
|
||||||
|
const saveName = async () => {
|
||||||
|
const trimmed = nameValue.trim();
|
||||||
|
if (!trimmed || trimmed === group.name) return;
|
||||||
|
try {
|
||||||
|
await renameGroup.mutateAsync(trimmed);
|
||||||
|
setName(null);
|
||||||
|
toast.show("Название сохранено");
|
||||||
|
} catch (e) {
|
||||||
|
toast.show(e instanceof ApiError ? e.message : "Ошибка");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const saveExpansions = async () => {
|
const saveExpansions = async () => {
|
||||||
try {
|
try {
|
||||||
await setExpansions.mutateAsync([...selected]);
|
await setExpansions.mutateAsync([...selected]);
|
||||||
@@ -59,6 +82,26 @@ export function GroupSettingsPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<div className="card">
|
||||||
|
<h3>Название</h3>
|
||||||
|
<div className="row">
|
||||||
|
<input
|
||||||
|
value={nameValue}
|
||||||
|
onChange={(e) => setName(e.target.value)}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter") saveName();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className="btn btn-primary"
|
||||||
|
onClick={saveName}
|
||||||
|
disabled={renameGroup.isPending || !nameValue.trim() || nameValue.trim() === group.name}
|
||||||
|
>
|
||||||
|
Сохранить
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<h3>Дополнения</h3>
|
<h3>Дополнения</h3>
|
||||||
<div className="stack">
|
<div className="stack">
|
||||||
|
|||||||
Reference in New Issue
Block a user