feat: complete sign up apis added

This commit is contained in:
مهرزاد قدرتی
2025-08-11 14:19:32 +03:30
parent 1584b7d7a8
commit b8f7221780
4 changed files with 102 additions and 55 deletions

View File

@@ -31,6 +31,8 @@ export const AuthenticationSteps = (): JSX.Element => {
>('emailOrPhone'); >('emailOrPhone');
const [loginRegisterValue, setLoginRegisterValue] = useState<string>(''); const [loginRegisterValue, setLoginRegisterValue] = useState<string>('');
const [countryCode, setCountryCode] = useState<CountryCode>('+98'); const [countryCode, setCountryCode] = useState<CountryCode>('+98');
const [addPhoneCountryCode, setAddPhoneCountryCode] =
useState<CountryCode>('+98');
const [addedPhoneNumberValue, setAddedPhoneNumberValue] = const [addedPhoneNumberValue, setAddedPhoneNumberValue] =
useState<string>(''); useState<string>('');
@@ -57,14 +59,7 @@ export const AuthenticationSteps = (): JSX.Element => {
} }
}; };
const handleOTPVerfied = ( const handleOTPVerfied = (userId: GUID) => {
registeredWithoutPhoneNumber: boolean = false,
userId: GUID,
) => {
if (registeredWithoutPhoneNumber) {
setCurrentStep('addPhoneNumber');
}
handleUserLoggedIn(userId); handleUserLoggedIn(userId);
}; };
@@ -92,6 +87,7 @@ export const AuthenticationSteps = (): JSX.Element => {
{currentStep === 'verify' && ( {currentStep === 'verify' && (
<OtpVerifyForm <OtpVerifyForm
onVerifyPhoneNumber={() => setCurrentStep('addPhoneNumber')}
authReturnUrl={authReturnUrl} authReturnUrl={authReturnUrl}
countryCode={countryCode} countryCode={countryCode}
onOTPVerified={handleOTPVerfied} onOTPVerified={handleOTPVerfied}
@@ -117,6 +113,8 @@ export const AuthenticationSteps = (): JSX.Element => {
{currentStep === 'addPhoneNumber' && ( {currentStep === 'addPhoneNumber' && (
<CompleteSignUp <CompleteSignUp
countryCode={addPhoneCountryCode}
setCountryCode={setAddPhoneCountryCode}
value={addedPhoneNumberValue} value={addedPhoneNumberValue}
setValue={setAddedPhoneNumberValue} setValue={setAddedPhoneNumberValue}
email={loginRegisterValue} email={loginRegisterValue}
@@ -126,9 +124,11 @@ export const AuthenticationSteps = (): JSX.Element => {
{currentStep === 'addedPhoneNumberVerify' && ( {currentStep === 'addedPhoneNumberVerify' && (
<VerifyPhoneNumber <VerifyPhoneNumber
authReturnUrl={authReturnUrl}
countryCode={countryCode} countryCode={countryCode}
onEditValue={() => setCurrentStep('emailOrPhone')} onEditValue={() => setCurrentStep('addPhoneNumber')}
value={addedPhoneNumberValue} value={addedPhoneNumberValue}
email={loginRegisterValue}
onPhoneNumberVerified={handleUserLoggedIn} onPhoneNumberVerified={handleUserLoggedIn}
/> />
)} )}

View File

@@ -4,11 +4,15 @@ import React, { useRef, useState, type Dispatch } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { AuthenticationCard } from '../AuthenticationCard'; import { AuthenticationCard } from '../AuthenticationCard';
import { CountryCodeSelector } from '../CountryCodeSelector'; import { CountryCodeSelector } from '../CountryCodeSelector';
import { sendSmsOtp } from '../../api/authorizationAPI';
import type { CountryCode } from '@/types/commonTypes';
export interface CompleteSignUpProps { export interface CompleteSignUpProps {
email: string; email: string;
value: string; value: string;
setValue: Dispatch<string>; setValue: Dispatch<string>;
countryCode: CountryCode;
setCountryCode: Dispatch<CountryCode>;
onCompleteSignUp: (countryCode: string, value: string) => void; onCompleteSignUp: (countryCode: string, value: string) => void;
} }
@@ -16,15 +20,17 @@ export const CompleteSignUp = ({
email, email,
value, value,
setValue, setValue,
countryCode,
setCountryCode,
onCompleteSignUp, onCompleteSignUp,
}: CompleteSignUpProps) => { }: CompleteSignUpProps) => {
const { t } = useTranslation('authentication'); const { t } = useTranslation('authentication');
const [countryCode, setCountryCode] = useState('+98');
const [error, setError] = useState<string>(); const [error, setError] = useState<string>();
const textFieldRef = useRef<HTMLDivElement>(null); const textFieldRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const [touched, setTouched] = useState<boolean>(false); const [touched, setTouched] = useState<boolean>(false);
const inputError: boolean = touched && !!error; const inputError: boolean = touched && !!error;
const [sendOtpLoading, setSendOtpLoading] = useState<boolean>(false);
const isPhoneValid = (code: string, phone: string) => { const isPhoneValid = (code: string, phone: string) => {
const phoneNumber = parsePhoneNumberFromString(code + phone); const phoneNumber = parsePhoneNumberFromString(code + phone);
@@ -45,7 +51,7 @@ export const CompleteSignUp = ({
} }
}; };
const handleCompleteSignUp = () => { const handleCompleteSignUp = async () => {
if (!value) { if (!value) {
setError(t('loginForm.thisFieldIsRequired')); setError(t('loginForm.thisFieldIsRequired'));
inputRef.current?.focus(); inputRef.current?.focus();
@@ -55,7 +61,12 @@ export const CompleteSignUp = ({
inputRef.current?.focus(); inputRef.current?.focus();
} else { } else {
setError(undefined); setError(undefined);
setSendOtpLoading(true);
await sendSmsOtp({ phoneNumber: countryCode + value });
onCompleteSignUp(countryCode, value); onCompleteSignUp(countryCode, value);
setSendOtpLoading(false);
} }
}; };
@@ -99,7 +110,7 @@ export const CompleteSignUp = ({
sx={{ my: 4 }} sx={{ my: 4 }}
/> />
<Button onClick={handleCompleteSignUp}> <Button loading={sendOtpLoading} onClick={handleCompleteSignUp}>
{t('verify.confirmAndContinue')} {t('verify.confirmAndContinue')}
</Button> </Button>
</AuthenticationCard> </AuthenticationCard>

View File

@@ -6,9 +6,13 @@ import type { AuthMode, AuthType } from '../../types/authTypes';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { Toast } from '@/components/Toast'; import { Toast } from '@/components/Toast';
import { AuthenticationCard } from '../AuthenticationCard'; import { AuthenticationCard } from '../AuthenticationCard';
import type { LoginRequest } from '../../types/userTypes'; import type {
ConfirmEmailOtpRequest,
LoginRequest,
} from '../../types/userTypes';
import { useSearchParams } from 'react-router'; import { useSearchParams } from 'react-router';
import { import {
confirmEmailOtp,
loginOrSignUpWithOtp, loginOrSignUpWithOtp,
sendEmailOtp, sendEmailOtp,
sendSmsOtp, sendSmsOtp,
@@ -21,7 +25,8 @@ interface OtpVerifyFormProps {
authType: AuthType; authType: AuthType;
authMode: AuthMode; authMode: AuthMode;
onEditValue: () => void; onEditValue: () => void;
onOTPVerified: (registeredWithoutPhoneNumber: boolean, userID: GUID) => void; onOTPVerified: (userID: GUID) => void;
onVerifyPhoneNumber: () => void;
authReturnUrl: string; authReturnUrl: string;
} }
@@ -32,6 +37,7 @@ export function OtpVerifyForm({
authMode, authMode,
onEditValue, onEditValue,
onOTPVerified, onOTPVerified,
onVerifyPhoneNumber,
authReturnUrl, authReturnUrl,
}: OtpVerifyFormProps) { }: OtpVerifyFormProps) {
const [otpCode, setOtpCode] = useState<string>(''); const [otpCode, setOtpCode] = useState<string>('');
@@ -85,14 +91,44 @@ export function OtpVerifyForm({
setOtpCode(formattedValue); setOtpCode(formattedValue);
}; };
const handleVerifyOTP = async () => { const handleVerifyOTP = () => {
if (!otpCode || otpCode.length < 4) { if (!otpCode || otpCode.length < 4) {
setOtpDigitInvalid(true); setOtpDigitInvalid(true);
} else { } else {
if (authMode === 'register' && authType === 'email') {
handleConfirmEmailAndAddPhone();
} else {
handleLoginRequestWithOtp();
}
}
};
const handleConfirmEmailAndAddPhone = async () => {
setOtpDigitInvalid(false); setOtpDigitInvalid(false);
setVerifyStatusLoading(true); setVerifyStatusLoading(true);
// Change setTimeout to api call 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 = { const loginRequest: LoginRequest = {
otpCode: otpCode, otpCode: otpCode,
@@ -105,7 +141,7 @@ export function OtpVerifyForm({
if (jsonRes.success) { if (jsonRes.success) {
setVerifyStatus('success'); setVerifyStatus('success');
onOTPVerified(jsonRes.registeredWithOutPhoneNumber, jsonRes.userId); onOTPVerified(jsonRes.userId);
} else { } else {
setVerifyStatus('failed'); setVerifyStatus('failed');
setErrorMessage(jsonRes.message); setErrorMessage(jsonRes.message);
@@ -113,7 +149,6 @@ export function OtpVerifyForm({
setVerifyAlertOpen(true); setVerifyAlertOpen(true);
setVerifyStatusLoading(false); setVerifyStatusLoading(false);
}
}; };
const otpMessage = (): string => { const otpMessage = (): string => {

View File

@@ -16,19 +16,22 @@ import {
import type { CountryCode, GUID } from '@/types/commonTypes'; import type { CountryCode, GUID } from '@/types/commonTypes';
interface VerifyPhoneNumberProps { interface VerifyPhoneNumberProps {
authReturnUrl: string;
value: string; value: string;
email: string;
countryCode: CountryCode; countryCode: CountryCode;
onEditValue: () => void; onEditValue: () => void;
onPhoneNumberVerified: (userId: GUID) => void; onPhoneNumberVerified: (userId: GUID) => void;
} }
export function VerifyPhoneNumber({ export function VerifyPhoneNumber({
authReturnUrl,
email,
value, value,
countryCode, countryCode,
onEditValue, onEditValue,
onPhoneNumberVerified, onPhoneNumberVerified,
}: VerifyPhoneNumberProps) { }: VerifyPhoneNumberProps) {
const [searchParams] = useSearchParams();
const [otpCode, setOtpCode] = useState<string>(''); const [otpCode, setOtpCode] = useState<string>('');
const [otpDigitInvalid, setOtpDigitInvalid] = useState<boolean>(false); const [otpDigitInvalid, setOtpDigitInvalid] = useState<boolean>(false);
const [verifyStatus, setVerifyStatus] = useState<'success' | 'failed'>(); const [verifyStatus, setVerifyStatus] = useState<'success' | 'failed'>();
@@ -83,24 +86,22 @@ export function VerifyPhoneNumber({
setOtpDigitInvalid(false); setOtpDigitInvalid(false);
setVerifyStatusLoading(true); 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 = { if (jsonRes.success) {
// otpCode: otpCode, setVerifyStatus('success');
// phoneNumber: authType === 'phone' ? countryCode + value : undefined, onPhoneNumberVerified(jsonRes.userId);
// email: authType === 'email' ? value : undefined, } else {
// returnUrl: searchParams.get('returnUrl') ?? '/', setVerifyStatus('failed');
// }; setErrorMessage(jsonRes.message);
// const result = await loginOrSignUpWithOtp(loginRequest); }
// const jsonRes = await result.json();
// if (jsonRes.success) {
// setVerifyStatus('success');
// onOTPVerified(jsonRes.registeredWithOutPhoneNumber);
// } else {
// setVerifyStatus('failed');
// setErrorMessage(jsonRes.message);
// }
setVerifyAlertOpen(true); setVerifyAlertOpen(true);
setVerifyStatusLoading(false); setVerifyStatusLoading(false);