"use client"; import { useEffect, useRef, useState } from "react"; declare global { interface Window { google?: { accounts?: { id?: { initialize: (options: { client_id: string; callback: (response: { credential?: string }) => void; }) => void; renderButton: ( parent: HTMLElement, options: { theme?: "outline" | "filled_blue" | "filled_black"; size?: "large" | "medium" | "small"; width?: number; text?: "signin_with" | "signup_with" | "continue_with" | "signin"; shape?: "rectangular" | "pill" | "circle" | "square"; } ) => void; }; }; }; } } const GOOGLE_SCRIPT_ID = "google-identity-services"; const GOOGLE_CLIENT_ID = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || ""; function loadGoogleScript(): Promise { if (typeof window === "undefined") return Promise.resolve(); if (window.google?.accounts?.id) return Promise.resolve(); const existing = document.getElementById(GOOGLE_SCRIPT_ID) as HTMLScriptElement | null; if (existing) { return new Promise((resolve, reject) => { existing.addEventListener("load", () => resolve(), { once: true }); existing.addEventListener("error", () => reject(new Error("Google 登录加载失败")), { once: true }); }); } return new Promise((resolve, reject) => { const script = document.createElement("script"); script.id = GOOGLE_SCRIPT_ID; script.src = "https://accounts.google.com/gsi/client"; script.async = true; script.defer = true; script.onload = () => resolve(); script.onerror = () => reject(new Error("Google 登录加载失败")); document.head.appendChild(script); }); } export default function GoogleLoginButton({ onCredential, onError, disabled = false, }: { onCredential: (credential: string) => void; onError?: (message: string) => void; disabled?: boolean; }) { const ref = useRef(null); const [ready, setReady] = useState(false); useEffect(() => { if (!GOOGLE_CLIENT_ID || !ref.current) return; let cancelled = false; loadGoogleScript() .then(() => { if (cancelled || !ref.current || !window.google?.accounts?.id) return; ref.current.innerHTML = ""; window.google.accounts.id.initialize({ client_id: GOOGLE_CLIENT_ID, callback: (response) => { if (response.credential) onCredential(response.credential); else onError?.("Google 登录失败"); }, }); window.google.accounts.id.renderButton(ref.current, { theme: "outline", size: "large", width: 304, text: "continue_with", shape: "rectangular", }); setReady(true); }) .catch((error) => onError?.(error instanceof Error ? error.message : "Google 登录加载失败")); return () => { cancelled = true; }; }, [onCredential, onError]); if (!GOOGLE_CLIENT_ID) return null; return (
{!ready &&
}
); }