Skip to content

Commit

Permalink
[BarClerk-553] - [Markup] Create Password reset page (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
impaulintech authored Nov 7, 2022
1 parent 2abdd5d commit df036e8
Show file tree
Hide file tree
Showing 20 changed files with 322 additions and 84 deletions.
11 changes: 6 additions & 5 deletions client/components/atoms/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ type Props = {
isDisabled?: boolean
onClick?: (value?: any) => void
className?: string
isSubmitting: boolean
isSubmitting?: boolean
}

const Button = ({ isDisabled = false, onClick, value, className, isSubmitting }: Props) => {
Expand All @@ -15,10 +15,11 @@ const Button = ({ isDisabled = false, onClick, value, className, isSubmitting }:
onClick={onClick}
disabled={isDisabled || isSubmitting}
className={`
inline-flex w-full justify-center rounded-sm border border-transparent bg-barclerk-10
py-1.5 px-4 text-md font-medium text-white shadow-sm focus:outline-none disabled:cursor-not-allowed
disabled:opacity-50 hover:bg-barclerk-10/70 disabled:hover:bg-opacity-50 active:scale-95
${className}`}>
inline-flex w-full justify-center rounded-sm border border-transparent bg-barclerk-10
py-1.5 px-4 text-md font-medium text-white shadow-sm focus:outline-none disabled:cursor-not-allowed
disabled:opacity-50 hover:bg-barclerk-10/70 disabled:hover:bg-opacity-50 active:scale-95
${className}`}
>
{value}
</button>
);
Expand Down
8 changes: 4 additions & 4 deletions client/components/molecules/CustomForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const CustomForm = ({

return (
<div className="w-full">
<label htmlFor="last_name" className="block text-md font-medium text-white">
<label htmlFor="last_name" className="block text-md font-medium text-dark">
<small className="text-failed">*</small> {label}
</label>
<div>
Expand All @@ -39,8 +39,8 @@ const CustomForm = ({
px-2 pb-1
placeholder-text-failed
outline-none focus:ring-1 focus:border-failed
block w-full h-[36px] rounded-sm border-[2px] border-barclerk-light py-0.5
${touched && error && "text-failed border-failed"}
block w-full h-[36px] rounded-sm border-[2px] border-blue-400 py-0.5
${touched && error && "text-failed !border-failed"}
${className}
`}
/>
Expand All @@ -57,7 +57,7 @@ const CustomForm = ({
)}
</div>
</div>
{touched && error && <span className="text-failed">{error}</span>}
{touched && error && <span className="text-failed font-medium">{error}</span>}
</div>
);
};
Expand Down
13 changes: 13 additions & 0 deletions client/components/templates/AdminAuthTemplate/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react";

const AdminAuthTemplate = ({ children, hasBorder = false }: any) => {
return (
<main className="bg-barclerk-60 mobile:!bg-barclerk-30 min-h-screen h-full mobile:pb-20 mobile:pt-10 py-10 flex justify-center items-center px-10">
<div className={`bg-barclerk-30 p-20 mobile:p-0 rounded-3xl shadow-2xl mobile:shadow-none ${hasBorder && "!border-t-[15px] !border-barclerk-10 py-10 mobile:!border-none"}`}>
{children}
</div>
</main>
);
};

export default AdminAuthTemplate;
12 changes: 12 additions & 0 deletions client/components/templates/MaintenancePage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ const MaintenancePage = () => {
<h1 className='text-2xl text-slate-200 font-medium text-center'>This page is currently under maintenance.</h1>
<span className='text-xl text-slate-400 font-medium mobile:text-lg'>Please comeback soon!</span>
</main>
<button
type="submit"
onClick={() => {
window.location.pathname = "/";
}}
className={`
inline-flex w-[30%] justify-center rounded-lg border border-transparent bg-barclerk-10 mt-5
py-1.5 px-4 text-md font-medium text-white shadow-sm focus:outline-none disabled:cursor-not-allowed
disabled:opacity-50 hover:bg-els-10/70 disabled:hover:bg-opacity-50 active:scale-95
`}>
Go Home
</button>
</div>
);
};
Expand Down
54 changes: 36 additions & 18 deletions client/hooks/authMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import { reset, signIn, signOut, signUp } from 'redux/auth/authSlice';
export const useAuthMethods = () => {
const { error } = useAppSelector((state: Store) => state.auth);
const dispatch = useAppDispatch();
const router = useRouter();
const router = useRouter();

const handleAuthSignOut = async () => {
dispatch(reset());
toast.promise(
dispatch(signOut()).then(() => {
router.push('/');
router.push('/sign-in');
}),
{
loading: 'Signing out...',
Expand All @@ -24,35 +24,53 @@ export const useAuthMethods = () => {
);
};

const handleSignInSubmit = async ( data: SignInUpFormValues ): Promise<void> => {
dispatch(signIn(data))
.then(({ payload })=>{
const { content, status }= payload || {};
const handleSignInSubmit = async (
data: SignInUpFormValues
): Promise<void> => {
dispatch(signIn(data)).then(({ payload }) => {
const { content, status } = payload || {};

if(status) return toast.error(content?.email);
toast.success("Welcome to dashboard!");
if (status) return toast.error(content?.email);
toast.success('Welcome to dashboard!');
router.push('/');
})
});
};

const handleSignUpSubmit = async (
data: SignInUpFormValues
): Promise<void> => {
toast.promise(
dispatch(signUp(data)).then(() => {
router.push('/');
}),
{
loading: 'Creating your account please wait...',
success: 'Account created successfully!',
error: error.content,
const creatingAccount = toast.loading('Creating your account...');

dispatch(signUp(data)).then(({ payload }) => {
const { status } = payload || {};
toast.dismiss(creatingAccount);

if (status) {
return toast.error('Something went wrong.\nPlease try again later.');
}
);

toast.success('Account created successfully!');
router.push('/');
});
};

const ResetLinkSubmit = async (
data: SignInUpFormValues
): Promise<void> => {

};

const ForgotPasswordSubmit = async (
data: SignInUpFormValues
): Promise<void> => {

};

return {
ResetLinkSubmit,
handleAuthSignOut,
handleSignInSubmit,
handleSignUpSubmit,
ForgotPasswordSubmit,
};
};
34 changes: 34 additions & 0 deletions client/hooks/useRememberMe.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {
getCookie,
setCookie,
deleteCookie
} from "cookies-next";
import { Cookie } from "shared/types";
import React, { useState } from "react";

const useRememberMe = () => {
const [rememberMe, setRememberMe] = useState<string>("");

const rememberedEmail: Cookie = getCookie('email') || "";
const isRemembered: Cookie = getCookie('isRemembered') || false;

const onChangeRemember = (e: { target: any }) => {
const { value, name } = e.target;
if (name === "password") return;

setRememberMe(value);
if (isRemembered) return setCookie('email', value);
}

const onClickRemember = (e: { target: any }) => {
const { checked } = e.target;

setCookie('isRemembered', checked);
if (!checked) return deleteCookie('email');
setCookie('email', rememberMe)
}

return { rememberedEmail, isRemembered, onChangeRemember, onClickRemember };
};

export default useRememberMe;
11 changes: 5 additions & 6 deletions client/pages/404.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,23 @@ const NotFound: NextPage = (): JSX.Element => {
<span className='font-extrabold text-9xl'>4</span>
<div className='flex-shrink-0 z-50'>
<img
src="/images/404.png"
alt="Cry Emoji Image"
src="/images/lawgo.png"
alt="lawgo"
width={192}
height={192}
placeholder="blur"
height={192}
/>
</div>
<span className='font-extrabold text-9xl'>4</span>
</header>
<section className='flex flex-col items-center gap-3 pb-5'>
<h2 className='text-xl uppercase font-bold'>Oops! Page not be found</h2>
<p className='text-slate-300 text-sm text-center'>
Sorry but the page you are looking for does not exist, have been removed. name changed
Sorry but the page that you are looking for does not exist, have been removed, name changed,
or is temporarily unavailable
</p>
</section>
<Link href="/">
<span className='px-6 py-3 rounded-full bg-barclerk-10 hover:bg-barclerk-10/70 text-white font-semibold hover:shadow-xl transition ease-in-out duration-150 focus:outline-none cursor-pointer'>Back to Homepage</span>
<span className='px-6 py-3 rounded-xl bg-barclerk-10 hover:bg-barclerk-10/70 text-white font-semibold hover:shadow-xl transition ease-in-out duration-150 focus:outline-none cursor-pointer'>Back to Homepage</span>
</Link>
</div>
</main>
Expand Down
132 changes: 132 additions & 0 deletions client/pages/forgot-password.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@

/* eslint-disable @next/next/no-img-element */
import Router from "next/router";
import { Formik, Form } from "formik";
import React, { useState, useEffect } from "react";

import {
ForgotPasswordFormSchema,
ResetLinkSubmitFormSchema
} from "shared/validation";
import Button from "components/atoms/Button";
import NextHead from "components/atoms/NextHead";
import { useAuthMethods } from "hooks/authMethods";
import CustomForm from "components/molecules/CustomForm";
import AdminAuthTemplate from "components/templates/AdminAuthTemplate";

const ForgotPassword = () => {
const { state }: any = Router?.router || {};
const { user, verified } = state?.query || {};
const { handleSignInSubmit, ResetLinkSubmit } = useAuthMethods();
const [isPassHidden, setIsPassHidden] = useState<boolean>(true);
const [isLinkClicked, setIsLinkClicked] = useState<boolean>(false);

useEffect(() => {
setIsLinkClicked((user && verified) ? true : false);
}, [user, verified, isLinkClicked]);

const setRequestResetLinkInitialValue = {
email: "",
};
const RequestResetLink = () => {
return (
<Formik
initialValues={setRequestResetLinkInitialValue}
validationSchema={ResetLinkSubmitFormSchema}
onSubmit={async ({ email }: { email: any; }) => {
await ResetLinkSubmit(email);
}}
>
{({ isSubmitting }): any => {
return (
<Form >
<div className="flex flex-col gap-4">
<CustomForm
label="Email address"
name="email"
type="email"
placeholder="[email protected]"
/>
</div>
<div className="flex flex-row gap-3 mt-10 mb-5">
<Button
value="Go Back"
onClick={(e) => {
e.preventDefault();
Router.push("/sign-in");
}}
className="!bg-transparent !text-light !border-2 !border-barclerk-10 hover:!border-transparent hover:!bg-barclerk-10/70"
/>
<Button isSubmitting={isSubmitting} value="Continue" />
</div>
</Form>
);
}}
</Formik>
);
};

const setupNewPasswordInitialValue = {
password: "",
password_confirmation: "",
};
const SetupNewPassword = (
<div className="flex flex-col">
<Formik
initialValues={setupNewPasswordInitialValue}
validationSchema={ForgotPasswordFormSchema}
onSubmit={handleSignInSubmit}
>
{({ isSubmitting }): any => {
return (
<Form className="-mt-3">
<div className="flex flex-col gap-3">
<CustomForm
label="Password"
name="password"
type={isPassHidden ? "password" : "text"}
placeholder="●●●●●●●"
isPassHidden={isPassHidden}
setIsPassHidden={setIsPassHidden}
/>
<CustomForm
label="Confirm Password"
name="password_confirmation"
type={isPassHidden ? "password" : "text"}
placeholder="●●●●●●●●"
/>
</div>
<div className="flex flex-row gap-3 mt-10 mb-5">
<Button
value="Go Back"
onClick={(e) => {
e.preventDefault();
Router.push("/forgot-password");
}}
className="!bg-transparent !text-light !border-2 !border-barclerk-10 hover:!border-transparent hover:!bg-barclerk-10/70"
/>
<Button isSubmitting={isSubmitting} value="Continue" />
</div>
</Form>
);
}}
</Formik>
</div>
);

return (
<>
<NextHead title="BarClerk | Sign In" />
<AdminAuthTemplate hasBorder={true}>
<div className="flex flex-col gap-10 w-[360px]">
<header className="flex flex-col items-center h-full justify-center">
<h1 className="text-[27px] font-semibold text-dark">{isLinkClicked ? "Setup your new password" : "Request password reset link"}</h1>
</header>
{isLinkClicked ? SetupNewPassword : <RequestResetLink />}
</div>
</AdminAuthTemplate>
</>
);
};

export default ForgotPassword;
11 changes: 10 additions & 1 deletion client/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import Button from "components/atoms/Button";
import MaintenancePage from "components/templates/MaintenancePage";
import { useAuthMethods } from "hooks/authMethods";

export default function Home() {
return <MaintenancePage />
const { handleAuthSignOut } = useAuthMethods();
return (
<div>
<MaintenancePage />
<Button onClick={handleAuthSignOut} value="Temporary Logout Button" className="absolute top-10 right-10 max-w-[150px] rounded-lg" />
</div>
)
}

Loading

0 comments on commit df036e8

Please sign in to comment.