'use client'; import { useEffect, useRef, useState, useCallback } from 'react'; import { useAuth } from '@/context/AuthContext'; import { useLanguage } from '@/context/LanguageContext'; import { safeInternalPath } from '@/lib/safeRedirect'; import toast from 'react-hot-toast'; declare global { interface Window { google?: { accounts: { id: { initialize: (config: GoogleInitConfig) => void; renderButton: (element: HTMLElement | null, options: GoogleButtonOptions) => void; prompt: () => void; cancel: () => void; }; }; }; } } interface GoogleInitConfig { client_id: string; callback: (response: GoogleCredentialResponse) => void; auto_select?: boolean; cancel_on_tap_outside?: boolean; } interface GoogleButtonOptions { type?: 'standard' | 'icon'; theme?: 'outline' | 'filled_blue' | 'filled_black'; size?: 'large' | 'medium' | 'small'; text?: 'signin_with' | 'signup_with' | 'continue_with' | 'signin'; shape?: 'rectangular' | 'pill' | 'circle' | 'square'; logo_alignment?: 'left' | 'center'; width?: string | number; locale?: string; } interface GoogleCredentialResponse { credential: string; select_by?: string; } interface GoogleSignInButtonProps { onSuccess?: () => void; onError?: (error: string) => void; redirectTo?: string; text?: 'signin_with' | 'signup_with' | 'continue_with' | 'signin'; className?: string; } export default function GoogleSignInButton({ onSuccess, onError, redirectTo = '/dashboard', text = 'continue_with', className = '', }: GoogleSignInButtonProps) { const buttonRef = useRef(null); const [isLoading, setIsLoading] = useState(false); const [scriptLoaded, setScriptLoaded] = useState(false); const [scriptError, setScriptError] = useState(false); const { loginWithGoogle } = useAuth(); const { locale } = useLanguage(); const clientId = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID; const handleGoogleCallback = useCallback( async (response: GoogleCredentialResponse) => { if (!response.credential) { const errorMsg = locale === 'es' ? 'No se recibio credencial de Google' : 'No credential received from Google'; onError?.(errorMsg); toast.error(errorMsg); return; } setIsLoading(true); try { await loginWithGoogle(response.credential); toast.success(locale === 'es' ? 'Bienvenido!' : 'Welcome!'); onSuccess?.(); // Use window.location for navigation to ensure clean state. // Constrain to a same-origin path to avoid open redirects. window.location.href = safeInternalPath(redirectTo, '/dashboard'); } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : 'Google login failed'; const displayError = locale === 'es' ? 'Error al iniciar sesion con Google' : errorMessage; onError?.(displayError); toast.error(displayError); } finally { setIsLoading(false); } }, [loginWithGoogle, locale, onSuccess, onError, redirectTo] ); const initializeGoogleSignIn = useCallback(() => { if (!clientId) { console.warn('Google Client ID not configured'); return; } if (!window.google?.accounts?.id) { return; } try { window.google.accounts.id.initialize({ client_id: clientId, callback: handleGoogleCallback, auto_select: false, cancel_on_tap_outside: true, }); if (buttonRef.current) { // Clear any existing button buttonRef.current.innerHTML = ''; window.google.accounts.id.renderButton(buttonRef.current, { type: 'standard', theme: 'outline', size: 'large', text: text, shape: 'rectangular', logo_alignment: 'left', width: 280, locale: locale === 'es' ? 'es' : 'en', }); } } catch (error) { console.error('Error initializing Google Sign-In:', error); setScriptError(true); } }, [clientId, handleGoogleCallback, text, locale]); // Load Google Sign-In script useEffect(() => { if (!clientId) { return; } // Check if script is already loaded if (window.google?.accounts?.id) { setScriptLoaded(true); return; } // Check if script tag already exists const existingScript = document.querySelector('script[src="https://accounts.google.com/gsi/client"]'); if (existingScript) { // Script exists but may not be loaded yet existingScript.addEventListener('load', () => setScriptLoaded(true)); existingScript.addEventListener('error', () => setScriptError(true)); return; } // Load the script const script = document.createElement('script'); script.src = 'https://accounts.google.com/gsi/client'; script.async = true; script.defer = true; script.onload = () => setScriptLoaded(true); script.onerror = () => setScriptError(true); document.head.appendChild(script); return () => { // Cleanup is handled by checking for existing script }; }, [clientId]); // Initialize when script is loaded useEffect(() => { if (scriptLoaded) { // Small delay to ensure Google object is fully available const timer = setTimeout(initializeGoogleSignIn, 100); return () => clearTimeout(timer); } }, [scriptLoaded, initializeGoogleSignIn]); // Don't render if no client ID configured if (!clientId) { return null; } if (scriptError) { return (
{locale === 'es' ? 'Google Sign-In no disponible' : 'Google Sign-In unavailable'}
); } return (
{/* Google Sign-In Button Container */}
{/* Loading overlay */} {isLoading && (
)}
); }