From b8f72217804158bd6cb9ceb7bbfd7d6e00270004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D9=85=D9=87=D8=B1=D8=B2=D8=A7=D8=AF=20=D9=82=D8=AF=D8=B1?= =?UTF-8?q?=D8=AA=DB=8C?= Date: Mon, 11 Aug 2025 14:19:32 +0330 Subject: [PATCH] feat: complete sign up apis added --- .../AuthenticationSteps.tsx | 18 ++-- .../AuthenticationSteps/CompleteSignUp.tsx | 17 +++- .../AuthenticationSteps/OtpVerifyForm.tsx | 85 +++++++++++++------ .../AuthenticationSteps/VerifyPhoneNumber.tsx | 37 ++++---- 4 files changed, 102 insertions(+), 55 deletions(-) diff --git a/src/features/authorization/components/AuthenticationSteps/AuthenticationSteps.tsx b/src/features/authorization/components/AuthenticationSteps/AuthenticationSteps.tsx index ce4f113..8f08908 100644 --- a/src/features/authorization/components/AuthenticationSteps/AuthenticationSteps.tsx +++ b/src/features/authorization/components/AuthenticationSteps/AuthenticationSteps.tsx @@ -31,6 +31,8 @@ export const AuthenticationSteps = (): JSX.Element => { >('emailOrPhone'); const [loginRegisterValue, setLoginRegisterValue] = useState(''); const [countryCode, setCountryCode] = useState('+98'); + const [addPhoneCountryCode, setAddPhoneCountryCode] = + useState('+98'); const [addedPhoneNumberValue, setAddedPhoneNumberValue] = useState(''); @@ -57,14 +59,7 @@ export const AuthenticationSteps = (): JSX.Element => { } }; - const handleOTPVerfied = ( - registeredWithoutPhoneNumber: boolean = false, - userId: GUID, - ) => { - if (registeredWithoutPhoneNumber) { - setCurrentStep('addPhoneNumber'); - } - + const handleOTPVerfied = (userId: GUID) => { handleUserLoggedIn(userId); }; @@ -92,6 +87,7 @@ export const AuthenticationSteps = (): JSX.Element => { {currentStep === 'verify' && ( setCurrentStep('addPhoneNumber')} authReturnUrl={authReturnUrl} countryCode={countryCode} onOTPVerified={handleOTPVerfied} @@ -117,6 +113,8 @@ export const AuthenticationSteps = (): JSX.Element => { {currentStep === 'addPhoneNumber' && ( { {currentStep === 'addedPhoneNumberVerify' && ( setCurrentStep('emailOrPhone')} + onEditValue={() => setCurrentStep('addPhoneNumber')} value={addedPhoneNumberValue} + email={loginRegisterValue} onPhoneNumberVerified={handleUserLoggedIn} /> )} diff --git a/src/features/authorization/components/AuthenticationSteps/CompleteSignUp.tsx b/src/features/authorization/components/AuthenticationSteps/CompleteSignUp.tsx index 74a5cb3..063892c 100644 --- a/src/features/authorization/components/AuthenticationSteps/CompleteSignUp.tsx +++ b/src/features/authorization/components/AuthenticationSteps/CompleteSignUp.tsx @@ -4,11 +4,15 @@ import React, { useRef, useState, type Dispatch } from 'react'; import { useTranslation } from 'react-i18next'; import { AuthenticationCard } from '../AuthenticationCard'; import { CountryCodeSelector } from '../CountryCodeSelector'; +import { sendSmsOtp } from '../../api/authorizationAPI'; +import type { CountryCode } from '@/types/commonTypes'; export interface CompleteSignUpProps { email: string; value: string; setValue: Dispatch; + countryCode: CountryCode; + setCountryCode: Dispatch; onCompleteSignUp: (countryCode: string, value: string) => void; } @@ -16,15 +20,17 @@ export const CompleteSignUp = ({ email, value, setValue, + countryCode, + setCountryCode, onCompleteSignUp, }: CompleteSignUpProps) => { const { t } = useTranslation('authentication'); - const [countryCode, setCountryCode] = useState('+98'); const [error, setError] = useState(); const textFieldRef = useRef(null); const inputRef = useRef(null); const [touched, setTouched] = useState(false); const inputError: boolean = touched && !!error; + const [sendOtpLoading, setSendOtpLoading] = useState(false); const isPhoneValid = (code: string, phone: string) => { const phoneNumber = parsePhoneNumberFromString(code + phone); @@ -45,7 +51,7 @@ export const CompleteSignUp = ({ } }; - const handleCompleteSignUp = () => { + const handleCompleteSignUp = async () => { if (!value) { setError(t('loginForm.thisFieldIsRequired')); inputRef.current?.focus(); @@ -55,7 +61,12 @@ export const CompleteSignUp = ({ inputRef.current?.focus(); } else { setError(undefined); + setSendOtpLoading(true); + + await sendSmsOtp({ phoneNumber: countryCode + value }); onCompleteSignUp(countryCode, value); + + setSendOtpLoading(false); } }; @@ -99,7 +110,7 @@ export const CompleteSignUp = ({ sx={{ my: 4 }} /> - diff --git a/src/features/authorization/components/AuthenticationSteps/OtpVerifyForm.tsx b/src/features/authorization/components/AuthenticationSteps/OtpVerifyForm.tsx index baa6bc4..c1f992a 100644 --- a/src/features/authorization/components/AuthenticationSteps/OtpVerifyForm.tsx +++ b/src/features/authorization/components/AuthenticationSteps/OtpVerifyForm.tsx @@ -6,9 +6,13 @@ import type { AuthMode, AuthType } from '../../types/authTypes'; import { useEffect, useState } from 'react'; import { Toast } from '@/components/Toast'; import { AuthenticationCard } from '../AuthenticationCard'; -import type { LoginRequest } from '../../types/userTypes'; +import type { + ConfirmEmailOtpRequest, + LoginRequest, +} from '../../types/userTypes'; import { useSearchParams } from 'react-router'; import { + confirmEmailOtp, loginOrSignUpWithOtp, sendEmailOtp, sendSmsOtp, @@ -21,7 +25,8 @@ interface OtpVerifyFormProps { authType: AuthType; authMode: AuthMode; onEditValue: () => void; - onOTPVerified: (registeredWithoutPhoneNumber: boolean, userID: GUID) => void; + onOTPVerified: (userID: GUID) => void; + onVerifyPhoneNumber: () => void; authReturnUrl: string; } @@ -32,6 +37,7 @@ export function OtpVerifyForm({ authMode, onEditValue, onOTPVerified, + onVerifyPhoneNumber, authReturnUrl, }: OtpVerifyFormProps) { const [otpCode, setOtpCode] = useState(''); @@ -85,37 +91,66 @@ export function OtpVerifyForm({ setOtpCode(formattedValue); }; - const handleVerifyOTP = async () => { + const handleVerifyOTP = () => { if (!otpCode || otpCode.length < 4) { setOtpDigitInvalid(true); } else { - setOtpDigitInvalid(false); - setVerifyStatusLoading(true); - - // Change setTimeout to api call - - const loginRequest: LoginRequest = { - otpCode: otpCode, - phoneNumber: authType === 'phone' ? countryCode + value : undefined, - email: authType === 'email' ? value : undefined, - returnUrl: authReturnUrl, - }; - const result = await loginOrSignUpWithOtp(loginRequest); - const jsonRes = await result.json(); - - if (jsonRes.success) { - setVerifyStatus('success'); - onOTPVerified(jsonRes.registeredWithOutPhoneNumber, jsonRes.userId); + if (authMode === 'register' && authType === 'email') { + handleConfirmEmailAndAddPhone(); } else { - setVerifyStatus('failed'); - setErrorMessage(jsonRes.message); + handleLoginRequestWithOtp(); } - - setVerifyAlertOpen(true); - setVerifyStatusLoading(false); } }; + const handleConfirmEmailAndAddPhone = async () => { + setOtpDigitInvalid(false); + setVerifyStatusLoading(true); + + const confirmOtpRequest: ConfirmEmailOtpRequest = { + otpCode: otpCode, + email: value, + }; + const result = await confirmEmailOtp(confirmOtpRequest); + const jsonRes = await result.json(); + + if (jsonRes.success) { + setVerifyStatus('success'); + onVerifyPhoneNumber(); + } else { + setVerifyStatus('failed'); + setErrorMessage(jsonRes.message); + } + + setVerifyAlertOpen(true); + setVerifyStatusLoading(false); + }; + + const handleLoginRequestWithOtp = async () => { + setOtpDigitInvalid(false); + setVerifyStatusLoading(true); + + const loginRequest: LoginRequest = { + otpCode: otpCode, + phoneNumber: authType === 'phone' ? countryCode + value : undefined, + email: authType === 'email' ? value : undefined, + returnUrl: authReturnUrl, + }; + const result = await loginOrSignUpWithOtp(loginRequest); + const jsonRes = await result.json(); + + if (jsonRes.success) { + setVerifyStatus('success'); + onOTPVerified(jsonRes.userId); + } else { + setVerifyStatus('failed'); + setErrorMessage(jsonRes.message); + } + + setVerifyAlertOpen(true); + setVerifyStatusLoading(false); + }; + const otpMessage = (): string => { if (authType === 'phone' && authMode === 'login') { return t( diff --git a/src/features/authorization/components/AuthenticationSteps/VerifyPhoneNumber.tsx b/src/features/authorization/components/AuthenticationSteps/VerifyPhoneNumber.tsx index 4236d59..a7638a6 100644 --- a/src/features/authorization/components/AuthenticationSteps/VerifyPhoneNumber.tsx +++ b/src/features/authorization/components/AuthenticationSteps/VerifyPhoneNumber.tsx @@ -16,19 +16,22 @@ import { import type { CountryCode, GUID } from '@/types/commonTypes'; interface VerifyPhoneNumberProps { + authReturnUrl: string; value: string; + email: string; countryCode: CountryCode; onEditValue: () => void; onPhoneNumberVerified: (userId: GUID) => void; } export function VerifyPhoneNumber({ + authReturnUrl, + email, value, countryCode, onEditValue, onPhoneNumberVerified, }: VerifyPhoneNumberProps) { - const [searchParams] = useSearchParams(); const [otpCode, setOtpCode] = useState(''); const [otpDigitInvalid, setOtpDigitInvalid] = useState(false); const [verifyStatus, setVerifyStatus] = useState<'success' | 'failed'>(); @@ -83,24 +86,22 @@ export function VerifyPhoneNumber({ setOtpDigitInvalid(false); setVerifyStatusLoading(true); - // Change setTimeout to api call + const loginRequest: LoginRequest = { + otpCode: otpCode, + phoneNumber: countryCode + value, + email: email, + returnUrl: authReturnUrl, + }; + const result = await loginOrSignUpWithOtp(loginRequest); + const jsonRes = await result.json(); - // const loginRequest: LoginRequest = { - // otpCode: otpCode, - // phoneNumber: authType === 'phone' ? countryCode + value : undefined, - // email: authType === 'email' ? value : undefined, - // returnUrl: searchParams.get('returnUrl') ?? '/', - // }; - // const result = await loginOrSignUpWithOtp(loginRequest); - // const jsonRes = await result.json(); - - // if (jsonRes.success) { - // setVerifyStatus('success'); - // onOTPVerified(jsonRes.registeredWithOutPhoneNumber); - // } else { - // setVerifyStatus('failed'); - // setErrorMessage(jsonRes.message); - // } + if (jsonRes.success) { + setVerifyStatus('success'); + onPhoneNumberVerified(jsonRes.userId); + } else { + setVerifyStatus('failed'); + setErrorMessage(jsonRes.message); + } setVerifyAlertOpen(true); setVerifyStatusLoading(false);