refactor: remove email change functionality
This commit is contained in:
@@ -17,16 +17,12 @@ import { useUnit } from 'effector-react'
|
|||||||
import { useForm } from 'react-hook-form'
|
import { useForm } from 'react-hook-form'
|
||||||
import { AVATAR_STYLES, DEFAULT_STYLE_ID, getStyleById } from '@/shared/lib/avatar-styles'
|
import { AVATAR_STYLES, DEFAULT_STYLE_ID, getStyleById } from '@/shared/lib/avatar-styles'
|
||||||
import {
|
import {
|
||||||
$requestEmailChangeCodeError,
|
|
||||||
$updateProfileError,
|
$updateProfileError,
|
||||||
$user,
|
$user,
|
||||||
$verifyEmailChangeError,
|
|
||||||
fetchAuthMethodsFx,
|
fetchAuthMethodsFx,
|
||||||
requestEmailChangeCodeFx,
|
|
||||||
setPasswordFx,
|
setPasswordFx,
|
||||||
unlinkOAuthFx,
|
unlinkOAuthFx,
|
||||||
updateProfileFx,
|
updateProfileFx,
|
||||||
verifyEmailChangeFx,
|
|
||||||
type AuthMethod,
|
type AuthMethod,
|
||||||
} from '@/shared/model/auth'
|
} from '@/shared/model/auth'
|
||||||
import { UserAvatar } from '@/shared/ui/UserAvatar'
|
import { UserAvatar } from '@/shared/ui/UserAvatar'
|
||||||
@@ -41,17 +37,8 @@ function getApiErrorMessage(error: unknown): string | null {
|
|||||||
|
|
||||||
export function SettingsPage() {
|
export function SettingsPage() {
|
||||||
const user = useUnit($user)
|
const user = useUnit($user)
|
||||||
const pendingEmailReq = useUnit(requestEmailChangeCodeFx.pending)
|
|
||||||
const pendingEmailVerify = useUnit(verifyEmailChangeFx.pending)
|
|
||||||
const pendingProfile = useUnit(updateProfileFx.pending)
|
const pendingProfile = useUnit(updateProfileFx.pending)
|
||||||
const errorEmailReq = useUnit($requestEmailChangeCodeError)
|
|
||||||
const errorProfile = useUnit($updateProfileError)
|
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 }>({
|
const profileForm = useForm<{ displayName: string }>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@@ -60,7 +47,6 @@ export function SettingsPage() {
|
|||||||
mode: 'onChange',
|
mode: 'onChange',
|
||||||
})
|
})
|
||||||
|
|
||||||
const emailErrorMsg = getApiErrorMessage(errorEmailReq) ?? getApiErrorMessage(errorEmailVerify)
|
|
||||||
const profileErrorMsg = getApiErrorMessage(errorProfile)
|
const profileErrorMsg = getApiErrorMessage(errorProfile)
|
||||||
|
|
||||||
const [selectedStyle, setSelectedStyle] = useState(user?.avatarStyle || DEFAULT_STYLE_ID)
|
const [selectedStyle, setSelectedStyle] = useState(user?.avatarStyle || DEFAULT_STYLE_ID)
|
||||||
@@ -136,11 +122,6 @@ export function SettingsPage() {
|
|||||||
Текущая почта: <b>{user.email}</b>
|
Текущая почта: <b>{user.email}</b>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{emailErrorMsg && (
|
|
||||||
<Alert severity="error" sx={{ mb: 2 }}>
|
|
||||||
{emailErrorMsg}
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
{profileErrorMsg && (
|
{profileErrorMsg && (
|
||||||
<Alert severity="error" sx={{ mb: 2 }}>
|
<Alert severity="error" sx={{ mb: 2 }}>
|
||||||
{profileErrorMsg}
|
{profileErrorMsg}
|
||||||
@@ -408,39 +389,6 @@ export function SettingsPage() {
|
|||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
<Box>
|
|
||||||
<Typography variant="h6" gutterBottom>
|
|
||||||
Смена почты
|
|
||||||
</Typography>
|
|
||||||
<Stack spacing={2}>
|
|
||||||
<TextField label="Новая почта" {...emailForm.register('newEmail')} />
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
disabled={!emailForm.watch('newEmail') || pendingEmailReq}
|
|
||||||
onClick={() => requestEmailChangeCodeFx(emailForm.getValues('newEmail').trim())}
|
|
||||||
>
|
|
||||||
Отправить код на новую почту
|
|
||||||
</Button>
|
|
||||||
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
|
|
||||||
<TextField label="Код (6 цифр)" inputMode="numeric" {...emailForm.register('code')} />
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
disabled={emailForm.watch('code').trim().length !== 6 || pendingEmailVerify}
|
|
||||||
onClick={() =>
|
|
||||||
verifyEmailChangeFx({
|
|
||||||
newEmail: emailForm.getValues('newEmail').trim(),
|
|
||||||
code: emailForm.getValues('code').trim(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Подтвердить
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -60,17 +60,6 @@ sample({
|
|||||||
target: $user,
|
target: $user,
|
||||||
})
|
})
|
||||||
|
|
||||||
// ----- Email change -----
|
|
||||||
|
|
||||||
export const requestEmailChangeCodeFx = createEffect(async (newEmail: string) => {
|
|
||||||
await apiClient.post('me/change-email/request-code', { newEmail })
|
|
||||||
})
|
|
||||||
|
|
||||||
export const verifyEmailChangeFx = createEffect(async (params: { newEmail: string; code: string }) => {
|
|
||||||
const { data } = await apiClient.post<{ user: AuthUser }>('me/change-email/verify', params)
|
|
||||||
return data.user
|
|
||||||
})
|
|
||||||
|
|
||||||
// ----- Profile update -----
|
// ----- Profile update -----
|
||||||
|
|
||||||
export type UpdateProfileParams = {
|
export type UpdateProfileParams = {
|
||||||
@@ -113,17 +102,15 @@ export const unlinkOAuthFx = createEffect(async (provider: 'vk' | 'yandex') => {
|
|||||||
|
|
||||||
// ----- Error stores -----
|
// ----- Error stores -----
|
||||||
|
|
||||||
export const $requestEmailChangeCodeError = createErrorStore(requestEmailChangeCodeFx).$error
|
|
||||||
export const $verifyEmailChangeError = createErrorStore(verifyEmailChangeFx).$error
|
|
||||||
export const $updateProfileError = createErrorStore(updateProfileFx).$error
|
export const $updateProfileError = createErrorStore(updateProfileFx).$error
|
||||||
|
|
||||||
// ----- Re-exports -----
|
// ----- Re-exports -----
|
||||||
|
|
||||||
export { readStoredToken } from '@/shared/lib/persist-token'
|
export { readStoredToken } from '@/shared/lib/persist-token'
|
||||||
|
|
||||||
// ----- Sync user from profile/email changes -----
|
// ----- Sync user from profile changes -----
|
||||||
|
|
||||||
sample({
|
sample({
|
||||||
clock: [verifyEmailChangeFx.doneData, updateProfileFx.doneData],
|
clock: [updateProfileFx.doneData],
|
||||||
target: $user,
|
target: $user,
|
||||||
})
|
})
|
||||||
|
|||||||
Binary file not shown.
@@ -271,50 +271,6 @@ export async function registerAuthRoutes(fastify) {
|
|||||||
return { ok: true }
|
return { ok: true }
|
||||||
})
|
})
|
||||||
|
|
||||||
fastify.post('/api/me/change-email/request-code', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
|
||||||
const userId = request.user.sub
|
|
||||||
const newEmail = normalizeEmail(request.body?.newEmail)
|
|
||||||
if (!newEmail || !newEmail.includes('@')) return reply.code(400).send({ error: 'Некорректная почта' })
|
|
||||||
|
|
||||||
const exists = await prisma.user.findUnique({
|
|
||||||
where: { email: newEmail },
|
|
||||||
})
|
|
||||||
if (exists) return reply.code(409).send({ error: 'Эта почта уже занята' })
|
|
||||||
|
|
||||||
await issueEmailCode({
|
|
||||||
email: newEmail,
|
|
||||||
purpose: 'change_email',
|
|
||||||
userId,
|
|
||||||
})
|
|
||||||
return { ok: true }
|
|
||||||
})
|
|
||||||
|
|
||||||
fastify.post('/api/me/change-email/verify', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
|
||||||
const userId = request.user.sub
|
|
||||||
const newEmail = normalizeEmail(request.body?.newEmail)
|
|
||||||
const code = String(request.body?.code || '').trim()
|
|
||||||
if (!newEmail || !newEmail.includes('@')) return reply.code(400).send({ error: 'Некорректная почта' })
|
|
||||||
if (!code || code.length !== 6) return reply.code(400).send({ error: 'Код должен быть из 6 цифр' })
|
|
||||||
|
|
||||||
const exists = await prisma.user.findUnique({
|
|
||||||
where: { email: newEmail },
|
|
||||||
})
|
|
||||||
if (exists) return reply.code(409).send({ error: 'Эта почта уже занята' })
|
|
||||||
|
|
||||||
const ok = await verifyEmailCode({
|
|
||||||
email: newEmail,
|
|
||||||
purpose: 'change_email',
|
|
||||||
code,
|
|
||||||
userId,
|
|
||||||
})
|
|
||||||
if (!ok) return reply.code(401).send({ error: 'Неверный или истёкший код' })
|
|
||||||
|
|
||||||
const user = await prisma.user.update({
|
|
||||||
where: { id: userId },
|
|
||||||
data: { email: newEmail },
|
|
||||||
})
|
|
||||||
return { user: mapUserForClient(user) }
|
|
||||||
})
|
|
||||||
|
|
||||||
fastify.patch('/api/me/profile', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
fastify.patch('/api/me/profile', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||||
const userId = request.user.sub
|
const userId = request.user.sub
|
||||||
|
|||||||
Reference in New Issue
Block a user