129 lines
3.5 KiB
TypeScript
129 lines
3.5 KiB
TypeScript
import { useEffect, useRef, useState } from 'react';
|
|
import type {
|
|
LoginOrSignUpWithGoogleRequest,
|
|
LoginResult,
|
|
} from '../../types/userTypes';
|
|
import type { AuthFactory } from '../../types/authTypes';
|
|
import {
|
|
generateTokenWithGoogle,
|
|
type GenerateTokenResponse,
|
|
} from '../../api/identityAPI';
|
|
import { loginOrSignUpWithGoogle } from '../../api/authorizationAPI';
|
|
import { useApi } from '@/hooks/useApi';
|
|
import { useToast } from '@rkheftan/harmony-ui';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { Box, Button } from '@mui/material';
|
|
|
|
interface GoogleAuthenticationV2Props {
|
|
authFactory: AuthFactory;
|
|
onGoogleAuthenticated: (
|
|
loginResult: LoginResult,
|
|
tokenResponse: GenerateTokenResponse,
|
|
) => void;
|
|
}
|
|
|
|
export const GoogleAuthenticationV2 = ({
|
|
authFactory,
|
|
onGoogleAuthenticated,
|
|
}: GoogleAuthenticationV2Props) => {
|
|
const toast = useToast();
|
|
const { t } = useTranslation('authentication');
|
|
const { execute: loginWithGoogleCall } = useApi(loginOrSignUpWithGoogle);
|
|
const [isGoogleLoaded, setIsGoogleLoaded] = useState(false);
|
|
|
|
const googleBtnRef = useRef<HTMLDivElement>(null);
|
|
const renderedRef = useRef(false);
|
|
|
|
const handleCredentialResponse = async (response: any) => {
|
|
const idToken = response.credential;
|
|
|
|
try {
|
|
const apiRequest: LoginOrSignUpWithGoogleRequest = {
|
|
idToken: idToken,
|
|
returnUrl: authFactory.redirectUrl,
|
|
};
|
|
const res = await loginWithGoogleCall(apiRequest);
|
|
|
|
if (!res) return;
|
|
|
|
if (res.success) {
|
|
const tokenRes = await generateTokenWithGoogle({
|
|
...apiRequest,
|
|
client_id: authFactory.clientId,
|
|
});
|
|
|
|
onGoogleAuthenticated(res, tokenRes.data);
|
|
} else {
|
|
toast({
|
|
message: t('loginForm.googleAuthenticationFailed'),
|
|
severity: 'error',
|
|
});
|
|
}
|
|
} catch (error) {
|
|
toast({
|
|
message: t('loginForm.googleAuthenticationFailed'),
|
|
severity: 'error',
|
|
});
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
// Ensure the DOM element exists
|
|
if (!googleBtnRef.current || renderedRef.current) return;
|
|
|
|
// Logic to initialize Google Button
|
|
const initializeGoogle = () => {
|
|
if (!window.google) return;
|
|
|
|
setIsGoogleLoaded(true);
|
|
|
|
google.accounts.id.initialize({
|
|
client_id: import.meta.env.VITE_GOOGLE_CLIENT_ID,
|
|
callback: handleCredentialResponse,
|
|
});
|
|
|
|
google.accounts.id.renderButton(googleBtnRef.current, {
|
|
theme: 'outline', // Matches your MUI 'variant="outlined"'
|
|
size: 'large', // Standard button size
|
|
type: 'standard', // The standard "Sign in with Google" button
|
|
text: 'signin_with', // Text: "Sign in with Google"
|
|
shape: 'rectangular', // Matches your MUI button shape
|
|
width: '400', // Set a width (Google caps this at 400px)
|
|
logo_alignment: 'left',
|
|
|
|
height: '44',
|
|
});
|
|
|
|
renderedRef.current = true;
|
|
};
|
|
|
|
if (window.google?.accounts) {
|
|
initializeGoogle();
|
|
} else {
|
|
const timer = setInterval(() => {
|
|
if (window.google?.accounts) {
|
|
initializeGoogle();
|
|
clearInterval(timer);
|
|
}
|
|
}, 500);
|
|
return () => clearInterval(timer);
|
|
}
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
<Box
|
|
sx={{
|
|
width: '100%',
|
|
display: 'flex',
|
|
justifyContent: 'center',
|
|
minHeight: 44,
|
|
}}
|
|
>
|
|
{!isGoogleLoaded && <Button variant="outlined" loading />}
|
|
<div ref={googleBtnRef} id="google-signin-button"></div>
|
|
</Box>
|
|
</>
|
|
);
|
|
};
|