diff --git a/backend/app/rest/auth_routes.py b/backend/app/rest/auth_routes.py index 7fe0dc85..f74b0b18 100644 --- a/backend/app/rest/auth_routes.py +++ b/backend/app/rest/auth_routes.py @@ -271,3 +271,18 @@ def is_verified(): except Exception as e: error_message = getattr(e, "message", None) return jsonify({"error": (error_message if error_message else str(e))}), 500 + + +@blueprint.route( + "/resend-verify/", methods=["POST"], strict_slashes=False +) +def resend_verify(email): + """ + Resends a verification email to a specific email + """ + try: + auth_service.send_email_verification_link(email) + return "", 200 + except Exception as e: + error_message = getattr(e, "message", None) + return jsonify({"error": (error_message if error_message else str(e))}), 500 diff --git a/backend/app/services/implementations/auth_service.py b/backend/app/services/implementations/auth_service.py index 7539553b..ccf88e5b 100644 --- a/backend/app/services/implementations/auth_service.py +++ b/backend/app/services/implementations/auth_service.py @@ -253,5 +253,5 @@ def is_authorized_by_token(self, access_token): firebase_user = firebase_admin.auth.get_user(decoded_id_token["uid"]) return firebase_user.email_verified except Exception as e: - print(e) + self.logger.error(e) return False diff --git a/frontend/src/APIClients/AuthAPIClient.ts b/frontend/src/APIClients/AuthAPIClient.ts index d036a3e5..7d0f8801 100644 --- a/frontend/src/APIClients/AuthAPIClient.ts +++ b/frontend/src/APIClients/AuthAPIClient.ts @@ -175,6 +175,21 @@ const isVerified = async (): Promise => { } }; +const resendVerify = async (email: string): Promise => { + const bearerToken = `Bearer ${getLocalStorageObjProperty( + AUTHENTICATED_USER_KEY, + "accessToken", + )}`; + try { + await baseAPIClient.post(`/auth/resend-verify/${email}`, { + headers: { Authorization: bearerToken }, + }); + return true; + } catch (error) { + return false; + } +}; + // for testing only, refresh does not need to be exposed in the client const refresh = async (): Promise => { try { @@ -202,5 +217,6 @@ export default { register, resetPassword, isVerified, + resendVerify, refresh, }; diff --git a/frontend/src/components/pages/Auth/VerificationPage.tsx b/frontend/src/components/pages/Auth/VerificationPage.tsx index 14222ca6..6d2bc309 100644 --- a/frontend/src/components/pages/Auth/VerificationPage.tsx +++ b/frontend/src/components/pages/Auth/VerificationPage.tsx @@ -1,27 +1,28 @@ import React, { useState, useContext } from "react"; import { useHistory } from "react-router-dom"; import { Box, Button, Flex, Spinner, Text } from "@chakra-ui/react"; -import authAPIClient from "../../../APIClients/AuthAPIClient"; import CreateToast from "../../common/Toasts"; import AuthContext from "../../../contexts/AuthContext"; import { HOME_PAGE } from "../../../constants/Routes"; import AUTHENTICATED_USER_KEY from "../../../constants/AuthConstants"; import { AuthenticatedUser } from "../../../types/AuthTypes"; +import AuthAPIClient from "../../../APIClients/AuthAPIClient"; const VerificationPage = (): React.ReactElement => { const newToast = CreateToast(); const history = useHistory(); const { authenticatedUser, setAuthenticatedUser } = useContext(AuthContext); - const [isLoading, setIsLoading] = useState(false); + const [isVerifyLoading, setIsVerifyLoading] = useState(false); + const [isResendLoading, setIsResendLoading] = useState(false); const handleVerification = async () => { if (authenticatedUser) { - setIsLoading(true); - const isVerified = await authAPIClient.isVerified(); + setIsVerifyLoading(true); + const isVerified = await AuthAPIClient.isVerified(); if (isVerified === false) { - setIsLoading(false); + setIsVerifyLoading(false); newToast( "Not Verified", "Please check your email for the verification email.", @@ -44,6 +45,26 @@ const VerificationPage = (): React.ReactElement => { } }; + const resendVerify = async () => { + if (authenticatedUser) { + const { email } = authenticatedUser; + setIsResendLoading(true); + + const success = await AuthAPIClient.resendVerify(email); + + if (success) { + newToast("Success", `An email has been resent to ${email}.`, "success"); + } else { + newToast( + "Error", + `Unable to resend an email to ${email}. Please try again.`, + "error", + ); + } + setIsResendLoading(false); + } + }; + return ( @@ -60,13 +81,14 @@ const VerificationPage = (): React.ReactElement => { - In order to start using your SHOW account, you need to confirm - your email address. + To verify your email address, a verification link has been sent to + your inbox. After clicking the link in the email, click the button + below to proceed. - {isLoading ? ( + {isVerifyLoading ? ( { )} + + + + + Didn't recieve an email? + + resendVerify()}> + Click here to resend + + {isResendLoading && ( + + )} + +