From 370141c83bb0955f0457c83acb3de4850651ccd0 Mon Sep 17 00:00:00 2001 From: rassadin11 Date: Tue, 19 May 2026 15:50:47 +0300 Subject: [PATCH] 19.05.2026 okkk --- src/features/auth/api/profileApi.ts | 12 ++- .../ui/RestorePasswordForm.module.css | 6 ++ .../ui/RestorePasswordForm.tsx | 100 ++++++++++++------ src/widgets/swap-form/ui/SwapCard.module.css | 3 + src/widgets/swap-form/ui/SwapCard.tsx | 2 +- 5 files changed, 86 insertions(+), 37 deletions(-) diff --git a/src/features/auth/api/profileApi.ts b/src/features/auth/api/profileApi.ts index d65cd29..ea0a282 100644 --- a/src/features/auth/api/profileApi.ts +++ b/src/features/auth/api/profileApi.ts @@ -69,14 +69,20 @@ export async function uploadAvatar(payload: UploadAvatarPayload): Promise { +export interface PasswordResetStartPayload { + email: string +} + +export async function passwordResetStart(payload: PasswordResetStartPayload): Promise { const csrf = await getCsrfToken() - const res = await fetch(`${USERS_API_URL}/me/settings/password/start`, { + const res = await fetch(`${USERS_API_URL}/me/settings/password/forgot/start`, { method: 'POST', credentials: 'include', headers: { + 'Content-Type': 'application/json', 'X-CSRF-Token': csrf, }, + body: JSON.stringify(payload), }) if (!res.ok) { const data = await res.json().catch(() => ({})) @@ -92,7 +98,7 @@ export interface PasswordResetCompletePayload { export async function passwordResetComplete(payload: PasswordResetCompletePayload): Promise { const csrf = await getCsrfToken() - const res = await fetch(`${USERS_API_URL}/me/settings/password/complete`, { + const res = await fetch(`${USERS_API_URL}/me/settings/password/forgot/complete`, { method: 'POST', credentials: 'include', headers: { diff --git a/src/widgets/restore-password-form/ui/RestorePasswordForm.module.css b/src/widgets/restore-password-form/ui/RestorePasswordForm.module.css index c1033fc..6476e12 100644 --- a/src/widgets/restore-password-form/ui/RestorePasswordForm.module.css +++ b/src/widgets/restore-password-form/ui/RestorePasswordForm.module.css @@ -32,6 +32,12 @@ gap: 20px; } +.emailRow { + display: flex; + flex-direction: column; + gap: 12px; +} + .error { color: #ff5a5a; font-size: 13px; diff --git a/src/widgets/restore-password-form/ui/RestorePasswordForm.tsx b/src/widgets/restore-password-form/ui/RestorePasswordForm.tsx index 7d4aff2..34edbd7 100644 --- a/src/widgets/restore-password-form/ui/RestorePasswordForm.tsx +++ b/src/widgets/restore-password-form/ui/RestorePasswordForm.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react' +import { useState } from 'react' import { useNavigate } from 'react-router-dom' import { FormField } from '@shared/ui' import { PrimaryButton } from '@shared/ui' @@ -11,6 +11,9 @@ import styles from './RestorePasswordForm.module.css' type NotificationState = { message: string; status: 'success' | 'error' } export function RestorePasswordForm() { + const [email, setEmail] = useState('') + const [codeSent, setCodeSent] = useState(false) + const [isSendingCode, setIsSendingCode] = useState(false) const [code, setCode] = useState('') const [newPassword, setNewPassword] = useState('') const [confirmPassword, setConfirmPassword] = useState('') @@ -19,11 +22,19 @@ export function RestorePasswordForm() { const [notification, setNotification] = useState(null) const navigate = useNavigate() - useEffect(() => { - passwordResetStart() - .then(() => setNotification({ status: 'success', message: 'На вашу почту отправлено письмо с кодом' })) - .catch(() => setNotification({ status: 'error', message: 'Не удалось отправить письмо. Попробуйте позже.' })) - }, []) + async function handleSendCode() { + setError('') + setIsSendingCode(true) + try { + await passwordResetStart({ email }) + setCodeSent(true) + setNotification({ status: 'success', message: `Код отправлен на ${email}` }) + } catch { + setNotification({ status: 'error', message: 'Не удалось отправить письмо. Проверьте email и попробуйте снова.' }) + } finally { + setIsSendingCode(false) + } + } async function handleSubmit(e: React.FormEvent) { e.preventDefault() @@ -54,37 +65,60 @@ export function RestorePasswordForm() {

Восстановление пароля

- - - +
+ + +
+ + {codeSent && ( + <> + + + + + )}
{error &&

{error}

} -
- -
+ {codeSent && ( +
+ +
+ )}
navigate(ROUTES.LOGIN)}> diff --git a/src/widgets/swap-form/ui/SwapCard.module.css b/src/widgets/swap-form/ui/SwapCard.module.css index 438c97f..bb93000 100644 --- a/src/widgets/swap-form/ui/SwapCard.module.css +++ b/src/widgets/swap-form/ui/SwapCard.module.css @@ -140,6 +140,9 @@ } .display { + flex: 1; + min-width: 0; + overflow: hidden; font-weight: 700; white-space: nowrap; line-height: 1; diff --git a/src/widgets/swap-form/ui/SwapCard.tsx b/src/widgets/swap-form/ui/SwapCard.tsx index 482388f..a4b8e88 100644 --- a/src/widgets/swap-form/ui/SwapCard.tsx +++ b/src/widgets/swap-form/ui/SwapCard.tsx @@ -25,7 +25,7 @@ export function SwapCard({ onTokenChange, onAmountChange, onSetPercent, selectedNetwork, onNetworkChange, hideNetworkSelect, }: Props) { - const [intPart, decPart] = amount.split('.') + const [intPart, decPart] = truncateDecimals(amount, 8).split('.') const pills = onSetPercent && ( <>