refactor(SettingsPage): split into ProfileSection, AvatarSection, AuthMethodsSection

- Extract ProfileSection (45 lines): display name form with save button
- Extract AvatarSection (114 lines): avatar preview, style selector, generate/save/cancel
- Extract AuthMethodsSection (204 lines): auth methods list, set/change password forms
- Rewrite SettingsPage as composer (41 lines): composes 3 sections with dividers
- Add tests for all 3 sections
This commit is contained in:
Kirill
2026-05-22 15:04:49 +05:00
parent 03e60e46f3
commit e273c29c36
7 changed files with 473 additions and 361 deletions
@@ -0,0 +1,45 @@
import Box from '@mui/material/Box'
import Button from '@mui/material/Button'
import Stack from '@mui/material/Stack'
import TextField from '@mui/material/TextField'
import Typography from '@mui/material/Typography'
import { useUnit } from 'effector-react'
import { useForm } from 'react-hook-form'
import { $user, updateProfileFx } from '@/shared/model/auth'
export function ProfileSection() {
const user = useUnit($user)
const pendingProfile = useUnit(updateProfileFx.pending)
const profileForm = useForm<{ displayName: string }>({
defaultValues: { displayName: user?.displayName ? String(user.displayName) : '' },
mode: 'onChange',
})
return (
<Box>
<Typography variant="h6" gutterBottom>
Профиль
</Typography>
<Stack spacing={2}>
<TextField
label="Имя или ник"
helperText="До 40 символов"
slotProps={{ htmlInput: { maxLength: 40 } }}
{...profileForm.register('displayName')}
/>
<Button
variant="contained"
disabled={pendingProfile}
onClick={() => {
const raw = profileForm.getValues('displayName')
const name = raw.trim()
updateProfileFx({ displayName: name.length ? name : null })
}}
>
Сохранить
</Button>
</Stack>
</Box>
)
}