feat: multi client id use added

This commit is contained in:
2025-08-26 14:15:13 +03:30
parent d1cadad183
commit 4cf45ccb5e
8 changed files with 103 additions and 61 deletions

View File

@@ -3,7 +3,6 @@ import { LoginRegisterForm } from './LoginRegiserForm';
import type {
AuthFactory,
AuthMode,
AuthRedirector,
AuthStep,
AuthType,
} from '../../types/authTypes';
@@ -15,7 +14,8 @@ import { UserStatus, type LoginResult } from '../../types/userTypes';
import type { CountryCode } from '@/types/commonTypes';
import { VerifyPhoneNumber } from './VerifyPhoneNumber';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { REFRESH_TOKEN_KEY } from '@/providers/AuthProvider';
import type { GenerateTokenResponse } from '../../api/identityAPI';
import { useAuth } from '@/hooks/useAuth';
export const AuthenticationSteps = (): JSX.Element => {
const navigate = useNavigate();
@@ -29,6 +29,8 @@ export const AuthenticationSteps = (): JSX.Element => {
useState<CountryCode>('+98');
const [addedPhoneNumberValue, setAddedPhoneNumberValue] =
useState<string>('');
const [memoryTokenRes, setMemoryTokenRes] = useState<GenerateTokenResponse>();
const { login } = useAuth();
const authFactory: AuthFactory = useMemo(() => {
const redirectUrl = searchParams.get('redirect_url');
@@ -37,9 +39,13 @@ export const AuthenticationSteps = (): JSX.Element => {
if (!clientId) {
const defaultFactory: AuthFactory = {
clientId: import.meta.env.VITE_IDENTITY_CLIENT_ID,
redirectUrl: 'accounts.',
accountsApplication
setLocalToken: true,
redirectUrl: import.meta.env.VITE_APP_URL,
isCurrentApplication: function () {
return this.clientId === import.meta.env.VITE_IDENTITY_CLIENT_ID;
},
getFullRedirectUrl: function (token: string) {
return this.redirectUrl + '?token=' + token;
},
};
return defaultFactory;
@@ -48,7 +54,9 @@ export const AuthenticationSteps = (): JSX.Element => {
const resFactory: AuthFactory = {
clientId: clientId,
redirectUrl: redirectUrl as string,
setLocalToken: true,
isCurrentApplication: function () {
return this.clientId === import.meta.env.VITE_IDENTITY_CLIENT_ID;
},
getFullRedirectUrl: function (token: string) {
return this.redirectUrl + '?token=' + token;
},
@@ -82,17 +90,22 @@ export const AuthenticationSteps = (): JSX.Element => {
const handleUserLoggedIn = (
loginResult: LoginResult,
refreshToken: string,
tokenResponse: GenerateTokenResponse,
) => {
setMemoryTokenRes(tokenResponse);
if (authFactory.isCurrentApplication()) {
login(tokenResponse);
}
if (loginResult.registeredWithOutPhoneNumber) {
setCurrentStep('addPhoneNumber');
return;
}
if (!loginResult.completedUserInformation) {
if (authFactory.redirectUrl) {
if (!authFactory.isCurrentApplication()) {
navigate(
`/signup?returnUrl=${authFactory.getFullRedirectUrl(refreshToken)}`,
`/signup?returnUrl=${authFactory.getFullRedirectUrl(tokenResponse.refresh_token)}`,
);
} else {
navigate(`/signup`);
@@ -100,13 +113,13 @@ export const AuthenticationSteps = (): JSX.Element => {
return;
}
redirectToReturnUrl(refreshToken);
redirectToReturnUrl(tokenResponse.refresh_token);
};
const handlePhoneNumberVerified = (refreshToken: string) => {
if (authFactory.redirectUrl) {
const handlePhoneNumberVerified = () => {
if (!authFactory.isCurrentApplication()) {
navigate(
`/signup?returnUrl=${authFactory.getFullRedirectUrl(refreshToken)}`,
`/signup?returnUrl=${authFactory.getFullRedirectUrl(memoryTokenRes?.refresh_token as string)}`,
);
} else {
navigate(`/signup`);
@@ -114,7 +127,7 @@ export const AuthenticationSteps = (): JSX.Element => {
};
const redirectToReturnUrl = (refreshToken: string) => {
if (!authFactory.redirectUrl) {
if (authFactory.isCurrentApplication()) {
navigate(import.meta.env.VITE_DEFUALT_AUTH_RETURN_URL);
} else {
if (authMode === 'register') {
@@ -131,7 +144,7 @@ export const AuthenticationSteps = (): JSX.Element => {
<>
{currentStep === 'emailOrPhone' && (
<LoginRegisterForm
authReturnUrl={authReturnUrlOrDefault}
authFactory={authFactory}
onGoogleAuthenticated={handleUserLoggedIn}
countryCode={countryCode}
setCountryCode={setCountryCode}
@@ -145,7 +158,7 @@ export const AuthenticationSteps = (): JSX.Element => {
{currentStep === 'verify' && (
<OtpVerifyForm
authReturnUrl={authReturnUrlOrDefault}
authFactory={authFactory}
countryCode={countryCode}
onOTPVerified={handleUserLoggedIn}
onEditValue={() => setCurrentStep('emailOrPhone')}
@@ -157,7 +170,7 @@ export const AuthenticationSteps = (): JSX.Element => {
{currentStep === 'enterPassword' && (
<EnterPasswordForm
authReturnUrl={authReturnUrlOrDefault}
authFactory={authFactory}
loginRegisterValue={loginRegisterValue}
countryCode={countryCode}
authType={authType}

View File

@@ -11,7 +11,7 @@ import {
} from '@mui/material';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import type { AuthType } from '../../types/authTypes';
import type { AuthFactory, AuthType } from '../../types/authTypes';
import type { CountryCode } from '@/types/commonTypes';
import {
loginWithPassword,
@@ -22,17 +22,23 @@ import type { LoginResult, PasswordLoginRequest } from '../../types/userTypes';
import { Icon, useToast } from '@rkheftan/harmony-ui';
import { useApi } from '@/hooks/useApi';
import { useAuth } from '@/hooks/useAuth';
import { generateTokenWithPassword } from '../../api/identityAPI';
import {
generateTokenWithPassword,
type GenerateTokenResponse,
} from '../../api/identityAPI';
export interface EnterPasswordFormProps {
onEditValue: () => void;
onLoginWithOTP: () => void;
onLoggedIn: (loginResult: LoginResult) => void;
onLoggedIn: (
loginResult: LoginResult,
tokenResponse: GenerateTokenResponse,
) => void;
emailOrPhone: string;
authType: AuthType;
loginRegisterValue: string;
countryCode: CountryCode;
authReturnUrl: string;
authFactory: AuthFactory;
}
export const EnterPasswordForm = ({
@@ -43,7 +49,7 @@ export const EnterPasswordForm = ({
authType,
loginRegisterValue,
countryCode,
authReturnUrl,
authFactory,
}: EnterPasswordFormProps) => {
const { t } = useTranslation('authentication');
const [passValue, setPassValue] = useState<string>('');
@@ -57,7 +63,6 @@ export const EnterPasswordForm = ({
useApi(sendEmailOtp);
const { loading: loginWithPassLoading, execute: loginWithPassCall } =
useApi(loginWithPassword);
const auth = useAuth();
const handleBlur = () => {
setInputTouched(true);
@@ -72,7 +77,7 @@ export const EnterPasswordForm = ({
authType === 'phone' ? countryCode + loginRegisterValue : undefined,
email: authType === 'email' ? loginRegisterValue : undefined,
password: passValue,
returnUrl: authReturnUrl,
returnUrl: authFactory.redirectUrl,
};
const res = await loginWithPassCall(apiRequest);
@@ -82,12 +87,10 @@ export const EnterPasswordForm = ({
const tokenRes = await generateTokenWithPassword({
username: apiRequest.email ?? (apiRequest.phoneNumber as string),
password: apiRequest.password,
});
auth.login({
...tokenRes.data,
client_id: authFactory.clientId,
});
onLoggedIn(res);
onLoggedIn(res, tokenRes.data);
toast({
message: t('verify.youHaveSuccessfullyLoggedIn'),
severity: 'success',
@@ -134,7 +137,7 @@ export const EnterPasswordForm = ({
endIcon={<Icon Component={Edit2} />}
onClick={onEditValue}
>
{emailOrPhone}
{authType === 'phone' ? countryCode + emailOrPhone : emailOrPhone}
</Button>
</Box>

View File

@@ -10,14 +10,20 @@ import { loginOrSignUpWithGoogle } from '../../api/authorizationAPI';
import { Google } from 'iconsax-react';
import { Icon, useToast } from '@rkheftan/harmony-ui';
import { useApi } from '@/hooks/useApi';
import { generateTokenWithGoogle } from '../../api/identityAPI';
import {
generateTokenWithGoogle,
type GenerateTokenResponse,
} from '../../api/identityAPI';
import { useAuth } from '@/hooks/useAuth';
import type { AuthFactory } from '../../types/authTypes';
export interface GoogleAuthenticationProps {
disabled: boolean;
authFactory: AuthFactory;
onGoogleAuthenticated: (loginResult: LoginResult) => void;
onGoogleAuthenticated: (
loginResult: LoginResult,
tokenResponse: GenerateTokenResponse,
) => void;
}
export const GoogleAuthentication = ({
@@ -30,7 +36,6 @@ export const GoogleAuthentication = ({
useApi(loginOrSignUpWithGoogle);
const toast = useToast();
const clientRef = useRef<any>(null);
const auth = useAuth();
useEffect(() => {
const script = document.createElement('script');
@@ -55,12 +60,12 @@ export const GoogleAuthentication = ({
if (!res) return;
if (res.success) {
const tokenRes = await generateTokenWithGoogle(apiRequest);
auth.login({
...tokenRes.data,
const tokenRes = await generateTokenWithGoogle({
...apiRequest,
client_id: authFactory.clientId,
});
onGoogleAuthenticated(res);
onGoogleAuthenticated(res, tokenRes.data);
} else {
toast({
message: t('loginForm.googleAuthenticationFailed'),

View File

@@ -13,6 +13,7 @@ import { GoogleAuthentication } from './GoogleAuthentication';
import { isPhoneNumber } from '@/utils/regexes/isValidPhoneNumber';
import { useToast } from '@rkheftan/harmony-ui';
import { useApi } from '@/hooks/useApi';
import type { GenerateTokenResponse } from '../../api/identityAPI';
export interface LoginRegisterFormProps {
loginRegisterValue: string;
@@ -22,7 +23,10 @@ export interface LoginRegisterFormProps {
authType: AuthType;
setAuthType: Dispatch<AuthType>;
onLoginRegisterSubmit: (value: string, userStatus: UserStatus) => void;
onGoogleAuthenticated: (loginResult: LoginResult) => void;
onGoogleAuthenticated: (
loginResult: LoginResult,
tokenResponse: GenerateTokenResponse,
) => void;
authFactory: AuthFactory;
}
@@ -156,7 +160,7 @@ export function LoginRegisterForm({
</Button>
<GoogleAuthentication
authReturnUrl={authReturnUrl}
authFactory={authFactory}
onGoogleAuthenticated={onGoogleAuthenticated}
disabled={userStatusLoading}
/>

View File

@@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next';
import { Box, Button, Stack, Typography } from '@mui/material';
import { Edit2 } from 'iconsax-react';
import DigitInput from '@/components/DigitsInput';
import type { AuthMode, AuthType } from '../../types/authTypes';
import type { AuthFactory, AuthMode, AuthType } from '../../types/authTypes';
import { useEffect, useState } from 'react';
import { AuthenticationCard } from '../AuthenticationCard';
import type { LoginRequest, LoginResult } from '../../types/userTypes';
@@ -14,7 +14,10 @@ import {
import type { CountryCode } from '@/types/commonTypes';
import { Icon, useToast } from '@rkheftan/harmony-ui';
import { useApi } from '@/hooks/useApi';
import { generateTokenWithOtp } from '../../api/identityAPI';
import {
generateTokenWithOtp,
type GenerateTokenResponse,
} from '../../api/identityAPI';
import { useAuth } from '@/hooks/useAuth';
interface OtpVerifyFormProps {
@@ -23,8 +26,11 @@ interface OtpVerifyFormProps {
authType: AuthType;
authMode: AuthMode;
onEditValue: () => void;
onOTPVerified: (loginResult: LoginResult) => void;
authReturnUrl: string;
onOTPVerified: (
loginResult: LoginResult,
tokenResponse: GenerateTokenResponse,
) => void;
authFactory: AuthFactory;
}
export function OtpVerifyForm({
@@ -34,7 +40,7 @@ export function OtpVerifyForm({
authMode,
onEditValue,
onOTPVerified,
authReturnUrl,
authFactory,
}: OtpVerifyFormProps) {
const [otpCode, setOtpCode] = useState<string>('');
const [otpDigitInvalid, setOtpDigitInvalid] = useState<boolean>(false);
@@ -49,7 +55,6 @@ export function OtpVerifyForm({
useApi(sendEmailOtp);
const { loading: loginSignUpLoading, execute: loginSignUpCall } =
useApi(loginOrSignUpWithOtp);
const auth = useAuth();
useEffect(() => {
let interval: NodeJS.Timeout;
@@ -96,7 +101,7 @@ export function OtpVerifyForm({
otpCode: otpCode,
phoneNumber: authType === 'phone' ? countryCode + value : undefined,
email: authType === 'email' ? value : undefined,
returnUrl: authReturnUrl,
returnUrl: authFactory.redirectUrl,
};
const res = await loginSignUpCall(loginRequest);
@@ -111,12 +116,10 @@ export function OtpVerifyForm({
email: loginRequest.email,
phonenumber: loginRequest.phoneNumber,
otp: loginRequest.otpCode,
});
auth.login({
...tokenRes.data,
client_id: authFactory.clientId,
});
onOTPVerified(res);
onOTPVerified(res, tokenRes.data);
toast({
message: