feat: login with password apis added
This commit is contained in:
@@ -12,8 +12,8 @@ function App() {
|
|||||||
<LanguageManager />
|
<LanguageManager />
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Navigate to="auth" />} />
|
<Route path="/" element={<Navigate to="login" />} />
|
||||||
<Route path="/auth" element={<AuthenticationPage />} />
|
<Route path="/login" element={<AuthenticationPage />} />
|
||||||
<Route path="/forget-password" element={<ForgetPasswordPage />} />
|
<Route path="/forget-password" element={<ForgetPasswordPage />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import type {
|
|||||||
LoginOrSignUpWithGoogleResponse,
|
LoginOrSignUpWithGoogleResponse,
|
||||||
LoginRequest,
|
LoginRequest,
|
||||||
LoginResponse,
|
LoginResponse,
|
||||||
|
PasswordLoginRequest,
|
||||||
ResetPasswordRequest,
|
ResetPasswordRequest,
|
||||||
ResetPasswordResponse,
|
ResetPasswordResponse,
|
||||||
SendEmailOtpRequest,
|
SendEmailOtpRequest,
|
||||||
@@ -49,7 +50,7 @@ export const loginOrSignUpWithOtp = async (body: LoginRequest) => {
|
|||||||
return fetchRequest<LoginResponse>('User/LoginOrSignUpWithOtp', body);
|
return fetchRequest<LoginResponse>('User/LoginOrSignUpWithOtp', body);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loginWithPassword = async (body: LoginRequest) => {
|
export const loginWithPassword = async (body: PasswordLoginRequest) => {
|
||||||
return fetchRequest<LoginResponse>('User/LoginWithPassword', body);
|
return fetchRequest<LoginResponse>('User/LoginWithPassword', body);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,11 @@ import { OtpVerifyForm } from './OtpVerifyForm';
|
|||||||
import { isNumeric } from '@/utils/regexes/isNumeric';
|
import { isNumeric } from '@/utils/regexes/isNumeric';
|
||||||
import { CompleteSignUp } from './CompleteSignUp';
|
import { CompleteSignUp } from './CompleteSignUp';
|
||||||
import { EnterPasswordForm } from './EnterPasswordForm';
|
import { EnterPasswordForm } from './EnterPasswordForm';
|
||||||
import { getUserStatusByPhoneNumberOrEmail } from '../../api/authorizationAPI';
|
import {
|
||||||
|
getUserStatusByPhoneNumberOrEmail,
|
||||||
|
sendEmailOtp,
|
||||||
|
sendSmsOtp,
|
||||||
|
} from '../../api/authorizationAPI';
|
||||||
import { UserStatus } from '../../types/userTypes';
|
import { UserStatus } from '../../types/userTypes';
|
||||||
import type { CountryCode, GUID } from '@/types/commonTypes';
|
import type { CountryCode, GUID } from '@/types/commonTypes';
|
||||||
import { VerifyPhoneNumber } from './VerifyPhoneNumber';
|
import { VerifyPhoneNumber } from './VerifyPhoneNumber';
|
||||||
@@ -51,11 +55,16 @@ export const AuthenticationSteps = (): JSX.Element => {
|
|||||||
const handleOTPVerfied = (
|
const handleOTPVerfied = (
|
||||||
registeredWithoutPhoneNumber: boolean = false,
|
registeredWithoutPhoneNumber: boolean = false,
|
||||||
userId: GUID,
|
userId: GUID,
|
||||||
|
returnUrl?: string,
|
||||||
) => {
|
) => {
|
||||||
localStorage.setItem('userID', userId);
|
localStorage.setItem('userID', userId);
|
||||||
// if (registeredWithoutPhoneNumber) {
|
// if (registeredWithoutPhoneNumber) {
|
||||||
// setCurrentStep('addPhoneNumber');
|
// setCurrentStep('addPhoneNumber');
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
if (returnUrl) {
|
||||||
|
location.href = returnUrl;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditValue = () => {
|
const handleEditValue = () => {
|
||||||
@@ -74,7 +83,17 @@ export const AuthenticationSteps = (): JSX.Element => {
|
|||||||
setCurrentStep('emailOrPhone');
|
setCurrentStep('emailOrPhone');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLoggedInWithPassowrd = () => {};
|
const handleLoggedInWithPassowrd = (userId: GUID, returnUrl?: string) => {
|
||||||
|
localStorage.setItem('userID', userId);
|
||||||
|
|
||||||
|
if (returnUrl) {
|
||||||
|
location.href = returnUrl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLoginWithOtpInsteadOfPassword = async () => {
|
||||||
|
setCurrentStep('verify');
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -103,9 +122,12 @@ export const AuthenticationSteps = (): JSX.Element => {
|
|||||||
|
|
||||||
{currentStep === 'enterPassword' && (
|
{currentStep === 'enterPassword' && (
|
||||||
<EnterPasswordForm
|
<EnterPasswordForm
|
||||||
|
loginRegisterValue={loginRegisterValue}
|
||||||
|
countryCode={countryCode}
|
||||||
|
authType={authType}
|
||||||
onLoggedIn={handleLoggedInWithPassowrd}
|
onLoggedIn={handleLoggedInWithPassowrd}
|
||||||
onEditValue={handleEditValue}
|
onEditValue={handleEditValue}
|
||||||
onLoginWithOTP={() => setCurrentStep('verify')}
|
onLoginWithOTP={handleLoginWithOtpInsteadOfPassword}
|
||||||
emailOrPhone={loginRegisterValue}
|
emailOrPhone={loginRegisterValue}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -11,12 +11,24 @@ import {
|
|||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Toast } from '@/components/Toast';
|
import { Toast } from '@/components/Toast';
|
||||||
|
import { Link, Navigate, useSearchParams } from 'react-router';
|
||||||
|
import type { AuthType } from '../../types/authTypes';
|
||||||
|
import type { CountryCode, GUID } from '@/types/commonTypes';
|
||||||
|
import {
|
||||||
|
loginWithPassword,
|
||||||
|
sendEmailOtp,
|
||||||
|
sendSmsOtp,
|
||||||
|
} from '../../api/authorizationAPI';
|
||||||
|
import type { LoginRequest, PasswordLoginRequest } from '../../types/userTypes';
|
||||||
|
|
||||||
export interface EnterPasswordFormProps {
|
export interface EnterPasswordFormProps {
|
||||||
onEditValue: () => void;
|
onEditValue: () => void;
|
||||||
onLoginWithOTP: () => void;
|
onLoginWithOTP: () => void;
|
||||||
onLoggedIn: () => void;
|
onLoggedIn: (userId: GUID, returnUrl?: string) => void;
|
||||||
emailOrPhone: string;
|
emailOrPhone: string;
|
||||||
|
authType: AuthType;
|
||||||
|
loginRegisterValue: string;
|
||||||
|
countryCode: CountryCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EnterPasswordForm = ({
|
export const EnterPasswordForm = ({
|
||||||
@@ -24,7 +36,12 @@ export const EnterPasswordForm = ({
|
|||||||
onLoginWithOTP,
|
onLoginWithOTP,
|
||||||
onLoggedIn,
|
onLoggedIn,
|
||||||
emailOrPhone,
|
emailOrPhone,
|
||||||
|
authType,
|
||||||
|
loginRegisterValue,
|
||||||
|
countryCode,
|
||||||
}: EnterPasswordFormProps) => {
|
}: EnterPasswordFormProps) => {
|
||||||
|
const DEFAULT_RETURN_URL = 'https://account.business-harmony.com/';
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
const { t } = useTranslation('authentication');
|
const { t } = useTranslation('authentication');
|
||||||
const [passValue, setPassValue] = useState<string>('');
|
const [passValue, setPassValue] = useState<string>('');
|
||||||
const [inputTouched, setInputTouched] = useState<boolean>(false);
|
const [inputTouched, setInputTouched] = useState<boolean>(false);
|
||||||
@@ -34,27 +51,51 @@ export const EnterPasswordForm = ({
|
|||||||
const [loginStatus, setLoginStatus] = useState<'success' | 'failed'>();
|
const [loginStatus, setLoginStatus] = useState<'success' | 'failed'>();
|
||||||
const [loginAlertOpen, setLoginAlertOpen] = useState<boolean>(false);
|
const [loginAlertOpen, setLoginAlertOpen] = useState<boolean>(false);
|
||||||
const [loginFailedMessage, setLoginFailedMessage] = useState<string>('');
|
const [loginFailedMessage, setLoginFailedMessage] = useState<string>('');
|
||||||
|
const [sendOtpLoading, setSendOtpLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
const handleBlur = () => {
|
const handleBlur = () => {
|
||||||
setInputTouched(true);
|
setInputTouched(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = async () => {
|
||||||
if (!passValue) {
|
if (!passValue) {
|
||||||
inputRef.current?.focus();
|
inputRef.current?.focus();
|
||||||
} else {
|
} else {
|
||||||
setLoginLoading(true);
|
setLoginLoading(true);
|
||||||
|
|
||||||
// Change setTimeout to api call
|
const apiRequest: PasswordLoginRequest = {
|
||||||
setTimeout(() => {
|
phoneNumber:
|
||||||
setLoginAlertOpen(true);
|
authType === 'phone' ? countryCode + loginRegisterValue : undefined,
|
||||||
// setLoginStatus('success');
|
email: authType === 'email' ? loginRegisterValue : undefined,
|
||||||
|
password: passValue,
|
||||||
|
returnUrl: searchParams.get('returnUrl') ?? DEFAULT_RETURN_URL,
|
||||||
|
};
|
||||||
|
const result = await loginWithPassword(apiRequest);
|
||||||
|
const jsonRes = await result.json();
|
||||||
|
|
||||||
|
if (jsonRes.success) {
|
||||||
|
setLoginStatus('success');
|
||||||
|
onLoggedIn(jsonRes.userId, jsonRes.returnUrl);
|
||||||
|
} else {
|
||||||
setLoginStatus('failed');
|
setLoginStatus('failed');
|
||||||
setLoginFailedMessage('رمز عبور اشتباه میباشد');
|
setLoginFailedMessage(jsonRes.message);
|
||||||
onLoggedIn();
|
|
||||||
setLoginLoading(false);
|
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
|
setLoginAlertOpen(true);
|
||||||
|
setLoginLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLoginWithOtp = async () => {
|
||||||
|
setSendOtpLoading(true);
|
||||||
|
|
||||||
|
if (authType === 'phone') {
|
||||||
|
await sendSmsOtp({ phoneNumber: countryCode + loginRegisterValue });
|
||||||
|
} else {
|
||||||
|
await sendEmailOtp({ email: loginRegisterValue });
|
||||||
|
}
|
||||||
|
|
||||||
|
setSendOtpLoading(false);
|
||||||
|
onLoginWithOTP();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -127,9 +168,10 @@ export const EnterPasswordForm = ({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={onLoginWithOTP}
|
onClick={handleLoginWithOtp}
|
||||||
sx={{ width: 'auto', mb: 2 }}
|
sx={{ width: 'auto', mb: 2 }}
|
||||||
variant="text"
|
variant="text"
|
||||||
|
loading={sendOtpLoading}
|
||||||
endIcon={<ArrowLeft />}
|
endIcon={<ArrowLeft />}
|
||||||
>
|
>
|
||||||
{t('enterPassword.loginWithOneTimeCode')}
|
{t('enterPassword.loginWithOneTimeCode')}
|
||||||
@@ -139,7 +181,9 @@ export const EnterPasswordForm = ({
|
|||||||
<Button loading={loginLoading} onClick={handleSubmit}>
|
<Button loading={loginLoading} onClick={handleSubmit}>
|
||||||
{t('verify.confirmAndLogin')}
|
{t('verify.confirmAndLogin')}
|
||||||
</Button>
|
</Button>
|
||||||
|
<Link to="/forget-password">
|
||||||
<Button variant="text">{t('enterPassword.iForgotMyPassword')}</Button>
|
<Button variant="text">{t('enterPassword.iForgotMyPassword')}</Button>
|
||||||
|
</Link>
|
||||||
</Stack>
|
</Stack>
|
||||||
</AuthenticationCard>
|
</AuthenticationCard>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,7 +21,11 @@ interface OtpVerifyFormProps {
|
|||||||
authType: AuthType;
|
authType: AuthType;
|
||||||
authMode: AuthMode;
|
authMode: AuthMode;
|
||||||
onEditValue: () => void;
|
onEditValue: () => void;
|
||||||
onOTPVerified: (registeredWithoutPhoneNumber: boolean, userID: GUID) => void;
|
onOTPVerified: (
|
||||||
|
registeredWithoutPhoneNumber: boolean,
|
||||||
|
userID: GUID,
|
||||||
|
returnUrl?: string,
|
||||||
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OtpVerifyForm({
|
export function OtpVerifyForm({
|
||||||
@@ -32,6 +36,7 @@ export function OtpVerifyForm({
|
|||||||
onEditValue,
|
onEditValue,
|
||||||
onOTPVerified,
|
onOTPVerified,
|
||||||
}: OtpVerifyFormProps) {
|
}: OtpVerifyFormProps) {
|
||||||
|
const DEFAULT_RETURN_URL = 'https://account.business-harmony.com/';
|
||||||
const [searchParams] = useSearchParams();
|
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);
|
||||||
@@ -97,14 +102,18 @@ export function OtpVerifyForm({
|
|||||||
otpCode: otpCode,
|
otpCode: otpCode,
|
||||||
phoneNumber: authType === 'phone' ? countryCode + value : undefined,
|
phoneNumber: authType === 'phone' ? countryCode + value : undefined,
|
||||||
email: authType === 'email' ? value : undefined,
|
email: authType === 'email' ? value : undefined,
|
||||||
returnUrl: searchParams.get('returnUrl') ?? '/',
|
returnUrl: searchParams.get('returnUrl') ?? DEFAULT_RETURN_URL,
|
||||||
};
|
};
|
||||||
const result = await loginOrSignUpWithOtp(loginRequest);
|
const result = await loginOrSignUpWithOtp(loginRequest);
|
||||||
const jsonRes = await result.json();
|
const jsonRes = await result.json();
|
||||||
|
|
||||||
if (jsonRes.success) {
|
if (jsonRes.success) {
|
||||||
setVerifyStatus('success');
|
setVerifyStatus('success');
|
||||||
onOTPVerified(jsonRes.registeredWithOutPhoneNumber, jsonRes.userId);
|
onOTPVerified(
|
||||||
|
jsonRes.registeredWithOutPhoneNumber,
|
||||||
|
jsonRes.userId,
|
||||||
|
jsonRes.returnUrl,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
setVerifyStatus('failed');
|
setVerifyStatus('failed');
|
||||||
setErrorMessage(jsonRes.message);
|
setErrorMessage(jsonRes.message);
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ export const ChangePassword = ({
|
|||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
|
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
|
||||||
>
|
>
|
||||||
{showPassword ? <Eye /> : <EyeSlash />}
|
{showConfirmPassword ? <Eye /> : <EyeSlash />}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
) : (
|
) : (
|
||||||
''
|
''
|
||||||
|
|||||||
@@ -137,7 +137,9 @@ export function ForgetPasswordOtp({
|
|||||||
endIcon={<Edit2 />}
|
endIcon={<Edit2 />}
|
||||||
onClick={onEditInfo}
|
onClick={onEditInfo}
|
||||||
>
|
>
|
||||||
{forgettedPasswordInfo}
|
{infoType === 'phone'
|
||||||
|
? countryCode + forgettedPasswordInfo
|
||||||
|
: forgettedPasswordInfo}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,13 @@ export interface LoginRequest {
|
|||||||
returnUrl: string;
|
returnUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PasswordLoginRequest {
|
||||||
|
phoneNumber?: string;
|
||||||
|
email?: string;
|
||||||
|
password: string;
|
||||||
|
returnUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface LoginResponse extends ApiResponse {
|
export interface LoginResponse extends ApiResponse {
|
||||||
returnUrl: string;
|
returnUrl: string;
|
||||||
userId: GUID;
|
userId: GUID;
|
||||||
|
|||||||
Reference in New Issue
Block a user