diff --git a/public/locales/fa/app.json b/public/locales/fa/app.json index 60890a7..4450c55 100644 --- a/public/locales/fa/app.json +++ b/public/locales/fa/app.json @@ -23,7 +23,8 @@ "passenger-boss": "رئیس مسافر", "transportation-assistance": "معاونت حمل و نقل", "manager": "مدیر کل", - "change-password": "تغییر رمز عبور" + "change-password": "تغییر رمز عبور", + "edit-profile": "ویرایش پروفایل" }, "Authorization": { "typography_your_login_is_valid_and_you_do_not_need_to_login_again": "شما دسترسی لازم به این صفحه را دارید نیاز به ورود مجدد نیست.", @@ -45,8 +46,13 @@ }, "Dashboard": { "dashboard_page": "داشبورد", +<<<<<<< HEAD "passenger_boss": "رئیس مسافر", "change_password": "تغییر رمز عبور" +======= + "change_password": "تغییر رمز عبور", + "edit_profile": "ویرایش پروفایل" +>>>>>>> 135f6d1e2f3495abe68e3ca758870023dcd85d76 }, "MuiDatePicker": { "date_picker_birthday": "تاریخ" @@ -64,5 +70,27 @@ "SubmitButton": { "button_while_submit": "در حال ثبت", "button_submit": "ثبت" + }, + "UpdateProfile": { + "error_invalid_email": "ایمیل نامعتبر است", + "typography_edit_profile": "ویرایش پروفایل", + "text_field_email": "ایمیل", + "text_field_enter_your_password": "رمز عبور خود را وارد کنید", + "text_field_username": "نام کاربری", + "text_field_name": "نام", + "text_field_phone_number": "شماره تماس", + "text_field_position": "سمت", + "text_field_province_name": "نام استان", + "error_message_required": "اجباری !" + }, + "notifications": { + "code": "کد", + "error": "خطا", + "warning": "خطر", + "success": "موفق", + "error_static_text": "عملیات شما با خطا مواجه شد", + "warning_static_text": "خطا سرور", + "success_static_text": "عملیات شما با موفقیت انجام شد", + "pending": "در حال انجام..." } } diff --git a/src/components/dashboard/change-password/index.jsx b/src/components/dashboard/change-password/index.jsx index 62d6fe3..c2b5fd4 100644 --- a/src/components/dashboard/change-password/index.jsx +++ b/src/components/dashboard/change-password/index.jsx @@ -28,7 +28,7 @@ const DashboardChangePasswordComponent = () => { const handleSubmit = (values, { setSubmitting, resetForm }) => { toast.dismiss(); - const pendingToast = toast("Pending...", { + const pendingToast = toast(t("notifications.pending"), { position: directionApp === "ltr" ? "top-left" : "top-right", autoClose: false, closeOnClick: false, diff --git a/src/components/dashboard/edit-profile/index.jsx b/src/components/dashboard/edit-profile/index.jsx new file mode 100644 index 0000000..fa3e2e1 --- /dev/null +++ b/src/components/dashboard/edit-profile/index.jsx @@ -0,0 +1,299 @@ +import StyledForm from "@/core/components/StyledForm"; +import CenterLayout from "@/layouts/CenterLayout"; +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import useUser from "@/lib/app/hooks/useUser"; +import { + Box, + Button, + Container, + Grid, + Paper, + Stack, + TextField, + Typography, +} from "@mui/material"; +import * as Yup from "yup"; +import { Field, Formik } from "formik"; +import { useTranslations } from "next-intl"; +import AvatarUpload from "@/core/components/AvatarUpload"; +import axios from "axios"; +import { UPDATE_PROFILE, UPDATE_AVATAR } from "@/core/data/apiRoutes"; +import useDirection from "@/lib/app/hooks/useDirection"; +import Notifications from "@/core/components/notifications"; +import ImageResizer from "@/core/components/ImageConvertor"; + +const DashboardEditProfile = () => { + const t = useTranslations(); + const { user, token, getUser, changeUser } = useUser(); + console.log(user); + const { directionApp } = useDirection(); + + const editAvatar = async (avatar) => { + try { + const formData = new FormData(); + + if (avatar != null) { + var resizedAvatar; + resizedAvatar = await ImageResizer(avatar); + formData.append("avatar", resizedAvatar); + } + + await axios.post(UPDATE_AVATAR, formData, { + headers: { + authorization: `Bearer ${token}`, + "Content-Type": "multipart/form-data", + }, + }); + } catch (error) { + Notifications(directionApp, error.response, t); + throw error; + } + }; + const handleSubmit = (values, { setSubmitting }) => { + // const formData = new FormData(); + // formData.append("email", values.expert_email); + // if (values.change_avatar !== false) { + // editAvatar(values.expert_avatar) + // .then(() => { + // return axios.post(UPDATE_PROFILE, formData, { + // headers: { + // authorization: `Bearer ${token}`, + // "Content-Type": "multipart/form-data", + // }, + // }); + // }) + // .then((response) => { + // Notifications(directionApp, response, t); + // getUser((data) => { + // changeUser(data); + // }); + // }) + // .catch((error) => { + // Notifications(directionApp, error.response, t); + // }) + // .finally(() => { + // setSubmitting(false); + // }); + // } else { + // axios + // .post(UPDATE_PROFILE, formData, { + // headers: { + // authorization: `Bearer ${token}`, + // "Content-Type": "multipart/form-data", + // }, + // }) + // .then((response) => { + // Notifications(directionApp, response, t); + // getUser((data) => { + // changeUser(data); + // }); + // }) + // .catch((error) => { + // Notifications(directionApp, error.response, t); + // }) + // .finally(() => { + // setSubmitting(false); + // }); + // } + }; + const initialValues = { + expert_avatar: null, + username: user.username, + name: user.name, + email: user.email, + province_name: user.province_name, + position: user.position, + }; + const validationSchema = Yup.object().shape({ + // username: Yup.string().required(t("UpdateProfile.error_message_required")), + // name: Yup.string().required(t("UpdateProfile.error_message_required")), + // email: Yup.string() + // .email(t("UpdateProfile.error_invalid_email")) + // .required(t("UpdateProfile.error_message_required")), + // province_name: Yup.string().required( + // t("UpdateProfile.error_message_required") + // ), + // position: Yup.string().required(t("UpdateProfile.error_message_required")), + }); + + return ( + + + + + {(props) => ( + { + e.preventDefault(); + props.handleSubmit(); + }} + > + + + + {t("UpdateProfile.typography_edit_profile")} + + + + + + + + + + + + + + + + + + + + + + + {/* */} + + + + )} + + + + + ); +}; + +export default DashboardEditProfile; diff --git a/src/components/login-expert/index.jsx b/src/components/login-expert/index.jsx index 65b1e1c..bcc3b1a 100644 --- a/src/components/login-expert/index.jsx +++ b/src/components/login-expert/index.jsx @@ -2,7 +2,7 @@ import LinkRouting from "@/core/components/LinkRouting"; // import Notifications from "@/core/components/notifications"; import PasswordField from "@/core/components/PasswordField"; import StyledForm from "@/core/components/StyledForm"; -// import { GET_USER_TOKEN } from "@/core/data/apiRoutes"; +import { GET_USER_TOKEN } from "@/core/data/apiRoutes"; import CenterLayout from "@/layouts/CenterLayout"; import FullPageLayout from "@/layouts/FullPageLayout"; import useDirection from "@/lib/app/hooks/useDirection"; @@ -17,7 +17,7 @@ import { TextField, Typography, } from "@mui/material"; -// import axios from "axios"; +import axios from "axios"; import { Field, Formik } from "formik"; import { useTranslations } from "next-intl"; import Image from "next/image"; @@ -33,21 +33,23 @@ const LoginComponent = () => { const searchParams = useSearchParams(); const backUrlDecodedPath = searchParams.get("back_url"); - // formik properties - // const handleSubmit = async (values, props) => { - // await axios - // .post(GET_USER_TOKEN, { - // username: values.username, - // password: values.password, - // }) - // .then(function (response) { - // setToken(response.data.token); - // }) - // .catch(function (error) { - // Notifications(directionApp, error.response, t); - // props.setSubmitting(false); - // }); - // }; + //formik properties + const handleSubmit = async (values, props) => { + await axios + .post(GET_USER_TOKEN, { + username: values.username, + password: values.password, + }) + .then(function (response) { + console.log(response); + setToken(response.data.token); + }) + .catch(function (error) { + // Notifications(directionApp, error.response, t); + console.log(error); + props.setSubmitting(false); + }); + }; const initialValues = { username: "", password: "", @@ -64,7 +66,7 @@ const LoginComponent = () => { {(props) => ( diff --git a/src/core/components/AvatarUpload.jsx b/src/core/components/AvatarUpload.jsx new file mode 100644 index 0000000..e1ade5c --- /dev/null +++ b/src/core/components/AvatarUpload.jsx @@ -0,0 +1,128 @@ +import { Avatar, Box, TextField } from "@mui/material"; +import { useState } from "react"; +import DeleteIcon from "@mui/icons-material/Delete"; +import AddIcon from "@mui/icons-material/Add"; + +const AvatarUpload = ({ user, setFieldValue, valueAvatar, changeFlag }) => { + const [selectedImage, setSelectedImage] = useState(user.expert_avatar); + const [isHovered, setIsHovered] = useState(false); + + const handleImageChange = (event) => { + const newImage = event.target?.files?.[0]; + if (newImage) { + setSelectedImage(URL.createObjectURL(newImage)); + setFieldValue(valueAvatar, newImage); + setFieldValue(changeFlag, true); + } else { + setSelectedImage(""); + setFieldValue(valueAvatar, null); + } + }; + + const handleDeleteImage = () => { + setSelectedImage(""); + setFieldValue(valueAvatar, null); + setFieldValue(changeFlag, true); + }; + + const handleMouseEnter = () => { + setIsHovered(true); + }; + + const handleMouseLeave = () => { + setIsHovered(false); + }; + + return ( + + + + + {isHovered && ( + + {selectedImage ? ( + + ) : ( + + )} + + )} + + + + + ); +}; + +export default AvatarUpload; diff --git a/src/core/data/apiRoutes.js b/src/core/data/apiRoutes.js index 0877232..1b299cc 100644 --- a/src/core/data/apiRoutes.js +++ b/src/core/data/apiRoutes.js @@ -1,6 +1,13 @@ const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL; +//login +export const GET_USER_TOKEN = BASE_URL + "/dashboard/login"; +//end login + //change password -export const CHANGE_PASSWORD = - BASE_URL + "/dashboard/profile/change_password"; -//end change password \ No newline at end of file +export const CHANGE_PASSWORD = BASE_URL + "/dashboard/profile/change_password"; +//end change password + +//user data +export const GET_USER_ROUTE = BASE_URL + "/dashboard/profile/info"; +//user data \ No newline at end of file diff --git a/src/lib/app/contexts/user.jsx b/src/lib/app/contexts/user.jsx index 49d55af..30875d9 100644 --- a/src/lib/app/contexts/user.jsx +++ b/src/lib/app/contexts/user.jsx @@ -51,27 +51,7 @@ export const UserProvider = ({ children }) => { dispatch({ type: "CHANGE_USER", user }); }, []); - const changeUserLanguage = useCallback( - (language) => { - dispatch({ type: "CHANGE_USER_LANGUAGE", language }); - axios - .post( - SET_LANGUAGE, - { language: language }, - { - headers: { - authorization: `Bearer ${state.token}`, - }, - } - ) - .then(() => { - getUser((data) => { - changeUser(data); - }); - }); - }, - [state.token] - ); + const changeUserLanguage = useCallback(/* use in multi language app */); const changeAuthState = useCallback((isAuth) => { dispatch({ type: "CHANGE_AUTH_STATE", isAuth }); diff --git a/src/lib/app/hooks/useUser.jsx b/src/lib/app/hooks/useUser.jsx index baa0aaa..56bdf7c 100644 --- a/src/lib/app/hooks/useUser.jsx +++ b/src/lib/app/hooks/useUser.jsx @@ -10,7 +10,6 @@ const useUser = () => { getUser, clearUser, changeUser, - changeUserLanguage, changeAuthState, changeLanguageState, clearToken, @@ -25,7 +24,6 @@ const useUser = () => { getUser, clearUser, changeUser, - changeUserLanguage, changeAuthState, changeLanguageState, clearToken, diff --git a/src/middlewares/WithAuth.jsx b/src/middlewares/WithAuth.jsx index d158bf3..3fa5f43 100644 --- a/src/middlewares/WithAuth.jsx +++ b/src/middlewares/WithAuth.jsx @@ -16,7 +16,7 @@ const WithAuthMiddleware = ({ children }) => { text={ {t( - "typography_your_access_to_this_page_has_expired_Please_login_again" + "Authorization.typography_your_access_to_this_page_has_expired_Please_login_again" )} } @@ -26,7 +26,7 @@ const WithAuthMiddleware = ({ children }) => { variant="contained" component={NextLinkComposed} to={{ - pathname: "/login", + pathname: "/login-expert", query: { back_url: encodeURIComponent(router.asPath) }, }} > diff --git a/src/middlewares/WithoutAuth.jsx b/src/middlewares/WithoutAuth.jsx index 5fb4f93..cb8e571 100644 --- a/src/middlewares/WithoutAuth.jsx +++ b/src/middlewares/WithoutAuth.jsx @@ -37,14 +37,14 @@ const WithoutAuthMiddleware = ({ children }) => { {t( - "typography_your_login_is_valid_and_you_do_not_need_to_login_again" + "Authorization.typography_your_login_is_valid_and_you_do_not_need_to_login_again" )} - {t("typography_redirect_to")}{" "} + {t("Authorization.typography_redirect_to")}{" "} {backUrlDecodedPath - ? t("typography_routing_previuos_page") - : t("typography_routing_dashbaord_page")} + ? t("Authorization.typography_routing_previuos_page") + : t("Authorization.typography_routing_dashbaord_page")} } diff --git a/src/pages/dashboard/change-password/index.jsx b/src/pages/dashboard/change-password/index.jsx index 85660ff..30685f1 100644 --- a/src/pages/dashboard/change-password/index.jsx +++ b/src/pages/dashboard/change-password/index.jsx @@ -1,6 +1,6 @@ import DashboardChangePasswordComponent from "@/components/dashboard/change-password"; import TitlePage from "@/core/components/TitlePage"; -import WithAuthMiddleware from "@/middlewares/WithoutAuth"; +import WithAuthMiddleware from "@/middlewares/WithAuth"; import { parse } from "next-useragent"; export default function LoanFollowUp() { diff --git a/src/pages/dashboard/edit-profile/index.jsx b/src/pages/dashboard/edit-profile/index.jsx new file mode 100644 index 0000000..0adabf6 --- /dev/null +++ b/src/pages/dashboard/edit-profile/index.jsx @@ -0,0 +1,23 @@ +import DashboardEditProfile from "@/components/dashboard/edit-profile"; +import TitlePage from "@/core/components/TitlePage"; +import WithAuthMiddleware from "@/middlewares/WithAuth"; +import { parse } from "next-useragent"; + +export default function LoanFollowUp() { + return ( + + + + + ); +} + +export async function getServerSideProps({ req, locale }) { + const { isBot } = parse(req.headers["user-agent"]); + return { + props: { + messages: (await import(`&/locales/${locale}/app.json`)).default, + isBot, + }, + }; +} diff --git a/src/pages/dashboard/index.jsx b/src/pages/dashboard/index.jsx index 5ebc479..c3c3933 100644 --- a/src/pages/dashboard/index.jsx +++ b/src/pages/dashboard/index.jsx @@ -1,12 +1,12 @@ import DashboardFirstComponent from "@/components/dashboard/first"; import TitlePage from "@/core/components/TitlePage"; -import WithAuthMiddleware from "@/middlewares/WithoutAuth"; +import WithAuthMiddleware from "@/middlewares/WithAuth"; import { parse } from "next-useragent"; export default function Dashboard() { return ( - + ); diff --git a/src/pages/dashboard/loan-follow-up/index.jsx b/src/pages/dashboard/loan-follow-up/index.jsx index fc299c4..6bab35f 100644 --- a/src/pages/dashboard/loan-follow-up/index.jsx +++ b/src/pages/dashboard/loan-follow-up/index.jsx @@ -6,7 +6,7 @@ import { parse } from "next-useragent"; export default function LoanFollowUp() { return ( - + ); diff --git a/src/pages/dashboard/loan-request/index.jsx b/src/pages/dashboard/loan-request/index.jsx index b76f172..ad64ce8 100644 --- a/src/pages/dashboard/loan-request/index.jsx +++ b/src/pages/dashboard/loan-request/index.jsx @@ -6,7 +6,7 @@ import { parse } from "next-useragent"; export default function LoanRequest() { return ( - + );