Add submit new password funtion
This commit is contained in:
parent
98beb33993
commit
ab6a6ad5df
14
src/app/[locale]/sign-in/reset-code/icons/key.svg
Normal file
14
src/app/[locale]/sign-in/reset-code/icons/key.svg
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<svg width="24.000000" height="24.000000" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<desc>
|
||||||
|
Created with Pixso.
|
||||||
|
</desc>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip1668_53329">
|
||||||
|
<rect id="key" width="24.000000" height="24.000000" fill="white" fill-opacity="0"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<rect id="key" width="24.000000" height="24.000000" fill="#FFFFFF" fill-opacity="0"/>
|
||||||
|
<g clip-path="url(#clip1668_53329)">
|
||||||
|
<path id="Vector" d="M21 2L19 4L15.5 7.5L11.3906 11.6104L11.3896 11.6113C10.3516 10.6094 8.96289 10.0547 7.52051 10.0674C6.07812 10.0801 4.69922 10.6582 3.67969 11.6777C2.65918 12.6973 2.08105 14.0771 2.06836 15.5195C2.05566 16.9609 2.61035 18.3506 3.6123 19.3877C4.12207 19.9043 4.72852 20.3145 5.39746 20.5957C6.06543 20.877 6.7832 21.0225 7.50879 21.0254C8.23438 21.0273 8.95312 20.8867 9.62402 20.6104C10.2939 20.333 10.9033 19.9268 11.416 19.4141C11.9297 18.9014 12.3359 18.292 12.6123 17.6211C12.8887 16.9502 13.0293 16.2324 13.0273 15.5068C13.0244 14.7812 12.8789 14.0635 12.5977 13.3945C12.3174 12.7256 11.9062 12.1191 11.3906 11.6104M15.5 7.5L18.5 10.5L22 7L19 4" stroke="#489FE1" stroke-opacity="1.000000" stroke-width="2.000000" stroke-linejoin="round"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
29
src/app/[locale]/sign-in/reset-code/page.tsx
Normal file
29
src/app/[locale]/sign-in/reset-code/page.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import Image from "next/image";
|
||||||
|
import key from "./icons/key.svg";
|
||||||
|
import ResetCodeForm from "@/widgets/forms/ResetCodeForm";
|
||||||
|
|
||||||
|
const ResetCode = () => {
|
||||||
|
return (
|
||||||
|
<div className="h-full min-h-[800px] flex justify-center w-full ">
|
||||||
|
<div className="flex flex-col items-center gap-6">
|
||||||
|
<div className="min-w-[60px] min-h-[60px] flex items-center justify-center border border-light-blue rounded-full">
|
||||||
|
<Image src={key} alt="Key Icon" className="w-[24px] h-[24px]" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-2 flex flex-col items-center gap-2 text-center">
|
||||||
|
<h2 className="text-[24px] font-bold leading-8 text-gray-900">
|
||||||
|
Введите новый пароль
|
||||||
|
</h2>
|
||||||
|
<p className="leading-6 text-gray-500">
|
||||||
|
Пароль должен содерждать минимум 8 символов, 1 заглавная буква и
|
||||||
|
цифра
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ResetCodeForm />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ResetCode;
|
174
src/widgets/forms/ResetCodeForm.tsx
Normal file
174
src/widgets/forms/ResetCodeForm.tsx
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import AuthInput from "@/features/AuthInput/AuthInput";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { apiInstance } from "@/shared/config/apiConfig";
|
||||||
|
import { ITokens } from "@/shared/types/token-type";
|
||||||
|
import { useRouter } from "@/shared/config/navigation";
|
||||||
|
import { AxiosError } from "axios";
|
||||||
|
import Loader from "@/shared/ui/Loader/Loader";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import Image from "next/image";
|
||||||
|
import eye_off from "./icons/eye-off.svg";
|
||||||
|
import eye_on from "./icons/eye-on.svg";
|
||||||
|
import alert from "./icons/alert-circle.svg";
|
||||||
|
|
||||||
|
const ResetCodeForm = () => {
|
||||||
|
const [passwordWarning, setPasswordWarning] = useState<string>("");
|
||||||
|
const [passwordConfirmWarning, setPasswordConfirmWarning] =
|
||||||
|
useState<string>("");
|
||||||
|
const [error, setError] = useState<string>("");
|
||||||
|
const [loader, setLoader] = useState<boolean>(false);
|
||||||
|
const [showPasswordOne, setShowPasswordOne] = useState(false);
|
||||||
|
const [showPasswordTwo, setShowPasswordTwo] = useState(false);
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const resetCodeFormScheme = z
|
||||||
|
.object({
|
||||||
|
new_password1: z
|
||||||
|
.string()
|
||||||
|
.min(8, "Пароль должен содержать минимум 8 символов"),
|
||||||
|
new_password2: z
|
||||||
|
.string()
|
||||||
|
.min(8, "Пароль должен содержать минимум 8 символов"),
|
||||||
|
})
|
||||||
|
.refine((data) => data.new_password1 === data.new_password2, {
|
||||||
|
message: "Пароли не совпадают",
|
||||||
|
path: ["new_password2"],
|
||||||
|
});
|
||||||
|
type FormFields = z.infer<typeof resetCodeFormScheme>;
|
||||||
|
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors, isSubmitting },
|
||||||
|
} = useForm<FormFields>({
|
||||||
|
resolver: zodResolver(resetCodeFormScheme),
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = async (data: FormFields) => {
|
||||||
|
try {
|
||||||
|
setError("");
|
||||||
|
setLoader(true);
|
||||||
|
|
||||||
|
const storage = localStorage.getItem("transitional");
|
||||||
|
if (storage === null) return;
|
||||||
|
const transitional: ITokens = JSON.parse(storage);
|
||||||
|
|
||||||
|
const Authorization = `Bearer ${transitional.access_token}`;
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
headers: {
|
||||||
|
Authorization,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await apiInstance.patch(
|
||||||
|
"/auth/password_reset/",
|
||||||
|
data,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
if ([200, 201].includes(response.status)) {
|
||||||
|
localStorage.removeItem("transitional");
|
||||||
|
router.push("/sign-in");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof AxiosError) {
|
||||||
|
if (
|
||||||
|
[500, 501, 502, 503, 504].includes(error.response?.status as number)
|
||||||
|
) {
|
||||||
|
setError("Ошибка на стороне сервера");
|
||||||
|
} else if ([400, 404].includes(error.response?.status as number)) {
|
||||||
|
setError("Слабый пароль, прошу избегайте очевидных паролей");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setError("Произошла непредвиденная ошибка");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
setLoader(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)} className="w-[360px] flex flex-col">
|
||||||
|
<div className="flex flex-col gap-8">
|
||||||
|
<div>
|
||||||
|
<label className="text-[14px] leading-5 text-gray-700">
|
||||||
|
Введите пароль
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
className={`flex items-center border border-gray-300 rounded-lg shadow-sm bg-white${
|
||||||
|
errors?.new_password1?.message && "border border-red-400"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
placeholder="Введите новый пароль"
|
||||||
|
className="w-full text-[16px] leading-6 text-gray-900 px-[10px] py-[14px]"
|
||||||
|
type={showPasswordOne ? "text" : "password"}
|
||||||
|
{...register("new_password1", { required: true })}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowPasswordOne((prev) => !prev)}
|
||||||
|
type="button"
|
||||||
|
className="pr-2"
|
||||||
|
>
|
||||||
|
<Image src={showPasswordOne ? eye_on : eye_off} alt="Eye Icon" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{errors?.new_password1?.message && (
|
||||||
|
<p className="flex items-center justify-between text-[14px] font-normal leading-5 text-red-500">
|
||||||
|
{errors.new_password1.message}{" "}
|
||||||
|
<Image src={alert} alt="Alert Icon" />
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-[14px] leading-5 text-gray-700">
|
||||||
|
Повторите пароль
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
className={`flex items-center border border-gray-300 rounded-lg shadow-sm bg-white${
|
||||||
|
errors?.new_password2?.message && "border border-red-400"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
placeholder="Повторите новый пароль"
|
||||||
|
className="w-full text-[16px] leading-6 text-gray-900 px-[10px] py-[14px]"
|
||||||
|
type={showPasswordTwo ? "text" : "password"}
|
||||||
|
{...register("new_password2", { required: true })}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowPasswordTwo((prev) => !prev)}
|
||||||
|
type="button"
|
||||||
|
className="pr-2"
|
||||||
|
>
|
||||||
|
<Image src={showPasswordTwo ? eye_on : eye_off} alt="Eye Icon" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{errors?.new_password2?.message && (
|
||||||
|
<p className="flex items-center justify-between text-[14px] font-normal leading-5 text-red-500">
|
||||||
|
{errors.new_password2.message}{" "}
|
||||||
|
<Image src={alert} alt="Alert Icon" />
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{errors.root && (
|
||||||
|
<p className="text-sm leading-5 text-red-500">{errors.root.message}</p>
|
||||||
|
)}
|
||||||
|
{error ? <p className="text-red-500 leading-5 text-sm">{error}</p> : null}
|
||||||
|
<button
|
||||||
|
className="mt-8 h-[44px] w-full rounded-md shadow-sm bg-light-blue font-bold leading-6 text-white"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
{loader ? <Loader /> : "Сохранить"}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ResetCodeForm;
|
Loading…
Reference in New Issue
Block a user