Add confirm email page

This commit is contained in:
ariari04 2024-08-22 16:49:35 +06:00
parent 52c9f9a3b1
commit 38b869084d
8 changed files with 78 additions and 172 deletions

View File

@ -61,5 +61,14 @@
}, },
"rights": { "rights": {
"text": "All rights reserved" "text": "All rights reserved"
},
"confirmEmail": {
"checkEmail": "Check your email",
"codeSent": "We sent the code by email",
"code": "Confirmation code",
"submitBtn": "Submit",
"resendIn": "Resend code via",
"resendBtn": "Resend code",
"error": "An error occurred"
} }
} }

View File

@ -61,5 +61,14 @@
}, },
"rights": { "rights": {
"text": "Бардык укуктар корголгон" "text": "Бардык укуктар корголгон"
},
"confirmEmail": {
"checkEmail": "Электрондук почтаңызды текшериңиз",
"codeSent": "Кодду электрондук почта аркылуу жөнөттүк",
"code": "Ырастоо коду",
"submitBtn": "Тапшыруу",
"resendIn": "Кодду кайра жөнөтүү",
"resendBtn": "Кодду кайра жөнөтүү",
"error": "Ката кетти"
} }
} }

View File

@ -62,5 +62,14 @@
}, },
"rights": { "rights": {
"text": "Все права защищены" "text": "Все права защищены"
},
"confirmEmail": {
"checkEmail": "Проверьте свою почту",
"codeSent": "Мы отправили код на почту",
"code": "Код подтверждения",
"submitBtn": "Подтвердить",
"resendIn": "Отправить код повторно через",
"resendBtn": "Отправить код повторно",
"error": "Произошла ошибка"
} }
} }

View File

@ -1,6 +1,7 @@
import Image from "next/image"; import Image from "next/image";
import mail from "./icons/mail.svg"; import mail from "./icons/mail.svg";
import ConfirmEmailForm from "@/widgets/forms/ConfirmEmailForm/ConfirmEmailForm"; import ConfirmEmailForm from "@/widgets/forms/ConfirmEmailForm/ConfirmEmailForm";
import { useTranslations } from "next-intl";
const ConfirmEmail = ({ const ConfirmEmail = ({
searchParams, searchParams,
@ -9,6 +10,7 @@ const ConfirmEmail = ({
email: string; email: string;
}; };
}) => { }) => {
const t = useTranslations("confirmEmail");
return ( return (
<div className="py-[40px] px-[90px]"> <div className="py-[40px] px-[90px]">
<div className="h-full min-h-[800px] w-full flex justify-center"> <div className="h-full min-h-[800px] w-full flex justify-center">
@ -18,10 +20,10 @@ const ConfirmEmail = ({
</div> </div>
<div className="mb-2 flex flex-col items-center gap-2 text-center"> <div className="mb-2 flex flex-col items-center gap-2 text-center">
<h2 className="text-6 font-bold leading-8 text-gray-900"> <h2 className="text-6 font-bold leading-8 text-gray-900">
Проверьте свою почту {t("checkEmail")}
</h2> </h2>
<p className="leading-6 text-gray-500"> <p className="leading-6 text-gray-500">
Мы отправили код на почту {searchParams.email} {t("codeSent")} {searchParams.email}
</p> </p>
</div> </div>
<ConfirmEmailForm email={searchParams.email} /> <ConfirmEmailForm email={searchParams.email} />

View File

@ -18,7 +18,7 @@ const Footer = () => {
<p className="text-white font-normal">© {tRights("text")}</p> <p className="text-white font-normal">© {tRights("text")}</p>
<p className="text-white font-normal">{tDisclaimer("text")}</p> <p className="text-white font-normal">{tDisclaimer("text")}</p>
</div> </div>
<div className="flex flex-col gap-6"> <div className="flex flex-col gap-6 items-center">
<h4 className="h-fit text-white flex justify-start text-base font-bold leading-[110%]"> <h4 className="h-fit text-white flex justify-start text-base font-bold leading-[110%]">
{t("navigation")} {t("navigation")}
</h4> </h4>

View File

@ -44,7 +44,7 @@ const Navbar = () => {
/> />
<NavLanguage /> <NavLanguage />
</div> </div>
<nav className="hidden lg:flex lg:gap-x-6"> <nav className="hidden lg:flex lg:gap-x-4">
{LINKS().map((link) => ( {LINKS().map((link) => (
<Link <Link
className={`text-black opacity-0.5 size-4 font-normal min-w-[150px] flex justify-center${ className={`text-black opacity-0.5 size-4 font-normal min-w-[150px] flex justify-center${

View File

@ -1,140 +0,0 @@
.confirmEmailForm {
width: 360px;
display: flex;
flex-direction: column;
align-items: center;
&__inputs {
max-width: 360px;
margin-bottom: 50px;
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
label {
align-self: flex-start;
font-size: 14px;
font-weight: 400;
line-height: 20px;
color: gray;
}
}
.confirmEmailForm__inputsWrapper {
display: flex;
align-items: center;
gap: 6px;
input {
text-align: center;
padding: 8px;
max-width: 55px;
height: 64px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid rgb(208, 213, 221);
border-radius: 8px;
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
background: rgb(255, 255, 255);
font-size: 48px;
font-weight: 500;
line-height: 60px;
color: rgb(54, 149, 216);
::placeholder {
font-size: 48px;
font-weight: 500;
line-height: 60px;
color: gray;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input:focus {
border: 1px solid rgb(54, 149, 216);
border-radius: 8px;
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
background: rgb(255, 255, 255);
}
}
}
#confirmEmailForm__inputActive {
border: 1px solid rgb(54, 149, 216);
border-radius: 8px;
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
background: rgb(255, 255, 255);
}
button {
padding: 10px 18px;
height: 44px;
width: 100%;
border-radius: 8px;
font-size: 16px;
font-weight: 700;
line-height: 24px;
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
}
#confirm-email-form__send-code,
#confirm-email-form__send-code_active {
background-color: rgb(158, 167, 175);
color: #fff;
}
#confirm-email-form__send-code_active {
background-color: rgb(54, 149, 216);
color: #fff;
}
#confirm-email-form__resend-code,
#confirm-email-form__resend-code_active {
border: 1px solid rgb(158, 167, 175);
background-color: rgb(255, 255, 255);
color: rgb(158, 167, 175);
}
#confirm-email-form__resend-code_active {
background-color: rgb(54, 149, 216);
color: #fff;
}
&__error {
font-size: 16px;
font-weight: 400;
line-height: 24px;
color: red;
}
&__timer {
text-align: center;
margin: 32px 0;
font-size: 16px;
font-weight: 400;
line-height: 24px;
color: rgb(102, 112, 133);
span {
color: rgb(54, 149, 216);
}
}
}
@media screen and (max-width: 550px) {
.confirm-email-form {
width: 100%;
&__inputs {
&-wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
input {
width: 100%;
}
}
}
}
}

View File

@ -5,7 +5,8 @@ import { apiInstance } from "@/shared/config/apiConfig";
import { useRouter } from "@/shared/config/navigation"; import { useRouter } from "@/shared/config/navigation";
import { AxiosError } from "axios"; import { AxiosError } from "axios";
import Loader from "@/shared/ui/Loader/Loader"; import Loader from "@/shared/ui/Loader/Loader";
import s from "./ConfirmEmailForm.module.scss"; import { cn } from "@/lib/utils";
import { useTranslations } from "next-intl";
interface IConfirmEmailFormProps { interface IConfirmEmailFormProps {
email: string; email: string;
@ -14,6 +15,7 @@ interface IConfirmEmailFormProps {
const ConfirmEmailForm: React.FC<IConfirmEmailFormProps> = ({ const ConfirmEmailForm: React.FC<IConfirmEmailFormProps> = ({
email, email,
}: IConfirmEmailFormProps) => { }: IConfirmEmailFormProps) => {
const t = useTranslations("confirmEmail");
const router = useRouter(); const router = useRouter();
const [otp, setOtp] = useState(new Array(6).fill("")); const [otp, setOtp] = useState(new Array(6).fill(""));
const [seconds, setSeconds] = useState<number>(0); const [seconds, setSeconds] = useState<number>(0);
@ -32,19 +34,19 @@ const ConfirmEmailForm: React.FC<IConfirmEmailFormProps> = ({
e.target.previousSibling.focus(); e.target.previousSibling.focus();
} }
}; };
const handleSubmit: React.MouseEventHandler<HTMLFormElement> = async (e) => { const handleSubmit: React.MouseEventHandler<HTMLFormElement> = async (e) => {
e.preventDefault(); e.preventDefault();
const code = { const codeString = otp.join("");
code: +otp.join(""), const codeNumber = parseInt(codeString);
}; console.log(parseInt("01"));
try { try {
setLoader(true); setLoader(true);
console.log(codeNumber);
const response = await apiInstance.post("/users/confirm/", code); const response = await apiInstance.post("/auth/confirm_user/", {
code: codeNumber,
});
console.log(response);
if (response.status === 200 || response.status === 201) { if (response.status === 200 || response.status === 201) {
router.push("/sign-in"); router.push("/sign-in");
} }
@ -68,7 +70,7 @@ const ConfirmEmailForm: React.FC<IConfirmEmailFormProps> = ({
const data = { const data = {
email, email,
}; };
const response = await apiInstance.post("/users/resend_code/", data); const response = await apiInstance.post("/auth/send_mailcode/", data);
if ([200, 201].includes(response.status)) { if ([200, 201].includes(response.status)) {
setMinutes(1); setMinutes(1);
@ -96,36 +98,47 @@ const ConfirmEmailForm: React.FC<IConfirmEmailFormProps> = ({
}, [minutes, seconds]); }, [minutes, seconds]);
return ( return (
<form onSubmit={handleSubmit} className={s.confirmEmailForm}> <form
<div className={s.confirmEmailForm__inputs}> onSubmit={handleSubmit}
<label>Код подтверждения</label> className="w-[360px] flex flex-col items-center sm:w-full"
<div className={s.confirmEmailForm__inputsWrapper}> >
<div className="max-w-[360px] mb-[50px] flex flex-col items-center gap-[6px]">
<label className="self-start text-sm leading-5 text-gray-500">
{t("code")}
</label>
<div className="flex items-center gap-[6px] sm:grid sm:grid-cols-6">
{otp.map((data, index) => ( {otp.map((data, index) => (
<input <input
id={data ? s.confirmEmailForm__inputActive : ""} id={
data && "border border-blue-500 rounded-sm shadow-sm bg-white"
}
key={index} key={index}
onChange={(e) => handleChange(e, index)} onChange={(e) => handleChange(e, index)}
value={data} value={data}
maxLength={1} maxLength={1}
type="text" type="text"
className="text-center p-2 max-w-[55px] h-[64px] flex items-center justify-center border border-gray-300 rounded-md shadow-sm bg-white text-[48px] font-medium leading-[60px] text-light-blue sm:w-full"
/> />
))} ))}
</div> </div>
{error ? <p className={s.confirmEmailForm__error}>{error}</p> : null} {error && <p className="leading-6 text-red-500">{error}</p>}
</div> </div>
<button <button
disabled={otp.join("").length === 6 ? false : true} disabled={otp.join("").length === 6 ? false : true}
id={`${s.confirmEmailForm__sendCode}${ className={cn(
otp.join("").length === 6 ? "__active" : "" "bg-gray-300 text-white py-[10px] px-[18px] w-full rounded-md text-bold leading-6 shadow-md",
}`} {
"bg-light-blue text-white": otp.join("").length === 6,
}
)}
type="submit" type="submit"
> >
{loader ? <Loader /> : "Подтвердить"} {loader ? <Loader /> : t("submitBtn")}
</button> </button>
<p className={s.confirmEmailForm__timer}> <p className="text-center my-8 leading-6 text-gray-500">
Отправить код повторно через{" "} {t("resendIn")}{" "}
<span> <span className="text-light-blue">
0{minutes}:{seconds.toString().length === 1 ? `0${seconds}` : seconds} 0{minutes}:{seconds.toString().length === 1 ? `0${seconds}` : seconds}
</span> </span>
</p> </p>
@ -134,11 +147,15 @@ const ConfirmEmailForm: React.FC<IConfirmEmailFormProps> = ({
type="button" type="button"
onClick={handleClick} onClick={handleClick}
disabled={minutes === 0 && seconds === 0 ? false : true} disabled={minutes === 0 && seconds === 0 ? false : true}
id={`${s.confirmEmailForm__resendCode}${ className={cn(
minutes === 0 && seconds === 0 ? "__active" : "" "border border-gray-400 bg-white text-gray-300 py-[10px] px-[18px] w-full rounded-md text-bold leading-6 shadow-md",
}`} {
"bg-light-blue text-white border-none":
minutes === 0 && seconds === 0,
}
)}
> >
{loader ? <Loader /> : "Отправить код повторно"} {loader ? <Loader /> : t("resendBtn")}
</button> </button>
</form> </form>
); );