-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add GitHub and Google sign-in buttons
- 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
- Loading branch information
1 parent
d4b819d
commit 31632e2
Showing
10 changed files
with
219 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Props> = () => { | ||
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<string>(); | ||
const [gitCode, setGitCode] = useState<null | string>(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 ( | ||
<Link | ||
passHref | ||
legacyBehavior | ||
href={`https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${`${loginCallBackURL}/home/login`}&scope=read:user,user:email`} | ||
> | ||
<AuthProviderButton | ||
provider="github" | ||
width="full" | ||
columnSpan={2} | ||
textSize="sm" | ||
/> | ||
</Link> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<TGoogleSignInSuccessResponse>( | ||
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<TGoogleSignInErrorResponse>; | ||
// TODO: Handle error | ||
} | ||
}; | ||
|
||
// refs | ||
const googleSignInButton = useRef<HTMLDivElement>(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 ( | ||
<> | ||
<Script | ||
src="https://accounts.google.com/gsi/client" | ||
async | ||
defer | ||
onLoad={loadScript} | ||
/> | ||
<div | ||
className="w-full rounded" | ||
id="googleSignInButton" | ||
ref={googleSignInButton} | ||
/> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './github-signin' | ||
export * from './google-signin' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
}, | ||
"include": [ | ||
"next-env.d.ts", | ||
"./types", | ||
"next.config.js", | ||
"**/*.ts", | ||
"**/*.tsx", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './window' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { RefObject } from "react"; | ||
import { GsiButtonConfiguration, TGoogleSignInFunction } from "../google-auth"; | ||
|
||
export {} | ||
|
||
declare global { | ||
interface Window { | ||
google: { | ||
accounts: { | ||
id: { | ||
initialize: (config: { client_id: string | undefined; callback: ({ clientId, credential, }: TGoogleSignInFunction) => Promise<void> }) => void; | ||
renderButton: (element: HTMLDivElement, options: GsiButtonConfiguration) => void; | ||
prompt: () => void; | ||
cancel: () => void; | ||
}; | ||
}; | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export interface GsiButtonConfiguration { | ||
type: "standard" | "icon"; | ||
theme?: "outline" | "filled_blue" | "filled_black"; | ||
size?: "large" | "medium" | "small"; | ||
text?: "signin_with" | "signup_with" | "continue_with" | "signup_with"; | ||
shape?: "rectangular" | "pill" | "circle" | "square"; | ||
logo_alignment?: "left" | "center"; | ||
width?: number; | ||
local?: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './gsi-button' | ||
export * from './signin-function' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export interface TGoogleSignInFunction { | ||
clientId: string; | ||
credential: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
export * from './authentication' | ||
export * from './authentication' | ||
export * from './global' | ||
export * from './google-auth' |