import { useCallback, useEffect, useState } from 'react' import Alert from '@mui/material/Alert' import Box from '@mui/material/Box' import Button from '@mui/material/Button' import Chip from '@mui/material/Chip' import Divider from '@mui/material/Divider' import FormControl from '@mui/material/FormControl' import InputLabel from '@mui/material/InputLabel' import MenuItem from '@mui/material/MenuItem' import Select from '@mui/material/Select' import Stack from '@mui/material/Stack' import TextField from '@mui/material/TextField' import Typography from '@mui/material/Typography' import { createAvatar } from '@dicebear/core' import { useMutation } from '@tanstack/react-query' import { useUnit } from 'effector-react' import { useForm } from 'react-hook-form' import { AVATAR_STYLES, DEFAULT_STYLE_ID, getStyleById } from '@/shared/lib/avatar-styles' import { $requestEmailChangeCodeError, $updateProfileError, $user, $verifyEmailChangeError, fetchAuthMethodsFx, requestEmailChangeCodeFx, setPasswordFx, unlinkOAuthFx, updateProfileFx, verifyEmailChangeFx, type AuthMethod, } from '@/shared/model/auth' import { UserAvatar } from '@/shared/ui/UserAvatar' import { apiClient } from '@/shared/api/client' import type { AxiosError } from 'axios' function getApiErrorMessage(error: unknown): string | null { const e = error as AxiosError<{ error?: string }> const msg = e?.response?.data?.error return msg ? String(msg) : null } export function SettingsPage() { const user = useUnit($user) const pendingEmailReq = useUnit(requestEmailChangeCodeFx.pending) const pendingEmailVerify = useUnit(verifyEmailChangeFx.pending) const pendingProfile = useUnit(updateProfileFx.pending) const errorEmailReq = useUnit($requestEmailChangeCodeError) const errorProfile = useUnit($updateProfileError) const errorEmailVerify = useUnit($verifyEmailChangeError) const emailForm = useForm<{ newEmail: string; code: string }>({ defaultValues: { newEmail: '', code: '' }, mode: 'onChange', }) const profileForm = useForm<{ displayName: string }>({ defaultValues: { displayName: user?.displayName ? String(user.displayName) : '', }, mode: 'onChange', }) const emailErrorMsg = getApiErrorMessage(errorEmailReq) ?? getApiErrorMessage(errorEmailVerify) const profileErrorMsg = getApiErrorMessage(errorProfile) const [selectedStyle, setSelectedStyle] = useState(user?.avatarStyle || DEFAULT_STYLE_ID) const [previewSrc, setPreviewSrc] = useState(null) const [previewStyle, setPreviewStyle] = useState(DEFAULT_STYLE_ID) const hasUnsavedPreview = previewSrc !== null const [authMethods, setAuthMethods] = useState([]) const [showSetPassword, setShowSetPassword] = useState(false) const passwordForm = useForm<{ password: string; passwordConfirm: string }>({ defaultValues: { password: '', passwordConfirm: '' }, }) useEffect(() => { fetchAuthMethodsFx() .then(setAuthMethods) .catch(() => { setAuthMethods([]) }) }, []) const setPasswordMutation = useMutation({ mutationFn: async (pw: string) => { await setPasswordFx(pw) const methods = await fetchAuthMethodsFx() setAuthMethods(methods) setShowSetPassword(false) }, onError: () => {}, }) const unlinkMutation = useMutation({ mutationFn: async (provider: 'vk' | 'yandex') => { await unlinkOAuthFx(provider) const methods = await fetchAuthMethodsFx() setAuthMethods(methods) }, onError: () => {}, }) const [showChangePassword, setShowChangePassword] = useState(false) const changePasswordForm = useForm<{ oldPassword: string; newPassword: string; confirmPassword: string }>({ defaultValues: { oldPassword: '', newPassword: '', confirmPassword: '' }, }) const changePasswordMutation = useMutation({ mutationFn: async (params: { oldPassword: string; newPassword: string }) => { await apiClient.post('me/change-password', params) }, onSuccess: () => { setShowChangePassword(false) changePasswordForm.reset() }, }) const linkedCount = useCallback(() => { return authMethods.filter((m) => m.active).length }, [authMethods]) const METHOD_LABELS: Record = { password: 'Пароль', vk: 'ВКонтакте', yandex: 'Яндекс' } if (!user) { return Нужно войти. Перейдите на страницу «Вход». } return ( Настройки Текущая почта: {user.email} {emailErrorMsg && ( {emailErrorMsg} )} {profileErrorMsg && ( {profileErrorMsg} )} Профиль Аватар {hasUnsavedPreview ? 'Предпросмотр' : user.avatar ? 'Сохранён' : 'Авто'} {hasUnsavedPreview && ( Текущий )} Стиль {hasUnsavedPreview && ( )} {!user.isAdmin && ( <> Методы входа {authMethods.map((m) => ( {METHOD_LABELS[m.type] || m.type} {m.active && m.type !== 'password' && ( )} {m.active && m.type === 'password' && ( )} {!m.active && m.type === 'password' && ( )} {!m.active && m.type !== 'password' && ( )} ))} {showSetPassword && ( )} {showChangePassword && ( )} )} Смена почты ) }