- админка, записи: удаление партии раньше срабатывало сразу по клику на иконку и показывало «Удалено» даже при ошибке — теперь модалка подтверждения и честная обработка ошибок; - ачивки и dev-удаление аккаунта: window.confirm заменён на ConfirmDialog (в приложении принят именно он); - настройки группы: удаление участника — с подтверждением. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
69 lines
2.6 KiB
TypeScript
69 lines
2.6 KiB
TypeScript
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
import { useState } from "react";
|
|
|
|
import { ApiError, api, unwrap } from "../../api/client";
|
|
import { qk } from "../../api/queryKeys";
|
|
import { ConfirmDialog } from "../../components/ConfirmDialog";
|
|
import { useToast } from "../../context/ToastContext";
|
|
|
|
/**
|
|
* DEV-ТОЛЬКО кнопка жёсткого удаления аккаунта.
|
|
*
|
|
* Эндпоинт `DELETE /api/admin/dev/users/{id}` существует только в dev-сборке бэкенда
|
|
* (backend/app/routers/dev_admin.py, исключён из прод/тест-образа). Этот модуль
|
|
* рендерится лишь под `import.meta.env.DEV` в AdminAccountsPage, поэтому в прод-сборке
|
|
* он не используется и вырезается тришейкингом — в прод/тест удаление недоступно.
|
|
*/
|
|
export function DevDeleteAccountButton({
|
|
userId,
|
|
nickname,
|
|
}: {
|
|
userId: number;
|
|
nickname: string;
|
|
}) {
|
|
const qc = useQueryClient();
|
|
const toast = useToast();
|
|
const [confirmOpen, setConfirmOpen] = useState(false);
|
|
const del = useMutation({
|
|
mutationFn: async () =>
|
|
unwrap(
|
|
await api.DELETE("/api/admin/dev/users/{user_id}", {
|
|
params: { path: { user_id: userId } },
|
|
}),
|
|
),
|
|
onSuccess: () => qc.invalidateQueries({ queryKey: qk.adminUsers }),
|
|
});
|
|
|
|
return (
|
|
<>
|
|
<button
|
|
className="btn small"
|
|
// Яркая (сплошная) красная кнопка. Стиль инлайном, а не классом в общем CSS,
|
|
// чтобы в прод/тест-стили не попало ничего, связанного с удалением.
|
|
style={{ background: "var(--danger)", borderColor: "var(--danger)", color: "#fff" }}
|
|
disabled={del.isPending}
|
|
onClick={() => setConfirmOpen(true)}
|
|
>
|
|
Удалить
|
|
</button>
|
|
<ConfirmDialog
|
|
open={confirmOpen}
|
|
danger
|
|
title={`Удалить аккаунт «${nickname}»?`}
|
|
message="Партии сохранятся, но игрок будет вычеркнут из них. Действие необратимо."
|
|
confirmLabel="Удалить"
|
|
onCancel={() => setConfirmOpen(false)}
|
|
onConfirm={async () => {
|
|
setConfirmOpen(false);
|
|
try {
|
|
await del.mutateAsync();
|
|
toast.show("Аккаунт удалён");
|
|
} catch (e) {
|
|
toast.show(e instanceof ApiError ? e.message : "Не удалось удалить");
|
|
}
|
|
}}
|
|
/>
|
|
</>
|
|
);
|
|
}
|