Add confirm email page
This commit is contained in:
parent
52c9f9a3b1
commit
38b869084d
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,5 +61,14 @@
|
|||||||
},
|
},
|
||||||
"rights": {
|
"rights": {
|
||||||
"text": "Бардык укуктар корголгон"
|
"text": "Бардык укуктар корголгон"
|
||||||
|
},
|
||||||
|
"confirmEmail": {
|
||||||
|
"checkEmail": "Электрондук почтаңызды текшериңиз",
|
||||||
|
"codeSent": "Кодду электрондук почта аркылуу жөнөттүк",
|
||||||
|
"code": "Ырастоо коду",
|
||||||
|
"submitBtn": "Тапшыруу",
|
||||||
|
"resendIn": "Кодду кайра жөнөтүү",
|
||||||
|
"resendBtn": "Кодду кайра жөнөтүү",
|
||||||
|
"error": "Ката кетти"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,5 +62,14 @@
|
|||||||
},
|
},
|
||||||
"rights": {
|
"rights": {
|
||||||
"text": "Все права защищены"
|
"text": "Все права защищены"
|
||||||
|
},
|
||||||
|
"confirmEmail": {
|
||||||
|
"checkEmail": "Проверьте свою почту",
|
||||||
|
"codeSent": "Мы отправили код на почту",
|
||||||
|
"code": "Код подтверждения",
|
||||||
|
"submitBtn": "Подтвердить",
|
||||||
|
"resendIn": "Отправить код повторно через",
|
||||||
|
"resendBtn": "Отправить код повторно",
|
||||||
|
"error": "Произошла ошибка"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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} />
|
||||||
|
@ -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>
|
||||||
|
@ -44,11 +44,11 @@ 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${
|
||||||
pathname === link.pathname ? "opacity-1 font-extrabold" : ""
|
pathname === link.pathname ? " opacity-1 font-extrabold" : ""
|
||||||
}`}
|
}`}
|
||||||
key={link.id}
|
key={link.id}
|
||||||
href={link.pathname}
|
href={link.pathname}
|
||||||
|
@ -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%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user