Фронт: вход по паролю, окно установки пароля, профиль и админка

Страница входа начинается с карточки «Вход» (ник и пароль), в ней же
переключатель на регистрацию с повтором пароля. Telegram стоит ниже вторым
способом. Под ним подсказка: аккаунт, созданный по паролю, сначала привязывают к
Telegram в профиле, иначе вход через Telegram заведёт новый аккаунт. Поле логина
без автозаглавной буквы и автоисправления, у полей правильный autocomplete для
менеджеров паролей.

SetPasswordDialog показывается в AppShell всем, у кого has_password=false:
аккаунтам из Telegram и созданным до паролей. Закрыть окно нельзя, только задать
пароль или выйти. Успешный ответ кладёт в кэш профиль с has_password=true, и окно
исчезает само. Кнопка «Позже (dev)» есть лишь под import.meta.env.DEV: в
прод-бандле её строки нет, это проверено по dist.

В профиле появилась карточка «Вход в аккаунт»: смена пароля (текущий, если он
задан, новый и повтор) и привязка Telegram тем же виджетом, что при входе. У
смены ника подсказка, что ник — это и логин. В админке у игрока появилась кнопка
«Задать пароль» с вводом в той же строке, как у переименования, а в строке
игрока — пометка «без пароля».

schema.d.ts перегенерирован с живого бэкенда.

#24

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfTsytzT6TojfmprRDKiV6
This commit is contained in:
2026-09-13 14:11:57 +03:00
co-authored by Claude Opus 5
parent c73b4519cb
commit 462079d835
8 changed files with 775 additions and 17 deletions
+303
View File
@@ -21,6 +21,46 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/auth/register": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Password Register
* @description Регистрация по логину (нику) и паролю. Telegram привязывается позже в профиле.
*/
post: operations["password_register_api_auth_register_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/auth/login": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Password Login
* @description Вход игрока по нику и паролю. Неверная пара — 401, перебор — 429.
*/
post: operations["password_login_api_auth_login_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/auth/telegram": {
parameters: {
query?: never;
@@ -122,6 +162,46 @@ export interface paths {
patch: operations["update_my_profile_api_users_me_profile_patch"];
trace?: never;
};
"/api/users/me/password": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
/**
* Change My Password
* @description Задать пароль (первый раз — без текущего) или сменить его (нужен текущий).
*/
put: operations["change_my_password_api_users_me_password_put"];
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/users/me/telegram": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Link My Telegram
* @description Привязать Telegram к аккаунту. Подпись виджета проверяется так же, как при входе.
*/
post: operations["link_my_telegram_api_users_me_telegram_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/users/me/avatar": {
parameters: {
query?: never;
@@ -844,6 +924,26 @@ export interface paths {
patch: operations["update_user_api_admin_users__user_id__patch"];
trace?: never;
};
"/api/admin/users/{user_id}/password": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
/**
* Set User Password
* @description Задать игроку новый пароль — когда он забыл свой. Сам пароль в аудит не пишется.
*/
put: operations["set_user_password_api_admin_users__user_id__password_put"];
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/admin/groups": {
parameters: {
query?: never;
@@ -1224,6 +1324,11 @@ export interface components {
/** Role */
role: string;
};
/** AdminPasswordSet */
AdminPasswordSet: {
/** New Password */
new_password: string;
};
/** AdminUserRead */
AdminUserRead: {
/** Id */
@@ -1240,6 +1345,11 @@ export interface components {
telegram_id?: number | null;
/** Created At */
created_at: string;
/**
* Has Password
* @default false
*/
has_password: boolean;
};
/** AdminUserUpdate */
AdminUserUpdate: {
@@ -1887,6 +1997,11 @@ export interface components {
* @default []
*/
groups: components["schemas"]["GroupBrief"][];
/**
* Has Password
* @default false
*/
has_password: boolean;
};
/** MemberAdd */
MemberAdd: {
@@ -1990,6 +2105,27 @@ export interface components {
/** Comment */
comment?: string | null;
};
/** PasswordChange */
PasswordChange: {
/** Current Password */
current_password?: string | null;
/** New Password */
new_password: string;
};
/** PasswordLogin */
PasswordLogin: {
/** Nickname */
nickname: string;
/** Password */
password: string;
};
/** PasswordRegister */
PasswordRegister: {
/** Nickname */
nickname: string;
/** Password */
password: string;
};
/** ProfileStats */
ProfileStats: {
/** User Id */
@@ -2198,6 +2334,72 @@ export interface operations {
};
};
};
password_register_api_auth_register_post: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["PasswordRegister"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["MeRead"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
password_login_api_auth_login_post: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["PasswordLogin"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["MeRead"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
telegram_login_api_auth_telegram_post: {
parameters: {
query?: never;
@@ -2370,6 +2572,72 @@ export interface operations {
};
};
};
change_my_password_api_users_me_password_put: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["PasswordChange"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["MeRead"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
link_my_telegram_api_users_me_telegram_post: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["TelegramAuthPayload"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["MeRead"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
upload_my_avatar_api_users_me_avatar_put: {
parameters: {
query?: never;
@@ -3789,6 +4057,41 @@ export interface operations {
};
};
};
set_user_password_api_admin_users__user_id__password_put: {
parameters: {
query?: never;
header?: never;
path: {
user_id: number;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["AdminPasswordSet"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["AdminUserRead"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
list_groups_api_admin_groups_get: {
parameters: {
query?: never;