Skip to content

Commit

Permalink
feat: Password reset (#42)
Browse files Browse the repository at this point in the history
* feat: forgot paassword

* feat: update client
  • Loading branch information
bhoopesh369 authored Feb 22, 2024
1 parent 9495682 commit d1cbe68
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 42 deletions.
2 changes: 1 addition & 1 deletion fest-web-client
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
},
"dependencies": {
"@fest-web-client/client": "./fest-web-client/client/",
"@types/react-modal": "^3.16.3",
"axios": "^1.6.2",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
Expand All @@ -24,6 +25,7 @@
"react-google-recaptcha": "^3.1.0",
"react-hot-toast": "^2.4.1",
"react-markdown": "^9.0.1",
"react-modal": "^3.16.1",
"react-parallax-tilt": "^1.7.201",
"rehype-raw": "^7.0.0",
"sharp": "^0.33.2",
Expand Down
124 changes: 124 additions & 0 deletions src/app/forgotPassword/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/* eslint-disable camelcase */
/* eslint-disable @typescript-eslint/ban-ts-comment */
'use client';
import Modal from 'react-modal';

import styles from './resetpass.module.css';
import toast from 'react-hot-toast';
import { useRouter, useSearchParams } from 'next/navigation';
import { useState } from 'react';
import { UserApi } from '../../../fest-web-client/client/src';
import { apiConfig } from '@/utils/ApiConfig';
import ReCAPTCHA from 'react-google-recaptcha';
import { RECAPTCHA_SITE_KEY } from '@/config/config';

const ForgotPasswordPage: React.FC = () => {
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [recaptchaToken, setRecaptchaToken] = useState<string>('');

const router = useRouter();

const searchParams = useSearchParams();

const handleResetPassword = () => {
if (recaptchaToken == '') {
toast.error('Please verify the captcha');
return;
}

if (!password || password.length < 8) {
toast.error('Password must be atleast 8 characters long');
return;
}
if (password !== confirmPassword) {
toast.error('Passwords do not match');
return;
}

const code = searchParams.get('code');
const email = searchParams.get('email');

const userApi = new UserApi(apiConfig);

if (code && email) {
userApi
.changePassword({
// @ts-ignore-next-line
user_code: code,
user_email: email,
user_password: password,
user_recaptcha_code: recaptchaToken,
})
.then(res => {
// @ts-ignore-next-line
toast.success(res.message);
router.push('/login');
})
.catch(err => {
toast.error(err.message);
});
} else {
toast.error('Invalid code or email');
}
};

const handleCaptchaSubmission = (token: string | null) => {
if (token) {
setRecaptchaToken(token);
}
};

return (
<>
<div className={styles.forgotPasswordPage}>
<Modal
isOpen={true}
ariaHideApp={false}
className="w-[50%] h-[50%] bg-[#1d1c1c] rounded-xl absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
>
<div className={styles.resetFormContainer}>
<div className={styles.formFields}>
<div className={styles.formField}>
<div className={styles.formLabel}>New Password*</div>
<input
className={styles.formInput}
type="password"
onChange={e => {
setPassword(e.target.value);
}}
/>
</div>
<div className={styles.formField}>
<div className={styles.formLabel}>Confirm Password*</div>
<input
className={styles.formInput}
type="password"
onChange={e => {
setConfirmPassword(e.target.value);
}}
/>
</div>
</div>
<div
className={
styles.recaptchaContainer + ' flex items-center justify-center'
}
>
<ReCAPTCHA
sitekey={RECAPTCHA_SITE_KEY}
onChange={handleCaptchaSubmission}
theme={'dark'}
/>
</div>
<button className={styles.registerButton} onClick={handleResetPassword}>
Reset Password
</button>
</div>
</Modal>
</div>
</>
);
};

export default ForgotPasswordPage;
89 changes: 89 additions & 0 deletions src/app/forgotPassword/resetpass.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
.forgotPasswordPage {
background-color: #000000;
background-image: radial-gradient(#3391e880 2%, transparent 0%);
width: calc(100vw);
height: calc(100vh);
display: flex;
justify-content: center;
align-items: center;
}

.formFields {
display: flex;
flex-direction: column;
width: 100%;
justify-content: center;
align-items: center;
}

.formField {
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
margin-bottom: 8%;
}

.formField:last-child {
margin-bottom: 3%;
}

.formLabel {
font-size: 1rem;
margin-bottom: 0.5rem;
color: #e4e4e4;
}

.formInput {
background: #230d0e;
border: none;
border-left: 1rem solid #56d1da80;
border-right: 1rem solid #56d1da80;
height: 2.5rem;
width: 100%;
width: 100%;
color: #a3a4a3;
padding: 0rem 1rem;
}

.resetFormContainer {
display: flex;
flex-direction: column;
color: #242424;
font-family: "Space Grotesk", sans-serif;
padding: 2.5rem;
border: 1px solid #56d1da80;
margin: 1px;
}

.registerButton {
font-family: "Space Grotesk";
background-color: transparent;
border: none;
/* background: url("../../assets/button-bg.svg"); */
background-size: 100% 100%;
position: relative;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
margin-top: 1rem;
color: #4aff1c;
font-size: 1.1rem;
padding: 0.8rem 0.8rem;
font-weight: 600;
border: 2px solid #56d1da80;
border-radius: 10px;
}

@media screen and (max-width: 600px) {
.resetFormContainer {
margin: 1.5rem;
}
}

@media screen and (max-width: 400px) {
.resetFormContainer {
padding: 1rem;
}
}
1 change: 0 additions & 1 deletion src/components/AuthLayout/form.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ div.formInput {
flex-direction: column;
color: #cacac9;
padding: 2.5rem;
border: 1px solid #e8333b80;
margin: 1px;
}

Expand Down
110 changes: 73 additions & 37 deletions src/components/AuthLayout/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import { useCallback, useState } from 'react';
import styles from './form.module.css';
import { FormInput } from './input';
import { UserApi } from '../../../fest-web-client/client/src';
import { authConfig } from '@/utils/ApiConfig';
import { apiConfig, authConfig } from '@/utils/ApiConfig';
import { useRouter } from 'next/navigation';
import { DAUTH_CLIENT_ID, DAUTH_REDIRECT_URI } from '@/config/config';
import { DAUTH_CLIENT_ID, DAUTH_REDIRECT_URI, RECAPTCHA_SITE_KEY } from '@/config/config';
import toast from 'react-hot-toast';
import Modal from 'react-modal';
import ReCAPTCHA from 'react-google-recaptcha';

interface DauthQueryParameters {
[key: string]: string;
Expand All @@ -21,6 +23,11 @@ export const Login: React.FC<SignupFormProps> = ({ setForm }) => {
userPassword: '',
});

const [isOpen, setIsOpen] = useState<boolean>(false);

const [forgotPasswordEmail, setForgotPasswordEmail] = useState<string>('');
const [recaptchaToken, setRecaptchaToken] = useState<string>('');

const isMobile = false;

const router = useRouter();
Expand Down Expand Up @@ -148,6 +155,34 @@ export const Login: React.FC<SignupFormProps> = ({ setForm }) => {
}
};

const handleForgotPassword = async () => {
const userApi = new UserApi(apiConfig);
try {
console.log(forgotPasswordEmail);
await userApi
.verifyEmail({
// @ts-ignore-next-line
user_email: forgotPasswordEmail,
user_recaptcha_code: recaptchaToken,
})
.then(res => {
// @ts-ignore-next-line
toast.success(res.message);
})
.catch(e => {
toast.error(e.message);
});
} catch (err) {
console.log(err);
}
};

const handleCaptchaSubmission = (token: string | null) => {
if (token) {
setRecaptchaToken(token);
}
};

return (
<>
<div className={styles.formContainer}>
Expand All @@ -170,11 +205,8 @@ export const Login: React.FC<SignupFormProps> = ({ setForm }) => {
/>
</div>
<div className={styles.formFieldExtras}>
<div
className={styles.forgotPassword}
// onClick={() => setIsOpen(true)}
>
<div>Forgot Password?</div>
<div className={styles.forgotPassword} onClick={() => setIsOpen(true)}>
<div className="font-ROG text-[#fffc47]">Forgot Password?</div>
</div>
<div>
<span className={styles.newHere}>New Here?</span>
Expand Down Expand Up @@ -203,36 +235,40 @@ export const Login: React.FC<SignupFormProps> = ({ setForm }) => {
</div>
<div className={styles.formFieldSubmitContainer}>{/* <DAuthLogin /> */}</div>
</div>
{/* <Modal
isOpen={modalIsOpen}
onRequestClose={() => setIsOpen(false)}
ariaHideApp={false}
>
<div className={styles.resetFormContainer}>
<div className={styles.formFields}>
<div className={styles.formField}>
<div className={styles.formLabel}>Email*</div>
<input
className={styles.formInput}
type="email"
value={forgotPasswordEmail}
onChange={(e) => {
setForgotPasswordEmail(e.target.value);
}}
/>
</div>
<div className={styles.formField}>
<Recaptcha handleFormFields={handleRecaptcha} />
</div>
</div>
<button
className={styles.registerButton}
onClick={handleForgotPassword}
>
Reset Password
</button>
</div>
</Modal> */}
<Modal
isOpen={isOpen}
onRequestClose={() => setIsOpen(false)}
ariaHideApp={false}
className="w-[50%] h-[50%] bg-[#1a1a1a] rounded-xl absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
>
<div className={styles.resetFormContainer}>
<div className={styles.formFields}>
<div className={styles.formField}>
<div className={styles.formLabel}>Email*</div>
<input
className={styles.formInput}
type="email"
value={forgotPasswordEmail}
onChange={e => {
console.log(e.target.value);
setForgotPasswordEmail(e.target.value);
}}
/>
</div>
<div className={styles.formField + ' flex items-center justify-center'}>
{/* <Recaptcha handleFormFields={handleRecaptcha} /> */}
<ReCAPTCHA
sitekey={RECAPTCHA_SITE_KEY}
onChange={handleCaptchaSubmission}
theme={'dark'}
/>
</div>
</div>
<button className={styles.registerButton} onClick={handleForgotPassword}>
Reset Password
</button>
</div>
</Modal>
</>
);
};
Loading

0 comments on commit d1cbe68

Please sign in to comment.