diff --git a/components/atomic/Button/patterns/GoogleSSOButton.js b/components/atomic/Button/patterns/GoogleSSOButton.js new file mode 100644 index 00000000..2cf2df02 --- /dev/null +++ b/components/atomic/Button/patterns/GoogleSSOButton.js @@ -0,0 +1,52 @@ +import PropTypes from "prop-types"; +import { useGoogleLogin } from "@react-oauth/google"; +import { useRouter } from "next/router"; +import { useAuthenticationContext } from "@/contexts/Authentication"; +import SSOButton from "./SSOButton"; + +export default function GoogleSSOButton({ children, ...buttonProps }) { + const { authenticateWithGoogle } = useAuthenticationContext(); + const { query, push, asPath, pathname } = useRouter(); + const goToGoogleSignIn = useGoogleLogin({ + state: asPath, + onSuccess: (response) => { + push( + { pathname: asPath.split("?")[0], query: { sso: true } }, + undefined, + { + shallow: true, + } + ); + fetch("/api/authGoogle", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ code: response.code }), + }) + .then((res) => res.json()) + .then((data) => { + authenticateWithGoogle(data); + }) + .catch(console.error); + }, + onError: (error) => { + console.error(error); + }, + flow: "auth-code", + }); + + return ( + + {children} + + ); +} + +GoogleSSOButton.propTypes = { + children: PropTypes.node, + service: PropTypes.oneOf(["google", "facebook", "email"]), +}; diff --git a/components/atomic/index.js b/components/atomic/index.js index fc309792..181f6fd7 100644 --- a/components/atomic/index.js +++ b/components/atomic/index.js @@ -1,4 +1,5 @@ export { default as SSOButton } from "./Button/patterns/SSOButton"; +export { default as GoogleSSOButton } from "./Button/patterns/GoogleSSOButton"; export { default as EarlyAccess } from "./Flag/patterns/EarlyAccess"; export { default as Tile } from "./Tile"; export { default as InvestigationTile } from "./Tile/patterns/InvestigationTile"; diff --git a/components/modal/RegisterModal/JoinForm/index.js b/components/modal/RegisterModal/JoinForm/index.js index 18600b1e..2c49a780 100644 --- a/components/modal/RegisterModal/JoinForm/index.js +++ b/components/modal/RegisterModal/JoinForm/index.js @@ -2,7 +2,7 @@ import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; import Link from "next/link"; import { Link as BaseLink } from "@rubin-epo/epo-react-lib"; -import { SSOButton } from "@/components/atomic"; +import { GoogleSSOButton, SSOButton } from "@/components/atomic"; import useAuthModal from "@/hooks/useAuthModal"; import { useAuthenticationContext } from "@/contexts/Authentication"; import AuthModal from "../../AuthModal"; @@ -14,7 +14,7 @@ export default function JoinForm({ onEmailSignup }) { const { pendingGroup, setPendingGroup, - goToGoogleSignIn, + // goToGoogleSignIn, goToFacebookSignIn, } = useAuthenticationContext(); @@ -47,9 +47,9 @@ export default function JoinForm({ onEmailSignup }) { */} - + {t("join.continue_with_google")} - + {/* { - const ssoModalUrl = { pathname: "/", query: { sso: true } }; - push(ssoModalUrl, undefined, { - shallow: true, - }); - // eslint-disable-next-line no-console - console.log("onSuccess", response, "onSuccess"); - authenticateWithGoogle({ idToken: response.tokenId }); - }, - onFailure: (error) => { - // eslint-disable-next-line no-console - console.log("onFailure", error, "onFailure"); - console.error(error); - }, - }); - useEffect(() => { // TODO: cancel promise if component unmounts first (async () => await maybeRefreshToken())(); @@ -442,8 +422,8 @@ export default function useAuthentication(data) { forgotPassword, setPassword, activateUser, - goToGoogleSignIn, goToFacebookSignIn, + authenticateWithGoogle, fetchUserData, requestAccountDeletion, }; diff --git a/package.json b/package.json index 9a686b8b..75f7166a 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "@headlessui/react": "^1.6.6", "@influxdata/influxdb-client": "^1.33.2", "@popperjs/core": "^2.11.5", + "@react-oauth/google": "^0.12.1", "@rubin-epo/epo-react-lib": "^1.2.9", "add": "^2.0.6", "classnames": "^2.3.1", @@ -68,6 +69,7 @@ "feed": "^4.2.2", "focus-trap": "^7.0.0", "focus-visible": "^5.1.0", + "google-auth-library": "^9.6.3", "graphql": "^16.5.0", "graphql-request": "^5.0.0", "hoist-non-react-statics": "^3.3.2", @@ -79,7 +81,6 @@ "npm-run-all": "^4.1.5", "react": "18.2.0", "react-dom": "18.2.0", - "react-google-login": "^5.2.2", "react-hook-form": "^7.33.1", "react-i18next": "^12.0.0", "react-is": "^18.2.0", diff --git a/pages/[[...uriSegments]].js b/pages/[[...uriSegments]].js index e49badeb..a23ce0c6 100644 --- a/pages/[[...uriSegments]].js +++ b/pages/[[...uriSegments]].js @@ -1,4 +1,5 @@ import PropTypes from "prop-types"; +import { GoogleOAuthProvider } from "@react-oauth/google"; import { getGlobalData } from "@/api/global"; import { getAllEntries } from "@/api/entries"; import { getEntryDataByUri, getEntrySectionTypeByUri } from "@/api/entry"; @@ -57,6 +58,7 @@ function logNextDir() { }); } +const GOOGLE_APP_ID = process.env.NEXT_PUBLIC_GOOGLE_APP_ID; export default function Page({ section, globalData, ...entryProps }) { globalData.localeInfo.locale === "es" ? updateI18n("es") : updateI18n("en"); @@ -75,9 +77,11 @@ export default function Page({ section, globalData, ...entryProps }) { const Template = sectionMap[section] || PageTemplate; return ( - -