From 6a53f9f912f337da87b5e962ac12c7288a764396 Mon Sep 17 00:00:00 2001 From: alij Date: Sun, 16 Jun 2024 01:25:58 +0430 Subject: [PATCH] feat : login mobile or email complated --- src/pages/login/components/LoginEmailForm.tsx | 120 +++++++++ .../login/components/LoginMobileForm.tsx | 236 ++++++++++++++++++ src/pages/login/index.tsx | 122 +-------- src/routes/PrivateRoute.tsx | 2 +- 4 files changed, 370 insertions(+), 110 deletions(-) create mode 100644 src/pages/login/components/LoginEmailForm.tsx create mode 100644 src/pages/login/components/LoginMobileForm.tsx diff --git a/src/pages/login/components/LoginEmailForm.tsx b/src/pages/login/components/LoginEmailForm.tsx new file mode 100644 index 0000000..8e8a2ec --- /dev/null +++ b/src/pages/login/components/LoginEmailForm.tsx @@ -0,0 +1,120 @@ +import { motion } from "framer-motion"; +import Input from "../../../components/input"; +import Button from "../../../components/button"; +import { useFormik } from "formik"; +import * as Yup from "yup"; +import { useMutation } from "@tanstack/react-query"; +import toast from "react-hot-toast"; +import { AxiosError } from "axios"; +import { useDispatch } from "react-redux"; +import { AppDispatch } from "../../../redux/store"; +import { setToken } from "../../../redux/slices/token"; +import { useNavigate } from "react-router-dom"; +import useAxios from "../../../hooks/useAxios"; + +const LoginEmailForm = () => { + const dispatch = useDispatch(); + const navigate = useNavigate(); + const axios = useAxios() + const mutationEmail = useMutation({ + mutationFn: (values: { email: string; password: string }) => { + return axios.post("/login", values); + }, + }); + const formikEmail = useFormik({ + initialValues: { + email: "", + password: "", + }, + validationSchema: Yup.object({ + email: Yup.string().email("ایمیل نامعتبر است"), + password: Yup.string().min(6, "رمز عبور حداقل باید 6 کاراکتر باشد"), + }), + onSubmit: (values) => { + toast.promise(mutationEmail.mutateAsync(values), { + loading: "در حال احراز هویت لطفا صبر نمایید...", + success: (res) => { + dispatch(setToken(res?.data?.result?.token)); + navigate("/"); + return `خوش آمدید ${res.data.alert}`; + }, + error: (err: AxiosError) => { + let errorMessage = "یک خطای غیرمنتظره رخ داد"; + + if ( + err.response?.data && + typeof err.response.data === "object" && + "message" in err.response.data + ) { + errorMessage = (err.response.data as { message: string }).message; + } + + return errorMessage; + }, + }); + }, + }); + + return ( + <> +
+
+ + + {formikEmail.errors.email && ( +

+ {formikEmail.errors.email} +

+ )} +
+ + + + {formikEmail.errors.password && ( +

+ {formikEmail.errors.password} +

+ )} +
+
+ +
+ +
+
+ + ); +}; + +export default LoginEmailForm; diff --git a/src/pages/login/components/LoginMobileForm.tsx b/src/pages/login/components/LoginMobileForm.tsx new file mode 100644 index 0000000..ed75648 --- /dev/null +++ b/src/pages/login/components/LoginMobileForm.tsx @@ -0,0 +1,236 @@ +import { motion } from "framer-motion"; +import Input from "../../../components/input"; +import OTPInput from "react-otp-input"; +import * as Yup from "yup"; +import { useFormik } from "formik"; +import Button from "../../../components/button"; +import { Dispatch, SetStateAction, useState } from "react"; +import { useMutation } from "@tanstack/react-query"; +import useAxios from "../../../hooks/useAxios"; +import { useNavigate } from "react-router-dom"; +import { useDispatch } from "react-redux"; +import { AppDispatch } from "../../../redux/store"; +import { AxiosError } from "axios"; +import { setToken } from "../../../redux/slices/token"; +import toast from "react-hot-toast"; + +const LoginMobileForm = ({ + setisShowLoginNumberOrEmail, +}: { + setisShowLoginNumberOrEmail: Dispatch>; +}) => { + const dispatch = useDispatch(); + const navigate = useNavigate(); + const [stepMobile, setStepMobile] = useState<1 | 2>(1); + const axios = useAxios(); + + // Mutation for mobile login + const mutationMobile = useMutation({ + mutationFn: (values: { mobile: string }) => { + return axios.post("/login-mobile", values); + }, + }); + + // Mutation for code verification + const mutationCode = useMutation({ + mutationFn: (values: { code: string }) => { + return axios.post("/verify", values); + }, + }); + + // Formik for mobile step + const formikMobile = useFormik({ + initialValues: { + mobile: "", + }, + validationSchema: Yup.object({ + mobile: Yup.string() + .matches(/^09\d{9}$/, "شماره باید با 09 شروع شود و باید 11 رقم باشد") + .required("لطفا شماره خود را برای ورود وارد کنید"), + }), + onSubmit: (values) => { + if (stepMobile === 1) { + toast.promise(mutationMobile.mutateAsync(values), { + loading: "در حال ارسال کد...", + success: (res) => { + dispatch(setToken(res?.data?.result?.token)); + setisShowLoginNumberOrEmail(false) + setStepMobile(2); + return `${res.data.alert}`; + }, + error: (err: AxiosError) => { + let errorMessage = "یک خطای غیرمنتظره رخ داد"; + + if ( + err.response?.data && + typeof err.response.data === "object" && + "message" in err.response.data + ) { + errorMessage = (err.response.data as { message: string }).message; + } + + return errorMessage; + }, + }); + } + }, + }); + + // Formik for code step + const formikMobileCode = useFormik({ + initialValues: { + code: "", + }, + validationSchema: Yup.object({ + code: Yup.string() + .length(4, "لطفا 4 رقم کد را وارد کنید") + .required("لطفا تمام فیلد را پر کنید"), + }), + onSubmit: (values) => { + const mainValue = { + mobile: formikMobile.values.mobile, + code: values.code, + }; + if (stepMobile === 2) { + toast.promise(mutationCode.mutateAsync(mainValue), { + loading: "در حال احراز هویت لطفا صبر نمایید...", + success: (res) => { + dispatch(setToken(res?.data?.result?.token)); + navigate("/"); + return `خوش آمدید ${res.data.alert}`; + }, + error: (err: AxiosError) => { + let errorMessage = "یک خطای غیرمنتظره رخ داد"; + + if ( + err.response?.data && + typeof err.response.data === "object" && + "message" in err.response.data + ) { + errorMessage = (err.response.data as { message: string }).message; + } + + return errorMessage; + }, + }); + } + }, + }); + + // Handle OTP input change + const handleChangeMobileCode = (otp: string) => { + formikMobileCode.setFieldValue("code", otp); + }; + + return ( + <> +
+
+ {stepMobile === 1 ? ( + + + {formikMobile.errors.mobile && ( +

+ {formikMobile.errors.mobile} +

+ )} +
+ ) : ( + stepMobile === 2 && ( + <> + + کد ارسال شده رو وارد نمایید: + +
+ ( + { + const input = e.target as HTMLInputElement; // تایپ‌کست کردن به HTMLInputElement + input.value = input.value.replace(/\D/g, ""); // حذف کاراکترهای غیر عددی + }} + type="text" // تغییر از "number" به "text" + initial={{ + y: 20, + opacity: 0, + border: "2px solid transparent", + }} + animate={{ + y: 0, + opacity: 1, + }} + className={`bg-gray-800 focus:outline-none focus:ring-1 focus:ring-gray-600 shadow-md max-sm:!w-[2.5rem] max-sm:!h-[2.5rem] shadow-gray-900 ${ + formikMobileCode.errors.code && + "!ring-1 !ring-rose-600" + } ${props.className}`} + /> + )} + /> + {formikMobileCode.errors.code && ( +

+ {formikMobileCode.errors.code} +

+ )} +
+ + ) + )} +
+
+ +
+
+ + ); +}; + +export default LoginMobileForm; diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index f78609f..9deda24 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -1,123 +1,27 @@ -// import Input from "../../components/input"; -import Button from "../../components/button"; import { useState } from "react"; -// import LoginNumberOrEmail from "./components/LoginNumberOrEmail"; -import { motion } from "framer-motion"; -// import Rabbit from "./components/Rabbit"; -import OTPInput from "react-otp-input"; + +import LoginNumberOrEmail from "./components/LoginNumberOrEmail"; +import LoginMobileForm from "./components/LoginMobileForm"; +import LoginEmailForm from "./components/LoginEmailForm"; const Login = () => { - // const [loginWithEmail, setLoginWithEmail] = useState(false); - // const [inputText, setInputText] = useState(false); - // const [inputPassword, setInputPassword] = useState(false); - - const [authCode, setAuthCode] = useState(false); - const [errorCode, setErrorCode] = useState(false); - - const [otp, setOtp] = useState(""); - - const handleChange = (otp: string) => { - setOtp(otp); - if (otp === "1111" && otp.length === 4) - setAuthCode(true), setErrorCode(false); - else if (otp.length === 4) setErrorCode(true), setAuthCode(false); - else setAuthCode(false), setErrorCode(false); - }; + const [loginWithEmail, setLoginWithEmail] = useState(false); + const [isShowLoginNumberOrEmail , setisShowLoginNumberOrEmail] = useState(true); return ( <>
- {/* */}

ورود

-

- کد ارسال شده رو وارد نمایید: -

- {/* */} -
-
- {/* {!loginWithEmail && ( - - setInputText(true)} - onBlur={() => setInputText(false)} - /> - - )} - {loginWithEmail && ( - - setInputText(true)} - onBlur={() => setInputText(false)} - /> - - )} */} - ( - - )} - /> -
- -
- -
-
+ {isShowLoginNumberOrEmail && ( + + )} + {!loginWithEmail ? : }
diff --git a/src/routes/PrivateRoute.tsx b/src/routes/PrivateRoute.tsx index ec6d86e..b2f5f84 100644 --- a/src/routes/PrivateRoute.tsx +++ b/src/routes/PrivateRoute.tsx @@ -2,7 +2,7 @@ import { Navigate, Outlet } from "react-router-dom"; import { isAuthenticated } from "../utils/auth"; const PrivateRoute = () => { - return !isAuthenticated() ? : ; + return isAuthenticated() ? : ; }; export default PrivateRoute;