diff --git a/package.json b/package.json index fee5c81..4132581 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "@emotion/cache": "^11.11.0", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", + "@hookform/resolvers": "^3.9.0", "@mui/icons-material": "^5.15.6", + "@mui/lab": "^5.0.0-alpha.173", "@mui/material": "^5.15.6", "@mui/material-nextjs": "^5.15.6", "@mui/x-date-pickers": "^6.19.5", diff --git a/src/core/components/Profile/ChangePass/Form.jsx b/src/core/components/Profile/ChangePass/Form.jsx new file mode 100644 index 0000000..3499394 --- /dev/null +++ b/src/core/components/Profile/ChangePass/Form.jsx @@ -0,0 +1,155 @@ +"use client"; + +import { + Chip, + Divider, + FormControl, + FormHelperText, + Grid, + IconButton, + InputAdornment, + InputLabel, + OutlinedInput, +} from "@mui/material"; +import StyledForm from "@/core/components/StyledForm"; +import { useForm } from "react-hook-form"; +import useRequest from "@/lib/hooks/useRequest"; +import { CHANGE_USER_PASSWORD } from "@/core/utils/routes"; +import { object, string } from "yup"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { useEffect, useState } from "react"; +import Visibility from "@mui/icons-material/Visibility"; +import VisibilityOff from "@mui/icons-material/VisibilityOff"; + +const validationSchema = object({ + current_password: string().required("اجباری"), + new_password: string().required("اجباری"), + repeat_new_password: string().required("اجباری").test( + "password-match", + "رمز عبور جدید و تکرار آن باید یکسان باشند", + function(value) { + return this.parent.new_password === value; + }, + ), +}); + +const Form = ({ handleCloseForm, setLoading }) => { + const request = useRequest(); + const [showNewPassword, setShowNewPassword] = useState(); + const [showRepeatNewPassword, setShowRepeatNewPassword] = useState(); + + const defaultValues = { + current_password: "", + new_password: "", + repeat_new_password: "", + }; + + const { + register, + handleSubmit, + formState: { isSubmitting, errors }, + } = useForm({ defaultValues, resolver: yupResolver(validationSchema) }); + + useEffect(() => { + setLoading(isSubmitting); + }, [isSubmitting]); + + const onSubmit = async (data) => { + const formData = new FormData(); + formData.append("current_password", data.current_password); + formData.append("new_password", data.new_password); + try { + await request(CHANGE_USER_PASSWORD, "post", { data: formData, signal: controller.signal }); + handleCloseForm(); + } catch (error) { + } + }; + + return ( + <> + + + + + + + + رمز عبور فعلی + + + {errors.current_password ? errors.current_password.message : null} + + + + + + رمز عبور جدید + + setShowNewPassword(!showNewPassword)} + onMouseDown={(event) => event.preventDefault()} + edge="end" + > + {showNewPassword ? : } + + + } + /> + + {errors.new_password ? errors.new_password.message : null} + + + + + + تکرار رمز عبور جدید + + setShowRepeatNewPassword(!showRepeatNewPassword)} + onMouseDown={(event) => event.preventDefault()} + edge="end" + > + {showRepeatNewPassword ? : } + + + } + /> + + {errors.repeat_new_password ? errors.repeat_new_password.message : null} + + + + + + + ); +}; +export default Form; \ No newline at end of file diff --git a/src/core/components/Profile/ChangePass/index.jsx b/src/core/components/Profile/ChangePass/index.jsx index 31df662..15e6fcd 100644 --- a/src/core/components/Profile/ChangePass/index.jsx +++ b/src/core/components/Profile/ChangePass/index.jsx @@ -1,50 +1,35 @@ "use client"; -import { - Box, - Button, - Dialog, - DialogActions, - DialogContent, - DialogTitle, - IconButton, - useMediaQuery, -} from "@mui/material"; -import { useTheme } from "@mui/material/styles"; -import CloseIcon from "@mui/icons-material/Close"; +import { Dialog, DialogActions, DialogContent } from "@mui/material"; +import Form from "./Form"; +import SaveIcon from "@mui/icons-material/Save"; +import { LoadingButton } from "@mui/lab"; +import { useState } from "react"; const ChangePass = ({ open, setOpen }) => { - const theme = useTheme(); - const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); + const [loading, setLoading] = useState(false); + + const handleCloseForm = () => { + setOpen(false); + }; return ( - { - setOpen(false); - }}> - - - تغییر رمز عبور - - { - setOpen(false); - }} - sx={{ color: (theme) => theme.palette.grey[500] }} - > - - - + - تست +
- +
); diff --git a/src/core/components/Profile/ProfileActions.jsx b/src/core/components/Profile/ProfileActions.jsx new file mode 100644 index 0000000..7683547 --- /dev/null +++ b/src/core/components/Profile/ProfileActions.jsx @@ -0,0 +1,50 @@ +"use client"; + +import { Box, Divider, IconButton, Tooltip } from "@mui/material"; +import PowerSettingsNewIcon from "@mui/icons-material/PowerSettingsNew"; +import ModeEditIcon from "@mui/icons-material/ModeEdit"; +import VpnKeyIcon from "@mui/icons-material/VpnKey"; +import { useState } from "react"; +import Update from "@/core/components/Profile/Update"; +import ChangePass from "@/core/components/Profile/ChangePass"; +import { useAuth } from "@/lib/contexts/auth"; + +const ProfileActions = () => { + const { getUser } = useAuth(); + const [openUpdate, setOpenUpdate] = useState(false); + const [openChangePass, setOpenChangePass] = useState(false); + + const openUpdateProfile = () => { + getUser(); + setOpenUpdate(true); + }; + + return ( + <> + + + + + + + + + + + + + + + { + setOpenChangePass(true); + }}> + + + + + + + + ); +}; +export default ProfileActions; diff --git a/src/core/components/Profile/ProfileInfo.jsx b/src/core/components/Profile/ProfileInfo.jsx new file mode 100644 index 0000000..ea33e8f --- /dev/null +++ b/src/core/components/Profile/ProfileInfo.jsx @@ -0,0 +1,34 @@ +"use client"; + +import { Avatar, Box, Chip, Divider, Stack, Typography } from "@mui/material"; + +const ProfileInfo = () => { + return ( + <> + + + + + حسن محمد زاده عبدالله + + .: اداره کل ستاد :. + + + + آخرین ورود + + 1 ساعت پیش + + + + + + + + ); +}; +export default ProfileInfo; diff --git a/src/core/components/Profile/Update/Form.jsx b/src/core/components/Profile/Update/Form.jsx new file mode 100644 index 0000000..7c9a340 --- /dev/null +++ b/src/core/components/Profile/Update/Form.jsx @@ -0,0 +1,248 @@ +"use client"; + +import { + Autocomplete, + Avatar, + Backdrop, + Box, + Button, + Chip, + Divider, + FormControl, + FormHelperText, + Grid, + InputLabel, + OutlinedInput, + TextField, +} from "@mui/material"; +import StyledForm from "@/core/components/StyledForm"; +import useRequest from "@/lib/hooks/useRequest"; +import { Controller, useForm } from "react-hook-form"; +import { useAuth } from "@/lib/contexts/auth"; +import CloudUploadIcon from "@mui/icons-material/CloudUpload"; +import { styled } from "@mui/material/styles"; +import { useEffect, useState } from "react"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { object, string } from "yup"; +import { UPDATE_USER_ROUTE } from "@/core/utils/routes"; + +const degreeItems = ["دیپلم", "کارشناسی", "کارشناسی ارشد", "دکترا"]; + +const VisuallyHiddenInput = styled("input")({ + clip: "rect(0 0 0 0)", + clipPath: "inset(50%)", + height: 1, + overflow: "hidden", + position: "absolute", + bottom: 0, + left: 0, + whiteSpace: "nowrap", + width: 1, +}); + +const validationSchema = object({ + first_name: string().required("اجباری"), + last_name: string().required("اجباری"), + degree: string().required("اجباری"), + major: string().required("اجباری"), + mobile: string().required("اجباری"), +}); + +const Form = ({ handleCloseForm, setLoading }) => { + const request = useRequest(); + const { user, getUser } = useAuth(); + const [uploadBackDrop, setUploadBackDrop] = useState(false); + const defaultValues = { + first_name: user.data.first_name, + last_name: user.data.last_name, + major: user.data.major, + degree: user.data.degree, + mobile: user.data.mobile, + avatar: null, + }; + + const { + control, + watch, + register, + setValue, + handleSubmit, + formState: { isSubmitting, errors }, + } = useForm({ defaultValues, resolver: yupResolver(validationSchema) }); + + useEffect(() => { + setLoading(isSubmitting); + }, [isSubmitting]); + + const onSubmit = async (data) => { + const formData = new FormData(); + formData.append("first_name", data.first_name); + formData.append("last_name", data.last_name); + formData.append("major", data.major); + formData.append("degree", data.degree); + formData.append("mobile", data.mobile); + if (data.avatar) { + formData.append("avatar", data.avatar); + } + + try { + await request(UPDATE_USER_ROUTE, "post", { data: formData }); + getUser(); + handleCloseForm(); + } catch (error) { + } + }; + + return ( + <> + + + + + + + + + + + نام + + {errors.first_name ? errors.first_name.message : null} + + + + + نام خانوادگی + + {errors.last_name ? errors.last_name.message : null} + + + + + رشته تحصیلی + + {errors.major ? errors.major.message : null} + + + + ( + + { + onChange(newValue); + }} + options={degreeItems} + renderInput={(params) => ( + + )} + /> + + {error ? error.message : null} + + + )} + /> + + + + موبایل + + {errors.mobile ? errors.mobile.message : null} + + + + + + ); +}; +export default Form; \ No newline at end of file diff --git a/src/core/components/Profile/Update/form.jsx b/src/core/components/Profile/Update/form.jsx deleted file mode 100644 index e69de29..0000000 diff --git a/src/core/components/Profile/Update/index.jsx b/src/core/components/Profile/Update/index.jsx index bb244ea..9228261 100644 --- a/src/core/components/Profile/Update/index.jsx +++ b/src/core/components/Profile/Update/index.jsx @@ -1,50 +1,36 @@ "use client"; -import { - Box, - Button, - Dialog, - DialogActions, - DialogContent, - DialogTitle, - IconButton, - useMediaQuery, -} from "@mui/material"; +import { Button, Dialog, DialogActions, DialogContent, useMediaQuery } from "@mui/material"; import { useTheme } from "@mui/material/styles"; -import CloseIcon from "@mui/icons-material/Close"; +import Form from "./Form"; +import SaveIcon from "@mui/icons-material/Save"; +import { LoadingButton } from "@mui/lab"; +import { useState } from "react"; const Update = ({ open, setOpen }) => { const theme = useTheme(); const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); + const [loading, setLoading] = useState(false); + + const handleCloseForm = () => { + setOpen(false); + }; return ( - { - setOpen(false); - }}> - - - ویرایش پروفایل - - { - setOpen(false); - }} - sx={{ color: (theme) => theme.palette.grey[500] }} - > - - - + - form will come here + - + }> + ثبت + ); diff --git a/src/core/components/Profile/index.jsx b/src/core/components/Profile/index.jsx index 0940b74..3741dc2 100644 --- a/src/core/components/Profile/index.jsx +++ b/src/core/components/Profile/index.jsx @@ -1,75 +1,20 @@ "use client"; -import { Avatar, Box, Chip, Divider, IconButton, Stack, Tooltip, Typography } from "@mui/material"; -import PowerSettingsNewIcon from "@mui/icons-material/PowerSettingsNew"; -import ModeEditIcon from "@mui/icons-material/ModeEdit"; -import VpnKeyIcon from "@mui/icons-material/VpnKey"; -import { useState } from "react"; -import Update from "@/core/components/Profile/Update"; -import ChangePass from "@/core/components/Profile/ChangePass"; +import { Stack } from "@mui/material"; +import ProfileInfo from "./ProfileInfo"; +import ProfileActions from "./ProfileActions"; const Profile = () => { - const [openUpdate, setOpenUpdate] = useState(false); - const [openChangePass, setOpenChangePass] = useState(false); - return ( - <> - - - - - - حسن محمد زاده عبدالله - - .: اداره کل ستاد :. - - - - آخرین ورود - - 1 ساعت پیش - - - - - - - - - { - setOpenUpdate(true); - }}> - - - - - - - - - - - - { - setOpenChangePass(true); - }}> - - - - - - - - + + + + ); }; export default Profile; diff --git a/src/core/utils/flattenObjectOfObjects.jsx b/src/core/utils/flattenObjectOfObjects.js similarity index 100% rename from src/core/utils/flattenObjectOfObjects.jsx rename to src/core/utils/flattenObjectOfObjects.js diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js index 5ab9d74..a666263 100644 --- a/src/core/utils/routes.js +++ b/src/core/utils/routes.js @@ -1,6 +1,8 @@ const api = process.env.NEXT_PUBLIC_API_URL; -export const GET_USER_ROUTE = api + "/webapi/user/get-permission"; +export const GET_USER_ROUTE = api + "/api/v3/profile/info"; +export const UPDATE_USER_ROUTE = api + "/api/v3/profile/edit"; +export const CHANGE_USER_PASSWORD = api + "/api/v3/profile/change_password"; export const GET_LOGIN_ROUTE = api + "/login_dev"; export const GET_INQUIRY_PRIVACY_FENCING_ROUTE = api + "/api/v3/harim/divarkeshi"; export const GET_PERMISSIONS_ROUTE = api + "/webapi/user/get-permission";