From 31632e2879bd81369ae62e80e9ca034232027a30 Mon Sep 17 00:00:00 2001 From: sidarth-23 Date: Thu, 28 Mar 2024 14:28:26 +0530 Subject: [PATCH] feat: Add GitHub and Google sign-in buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add GitHub sign-in button to allow users to sign in with GitHub. - Add Google sign-in button to allow users to sign in with Google. - These buttons will authenticate users and set cookies for access and refresh tokens. refactor: Fix import paths for actions and api-routes (#123) ✨ Add dynamic googleId reference in GoogleSignInButton ℹ️ Use dynamic googleId reference instead of hardcoding window.google.accounts.id in useState hooks and effects to improve code readability and maintainability. ✨ Fix useState initialization in GitHubSignInButton component ✨ Add error handling for Google Sign-in process Added comments to handle errors during Google Sign-in process for better error management and user experience. ✨ Add Google Sign-In button and configuration interfaces - Added new types for Google Sign-In button and Google Sign-In function. - Updated Google Sign-In button component to use the new interfaces. - Updated global window declaration for Google Sign-In functionality. ✨ Add type annotations for state variables in GitHubSignInButton component --- apps/admin/components/github-signin.tsx | 67 +++++++++++ apps/admin/components/google-signin.tsx | 110 ++++++++++++++++++ apps/admin/components/index.ts | 2 + apps/admin/tsconfig.json | 1 + apps/admin/types/global/index.ts | 1 + apps/admin/types/global/window.ts | 19 +++ apps/admin/types/google-auth/gsi-button.ts | 10 ++ apps/admin/types/google-auth/index.ts | 2 + .../types/google-auth/signin-function.ts | 4 + apps/admin/types/index.ts | 4 +- 10 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 apps/admin/components/github-signin.tsx create mode 100644 apps/admin/components/google-signin.tsx create mode 100644 apps/admin/components/index.ts create mode 100644 apps/admin/types/global/index.ts create mode 100644 apps/admin/types/global/window.ts create mode 100644 apps/admin/types/google-auth/gsi-button.ts create mode 100644 apps/admin/types/google-auth/index.ts create mode 100644 apps/admin/types/google-auth/signin-function.ts diff --git a/apps/admin/components/github-signin.tsx b/apps/admin/components/github-signin.tsx new file mode 100644 index 0000000..f3807ad --- /dev/null +++ b/apps/admin/components/github-signin.tsx @@ -0,0 +1,67 @@ +"use client"; + +import { useEffect, useState, FC } from "react"; +import { AuthProviderButton } from "@repo/ui/components"; + +import Link from "next/link"; +import { useSearchParams } from "next/navigation"; +import { cookieSetter } from "@/actions"; +import axios from "axios"; +import { GITHUB_SIGN_IN_URL } from "@/api-routes"; + +type Props = {}; + +export const GitHubSignInButton: FC = () => { + const clientId = process.env.NEXT_PUBLIC_GITHUB_CLIENT_ID; + const handleGitHubSignIn = async (credential: string) => { + try { + if (clientId && credential) { + const response = await axios.post(GITHUB_SIGN_IN_URL, { + code: credential, + }); + + cookieSetter({ + access: response.data.tokens.access, + refresh: response.data.tokens.refresh, + }); + } else throw Error("Cant find credentials"); + } catch (err: any) { + // TODO: Handle error + } + }; + const searchParams = useSearchParams(); + // states + const [loginCallBackURL, setLoginCallBackURL] = useState(); + const [gitCode, setGitCode] = useState(null); + + const code = searchParams.get("code"); + useEffect(() => { + if (code && !gitCode) { + setGitCode(code); + handleGitHubSignIn(code); + } + }, [code, gitCode, handleGitHubSignIn]); + + useEffect(() => { + const origin = + typeof window !== "undefined" && window.location.origin + ? window.location.origin + : ""; + setLoginCallBackURL(`${origin}/`); + }, []); + + return ( + + + + ); +}; diff --git a/apps/admin/components/google-signin.tsx b/apps/admin/components/google-signin.tsx new file mode 100644 index 0000000..b981797 --- /dev/null +++ b/apps/admin/components/google-signin.tsx @@ -0,0 +1,110 @@ +"use client"; + +import { FC, useEffect, useRef, useCallback, useState } from "react"; +import Script from "next/script"; +import axios, { AxiosError } from "axios"; +import { GOOGLE_SIGN_IN_URL } from "@/api-routes"; +import { + TGoogleSignInFunction, + TGoogleSignInErrorResponse, + TGoogleSignInSuccessResponse, +} from "@/types"; +import { cookieSetter } from "@/actions"; +import { useRouter } from "next/navigation"; + +export const GoogleSignInButton: FC = () => { + const router = useRouter(); + const clientId = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID; + const handleGoogleSignIn = async ({ + clientId, + credential, + }: TGoogleSignInFunction) => { + if (!clientId || !credential) { + throw Error("Cant find credentials"); + } + try { + const response = await axios.post( + GOOGLE_SIGN_IN_URL, + { + auth_token: credential, + } + ); + cookieSetter({ + access: response.data.tokens.access, + refresh: response.data.tokens.refresh, + }); + router.push("/admin/dashboard"); + } catch (err) { + const error = err as AxiosError; + // TODO: Handle error + } + }; + + // refs + const googleSignInButton = useRef(null); + // states + const [gsiScriptLoaded, setGsiScriptLoaded] = useState(false); + + const loadScript = useCallback(() => { + if (!googleSignInButton.current || gsiScriptLoaded) return; + console.log(process.env.GOOGLE_CLIENT_ID!); + + // Assign googleId the value of window.google.accounts.id + const googleId = window?.google?.accounts.id; + + if (!googleId) { + console.error("Google Sign-In library not loaded"); + return; + } + + googleId.initialize({ + client_id: clientId, + callback: handleGoogleSignIn, + }); + + try { + googleId.renderButton( + googleSignInButton.current, + { + type: "standard", + theme: "outline", + size: "large", + logo_alignment: "center", + text: "signin_with", + } // customization attributes + ); + } catch (err) { + // TODO: Handle error + } + + googleId.prompt(); // also display the One Tap dialog + + setGsiScriptLoaded(true); + }, [handleGoogleSignIn, gsiScriptLoaded, clientId]); + + useEffect(() => { + const googleId = window?.google?.accounts.id; + if (googleId) { + loadScript(); + } + return () => { + googleId.cancel(); + }; + }, [loadScript]); + + return ( + <> +