From 9d9b5838c41a2e3af4515b0ccbe8bad973a7cf11 Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Tue, 20 Aug 2024 16:19:39 +0330 Subject: [PATCH 1/4] working on uploading image --- src/core/components/Profile/Update/form.jsx | 131 +++++++++++++++++++ src/core/components/Profile/Update/index.jsx | 3 +- src/core/components/Profile/index.jsx | 11 +- src/core/utils/routes.js | 2 +- 4 files changed, 142 insertions(+), 5 deletions(-) diff --git a/src/core/components/Profile/Update/form.jsx b/src/core/components/Profile/Update/form.jsx index e69de29..c1b41a0 100644 --- a/src/core/components/Profile/Update/form.jsx +++ b/src/core/components/Profile/Update/form.jsx @@ -0,0 +1,131 @@ +"use client"; + +import { Autocomplete, Avatar, Backdrop, Badge, Box, Grid, 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 AddCircleIcon from "@mui/icons-material/AddCircle"; +import DataSAverOn from "@mui/icons-material/DataSAverOn"; +import { useState } from "react"; + +const degreeItems = ["دیپلم", "کارشناسی", "کارشناسی ارشد", "دکترا"]; + +const Form = () => { + const request = useRequest(); + const { user } = useAuth(); + const [uploadBackDrop, setUploadBackDrop] = useState(false); + const defaultValues = { + first_name: user.data.first_name, + last_name: user.data.last_name, + degree: user.data.degree, + major: user.data.major, + mobile: user.data.mobile, + avatar: user.data.avatar, + }; + + console.log("defaultValues", defaultValues); + + const { + control, + watch, + register, + handleSubmit, + setValue, + formState: { isSubmitting }, + } = useForm({ defaultValues: defaultValues }); + + return ( + + + } + > + setUploadBackDrop(true)} + onMouseLeave={() => setUploadBackDrop(false)} + alt={watch("first_name")} + src={`${process.env.NEXT_PUBLIC_API_URL}/${watch("avatar")}`} + sx={{ width: 150, height: 150, border: "1px solid #e1e1e1", cursor: "pointer" }} + /> + + theme.zIndex.drawer + 1, + position: "absolute", width: 150, height: 150, + marginLeft: "auto", marginRight: "auto", + borderRadius: "50%", + }} + open={uploadBackDrop} + > + + + + + + + + + + + + + + + ( + { + onChange(newValue); + }} + options={degreeItems} + renderInput={(params) => ( + + )} + /> + )} + /> + + + + + + + ); +}; +export default Form; \ No newline at end of file diff --git a/src/core/components/Profile/Update/index.jsx b/src/core/components/Profile/Update/index.jsx index bb244ea..e4183ac 100644 --- a/src/core/components/Profile/Update/index.jsx +++ b/src/core/components/Profile/Update/index.jsx @@ -12,6 +12,7 @@ import { } from "@mui/material"; import { useTheme } from "@mui/material/styles"; import CloseIcon from "@mui/icons-material/Close"; +import Form from "./form"; const Update = ({ open, setOpen }) => { const theme = useTheme(); @@ -37,7 +38,7 @@ const Update = ({ open, setOpen }) => { - form will come here +
+ + + + + + + + + + + + + + ( + { + onChange(newValue); + }} + options={degreeItems} + renderInput={(params) => ( + + )} + /> + )} + /> + + + + - - - - - + + ); }; export default Form; \ No newline at end of file diff --git a/src/core/components/Profile/Update/index.jsx b/src/core/components/Profile/Update/index.jsx index e4183ac..0353fcb 100644 --- a/src/core/components/Profile/Update/index.jsx +++ b/src/core/components/Profile/Update/index.jsx @@ -1,17 +1,7 @@ "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"; const Update = ({ open, setOpen }) => { @@ -23,25 +13,16 @@ const Update = ({ open, setOpen }) => { onClose={() => { setOpen(false); }}> - - - ویرایش پروفایل - - { - setOpen(false); - }} - sx={{ color: (theme) => theme.palette.grey[500] }} - > - - - - + - + ); 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 6520a50..d4d0558 100644 --- a/src/core/utils/routes.js +++ b/src/core/utils/routes.js @@ -1,6 +1,7 @@ const api = process.env.NEXT_PUBLIC_API_URL; export const GET_USER_ROUTE = api + "/api/v3/profile/info"; +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"; From 57ae81c791cb0f9e7e2c6c163733f1f8fc453fe6 Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Tue, 27 Aug 2024 15:51:05 +0330 Subject: [PATCH 4/4] complete profile update part and password completely --- .../components/Profile/ChangePass/Form.jsx | 27 +- .../components/Profile/ChangePass/index.jsx | 15 +- .../components/Profile/ProfileActions.jsx | 50 ++++ src/core/components/Profile/ProfileInfo.jsx | 34 +++ src/core/components/Profile/Update/Form.jsx | 248 ++++++++++++++++++ src/core/components/Profile/Update/form.jsx | 165 ------------ src/core/components/Profile/Update/index.jsx | 30 ++- src/core/components/Profile/index.jsx | 84 +----- src/core/utils/routes.js | 1 + 9 files changed, 381 insertions(+), 273 deletions(-) create mode 100644 src/core/components/Profile/ProfileActions.jsx create mode 100644 src/core/components/Profile/ProfileInfo.jsx create mode 100644 src/core/components/Profile/Update/Form.jsx delete mode 100644 src/core/components/Profile/Update/form.jsx diff --git a/src/core/components/Profile/ChangePass/Form.jsx b/src/core/components/Profile/ChangePass/Form.jsx index 75c0adb..3499394 100644 --- a/src/core/components/Profile/ChangePass/Form.jsx +++ b/src/core/components/Profile/ChangePass/Form.jsx @@ -13,7 +13,6 @@ import { } from "@mui/material"; import StyledForm from "@/core/components/StyledForm"; import { useForm } from "react-hook-form"; -import { useAuth } from "@/lib/contexts/auth"; import useRequest from "@/lib/hooks/useRequest"; import { CHANGE_USER_PASSWORD } from "@/core/utils/routes"; import { object, string } from "yup"; @@ -35,12 +34,10 @@ const validationSchema = object({ }); const Form = ({ handleCloseForm, setLoading }) => { + const request = useRequest(); const [showNewPassword, setShowNewPassword] = useState(); const [showRepeatNewPassword, setShowRepeatNewPassword] = useState(); - const request = useRequest(); - const { getUser } = useAuth(); - const defaultValues = { current_password: "", new_password: "", @@ -48,11 +45,8 @@ const Form = ({ handleCloseForm, setLoading }) => { }; const { - control, - watch, register, handleSubmit, - setValue, formState: { isSubmitting, errors }, } = useForm({ defaultValues, resolver: yupResolver(validationSchema) }); @@ -65,7 +59,7 @@ const Form = ({ handleCloseForm, setLoading }) => { formData.append("current_password", data.current_password); formData.append("new_password", data.new_password); try { - await request(CHANGE_USER_PASSWORD, "post", { data: formData }); + await request(CHANGE_USER_PASSWORD, "post", { data: formData, signal: controller.signal }); handleCloseForm(); } catch (error) { } @@ -77,7 +71,7 @@ const Form = ({ handleCloseForm, setLoading }) => { - + رمز عبور فعلی @@ -90,8 +84,9 @@ const Form = ({ handleCloseForm, setLoading }) => { fullWidth type="text" /> - {errors.current_password ? errors.current_password.message : null} + + {errors.current_password ? errors.current_password.message : null} + @@ -118,8 +113,9 @@ const Form = ({ handleCloseForm, setLoading }) => { } /> - {errors.new_password ? errors.new_password.message : null} + + {errors.new_password ? errors.new_password.message : null} + @@ -146,8 +142,9 @@ const Form = ({ handleCloseForm, setLoading }) => { } /> - {errors.repeat_new_password ? errors.repeat_new_password.message : null} + + {errors.repeat_new_password ? errors.repeat_new_password.message : null} + diff --git a/src/core/components/Profile/ChangePass/index.jsx b/src/core/components/Profile/ChangePass/index.jsx index 085f40c..15e6fcd 100644 --- a/src/core/components/Profile/ChangePass/index.jsx +++ b/src/core/components/Profile/ChangePass/index.jsx @@ -1,14 +1,12 @@ "use client"; -import { Button, Dialog, DialogActions, DialogContent } from "@mui/material"; -import { useTheme } from "@mui/material/styles"; +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 [loading, setLoading] = useState(false); const handleCloseForm = () => { @@ -16,16 +14,17 @@ const ChangePass = ({ open, setOpen }) => { }; return ( - + - - + }> 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 fe56a12..0000000 --- a/src/core/components/Profile/Update/form.jsx +++ /dev/null @@ -1,165 +0,0 @@ -"use client"; - -import { Autocomplete, Avatar, Backdrop, Box, Button, Chip, Divider, Grid, 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 { useState } from "react"; - -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 degreeItems = ["دیپلم", "کارشناسی", "کارشناسی ارشد", "دکترا"]; - -const Form = () => { - const request = useRequest(); - const { user } = useAuth(); - const [uploadBackDrop, setUploadBackDrop] = useState(false); - const defaultValues = { - first_name: user.data.first_name, - last_name: user.data.last_name, - degree: user.data.degree, - major: user.data.major, - mobile: user.data.mobile, - avatar: user.data.avatar, - }; - - const { - control, - watch, - register, - handleSubmit, - setValue, - formState: { isSubmitting }, - } = useForm({ defaultValues: defaultValues }); - - return ( - <> - - - - - - - - - - - - - - - - - - - ( - { - onChange(newValue); - }} - options={degreeItems} - renderInput={(params) => ( - - )} - /> - )} - /> - - - - - - - - ); -}; -export default Form; \ No newline at end of file diff --git a/src/core/components/Profile/Update/index.jsx b/src/core/components/Profile/Update/index.jsx index 0353fcb..9228261 100644 --- a/src/core/components/Profile/Update/index.jsx +++ b/src/core/components/Profile/Update/index.jsx @@ -2,31 +2,35 @@ import { Button, Dialog, DialogActions, DialogContent, useMediaQuery } from "@mui/material"; import { useTheme } from "@mui/material/styles"; -import Form from "./form"; +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); - }}> + - + - - + ); diff --git a/src/core/components/Profile/index.jsx b/src/core/components/Profile/index.jsx index bca57a4..3741dc2 100644 --- a/src/core/components/Profile/index.jsx +++ b/src/core/components/Profile/index.jsx @@ -1,80 +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 { useAuth } from "@/lib/contexts/auth"; +import { Stack } from "@mui/material"; +import ProfileInfo from "./ProfileInfo"; +import ProfileActions from "./ProfileActions"; const Profile = () => { - const { getUser } = useAuth(); - const [openUpdate, setOpenUpdate] = useState(false); - const [openChangePass, setOpenChangePass] = useState(false); - - const openUpdateProfile = () => { - getUser(); - setOpenUpdate(true); - }; - return ( - <> - - - - - - حسن محمد زاده عبدالله - - .: اداره کل ستاد :. - - - - آخرین ورود - - 1 ساعت پیش - - - - - - - - - - - - - - - - - - - - - { - setOpenChangePass(true); - }}> - - - - - - - - + + + + ); }; export default Profile; diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js index d4d0558..a209036 100644 --- a/src/core/utils/routes.js +++ b/src/core/utils/routes.js @@ -1,6 +1,7 @@ const api = process.env.NEXT_PUBLIC_API_URL; 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";