Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
sweepstake
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Arjun Jhukal
sweepstake
Commits
66776795
Commit
66776795
authored
Oct 10, 2025
by
Arjun Jhukal
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
updated the minor changes
parent
80064300
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
320 additions
and
320 deletions
+320
-320
index.tsx
src/components/pages/auth/VerifyOtp/index.tsx
+195
-195
index.tsx
src/components/pages/auth/forgotPassword/index.tsx
+125
-125
No files found.
src/components/pages/auth/VerifyOtp/index.tsx
View file @
66776795
"use client"
;
//
"use client";
import
React
,
{
useState
,
useEffect
,
useRef
}
from
"react"
;
//
import React, { useState, useEffect, useRef } from "react";
import
{
Box
,
Button
,
Typography
,
CircularProgress
}
from
"@mui/material"
;
//
import { Box, Button, Typography, CircularProgress } from "@mui/material";
import
Image
from
"next/image"
;
//
import Image from "next/image";
import
{
useRouter
}
from
"next/navigation"
;
//
import { useRouter } from "next/navigation";
import
{
PATH
}
from
"@/routes/PATH"
;
//
import { PATH } from "@/routes/PATH";
import
{
useForgotPasswordMutation
,
useVerifyOTPMutation
}
from
"@/services/authApi"
;
//
import { useForgotPasswordMutation, useVerifyOTPMutation } from "@/services/authApi";
import
{
useAppDispatch
}
from
"@/hooks/hook"
;
//
import { useAppDispatch } from "@/hooks/hook";
import
{
showToast
,
ToastVariant
}
from
"@/slice/toastSlice"
;
//
import { showToast, ToastVariant } from "@/slice/toastSlice";
export
default
function
VerifyOTPPage
()
{
//
export default function VerifyOTPPage() {
const
router
=
useRouter
();
//
const router = useRouter();
const
dispatch
=
useAppDispatch
();
//
const dispatch = useAppDispatch();
const
[
otp
,
setOtp
]
=
useState
<
string
[]
>
([
""
,
""
,
""
,
""
,
""
,
""
]);
//
const [otp, setOtp] = useState<string[]>(["", "", "", "", "", ""]);
const
inputRefs
=
useRef
<
(
HTMLInputElement
|
null
)[]
>
([]);
//
const inputRefs = useRef<(HTMLInputElement | null)[]>([]);
const
[
email
,
setEmail
]
=
useState
<
string
|
null
>
(
null
);
//
const [email, setEmail] = useState<string | null>(null);
const
[
forgotPassword
,
{
isLoading
:
sending
}]
=
useForgotPasswordMutation
();
//
const [forgotPassword, { isLoading: sending }] = useForgotPasswordMutation();
const
[
verifyOTP
,
{
isLoading
:
verifying
}]
=
useVerifyOTPMutation
();
//
const [verifyOTP, { isLoading: verifying }] = useVerifyOTPMutation();
// ✅ Get stored email
//
// ✅ Get stored email
useEffect
(()
=>
{
//
useEffect(() => {
const
storedData
=
localStorage
.
getItem
(
"passwordResetData"
);
//
const storedData = localStorage.getItem("passwordResetData");
if
(
storedData
)
{
//
if (storedData) {
const
parsed
=
JSON
.
parse
(
storedData
);
//
const parsed = JSON.parse(storedData);
setEmail
(
parsed
.
email
||
parsed
.
emailAddress
||
null
);
//
setEmail(parsed.email || parsed.emailAddress || null);
}
//
}
},
[]);
//
}, []);
// ✅ Back to login
//
// ✅ Back to login
const
handleBackToLogin
=
()
=>
{
//
const handleBackToLogin = () => {
localStorage
.
removeItem
(
"passwordResetData"
);
//
localStorage.removeItem("passwordResetData");
router
.
replace
(
PATH
.
AUTH
.
LOGIN
.
ROOT
);
//
router.replace(PATH.AUTH.LOGIN.ROOT);
};
//
};
// ✅ Handle OTP input change
//
// ✅ Handle OTP input change
const
handleChange
=
(
value
:
string
,
index
:
number
)
=>
{
//
const handleChange = (value: string, index: number) => {
if
(
!
/^
\d
*$/
.
test
(
value
))
return
;
//
if (!/^\d*$/.test(value)) return;
const
newOtp
=
[...
otp
];
//
const newOtp = [...otp];
newOtp
[
index
]
=
value
;
//
newOtp[index] = value;
setOtp
(
newOtp
);
//
setOtp(newOtp);
if
(
value
&&
index
<
5
)
{
//
if (value && index < 5) {
inputRefs
.
current
[
index
+
1
]?.
focus
();
//
inputRefs.current[index + 1]?.focus();
}
//
}
};
//
};
const
handleKeyDown
=
(
e
:
React
.
KeyboardEvent
<
HTMLInputElement
>
,
index
:
number
)
=>
{
//
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>, index: number) => {
if
(
e
.
key
===
"Backspace"
&&
!
otp
[
index
]
&&
index
>
0
)
{
//
if (e.key === "Backspace" && !otp[index] && index > 0) {
inputRefs
.
current
[
index
-
1
]?.
focus
();
//
inputRefs.current[index - 1]?.focus();
}
//
}
};
//
};
// ✅ Verify OTP
//
// ✅ Verify OTP
const
handleSubmit
=
async
(
e
:
React
.
FormEvent
)
=>
{
//
const handleSubmit = async (e: React.FormEvent) => {
e
.
preventDefault
();
//
e.preventDefault();
const
enteredOTP
=
otp
.
join
(
""
);
//
const enteredOTP = otp.join("");
if
(
enteredOTP
.
length
<
6
)
{
//
if (enteredOTP.length < 6) {
dispatch
(
showToast
({
message
:
"Please enter all 6 digits"
,
variant
:
ToastVariant
.
ERROR
}));
//
dispatch(showToast({ message: "Please enter all 6 digits", variant: ToastVariant.ERROR }));
return
;
//
return;
}
//
}
if
(
!
email
)
{
//
if (!email) {
dispatch
(
showToast
({
message
:
"Email not available"
,
variant
:
ToastVariant
.
ERROR
}));
//
dispatch(showToast({ message: "Email not available", variant: ToastVariant.ERROR }));
return
;
//
return;
}
//
}
try
{
//
try {
const
res
=
await
verifyOTP
({
email
,
otp
:
enteredOTP
}).
unwrap
();
//
const res = await verifyOTP({ email, otp: enteredOTP }).unwrap();
dispatch
(
//
dispatch(
showToast
({
//
showToast({
message
:
res
.
message
||
"OTP verified successfully!"
,
//
message: res.message || "OTP verified successfully!",
variant
:
ToastVariant
.
SUCCESS
,
//
variant: ToastVariant.SUCCESS,
})
//
})
);
//
);
router
.
push
(
PATH
.
AUTH
.
RESET_PASSWORD
.
ROOT
);
//
router.push(PATH.AUTH.RESET_PASSWORD.ROOT);
}
catch
(
err
:
any
)
{
//
} catch (err: any) {
dispatch
(
//
dispatch(
showToast
({
//
showToast({
message
:
err
?.
data
?.
message
||
"Invalid OTP"
,
//
message: err?.data?.message || "Invalid OTP",
variant
:
ToastVariant
.
ERROR
,
//
variant: ToastVariant.ERROR,
})
//
})
);
//
);
}
//
}
};
//
};
// ✅ Resend OTP using stored email
//
// ✅ Resend OTP using stored email
const
handleResendOTP
=
async
()
=>
{
//
const handleResendOTP = async () => {
if
(
!
email
)
{
//
if (!email) {
dispatch
(
//
dispatch(
showToast
({
//
showToast({
message
:
"Email not found in session. Please restart the process."
,
//
message: "Email not found in session. Please restart the process.",
variant
:
ToastVariant
.
ERROR
,
//
variant: ToastVariant.ERROR,
})
//
})
);
//
);
return
;
//
return;
}
//
}
try
{
//
try {
const
response
=
await
forgotPassword
({
email
}).
unwrap
();
//
const response = await forgotPassword({ email }).unwrap();
dispatch
(
//
dispatch(
showToast
({
//
showToast({
message
:
response
.
message
||
"OTP sent successfully!"
,
//
message: response.message || "OTP sent successfully!",
variant
:
ToastVariant
.
SUCCESS
,
//
variant: ToastVariant.SUCCESS,
})
//
})
);
//
);
}
catch
(
err
:
any
)
{
//
} catch (err: any) {
dispatch
(
//
dispatch(
showToast
({
//
showToast({
message
:
err
?.
data
?.
message
||
"Failed to resend OTP"
,
//
message: err?.data?.message || "Failed to resend OTP",
variant
:
ToastVariant
.
ERROR
,
//
variant: ToastVariant.ERROR,
})
//
})
);
//
);
}
//
}
};
//
};
return
(
//
return (
<
Box
className=
"max-w-[520px] mx-auto flex flex-col gap-3 items-center text-center"
>
//
<Box className="max-w-[520px] mx-auto flex flex-col gap-3 items-center text-center">
<
Image
src=
"/assets/images/verify-email.png"
alt=
"Verify OTP"
width=
{
180
}
height=
{
140
}
/>
//
<Image src="/assets/images/verify-email.png" alt="Verify OTP" width={180} height={140} />
<
h1
className=
"text-[24px] lg:text-[32px] leading-[120%] font-bold mb-4"
>
//
<h1 className="text-[24px] lg:text-[32px] leading-[120%] font-bold mb-4">
Enter the OTP to verify your account
//
Enter the OTP to verify your account
</
h1
>
//
</h1>
<
p
className=
"text-[14px] leading-[120%] font-normal lg:text-[16px] mb-6"
>
//
<p className="text-[14px] leading-[120%] font-normal lg:text-[16px] mb-6">
We’ve sent a 6-digit code to
{
" "
}
//
We’ve sent a 6-digit code to{" "}
<
strong
className=
"underline text-secondary"
>
//
<strong className="underline text-secondary">
{
email
||
"your email"
}
//
{email || "your email"}
</
strong
>
//
</strong>
</
p
>
//
</p>
<
form
onSubmit=
{
handleSubmit
}
className=
"w-full flex flex-col items-center gap-6"
>
//
<form onSubmit={handleSubmit} className="w-full flex flex-col items-center gap-6">
<
div
className=
"flex justify-center gap-3"
>
//
<div className="flex justify-center gap-3">
{
otp
.
map
((
digit
,
index
)
=>
(
//
{otp.map((digit, index) => (
<
input
//
<input
key=
{
index
}
//
key={index}
ref=
{
(
el
)
=>
(
inputRefs
.
current
[
index
]
=
el
)
}
// ✅ type safe ref
//
ref={(el) => (inputRefs.current[index] = el)} // ✅ type safe ref
type=
"text"
//
type="text"
inputMode=
"numeric"
//
inputMode="numeric"
maxLength=
{
1
}
//
maxLength={1}
value=
{
digit
}
//
value={digit}
onChange=
{
(
e
)
=>
handleChange
(
e
.
target
.
value
,
index
)
}
//
onChange={(e) => handleChange(e.target.value, index)}
onKeyDown=
{
(
e
)
=>
handleKeyDown
(
e
,
index
)
}
//
onKeyDown={(e) => handleKeyDown(e, index)}
className=
"w-12 h-14 text-center text-[24px] font-semibold border border-gray-300 rounded-md focus:outline-none focus:border-primary transition-all"
//
className="w-12 h-14 text-center text-[24px] font-semibold border border-gray-300 rounded-md focus:outline-none focus:border-primary transition-all"
/>
//
/>
))
}
//
))}
</
div
>
//
</div>
<
Button
//
<Button
fullWidth
//
fullWidth
size=
"large"
//
size="large"
type=
"submit"
//
type="submit"
variant=
"contained"
//
variant="contained"
color=
"primary"
//
color="primary"
disabled=
{
verifying
}
//
disabled={verifying}
>
//
>
{
verifying
?
"Verifying..."
:
"Verify OTP"
}
//
{verifying ? "Verifying..." : "Verify OTP"}
</
Button
>
//
</Button>
</
form
>
//
</form>
<
Typography
variant=
"h6"
className=
"text-[20px] lg:text-[28px] leading-[120%] font-bold"
>
//
<Typography variant="h6" className="text-[20px] lg:text-[28px] leading-[120%] font-bold">
Didn’t get the code?
//
Didn’t get the code?
</
Typography
>
//
</Typography>
<
p
className=
"text-[11px] lg:text-[14px] leading-[150%] font-normal"
>
//
<p className="text-[11px] lg:text-[14px] leading-[150%] font-normal">
Please check your
<
strong
>
spam or junk folder
</
strong
>
. Still not found?
{
" "
}
//
Please check your <strong>spam or junk folder</strong>. Still not found?{" "}
<
strong
>
Resend OTP below
</
strong
>
.
//
<strong>Resend OTP below</strong>.
</
p
>
//
</p>
<
Button
//
<Button
fullWidth
//
fullWidth
variant=
"contained"
//
variant="contained"
color=
"secondary"
//
color="secondary"
disabled=
{
sending
}
//
disabled={sending}
onClick=
{
handleResendOTP
}
//
onClick={handleResendOTP}
startIcon=
{
sending
&&
<
CircularProgress
size=
{
18
}
color=
"inherit"
/>
}
//
startIcon={sending && <CircularProgress size={18} color="inherit" />}
>
//
>
{
sending
?
"Sending..."
:
"Send Again"
}
//
{sending ? "Sending..." : "Send Again"}
</
Button
>
//
</Button>
<
Button
//
<Button
fullWidth
//
fullWidth
variant=
"outlined"
//
variant="outlined"
color=
"primary"
//
color="primary"
onClick=
{
handleBackToLogin
}
//
onClick={handleBackToLogin}
className=
"!mt-4"
//
className="!mt-4"
>
//
>
Back to Login
//
Back to Login
</
Button
>
//
</Button>
</
Box
>
//
</Box>
);
//
);
}
//
}
src/components/pages/auth/forgotPassword/index.tsx
View file @
66776795
"use client"
;
//
"use client";
import
React
from
"react"
;
//
import React from "react";
import
Link
from
"next/link"
;
//
import Link from "next/link";
import
{
PATH
}
from
"@/routes/PATH"
;
//
import { PATH } from "@/routes/PATH";
import
{
//
import {
Box
,
//
Box,
InputLabel
,
//
InputLabel,
OutlinedInput
,
//
OutlinedInput,
}
from
"@mui/material"
;
//
} from "@mui/material";
import
AuthMessageBlock
from
"../authMessageBlock"
;
//
import AuthMessageBlock from "../authMessageBlock";
import
{
useFormik
}
from
"formik"
;
//
import { useFormik } from "formik";
import
*
as
Yup
from
"yup"
;
//
import * as Yup from "yup";
import
{
useRouter
}
from
"next/navigation"
;
//
import { useRouter } from "next/navigation";
import
{
useAppDispatch
}
from
"@/hooks/hook"
;
//
import { useAppDispatch } from "@/hooks/hook";
import
{
useForgotPasswordMutation
}
from
"@/services/authApi"
;
//
import { useForgotPasswordMutation } from "@/services/authApi";
import
{
showToast
,
ToastVariant
}
from
"@/slice/toastSlice"
;
//
import { showToast, ToastVariant } from "@/slice/toastSlice";
export
default
function
ForgotPasswordPage
()
{
//
export default function ForgotPasswordPage() {
const
router
=
useRouter
();
//
const router = useRouter();
const
dispatch
=
useAppDispatch
();
//
const dispatch = useAppDispatch();
const
[
forgotPassword
,
{
isLoading
}]
=
useForgotPasswordMutation
();
//
const [forgotPassword, { isLoading }] = useForgotPasswordMutation();
const
{
//
const {
values
,
//
values,
errors
,
//
errors,
touched
,
//
touched,
handleBlur
,
//
handleBlur,
handleChange
,
//
handleChange,
handleSubmit
,
//
handleSubmit,
dirty
,
//
dirty,
}
=
useFormik
({
//
} = useFormik({
initialValues
:
{
//
initialValues: {
emailAddress
:
""
,
//
emailAddress: "",
},
//
},
validationSchema
:
Yup
.
object
({
//
validationSchema: Yup.object({
emailAddress
:
Yup
.
string
()
//
emailAddress: Yup.string()
.
email
(
"Invalid email format"
)
//
.email("Invalid email format")
.
required
(
"Email is required"
),
//
.required("Email is required"),
}),
//
}),
onSubmit
:
async
(
values
)
=>
{
//
onSubmit: async (values) => {
try
{
//
try {
const
response
=
await
forgotPassword
({
//
const response = await forgotPassword({
email
:
values
.
emailAddress
,
//
email: values.emailAddress,
}).
unwrap
();
//
}).unwrap();
// ✅ Show success toast
//
// ✅ Show success toast
dispatch
(
//
dispatch(
showToast
({
//
showToast({
message
:
response
.
message
||
"OTP sent successfully!"
,
//
message: response.message || "OTP sent successfully!",
variant
:
ToastVariant
.
SUCCESS
,
//
variant: ToastVariant.SUCCESS,
})
//
})
);
//
);
// ✅ Store email in localStorage correctly
//
// ✅ Store email in localStorage correctly
localStorage
.
setItem
(
//
localStorage.setItem(
"passwordResetData"
,
//
"passwordResetData",
JSON
.
stringify
({
email
:
values
.
emailAddress
})
//
JSON.stringify({ email: values.emailAddress })
);
//
);
// ✅ Navigate to Verify OTP page
//
// ✅ Navigate to Verify OTP page
router
.
push
(
PATH
.
AUTH
.
VERIFY_OTP
.
ROOT
);
//
router.push(PATH.AUTH.VERIFY_OTP.ROOT);
}
catch
(
error
:
any
)
{
//
} catch (error: any) {
console
.
error
(
"Error:"
,
error
);
//
console.error("Error:", error);
dispatch
(
//
dispatch(
showToast
({
//
showToast({
message
:
error
.
message
||
"Something went wrong"
,
//
message: error.message || "Something went wrong",
variant
:
ToastVariant
.
ERROR
,
//
variant: ToastVariant.ERROR,
})
//
})
);
//
);
}
//
}
},
//
},
});
//
});
return
(
//
return (
<>
//
<>
<
AuthMessageBlock
//
<AuthMessageBlock
title=
"Ready to get started and win BIG?"
//
title="Ready to get started and win BIG?"
features=
{
[
//
features={[
"Fun & Fair Gameplay"
,
//
"Fun & Fair Gameplay",
"Exciting Prizes"
,
//
"Exciting Prizes",
"Accessible Anytime, Anywhere"
,
//
"Accessible Anytime, Anywhere",
"Trusted & Secure"
,
//
"Trusted & Secure",
]
}
//
]}
/>
//
/>
<
Box
className=
"auth__form__wrapper lg:w-[50%] p-8"
>
//
<Box className="auth__form__wrapper lg:w-[50%] p-8">
<
div
className=
"section__title mb-4 lg:mb-6"
>
//
<div className="section__title mb-4 lg:mb-6">
<
h1
className=
"text-[24px] leading-[120%] font-bold lg:text-[48px]"
>
//
<h1 className="text-[24px] leading-[120%] font-bold lg:text-[48px]">
Setup an account
//
Setup an account
</
h1
>
//
</h1>
</
div
>
//
</div>
<
form
onSubmit=
{
handleSubmit
}
>
//
<form onSubmit={handleSubmit}>
<
div
className=
"grid md:grid-cols-2 gap-x-3 gap-y-5"
>
//
<div className="grid md:grid-cols-2 gap-x-3 gap-y-5">
<
div
className=
"col-span-2"
>
//
<div className="col-span-2">
<
div
className=
"input_field"
>
//
<div className="input_field">
<
InputLabel
htmlFor=
"emailAddress"
>
Email Address*
</
InputLabel
>
//
<InputLabel htmlFor="emailAddress">Email Address*</InputLabel>
<
OutlinedInput
//
<OutlinedInput
name=
"emailAddress"
//
name="emailAddress"
id=
"emailAddress"
//
id="emailAddress"
placeholder=
"example@example.com"
//
placeholder="example@example.com"
value=
{
values
.
emailAddress
}
//
value={values.emailAddress}
onChange=
{
handleChange
}
//
onChange={handleChange}
onBlur=
{
handleBlur
}
//
onBlur={handleBlur}
error=
{
Boolean
(
touched
.
emailAddress
&&
errors
.
emailAddress
)
}
//
error={Boolean(touched.emailAddress && errors.emailAddress)}
fullWidth
//
fullWidth
/>
//
/>
{
touched
.
emailAddress
&&
errors
.
emailAddress
?
(
//
{touched.emailAddress && errors.emailAddress ? (
<
span
className=
"error"
>
{
errors
.
emailAddress
}
</
span
>
//
<span className="error">{errors.emailAddress}</span>
)
:
null
}
//
) : null}
</
div
>
//
</div>
</
div
>
//
</div>
</
div
>
//
</div>
<
div
className=
"action__group text-center flex flex-col gap-4 mt-8"
>
//
<div className="action__group text-center flex flex-col gap-4 mt-8">
<
button
//
<button
type=
"submit"
//
type="submit"
className=
"ss-btn bg-primary-grad flex items-center justify-center"
//
className="ss-btn bg-primary-grad flex items-center justify-center"
disabled=
{
!
dirty
||
isLoading
}
//
disabled={!dirty || isLoading}
>
//
>
{
isLoading
?
"Sending OTP..."
:
"Send OTP"
}
//
{isLoading ? "Sending OTP..." : "Send OTP"}
</
button
>
//
</button>
<
Link
//
<Link
href=
{
PATH
.
AUTH
.
LOGIN
.
ROOT
}
//
href={PATH.AUTH.LOGIN.ROOT}
className=
"ss-btn bg-secondary-grad"
//
className="ss-btn bg-secondary-grad"
>
//
>
Back To Login
//
Back To Login
</
Link
>
//
</Link>
</
div
>
//
</div>
</
form
>
//
</form>
</
Box
>
//
</Box>
</>
//
</>
);
//
);
}
//
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment