From 9aba2f93e42fa773e53eb805589e7cbd6cb74a19 Mon Sep 17 00:00:00 2001 From: Mayura Andrew <48531182+mayura-andrew@users.noreply.github.com> Date: Tue, 11 Jun 2024 11:37:56 +0530 Subject: [PATCH] Bulk email send feature (#115) Co-authored-by: Anjula Shanaka --- src/App.tsx | 2 + src/components/ForgotPasswordModal/index.tsx | 117 ++++++++++++ src/components/Layout/Navbar/index.tsx | 8 + src/components/LoginModal/index.tsx | 10 +- .../MenteeApplication.component.tsx | 26 +-- src/components/MenteeProfile/index.tsx | 26 +-- .../MentorApplication.component.tsx | 26 +-- src/contexts/LoginModalContext.tsx | 19 ++ src/hooks/useForgotPassword.ts | 73 ++++++++ src/pages/Dashboard/scenes/Emails/Emails.tsx | 73 +++++++- .../MenteeApplications/MenteeApplications.tsx | 50 +----- .../MentorApplicationPage.tsx | 2 +- .../MentorApplications/MentorApplications.tsx | 40 +---- src/pages/PasswordReset/index.tsx | 170 ++++++++++++++++++ src/types.ts | 14 ++ 15 files changed, 537 insertions(+), 119 deletions(-) create mode 100644 src/components/ForgotPasswordModal/index.tsx create mode 100644 src/hooks/useForgotPassword.ts create mode 100644 src/pages/PasswordReset/index.tsx diff --git a/src/App.tsx b/src/App.tsx index 47dd96c6..9264e47b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -15,6 +15,7 @@ import MenteeDashboard from './pages/MenteeDashboard'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import MenteeApplications from './pages/MenteeApplicationsView/MenteeApplications.component.tsx'; import { LoginModalProvider } from './contexts/LoginModalContext.tsx'; +import PasswordReset from './pages/PasswordReset/index.tsx'; const queryClient = new QueryClient(); @@ -45,6 +46,7 @@ const App: React.FC = () => { } /> } /> } /> + } /> diff --git a/src/components/ForgotPasswordModal/index.tsx b/src/components/ForgotPasswordModal/index.tsx new file mode 100644 index 00000000..0e0de2c0 --- /dev/null +++ b/src/components/ForgotPasswordModal/index.tsx @@ -0,0 +1,117 @@ +import React, { useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { useResetPassword } from '../../hooks/useForgotPassword'; +import { type PasswordResetData } from '../../types'; +import { z } from 'zod'; +import Loading from '../../assets/svg/Loading'; +import closeIcon from '../../assets/svg/closeIcon.svg'; + +const ForgotPasswordDataSchema = z.object({ + email: z.string(), +}); + +interface ForgotPasswordModalProps { + handleClose: () => void; +} + +const ForgotPasswordModal: React.FC = ({ + handleClose, +}) => { + const { register, handleSubmit } = useForm(); + + const [message, setMessage] = useState(''); + const [messageType, setMessageType] = useState('default'); + const { requestPasswordReset } = useResetPassword(); + const [loading, setLoading] = useState(false); + + const onSubmit = (data: PasswordResetData) => { + setLoading(true); + + const validatedData = ForgotPasswordDataSchema.parse(data); + requestPasswordReset(validatedData, { + onSuccess: () => { + setMessage( + `A password reset link has been sent to your email address. Please check your email and follow the instructions to reset your password. ` + ); + setMessageType('success'); + setLoading(false); + }, + onError: () => { + setMessage('Error sending email, Check your email and try again.'); + setMessageType('error'); + setLoading(false); + }, + }); + }; + + return ( +
+
+
+
+
+ +
+ + +
+
+

+ Reset Password +

+
+ + {message.length > 0 && ( +
+ {message} +
+ )} +
+ {loading ? ( +
+ +
+ ) : ( + messageType !== 'success' && ( +
+ +
+ ) + )} +
+
+
+
+
+
+
+ ); +}; +export default ForgotPasswordModal; diff --git a/src/components/Layout/Navbar/index.tsx b/src/components/Layout/Navbar/index.tsx index 36929362..9226584a 100644 --- a/src/components/Layout/Navbar/index.tsx +++ b/src/components/Layout/Navbar/index.tsx @@ -17,6 +17,7 @@ import { import LogoutModal from '../../LogoutModal'; import { Link, useNavigate } from 'react-router-dom'; import { useLoginModalContext } from '../../../contexts/LoginModalContext'; +import ForgotPasswordModal from '../../ForgotPasswordModal'; const Navbar: React.FC = () => { const [openMenu, setOpenMenu] = useState(false); @@ -24,12 +25,15 @@ const Navbar: React.FC = () => { isLoginModalVisible, isRegisterModalVisible, isLogoutModalVisible, + isForgotPasswordModalVisible, handleLoginModalClose, handleLoginModalOpen, handleRegisterModalClose, handleRegisterModalOpen, handleLogoutModalClose, handleLogoutModalOpen, + handleForgotPasswordModalOpen, + handleForgotPasswordModalClose, } = useLoginModalContext(); const [isDropdownOpen, setIsDropdownOpen] = useState(false); const dropdownRef: RefObject = useRef(null); @@ -285,6 +289,7 @@ const Navbar: React.FC = () => { ) : null} {isRegisterModalVisible ? ( @@ -294,6 +299,9 @@ const Navbar: React.FC = () => { /> ) : null} {isLogoutModalVisible && } + {isForgotPasswordModalVisible ? ( + + ) : null} ); }; diff --git a/src/components/LoginModal/index.tsx b/src/components/LoginModal/index.tsx index 75eaf36a..54efef2d 100644 --- a/src/components/LoginModal/index.tsx +++ b/src/components/LoginModal/index.tsx @@ -8,11 +8,13 @@ import GoogleLoginButton from '../OAuth/Google'; interface LoginModalProps { handleClose: () => void; onRegistrationClick: () => void; + onForgotPasswordClick: () => void; } const LoginModal: React.FC = ({ handleClose, onRegistrationClick, + onForgotPasswordClick, }) => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); @@ -124,7 +126,13 @@ const LoginModal: React.FC = ({ -

+

{ + onForgotPasswordClick(); + handleClose(); + }} + > Forgot Password?