From 84b26d0f7a2cb6215aa0664b51440fc8454c5abe Mon Sep 17 00:00:00 2001 From: Brian Schroer Date: Fri, 9 Feb 2024 11:19:27 -0800 Subject: [PATCH] 689 Run prettier and lean up auth PR --- app/components/AppProvider.tsx | 6 +- app/components/ui/Navigation.tsx | 2 +- app/pages/Auth/LogoutPage.tsx | 6 +- app/pages/Auth/SignUpPage.tsx | 25 +++++--- app/pages/Auth/VerificationModal.tsx | 44 ++++--------- app/pages/HomePage/HomePage.tsx | 4 +- app/utils/AuthService.ts | 94 ++++++++++++++++------------ config.example.yml | 2 +- 8 files changed, 92 insertions(+), 91 deletions(-) diff --git a/app/components/AppProvider.tsx b/app/components/AppProvider.tsx index 010f8b2ad..c840d4ef5 100644 --- a/app/components/AppProvider.tsx +++ b/app/components/AppProvider.tsx @@ -63,7 +63,9 @@ export const AppProvider = ({ if ( authObject.isAuthenticated && authObject.accessTokenObject.expiresAt && - AuthService.hasAccessTokenExpired(new Date(authObject.accessTokenObject.expiresAt)) + AuthService.hasAccessTokenExpired( + new Date(authObject.accessTokenObject.expiresAt) + ) ) { AuthService.refreshAccessToken(contextValue.authClient) .then((result: unknown) => { @@ -82,7 +84,7 @@ export const AppProvider = ({ }, }); } else { - throw new Error("Token does not exist or is in unexpected token"); + throw new Error("Token does not exist or is unexpected token"); } }) .catch((err) => { diff --git a/app/components/ui/Navigation.tsx b/app/components/ui/Navigation.tsx index 0a07de53e..b02586092 100644 --- a/app/components/ui/Navigation.tsx +++ b/app/components/ui/Navigation.tsx @@ -101,7 +101,7 @@ const SiteLinks = () => { */} {authState.isAuthenticated && (
  • - Sign Out + Log Out
  • )}
  • diff --git a/app/pages/Auth/LogoutPage.tsx b/app/pages/Auth/LogoutPage.tsx index aebe5a174..711dc0d15 100644 --- a/app/pages/Auth/LogoutPage.tsx +++ b/app/pages/Auth/LogoutPage.tsx @@ -10,11 +10,7 @@ export const LogoutPage = () => { const authClient = context.authClient as WebAuth; useEffect(() => { - AuthService.logout( - authClient, - Config.AUTH0_CLIENT_ID, - setAuthState - ); + AuthService.logout(authClient, Config.AUTH0_CLIENT_ID, setAuthState); }); return ; diff --git a/app/pages/Auth/SignUpPage.tsx b/app/pages/Auth/SignUpPage.tsx index 7c35eda82..3626d0235 100644 --- a/app/pages/Auth/SignUpPage.tsx +++ b/app/pages/Auth/SignUpPage.tsx @@ -19,15 +19,20 @@ export const SignUpPage = () => { const signUp = (evt: React.SyntheticEvent) => { evt.preventDefault(); - initializeUserSignUp(authClient, email).then(() => { - setModalIsOpen(true); - }, (error) => { - if (error.message === 'userExists') { - // eslint-disable-next-line no-alert - // Todo: Handle this case with a proper error message - alert('Oops, there is already a user with that email in our system. Please try logging in instead.'); + initializeUserSignUp(authClient, email).then( + () => { + setModalIsOpen(true); + }, + (error) => { + if (error.message === "userExists") { + // eslint-disable-next-line no-alert + // TODO: Handle this case with a proper error message + alert( + "Oops, it looks like you may have already signed up. Please try logging in instead." + ); + } } - }) + ); }; return ( @@ -71,7 +76,9 @@ export const SignUpPage = () => { email={email} modalIsOpen={modalIsOpen} setModalIsOpen={setModalIsOpen} - verifyCode={(code) => completeUserSignup(authClient, code, email, name, organization)} + verifyCode={(code) => + completeUserSignup(authClient, code, email, name, organization) + } resendCode={() => passwordlessStart(authClient, email)} buttonText="Sign up" /> diff --git a/app/pages/Auth/VerificationModal.tsx b/app/pages/Auth/VerificationModal.tsx index d84a027cc..809308119 100644 --- a/app/pages/Auth/VerificationModal.tsx +++ b/app/pages/Auth/VerificationModal.tsx @@ -1,4 +1,4 @@ -import React, { useState, createRef, useEffect } from "react"; +import React, { useState, createRef } from "react"; import { Modal } from "components/ui/Modal/Modal"; import { Button } from "components/ui/inline/Button/Button"; @@ -98,39 +98,19 @@ export const VerificationModal = ({ }; const ResendCode = ({ resendCode }: { resendCode: () => Promise }) => { - const [timeLeft, setTimeLeft] = useState(60); - const [codeResent, setCodeResent] = useState(false); - - useEffect(() => { - const interval = setInterval(() => { - if (timeLeft === 0) { - clearInterval(interval); - resendCode(); - setCodeResent(true); - return; - } - - setTimeLeft(timeLeft - 1); - }, 1000); - - return () => clearInterval(interval); - }, [resendCode, setTimeLeft, timeLeft]); - return (
    - {codeResent ? ( -

    - Didn't receive a code? - -

    - ) : ( - <> - Resend code in: - {timeLeft} - - )} +

    + Didn't receive a code? Please check your spam folder. + +

    ); }; diff --git a/app/pages/HomePage/HomePage.tsx b/app/pages/HomePage/HomePage.tsx index c68544441..2a55b8c81 100644 --- a/app/pages/HomePage/HomePage.tsx +++ b/app/pages/HomePage/HomePage.tsx @@ -86,11 +86,11 @@ export const HomePage = () => { }); useEffect(() => { - // Todo: This effect should be moved to the case worker UI homepage when that page is created + // TODO: This effect should be moved to the case worker UI homepage when that page is created const { hash } = window.location; if (!hash || !hash.includes("access_token")) return; - AuthService.persistUser( + AuthService.initializeUserSession( window.location.hash, authClient as WebAuth, setAuthState diff --git a/app/utils/AuthService.ts b/app/utils/AuthService.ts index 91550ab60..9c10c168a 100644 --- a/app/utils/AuthService.ts +++ b/app/utils/AuthService.ts @@ -5,7 +5,7 @@ import type { AuthState } from "components/AppProvider"; /* This class provides a set of methods that serve as an interface between our application - and the Auth0 servers where the user's state and data is stored. + and the Auth0 servers where the user's auth state and data is stored. */ export default class AuthService { @@ -18,7 +18,11 @@ export default class AuthService { return expirationTime; } - static persistUser(hash: string, authClient: WebAuth, setAuthState: any) { + static initializeUserSession( + hash: string, + authClient: WebAuth, + setAuthState: any + ) { authClient.parseHash({ hash }, (err, authResult) => { if (err) { // TODO: Handle errors @@ -49,39 +53,41 @@ export default class AuthService { return new Promise((resolve, reject) => { this.userExists(email).then((exists) => { if (exists) { - reject(new Error('userExists')); + reject(new Error("userExists")); } else { this.passwordlessStart(authClient, email).then((result) => { resolve(result); - }) + }); } }); }); }; // Invokes the passwordlessLogin method and following that saves the user to our database - static completeUserSignup = (authClient: WebAuth, + static completeUserSignup = ( + authClient: WebAuth, verificationCode: string, email: string, name: string, - organization: (string | null) = null) => { - this.passwordlessLogin(authClient, email, verificationCode); - // We need to optimistically save the user to our database here. The user is saved to the _Auth0_ - // database after the passwordlessLogin method succeeds. We also want to save user data in our - // backend. This should be done after a success callback after passwordlessLogin succceds; however, - // the passwordlessLogin success callback does not fire within our app, because, upon success, Auth0 - // triggers a redirect to our home page. At that point, we do not have the user's name or organization, - // which we need to save in our database. Thus, we save the user here. - // - // If for some reason, the passwordlessLogin method errors, this code still save the user in our DB. - // At that point, the worst case scenario is that the user will be informed that they have already - // signed up if they try to sign up again and to log in instead. Since the Auth0 passwordless flow - // does not have a sign-up process separate from its log-in process, and thus the user will still - // be created within Auth0 upon going through our site's log-in flow. - this.saveUser(email, name, organization); + organization: string | null = null + ) => { + this.passwordlessLogin(authClient, email, verificationCode); + // We need to optimistically save the user to our database here. The user is saved to the _Auth0_ + // database after the passwordlessLogin method succeeds. Following that we need to save user data in our + // backend. Ideally, this should be done after a success callback after passwordlessLogin succceds; + // however, the passwordlessLogin success callback does not fire within our app, because, upon success, Auth0 + // triggers a redirect to our home page. At that point, we do not have the user's name or organization, + // which we need to save in our database. Thus, we save the user here. + // + // If for some reason, the passwordlessLogin method errors, this code still save the user in our DB. + // At that point, the worst case scenario is that the user will be informed that they have already + // signed up if they try to sign up again and to log in instead. The Auth0 passwordless flow does + // not have a sign-up process separate from its log-in process, and thus the user will still be + // created within Auth0 upon going through our site's log-in flow. + this.saveUser(email, name, organization); }; - // This method initiates the sign-in/sign-up process by sending a code + // This method initiates the log-in/sign-up process by sending a code // to the user's inbox. static passwordlessStart = (authClient: WebAuth, email: string) => { return new Promise((resolve, reject) => { @@ -109,7 +115,7 @@ export default class AuthService { authClient: WebAuth, email: string, verificationCode: string - ) => { + ) => { authClient.passwordlessLogin( { connection: "email", @@ -138,7 +144,7 @@ export default class AuthService { }; static hasAccessTokenExpired = (tokenExpiration: Date) => { - return !tokenExpiration || (new Date(tokenExpiration) < new Date()); + return !tokenExpiration || new Date(tokenExpiration) < new Date(); }; static refreshAccessToken = (authClient: WebAuth) => { @@ -155,28 +161,38 @@ export default class AuthService { static userExists = (email: string) => { return new Promise((resolve, reject) => { - post('/api/users/user_exists', { - email - }).then((resp) => { - resp.json().then(result => resolve(result.user_exists)); - }, (error) => { - reject(error); - }) + post("/api/users/user_exists", { + email, + }).then( + (resp) => { + resp.json().then((result) => resolve(result.user_exists)); + }, + (error) => { + reject(error); + } + ); }); - } + }; - static saveUser = (email: string, name: string, organization: (string | null) = null) => { + static saveUser = ( + email: string, + name: string, + organization: string | null = null + ) => { return new Promise((resolve, reject) => { - const response = post('/api/users', { + const response = post("/api/users", { email, name, organization, }); - response.then((result) => { - resolve(result); - }, (error) => { - reject(error); - }) + response.then( + (result) => { + resolve(result); + }, + (error) => { + reject(error); + } + ); }); - } + }; } diff --git a/config.example.yml b/config.example.yml index 072bb9abc..ee577734e 100644 --- a/config.example.yml +++ b/config.example.yml @@ -24,4 +24,4 @@ MOHCD_SUBDOMAIN: "testing" AUTH0_AUDIENCE: "http://localhost:8080/api" AUTH0_CLIENT_ID: "UcnuRrX6S0SeDEhW9PRe01wEhcvIRuwc" AUTH0_DOMAIN: "dev-nykixf8szsm220fi.us.auth0.com" -AUTH0_REDIRECT_URI: "http://localhost:8080" \ No newline at end of file +AUTH0_REDIRECT_URI: "http://localhost:8080"