feat: add password change and reset via email code
This commit is contained in:
@@ -30,6 +30,7 @@ import {
|
||||
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 {
|
||||
@@ -101,6 +102,21 @@ export function SettingsPage() {
|
||||
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])
|
||||
@@ -271,6 +287,11 @@ export function SettingsPage() {
|
||||
Отвязать
|
||||
</Button>
|
||||
)}
|
||||
{m.active && m.type === 'password' && (
|
||||
<Button size="small" variant="outlined" onClick={() => setShowChangePassword(true)}>
|
||||
Сменить пароль
|
||||
</Button>
|
||||
)}
|
||||
{!m.active && m.type === 'password' && (
|
||||
<Button size="small" variant="outlined" onClick={() => setShowSetPassword(true)}>
|
||||
Установить пароль
|
||||
@@ -328,6 +349,62 @@ export function SettingsPage() {
|
||||
</Stack>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{showChangePassword && (
|
||||
<Stack spacing={2} sx={{ mt: 2, p: 2, border: '1px solid', borderColor: 'divider', borderRadius: 1 }}>
|
||||
<TextField
|
||||
label="Текущий пароль"
|
||||
type="password"
|
||||
{...changePasswordForm.register('oldPassword')}
|
||||
fullWidth
|
||||
/>
|
||||
<TextField
|
||||
label="Новый пароль"
|
||||
type="password"
|
||||
{...changePasswordForm.register('newPassword')}
|
||||
fullWidth
|
||||
/>
|
||||
<TextField
|
||||
label="Подтверждение пароля"
|
||||
type="password"
|
||||
{...changePasswordForm.register('confirmPassword')}
|
||||
fullWidth
|
||||
error={
|
||||
Boolean(changePasswordForm.watch('confirmPassword')) &&
|
||||
changePasswordForm.watch('newPassword') !== changePasswordForm.watch('confirmPassword')
|
||||
}
|
||||
helperText={
|
||||
changePasswordForm.watch('confirmPassword') &&
|
||||
changePasswordForm.watch('newPassword') !== changePasswordForm.watch('confirmPassword')
|
||||
? 'Пароли не совпадают'
|
||||
: null
|
||||
}
|
||||
/>
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Button
|
||||
variant="contained"
|
||||
disabled={
|
||||
!changePasswordForm.watch('oldPassword') ||
|
||||
!changePasswordForm.watch('newPassword') ||
|
||||
changePasswordForm.watch('newPassword').length < 8 ||
|
||||
changePasswordForm.watch('newPassword') !== changePasswordForm.watch('confirmPassword') ||
|
||||
changePasswordMutation.isPending
|
||||
}
|
||||
onClick={() =>
|
||||
changePasswordMutation.mutate({
|
||||
oldPassword: changePasswordForm.getValues('oldPassword'),
|
||||
newPassword: changePasswordForm.getValues('newPassword'),
|
||||
})
|
||||
}
|
||||
>
|
||||
Сохранить
|
||||
</Button>
|
||||
<Button variant="text" onClick={() => setShowChangePassword(false)}>
|
||||
Отмена
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user