Профиль: выбор любимой фракции и строка «Чаще всего играет на»
В кастомизации профиля появился выбор любимой фракции из полного справочника (PickerSelect, все 12 фракций): фракция — свойство игрока, а не группы, поэтому список не зависит от подключённых дополнений. Дополнение показано в строке опции приглушённым текстом, снятие выбора — кнопкой «Убрать». В карточке статистики «Любимая фракция» теперь берётся из профиля, а «Основная фракция» переименована в «Чаще всего играет на» и печатает название в предложном падеже. Публичный профиль правок не потребовал — он использует ту же карточку и ту же схему. schema.d.ts пересобран с живого бэкенда (npm run gen:api). #17 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ps52xzuUXnWrJ5SRnEeaLk
This commit is contained in:
@@ -3,6 +3,7 @@ import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { ApiError } from "../api/client";
|
||||
import { Avatar } from "../components/Avatar";
|
||||
import { PickerSelect } from "../components/PickerSelect";
|
||||
import { ProfileStatsCard } from "../components/ProfileStatsCard";
|
||||
import { Spinner } from "../components/Spinner";
|
||||
import { useToast } from "../context/ToastContext";
|
||||
@@ -11,9 +12,11 @@ import {
|
||||
useLogout,
|
||||
useMe,
|
||||
useUpdateBio,
|
||||
useUpdateFavoriteFaction,
|
||||
useUpdateNickname,
|
||||
useUploadAvatar,
|
||||
} from "../hooks/auth";
|
||||
import { useExpansions, useFactions } from "../hooks/reference";
|
||||
import { useMyStats } from "../hooks/stats";
|
||||
|
||||
export function AccountPage() {
|
||||
@@ -21,6 +24,9 @@ export function AccountPage() {
|
||||
const { data: stats } = useMyStats();
|
||||
const updateNick = useUpdateNickname();
|
||||
const updateBio = useUpdateBio();
|
||||
const updateFavorite = useUpdateFavoriteFaction();
|
||||
const { data: factions } = useFactions();
|
||||
const { data: expansions } = useExpansions();
|
||||
const uploadAvatar = useUploadAvatar();
|
||||
const deleteAvatar = useDeleteAvatar();
|
||||
const logout = useLogout();
|
||||
@@ -35,6 +41,20 @@ export function AccountPage() {
|
||||
// bio редактируется локально; до первого ввода берём значение из профиля.
|
||||
const bioValue = bio ?? me.bio ?? "";
|
||||
|
||||
// Любимая фракция выбирается из ПОЛНОГО справочника: это свойство игрока, а не
|
||||
// группы, и не должно зависеть от подключённых у неё дополнений.
|
||||
const favorite = factions?.find((f) => f.id === me.favorite_faction_id) ?? null;
|
||||
const expansionName = (id: number) => expansions?.find((e) => e.id === id)?.name_ru ?? "";
|
||||
|
||||
const saveFavorite = async (factionId: number | null) => {
|
||||
try {
|
||||
await updateFavorite.mutateAsync(factionId);
|
||||
toast.show(factionId == null ? "Любимая фракция убрана" : "Любимая фракция сохранена");
|
||||
} catch (e) {
|
||||
toast.show(e instanceof ApiError ? e.message : "Ошибка");
|
||||
}
|
||||
};
|
||||
|
||||
const saveNick = async () => {
|
||||
const nick = nickname.trim();
|
||||
if (!nick) return;
|
||||
@@ -140,6 +160,36 @@ export function AccountPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field" style={{ marginTop: 10 }}>
|
||||
<label className="label">Любимая фракция</label>
|
||||
<div className="row">
|
||||
<PickerSelect
|
||||
selected={favorite}
|
||||
options={factions ?? []}
|
||||
placeholder="Не выбрана"
|
||||
renderOption={(f) => (
|
||||
<>
|
||||
<span className="nick">{f.name_ru}</span>
|
||||
<span className="muted small" style={{ marginLeft: "auto" }}>
|
||||
{expansionName(f.expansion_id)}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
renderValue={(f) => <span className="nick">{f.name_ru}</span>}
|
||||
onPick={(f) => saveFavorite(f.id)}
|
||||
/>
|
||||
{favorite && (
|
||||
<button
|
||||
className="btn btn-ghost small"
|
||||
onClick={() => saveFavorite(null)}
|
||||
disabled={updateFavorite.isPending}
|
||||
>
|
||||
Убрать
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field" style={{ marginTop: 10 }}>
|
||||
<label className="label">Сменить никнейм</label>
|
||||
<div className="row">
|
||||
|
||||
Reference in New Issue
Block a user