Files
reactShop/src/components/GoogleLoginButton.js

209 lines
6.4 KiB
JavaScript

import React, { Component } from 'react';
import Button from '@mui/material/Button';
import GoogleIcon from '@mui/icons-material/Google';
import GoogleAuthContext from '../contexts/GoogleAuthContext.js';
import { withI18n } from '../i18n/index.js';
class GoogleLoginButton extends Component {
static contextType = GoogleAuthContext;
constructor(props) {
super(props);
this.state = {
isInitialized: false,
isInitializing: false,
promptShown: false,
isPrompting: false // @note Added to prevent multiple simultaneous prompts
};
this.promptTimeout = null; // @note Added to track timeout
this.prevContextLoaded = false; // @note Track previous context loaded state
}
componentDidMount() {
// Check if Google libraries are already available
const hasGoogleLoaded = window.google && window.google.accounts && window.google.accounts.id;
const contextLoaded = this.context && this.context.isLoaded;
// @note Initialize the tracked context loaded state
this.prevContextLoaded = contextLoaded;
// @note Only initialize immediately if context is already loaded, otherwise let componentDidUpdate handle it
if (hasGoogleLoaded && this.context.clientId && contextLoaded) {
this.initializeGoogleSignIn();
}
}
componentDidUpdate(prevProps, prevState) {
// Initialize when all conditions are met and we haven't initialized before
const hasGoogleLoaded = window.google && window.google.accounts && window.google.accounts.id;
const contextLoaded = this.context && this.context.isLoaded;
// @note Only initialize when context becomes loaded for the first time
if (!this.state.isInitialized &&
!this.state.isInitializing &&
hasGoogleLoaded &&
this.context.clientId &&
contextLoaded &&
!this.prevContextLoaded) {
this.initializeGoogleSignIn();
}
// @note Update the tracked context loaded state
this.prevContextLoaded = contextLoaded;
// Auto-prompt if initialization is complete and autoInitiate is true
if (this.props.autoInitiate &&
this.state.isInitialized &&
!this.state.promptShown &&
!this.state.isPrompting && // @note Added check to prevent multiple prompts
(!prevState.isInitialized || !prevProps.autoInitiate)) {
this.setState({ promptShown: true });
this.schedulePrompt(100);
}
}
componentWillUnmount() {
// @note Clear timeout on unmount to prevent memory leaks
if (this.promptTimeout) {
clearTimeout(this.promptTimeout);
}
}
schedulePrompt = (delay = 0) => {
// @note Clear any existing timeout
if (this.promptTimeout) {
clearTimeout(this.promptTimeout);
}
this.promptTimeout = setTimeout(() => {
this.tryPrompt();
}, delay);
};
initializeGoogleSignIn = () => {
// Avoid multiple initialization attempts
if (this.state.isInitialized || this.state.isInitializing) {
return;
}
this.setState({ isInitializing: true });
if (!window.google || !window.google.accounts || !window.google.accounts.id) {
console.error('Google Sign-In API not loaded yet');
this.setState({ isInitializing: false });
return;
}
try {
window.google.accounts.id.initialize({
client_id: this.context.clientId,
callback: this.handleCredentialResponse,
});
this.setState({
isInitialized: true,
isInitializing: false
}, () => {
// Auto-prompt immediately if autoInitiate is true
if (this.props.autoInitiate && !this.state.promptShown && !this.state.isPrompting) {
this.setState({ promptShown: true });
this.schedulePrompt(100);
}
});
console.log('Google Sign-In initialized successfully');
} catch (error) {
console.error('Failed to initialize Google Sign-In:', error);
this.setState({
isInitializing: false
});
if (this.props.onError) {
this.props.onError(error);
}
}
};
handleCredentialResponse = (response) => {
console.log('cred',response);
const { onSuccess, onError } = this.props;
// @note Reset prompting state when response is received
this.setState({ isPrompting: false });
if (response && response.credential) {
// Call onSuccess with the credential
if (onSuccess) {
onSuccess(response);
}
} else {
// Call onError if something went wrong
if (onError) {
onError(new Error('Failed to get credential from Google'));
}
}
};
handleClick = () => {
// @note Prevent multiple clicks while prompting
if (this.state.isPrompting) {
return;
}
// If not initialized yet, try initializing first
if (!this.state.isInitialized && !this.state.isInitializing) {
this.initializeGoogleSignIn();
// Add a small delay before attempting to prompt
this.schedulePrompt(300);
return;
}
this.tryPrompt();
};
tryPrompt = () => {
// @note Prevent multiple simultaneous prompts
if (this.state.isPrompting) {
return;
}
if (!window.google || !window.google.accounts || !window.google.accounts.id) {
console.error('Google Sign-In API not loaded');
return;
}
try {
this.setState({ isPrompting: true });
window.google.accounts.id.prompt();
this.setState({ promptShown: true });
console.log('Google Sign-In prompt displayed');
} catch (error) {
console.error('Error prompting Google Sign-In:', error);
this.setState({ isPrompting: false });
if (this.props.onError) {
this.props.onError(error);
}
}
};
render() {
const { disabled, style, className, text = (this.props.t ? this.props.t('auth.loginWithGoogle') : 'Mit Google anmelden') } = this.props;
const { isInitializing, isPrompting } = this.state;
const isLoading = isInitializing || isPrompting || (this.context && !this.context.isLoaded);
return (
<Button
variant="contained"
startIcon={<GoogleIcon />}
onClick={this.handleClick}
disabled={disabled || isLoading}
style={{ backgroundColor: '#4285F4', color: 'white', ...style }}
className={className}
>
{isLoading ? 'Loading...' : text}
</Button>
);
}
}
export default withI18n(GoogleLoginButton);