Spaces:
Running
Running
File size: 5,985 Bytes
67c7241 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
'use client';
import { useEffect, useCallback, useRef, useState } from 'react';
import Script from 'next/script';
import { createClient } from '@/lib/supabase/client';
// Add type declarations for Google One Tap
declare global {
interface Window {
handleGoogleSignIn?: (response: GoogleSignInResponse) => void;
google: {
accounts: {
id: {
initialize: (config: GoogleInitializeConfig) => void;
renderButton: (element: HTMLElement, options: GoogleButtonOptions) => void;
prompt: (callback?: (notification: GoogleNotification) => void) => void;
cancel: () => void;
};
};
};
}
}
// Define types for Google Sign-In
interface GoogleSignInResponse {
credential: string;
clientId?: string;
select_by?: string;
}
interface GoogleInitializeConfig {
client_id: string | undefined;
callback: ((response: GoogleSignInResponse) => void) | undefined;
nonce?: string;
use_fedcm?: boolean;
context?: string;
itp_support?: boolean;
}
interface GoogleButtonOptions {
type?: string;
theme?: string;
size?: string;
text?: string;
shape?: string;
logoAlignment?: string;
width?: number;
}
interface GoogleNotification {
isNotDisplayed: () => boolean;
getNotDisplayedReason: () => string;
isSkippedMoment: () => boolean;
getSkippedReason: () => string;
isDismissedMoment: () => boolean;
getDismissedReason: () => string;
}
interface GoogleSignInProps {
returnUrl?: string;
}
export default function GoogleSignIn({ returnUrl }: GoogleSignInProps) {
const googleClientId = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID;
const [isLoading, setIsLoading] = useState(false);
const handleGoogleSignIn = useCallback(async (response: GoogleSignInResponse) => {
try {
setIsLoading(true);
const supabase = createClient();
const { error } = await supabase.auth.signInWithIdToken({
provider: 'google',
token: response.credential,
});
if (error) throw error;
// Add a small delay before redirecting to ensure localStorage is properly saved
setTimeout(() => {
window.location.href = returnUrl || "/dashboard";
}, 100);
} catch (error) {
console.error('Error signing in with Google:', error);
setIsLoading(false);
}
}, [returnUrl]);
useEffect(() => {
// Assign the callback to window object so it can be called from the Google button
window.handleGoogleSignIn = handleGoogleSignIn;
if (window.google && googleClientId) {
window.google.accounts.id.initialize({
client_id: googleClientId,
callback: handleGoogleSignIn,
use_fedcm: true,
context: 'signin',
itp_support: true
});
}
return () => {
// Cleanup
delete window.handleGoogleSignIn;
if (window.google) {
window.google.accounts.id.cancel();
}
};
}, [googleClientId, handleGoogleSignIn]);
if (!googleClientId) {
return (
<button
disabled
className="w-full h-12 flex items-center justify-center gap-2 text-sm font-medium tracking-wide rounded-full bg-background border border-border opacity-60 cursor-not-allowed"
>
<svg className="w-5 h-5" viewBox="0 0 24 24">
<path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4"/>
<path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/>
<path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill="#FBBC05"/>
<path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/>
</svg>
Google Sign-In Not Configured
</button>
);
}
return (
<>
{/* Google One Tap container */}
<div
id="g_id_onload"
data-client_id={googleClientId}
data-context="signin"
data-ux_mode="popup"
data-auto_prompt="false"
data-itp_support="true"
data-callback="handleGoogleSignIn"
/>
{/* Google Sign-In button container styled to match site design */}
<div id="google-signin-button" className="w-full h-12">
{/* The Google button will be rendered here */}
</div>
<Script
src="https://accounts.google.com/gsi/client"
strategy="afterInteractive"
onLoad={() => {
if (window.google && googleClientId) {
// Style the button after Google script loads
const buttonContainer = document.getElementById('google-signin-button');
if (buttonContainer) {
window.google.accounts.id.renderButton(buttonContainer, {
type: 'standard',
theme: 'outline',
size: 'large',
text: 'continue_with',
shape: 'pill',
logoAlignment: 'left',
width: buttonContainer.offsetWidth
});
// Apply custom styles to match site design
setTimeout(() => {
const googleButton = buttonContainer.querySelector('div[role="button"]');
if (googleButton instanceof HTMLElement) {
googleButton.style.borderRadius = '9999px';
googleButton.style.width = '100%';
googleButton.style.height = '56px';
googleButton.style.border = '1px solid var(--border)';
googleButton.style.background = 'var(--background)';
googleButton.style.transition = 'all 0.2s';
}
}, 100);
}
}
}}
/>
</>
);
} |