changes to green theme

This commit is contained in:
Vikas Nale 2025-10-23 12:41:58 +05:30
parent 394d28f80d
commit 0d0b7f2cbc
7 changed files with 187 additions and 151 deletions

View File

@ -31,6 +31,8 @@
<link rel="stylesheet" href="/assets/css/default.css" /> <link rel="stylesheet" href="/assets/css/default.css" />
<link rel="stylesheet" href="/assets/css/skeleton.css" /> <link rel="stylesheet" href="/assets/css/skeleton.css" />
<link rel="stylesheet" href="/assets/css/hover-utility.css" /> <link rel="stylesheet" href="/assets/css/hover-utility.css" />
<link rel="stylesheet" href="/assets/css/theme-green.css" />
<link rel="stylesheet" href="/assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css" /> <link rel="stylesheet" href="/assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css" />

View File

@ -0,0 +1,55 @@
.btn-green {
background-color: #49bf3c;
color: #fff;
border-radius: 50px;
padding: 10px 30px;
font-weight: 500;
text-decoration: none;
transition: all 0.3s ease;
}
.btn-green-outline {
border-color: #49bf3c;
background-color: transparent;
color: unset;
}
.btn-green-outline:hover {
background-color: #49bf3c;
color: #fff;
}
.btn-square-small {
border-radius: 3px;
padding-bottom: 5.072px;
padding-inline-end: 12px;
padding-inline-start: 12px;
padding-left: 12px;
padding-right: 12px;
padding-top: 5.072px;
}
.btn-green:hover {
background-color: #00a85a;
color: #fff;
}
.text-blue {
color: #696cff !important;
}
.text-green {
color: #49bf3c !important;
}
.btn-outline-green {
border-radius: 50px;
padding: 10px 30px;
font-weight: 500;
text-decoration: none;
transition: all 0.3s ease;
}
.btn-outline-green:hover {
background-color: #49bf3c;
color: #fff;
}

View File

@ -28,16 +28,13 @@
color: #4fc143; color: #4fc143;
} }
.text-primary { /* .text-primary {
color: #49bf3c !important; color: #49bf3c !important;
} } */
.text-blue {
color: #696cff !important;
}
.btn-primary { /* .btn-primary {
background-color: #49bf3c !important; background-color: #49bf3c !important;
} } */
body { body {
font-family: "Segoe UI", Roboto, sans-serif; font-family: "Segoe UI", Roboto, sans-serif;
@ -238,28 +235,3 @@ body {
margin-top: 15px; margin-top: 15px;
margin-bottom: 25px; margin-bottom: 25px;
} }
.btn-green {
background-color: #49bf3c;
color: #fff;
border-radius: 50px;
padding: 10px 30px;
font-weight: 500;
text-decoration: none;
transition: all 0.3s ease;
}
.btn-square-small {
border-radius: 3px;
padding-bottom: 5.072px;
padding-inline-end: 12px;
padding-inline-start: 12px;
padding-left: 12px;
padding-right: 12px;
padding-top: 5.072px;
}
.btn-green:hover {
background-color: #00a85a;
color: #fff;
}

View File

@ -14,7 +14,7 @@ const LandingPage = () => {
<div className="container-fluid px-5 w-100"> <div className="container-fluid px-5 w-100">
<div className="row w-100"> <div className="row w-100">
<div className="col-md-auto d-flex justify-content-between align-items-center"> <div className="col-md-auto d-flex justify-content-between align-items-center">
<a className="navbar-brand fw-bold text-primary" href="#"> <a className="navbar-brand fw-bold text-green" href="#">
<span className="text-blue">OnField</span> <span className="text-blue">OnField</span>
<span>Work</span> <span>Work</span>
<span className="text-dark">.com</span> <span className="text-dark">.com</span>
@ -187,7 +187,7 @@ const LandingPage = () => {
<div className="card-slider p-4 bg-light rounded-4 h-100 text-start border"> <div className="card-slider p-4 bg-light rounded-4 h-100 text-start border">
<div className="feature-icon mb-3"> <div className="feature-icon mb-3">
<img <img
src="../../../public/img/icons/dashboard.png" src="/img/icons/dashboard.png"
alt="Dashboard" alt="Dashboard"
className="w-14 mb-4 feature-icon-image" className="w-14 mb-4 feature-icon-image"
/> />
@ -203,7 +203,7 @@ const LandingPage = () => {
<div className="card-slider p-4 bg-light rounded-4 h-100 text-start border"> <div className="card-slider p-4 bg-light rounded-4 h-100 text-start border">
<div className="feature-icon mb-3"> <div className="feature-icon mb-3">
<img <img
src="../../../public/img/icons/attendance.png" src="/img/icons/attendance.png"
alt="Smart Attendance" alt="Smart Attendance"
className="w-14 mb-4 feature-icon-image" className="w-14 mb-4 feature-icon-image"
/> />
@ -220,7 +220,7 @@ const LandingPage = () => {
<div className="card-slider p-4 bg-light rounded-4 h-100 text-start border"> <div className="card-slider p-4 bg-light rounded-4 h-100 text-start border">
<div className="feature-icon mb-3"> <div className="feature-icon mb-3">
<img <img
src="../../../public/img/icons/spending.png" src="/img/icons/spending.png"
alt="Expense & Budget Tracking" alt="Expense & Budget Tracking"
className="w-14 mb-4 feature-icon-image" className="w-14 mb-4 feature-icon-image"
/> />
@ -236,7 +236,7 @@ const LandingPage = () => {
<div className="card-slider p-4 bg-light rounded-4 h-100 text-start border"> <div className="card-slider p-4 bg-light rounded-4 h-100 text-start border">
<div className="feature-icon mb-3"> <div className="feature-icon mb-3">
<img <img
src="../../../public/img/icons/directory.png" src="/img/icons/directory.png"
alt="Cloud Scalability" alt="Cloud Scalability"
className="w-14 mb-4 feature-icon-image" className="w-14 mb-4 feature-icon-image"
/> />
@ -252,7 +252,7 @@ const LandingPage = () => {
<div className="card-slider p-4 bg-light rounded-4 h-100 text-start border"> <div className="card-slider p-4 bg-light rounded-4 h-100 text-start border">
<div className="feature-icon mb-3"> <div className="feature-icon mb-3">
<img <img
src="../../../public/img/icons/report.png" src="/img/icons/report.png"
alt="Advanced Reporting" alt="Advanced Reporting"
className="w-14 mb-4 feature-icon-image" className="w-14 mb-4 feature-icon-image"
/> />
@ -269,7 +269,7 @@ const LandingPage = () => {
<div className="card-slider p-4 bg-light rounded-4 h-100 text-start border"> <div className="card-slider p-4 bg-light rounded-4 h-100 text-start border">
<div className="feature-icon mb-3"> <div className="feature-icon mb-3">
<img <img
src="../../../public/img/icons/cloud-service.png" src="/img/icons/cloud-service.png"
alt="Cloud Scalability" alt="Cloud Scalability"
className="w-14 mb-4 feature-icon-image" className="w-14 mb-4 feature-icon-image"
/> />
@ -298,7 +298,7 @@ const LandingPage = () => {
<div className="col-md-4"> <div className="col-md-4">
<div className="card pricing-card border-0 shadow-sm"> <div className="card pricing-card border-0 shadow-sm">
<div className="card-body"> <div className="card-body">
<h5 className="text-primary fw-bold">Starter</h5> <h5 className="text-green fw-bold">Starter</h5>
<h2> <h2>
499<span className="fs-6 text-muted">/month</span> 499<span className="fs-6 text-muted">/month</span>
</h2> </h2>
@ -317,7 +317,7 @@ const LandingPage = () => {
<div className="col-md-4"> <div className="col-md-4">
<div className="card pricing-card border-primary shadow-lg"> <div className="card pricing-card border-primary shadow-lg">
<div className="card-body"> <div className="card-body">
<h5 className="text-primary fw-bold">Professional</h5> <h5 className="text-green fw-bold">Professional</h5>
<h2> <h2>
999<span className="fs-6 text-muted">/month</span> 999<span className="fs-6 text-muted">/month</span>
</h2> </h2>
@ -339,7 +339,7 @@ const LandingPage = () => {
<div className="col-md-4"> <div className="col-md-4">
<div className="card pricing-card border-0 shadow-sm"> <div className="card pricing-card border-0 shadow-sm">
<div className="card-body"> <div className="card-body">
<h5 className="text-primary fw-bold">Enterprise</h5> <h5 className="text-green fw-bold">Enterprise</h5>
<h2>Custom</h2> <h2>Custom</h2>
<ul className="list-unstyled mt-3 mb-4 text-muted"> <ul className="list-unstyled mt-3 mb-4 text-muted">
<li>Dedicated support</li> <li>Dedicated support</li>
@ -360,14 +360,14 @@ const LandingPage = () => {
<div className="container text-start" style={{ maxWidth: "75%" }}> <div className="container text-start" style={{ maxWidth: "75%" }}>
<h2 className="fw-bold mb-4 text-center"> <h2 className="fw-bold mb-4 text-center">
About{" "} About{" "}
<a className="text-primary" href="#"> <a className="text-green" href="#">
<span className="text-blue">OnField</span> <span className="text-blue">OnField</span>
<span>Work</span> <span>Work</span>
<span className="text-dark">.com</span> <span className="text-dark">.com</span>
</a> </a>
</h2> </h2>
<p> <p>
<a className="text-primary" href="#"> <a className="text-green" href="#">
<span className="text-blue">OnField</span> <span className="text-blue">OnField</span>
<span>Work</span> <span>Work</span>
<span className="text-dark">.com</span> <span className="text-dark">.com</span>
@ -378,7 +378,7 @@ const LandingPage = () => {
<p> <p>
Whether you manage on-site teams, oversee multiple projects, or Whether you manage on-site teams, oversee multiple projects, or
coordinate vendors and suppliers,{" "} coordinate vendors and suppliers,{" "}
<a className="text-primary" href="#"> <a className="text-green" href="#">
<span className="text-blue">OnField</span> <span className="text-blue">OnField</span>
<span>Work</span> <span>Work</span>
<span className="text-dark">.com</span> <span className="text-dark">.com</span>
@ -388,7 +388,7 @@ const LandingPage = () => {
operations. operations.
</p> </p>
<h5> Our Mission</h5> At{" "} <h5> Our Mission</h5> At{" "}
<a className="text-primary" href="#"> <a className="text-green" href="#">
<span className="text-blue">OnField</span> <span className="text-blue">OnField</span>
<span>Work</span> <span>Work</span>
<span className="text-dark">.com</span> <span className="text-dark">.com</span>
@ -401,7 +401,7 @@ const LandingPage = () => {
a comprehensive suite of tools designed to handle every critical a comprehensive suite of tools designed to handle every critical
aspect of field management from workforce tracking to expense aspect of field management from workforce tracking to expense
control and reporting. With control and reporting. With
<a className="text-primary" href="#"> <a className="text-green" href="#">
<span className="text-blue">OnField</span> <span className="text-blue">OnField</span>
<span>Work</span> <span>Work</span>
<span className="text-dark">.com</span> <span className="text-dark">.com</span>
@ -443,7 +443,7 @@ const LandingPage = () => {
</ul> </ul>
<h5> <h5>
Why Choose{" "} Why Choose{" "}
<a className="text-primary" href="#"> <a className="text-green" href="#">
<span className="text-blue">OnField</span> <span className="text-blue">OnField</span>
<span>Work</span> <span>Work</span>
<span className="text-dark">.com</span> <span className="text-dark">.com</span>
@ -498,7 +498,7 @@ const LandingPage = () => {
aria-expanded="true" aria-expanded="true"
aria-controls="accordionOne" aria-controls="accordionOne"
> >
What is MarcoPMS? What is OnFieldWork.com?
</button> </button>
</h2> </h2>
<div <div
@ -552,7 +552,7 @@ const LandingPage = () => {
aria-expanded="false" aria-expanded="false"
aria-controls="accordionThree" aria-controls="accordionThree"
> >
How secure is Marco PMS? How secure is OnFieldWork.com?
</button> </button>
</h2> </h2>
<div <div
@ -562,14 +562,14 @@ const LandingPage = () => {
data-bs-parent="#accordionExample" data-bs-parent="#accordionExample"
> >
<div className="accordion-body text-start"> <div className="accordion-body text-start">
Security is at the core of Marco PMS. We use industry-standard Security is at the core of OnFieldWork.com. We use
encryption (SSL/TLS) to protect data in transit and advanced industry-standard encryption (SSL/TLS) to protect data in
encryption to safeguard data at rest. Role-based access transit and advanced encryption to safeguard data at rest.
controls ensure that only authorized users can access Role-based access controls ensure that only authorized users
sensitive information. Our system is hosted on secure, can access sensitive information. Our system is hosted on
cloud-ready infrastructure with regular backups, monitoring, secure, cloud-ready infrastructure with regular backups,
and compliance with best practices to keep your data safe and monitoring, and compliance with best practices to keep your
available at all times. data safe and available at all times.
</div> </div>
</div> </div>
</div> </div>
@ -621,8 +621,8 @@ const LandingPage = () => {
data-bs-parent="#accordionExample" data-bs-parent="#accordionExample"
> >
<div className="accordion-body text-start"> <div className="accordion-body text-start">
Marco PMS operate under a proprietary license combined with a OnFieldWork.com operate under a proprietary license combined
subscription model. This means customers dont own the with a subscription model. This means customers dont own the
software but are granted the right to access and use it software but are granted the right to access and use it
through the cloud under our Terms of Service. Depending on the through the cloud under our Terms of Service. Depending on the
plan, licensing may be based on users, features, or usage, and plan, licensing may be based on users, features, or usage, and
@ -640,7 +640,7 @@ const LandingPage = () => {
aria-expanded="false" aria-expanded="false"
aria-controls="accordionSix" aria-controls="accordionSix"
> >
Can I customize Marco PMS for my business needs? Can I customize OnFieldWork.com for my business needs?
</button> </button>
</h2> </h2>
<div <div
@ -650,8 +650,8 @@ const LandingPage = () => {
data-bs-parent="#accordionExample" data-bs-parent="#accordionExample"
> >
<div className="accordion-body text-start"> <div className="accordion-body text-start">
Yes, Marco PMS is designed to be flexible and adaptable. You Yes, OnFieldWork.com is designed to be flexible and adaptable.
can customize workflows, user roles, permissions, and You can customize workflows, user roles, permissions, and
reporting to match your organizations unique processes. reporting to match your organizations unique processes.
Depending on your plan, we also support advanced customization Depending on your plan, we also support advanced customization
such as integrating with third-party tools, adding custom such as integrating with third-party tools, adding custom
@ -680,7 +680,7 @@ const LandingPage = () => {
</div> </div>
<div className="col-lg-6 contact-text"> <div className="col-lg-6 contact-text">
<h2> <h2>
Contact <span className="text-success">Us</span> Contact <span className="text-green">Us</span>
</h2> </h2>
<p> <p>
Wed love to hear from you! Whether you have a question about Wed love to hear from you! Whether you have a question about

View File

@ -1,6 +1,6 @@
import { useState } from "react"; import { useState } from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { AuthWrapper } from "./AuthWrapper" import { AuthWrapper } from "./AuthWrapper";
import "./page-auth.css"; import "./page-auth.css";
import AuthRepository from "../../repositories/AuthRepository"; import AuthRepository from "../../repositories/AuthRepository";
import showToast from "../../services/toastService"; import showToast from "../../services/toastService";
@ -8,54 +8,65 @@ import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod"; import { z } from "zod";
const forgotPassSceham = z.object({ const forgotPassSceham = z.object({
email: z.string().trim().email(), email: z.string().trim().email(),
}) });
const ForgotPasswordPage = () => { const ForgotPasswordPage = () => {
const [loding, setLoading] = useState(false);
const [loding, setLoading] = useState(false) const {
register,
const { register,
handleSubmit, handleSubmit,
formState: { errors }, formState: { errors },
reset, reset,
getValues } = useForm({ getValues,
resolver: zodResolver(forgotPassSceham), } = useForm({
defaultValues: { resolver: zodResolver(forgotPassSceham),
email: "" defaultValues: {
} email: "",
}) },
});
const onSubmit = async (data) => { const onSubmit = async (data) => {
try { try {
setLoading(true) setLoading(true);
const response = await AuthRepository.forgotPassword(data) const response = await AuthRepository.forgotPassword(data);
if (response.data && response.success) if (response.data && response.success)
showToast("verification email has been sent to your registered email address", "success") showToast(
reset() "verification email has been sent to your registered email address",
setLoading(false) "success"
);
reset();
setLoading(false);
} catch (err) { } catch (err) {
reset() reset();
if (err.response.status === 404) { if (err.response.status === 404) {
showToast("verification email has been sent to your registered email address", "success") showToast(
"verification email has been sent to your registered email address",
"success"
);
} else { } else {
showToast("Something wrong", "error") showToast("Something wrong", "error");
} }
setLoading(false) setLoading(false);
} }
} };
return ( return (
<div className="col-12 col-lg-5 col-xl-4 d-flex align-items-center p-4 p-sm-5 bg-gray-60"> <div className="col-12 col-lg-5 col-xl-4 d-flex align-items-center p-4 p-sm-5 bg-gray-60">
<div className="w-100" style={{ maxWidth: 420, margin: "0 auto" }}> <div className="w-100" style={{ maxWidth: 420, margin: "0 auto" }}>
<h4 className="mb-2">Forgot Password? 🔒</h4> <h4 className="mb-2">Forgot Password? 🔒</h4>
<p className="mb-4"> <p className="mb-4">
Enter your email and we'll send you instructions to reset your password Enter your email and we'll send you instructions to reset your
password
</p> </p>
<form id="formAuthentication" className="mb-3" onSubmit={handleSubmit(onSubmit)}> <form
id="formAuthentication"
className="mb-3"
onSubmit={handleSubmit(onSubmit)}
>
<div className="mb-3 text-start"> <div className="mb-3 text-start">
<label htmlFor="email" className="form-label"> <label htmlFor="email" className="form-label">
Email Email
@ -78,23 +89,22 @@ const ForgotPasswordPage = () => {
</div> </div>
)} )}
</div> </div>
<button aria-label="Click me" className="btn btn-primary d-grid w-100"> <button aria-label="Click me" className=" btn-green d-grid w-100">
{loding ? "Please Wait..." : "Send Reset Link"} {loding ? "Please Wait..." : "Send Reset Link"}
</button> </button>
</form> </form>
<div className="text-center"> <div className="text-center">
<Link <Link
aria-label="Go to Login Page" aria-label="Go to Login Page"
to="/auth/login" to="/auth/login"
className="d-flex align-items-center justify-content-center" className="d-flex align-items-center justify-content-center text-green"
> >
<i className="bx bx-chevron-left scaleX-n1-rtl bx-sm"></i> <i className="bx bx-chevron-left scaleX-n1-rtl bx-sm text-green"></i>
Back to login Back to login
</Link> </Link>
</div> </div>
{/* Footer Text */} {/* Footer Text */}
</div> </div>
</div> </div>
); );

View File

@ -49,16 +49,16 @@ const LoginPage = () => {
// sessionStorage.setItem("refreshToken", response.data.refreshToken); // sessionStorage.setItem("refreshToken", response.data.refreshToken);
// } // }
setLoading(false); setLoading(false);
localStorage.setItem("jwtToken", response.data.token); localStorage.setItem("jwtToken", response.data.token);
localStorage.setItem("refreshToken", response.data.refreshToken); localStorage.setItem("refreshToken", response.data.refreshToken);
navigate("/dashboard",{ replace: true }); navigate("/dashboard", { replace: true });
} else { } else {
await AuthRepository.sendOTP({ email: data.username }); await AuthRepository.sendOTP({ email: data.username });
showToast("OTP has been sent to your email.", "success"); showToast("OTP has been sent to your email.", "success");
localStorage.setItem("otpUsername", data.username); localStorage.setItem("otpUsername", data.username);
localStorage.setItem("otpSentTime", now.toString()); localStorage.setItem("otpSentTime", now.toString());
// navigate("/auth/login-otp"); // navigate("/auth/login-otp");
navigate("/dashboard",{ replace: true }); navigate("/dashboard", { replace: true });
} }
} catch (err) { } catch (err) {
showToast("Invalid username or password.", "error"); showToast("Invalid username or password.", "error");
@ -78,14 +78,13 @@ const LoginPage = () => {
}, [IsLoginWithOTP]); }, [IsLoginWithOTP]);
useEffect(() => { useEffect(() => {
const token = const token =
localStorage.getItem("jwtToken") || localStorage.getItem("jwtToken") || sessionStorage.getItem("jwtToken");
sessionStorage.getItem("jwtToken");
if (token) { if (token) {
navigate("/dashboard", { replace: true }); navigate("/dashboard", { replace: true });
} }
}, []); }, []);
return ( return (
<div className="col-12 col-lg-5 col-xl-4 d-flex align-items-center p-4 p-sm-5 bg-gray-60"> <div className="col-12 col-lg-5 col-xl-4 d-flex align-items-center p-4 p-sm-5 bg-gray-60">
@ -182,7 +181,7 @@ const LoginPage = () => {
</div> </div>
<Link <Link
to="/auth/forgot-password" to="/auth/forgot-password"
className="text-decoration-none" className="text-decoration-none text-green"
> >
Forgot Password? Forgot Password?
</Link> </Link>
@ -191,11 +190,7 @@ const LoginPage = () => {
)} )}
{/* Submit */} {/* Submit */}
<button <button type="submit" className=" btn-green w-100" disabled={loading}>
type="submit"
className="btn btn-primary w-100"
disabled={loading}
>
{loading {loading
? "Please Wait..." ? "Please Wait..."
: IsLoginWithOTP : IsLoginWithOTP
@ -211,7 +206,7 @@ const LoginPage = () => {
</div> </div>
<button <button
type="button" type="button"
className="btn btn-outline-secondary w-100" className="btn-green btn-green-outline w-100"
onClick={() => setLoginWithOtp(true)} onClick={() => setLoginWithOtp(true)}
> >
Login With OTP Login With OTP
@ -224,17 +219,20 @@ const LoginPage = () => {
{!IsLoginWithOTP ? ( {!IsLoginWithOTP ? (
<p className="text-center mt-3"> <p className="text-center mt-3">
<span>New on our platform? </span> <span>New on our platform? </span>
<Link to="/auth/reqest/demo" className="btn btn-link p-0"> <Link
to="/auth/reqest/demo"
className="btn btn-link p-0 text-green"
>
Request a Demo Request a Demo
</Link> </Link>
</p> </p>
) : ( ) : (
<div className="text-center mt-3"> <div className="text-center mt-3">
<button <button
className="btn btn-link p-0" className="btn btn-link p-0 text-green"
onClick={() => setLoginWithOtp(false)} onClick={() => setLoginWithOtp(false)}
> >
<i className="bx bx-chevron-left scaleX-n1-rtl bx-sm"></i> <i className="bx bx-chevron-left scaleX-n1-rtl bx-sm "></i>
Back to login Back to login
</button> </button>
</div> </div>

View File

@ -21,7 +21,6 @@ const LoginWithOtp = () => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [timeLeft, setTimeLeft] = useState(0); const [timeLeft, setTimeLeft] = useState(0);
const inputRefs = useRef([]); const inputRefs = useRef([]);
const { const {
@ -43,17 +42,16 @@ const LoginWithOtp = () => {
try { try {
let requestedData = { let requestedData = {
email: username, email: username,
otp: finalOtp otp: finalOtp,
} };
const response = await AuthRepository.verifyOTP(requestedData) const response = await AuthRepository.verifyOTP(requestedData);
localStorage.setItem("jwtToken", response.data.token); localStorage.setItem("jwtToken", response.data.token);
localStorage.setItem("refreshToken", response.data.refreshToken); localStorage.setItem("refreshToken", response.data.refreshToken);
setLoading(false); setLoading(false);
localStorage.removeItem("otpUsername"); localStorage.removeItem("otpUsername");
localStorage.removeItem("otpSentTime"); localStorage.removeItem("otpSentTime");
navigate("/auth/switch/org"); navigate("/auth/switch/org");
} catch (err) { } catch (err) {
showToast("Invalid or expired OTP.", "error"); showToast("Invalid or expired OTP.", "error");
@ -61,7 +59,9 @@ const LoginWithOtp = () => {
} }
}; };
const formatTime = (seconds) => { const formatTime = (seconds) => {
const min = Math.floor(seconds / 60).toString().padStart(2, "0"); const min = Math.floor(seconds / 60)
.toString()
.padStart(2, "0");
const sec = (seconds % 60).toString().padStart(2, "0"); const sec = (seconds % 60).toString().padStart(2, "0");
return `${min}:${sec}`; return `${min}:${sec}`;
}; };
@ -78,7 +78,6 @@ const LoginWithOtp = () => {
} }
}, []); }, []);
useEffect(() => { useEffect(() => {
if (timeLeft <= 0) return; if (timeLeft <= 0) return;
@ -112,22 +111,22 @@ const LoginWithOtp = () => {
} }
trigger(["otp1", "otp2", "otp3", "otp4"]); trigger(["otp1", "otp2", "otp3", "otp4"]);
} else { } else {
showToast("Invalid OTP format pasted. Please enter 4 digits") showToast("Invalid OTP format pasted. Please enter 4 digits");
for (let i = 0; i < 4; i++) { for (let i = 0; i < 4; i++) {
setValue(`otp${i + 1}`, "") setValue(`otp${i + 1}`, "");
} }
} }
} };
return ( return (
// <AuthWrapper> // <AuthWrapper>
<div className="col-12 col-lg-5 col-xl-4 d-flex align-items-center justify-content-center p-4 p-sm-5 bg-gray-60 h-100"> <div className="col-12 col-lg-5 col-xl-4 d-flex align-items-center justify-content-center p-4 p-sm-5 bg-gray-60 h-100">
<div className="block p-4 p-sm-5 bg-gray-60"> <div className="block p-4 p-sm-5 bg-gray-60">
<h4>Verify Your OTP</h4> <h4>Verify Your OTP</h4>
<p className="mb-4">Please enter the 4-digit code sent to your email.</p> <p className="mb-4">
Please enter the 4-digit code sent to your email.
</p>
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<div className="d-flex justify-content-center gap-6 mb-3"> <div className="d-flex justify-content-center gap-6 mb-3">
@ -139,8 +138,9 @@ const LoginWithOtp = () => {
key={num} key={num}
type="text" type="text"
maxLength={1} maxLength={1}
className={`form-control text-center ${errors[`otp${num}`] ? "is-invalid" : "" className={`form-control text-center ${
}`} errors[`otp${num}`] ? "is-invalid" : ""
}`}
ref={(el) => { ref={(el) => {
inputRefs.current[idx] = el; inputRefs.current[idx] = el;
ref(el); ref(el);
@ -150,7 +150,6 @@ const LoginWithOtp = () => {
onChange(e); onChange(e);
if (/^\d$/.test(val) && idx < 3) { if (/^\d$/.test(val) && idx < 3) {
inputRefs.current[idx + 1]?.focus(); inputRefs.current[idx + 1]?.focus();
} else if (val === "" && idx > 0) { } else if (val === "" && idx > 0) {
inputRefs.current[idx - 1]?.focus(); inputRefs.current[idx - 1]?.focus();
} }
@ -164,7 +163,6 @@ const LoginWithOtp = () => {
inputRefs.current[idx - 1]?.focus(); inputRefs.current[idx - 1]?.focus();
} }
}} }}
onPaste={idx === 0 ? handlePaste : undefined} onPaste={idx === 0 ? handlePaste : undefined}
style={{ width: "40px", height: "40px", fontSize: "15px" }} style={{ width: "40px", height: "40px", fontSize: "15px" }}
{...rest} {...rest}
@ -184,7 +182,7 @@ const LoginWithOtp = () => {
<button <button
type="submit" type="submit"
className="btn btn-primary d-grid w-100" className="btn-green d-grid w-100"
disabled={loading} disabled={loading}
> >
{loading ? "Verifying..." : "Verify OTP"} {loading ? "Verifying..." : "Verify OTP"}
@ -199,19 +197,20 @@ const LoginWithOtp = () => {
</p> </p>
) : ( ) : (
<div> <div>
<p <p className="text-center text-danger mt-2 text small-text m-0">
className="text-center text-danger mt-2 text small-text m-0"
>
OTP has expired. Please request a new one. OTP has expired. Please request a new one.
</p> </p>
<a className="text-primary cursor-pointer" onClick={() => navigate('/auth/login')}>Try Again</a> <a
className="text-green cursor-pointer"
onClick={() => navigate("/auth/login")}
>
Try Again
</a>
</div> </div>
)} )}
</form> </form>
</div>
</div> </div>
</div>
// </AuthWrapper> // </AuthWrapper>
); );
}; };