From f2cebef2bf5e0e430e3a4dfb486940c509c0087f Mon Sep 17 00:00:00 2001 From: RezaAshrafi77 Date: Fri, 8 Oct 2021 20:48:44 +0330 Subject: [PATCH] reza added basic profile --- package.json | 1 + src/components/Input/index.js | 25 +- src/components/Navbar/index.scss | 4 +- src/components/Select/index.tsx | 7 +- src/components/Textarea/index.scss | 10 +- src/custom.scss | 26 +- src/redux/actions-type/file.tsx | 21 + src/redux/actions-type/index.tsx | 2 + src/redux/actions-type/public.tsx | 61 ++- src/redux/actions/file.js | 22 + src/redux/actions/index.tsx | 2 + src/redux/actions/public.tsx | 4 + src/redux/reducers/file.tsx | 27 + src/redux/reducers/index.tsx | 2 + src/redux/reducers/public.tsx | 7 +- src/router.js | 4 +- src/views/Auth/Login/index.tsx | 8 +- src/views/Auth/Profile/Birthdate/index.js | 61 +++ src/views/Auth/Profile/Birthdate/index.scss | 85 ++++ src/views/Auth/Profile/Document/index.js | 111 +++++ src/views/Auth/Profile/Document/index.scss | 28 ++ src/views/Auth/Profile/GenderSwitch/index.js | 28 ++ .../Auth/Profile/GenderSwitch/index.scss | 44 ++ .../Auth/Profile/MultipleSelector/index.js | 96 ++++ .../Auth/Profile/MultipleSelector/index.scss | 10 + src/views/Auth/Profile/Upload/index.js | 29 ++ src/views/Auth/Profile/Upload/index.scss | 55 +++ src/views/Auth/Profile/index.scss | 422 ++++++++++++++++ src/views/Auth/Profile/index.tsx | 460 +++++++++++++++++- src/views/Auth/SignUp/index.tsx | 24 +- src/views/Contact/index.tsx | 4 +- src/views/Home/Courses/index.tsx | 4 +- yarn.lock | 115 ++++- 33 files changed, 1733 insertions(+), 76 deletions(-) create mode 100644 src/redux/actions-type/file.tsx create mode 100644 src/redux/actions/file.js create mode 100644 src/redux/reducers/file.tsx create mode 100644 src/views/Auth/Profile/Birthdate/index.js create mode 100644 src/views/Auth/Profile/Birthdate/index.scss create mode 100644 src/views/Auth/Profile/Document/index.js create mode 100644 src/views/Auth/Profile/Document/index.scss create mode 100644 src/views/Auth/Profile/GenderSwitch/index.js create mode 100644 src/views/Auth/Profile/GenderSwitch/index.scss create mode 100644 src/views/Auth/Profile/MultipleSelector/index.js create mode 100644 src/views/Auth/Profile/MultipleSelector/index.scss create mode 100644 src/views/Auth/Profile/Upload/index.js create mode 100644 src/views/Auth/Profile/Upload/index.scss create mode 100644 src/views/Auth/Profile/index.scss diff --git a/package.json b/package.json index 0f3483d..a185c62 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "fs-extra": "^9.0.1", "html-webpack-plugin": "4.5.0", "identity-obj-proxy": "3.0.0", + "jalali-moment": "^3.3.10", "jest": "26.6.0", "jest-circus": "26.6.0", "jest-resolve": "26.6.0", diff --git a/src/components/Input/index.js b/src/components/Input/index.js index 4872881..d408fe5 100644 --- a/src/components/Input/index.js +++ b/src/components/Input/index.js @@ -2,7 +2,16 @@ import React from "react"; import TextField from "@mui/material/TextField"; import { makeStyles } from "@mui/styles"; -export default function FormPropsTextFields(props) { +export default function FormPropsTextFields({ + defaultValue, + maxLength, + inputMode, + onInput, + onChange, + align, + label, + name, +}) { const useStyles = makeStyles((theme) => ({ root: { "& .MuiTextField-root": { @@ -10,8 +19,8 @@ export default function FormPropsTextFields(props) { position: "relative", marginRight: 10, "& input": { - textAlign: props.align, - direction: props.align === "right" ? "rtl" : "ltr", + textAlign: align, + direction: align === "right" ? "rtl" : "ltr", }, fontFamily: "numeralLight", }, @@ -19,18 +28,16 @@ export default function FormPropsTextFields(props) { })); const classes = useStyles(); - const { defaultValue, maxLength, inputMode, onInput, variant, onChange } = - props; return (
onChange(e)} - defaultValue={defaultValue[props.name] || ""} + defaultValue={defaultValue[name] || ""} inputProps={{ maxLength }} onInput={ onInput diff --git a/src/components/Navbar/index.scss b/src/components/Navbar/index.scss index 00be9d9..e28aad1 100644 --- a/src/components/Navbar/index.scss +++ b/src/components/Navbar/index.scss @@ -1,12 +1,12 @@ .nav{ width: 100%; - background-color: #292929; + background-color: black; height: 60px; padding: 0px 10px; position: fixed !important; top: 0px !important; left: 0px; - z-index: 100; + z-index: 150; &__container{ width: 100%; font-family: numeralLight; diff --git a/src/components/Select/index.tsx b/src/components/Select/index.tsx index 876d7a2..1b893d1 100644 --- a/src/components/Select/index.tsx +++ b/src/components/Select/index.tsx @@ -32,9 +32,10 @@ export default function CustomizedSelects({ labelId="demo-simple-select-label" id="demo-simple-select" value={selectedOptions} - onChange={(e: any) => onChange(e)} + onChange={(e: any) => onChange(name, e.target.value)} + > - {options.map((option: any, i: any) => ( + {options?.map((option: any, i: any) => ( {option.name} @@ -45,7 +46,7 @@ export default function CustomizedSelects({ style={{ position: "absolute", left: 5, - top: 25, + top: 19, fontSize: 30, color: "#a5a5a5", }} diff --git a/src/components/Textarea/index.scss b/src/components/Textarea/index.scss index ca70370..8fdb7fb 100644 --- a/src/components/Textarea/index.scss +++ b/src/components/Textarea/index.scss @@ -4,7 +4,7 @@ color: white; border-radius: 10px; border: 1px solid #707070; - background-color: #272727; + background-color: black; margin-top: 10px; &::placeholder{ color: #a2a2a2; @@ -20,18 +20,18 @@ @media screen and (min-width: 1441px){ .custom-textarea{ - font-size: 20px; + font-size: 16px; &::placeholder{ - font-size: 20px; + font-size: 16px; } } } @media screen and (min-width: 1008px) and (max-width: 1440px) { .custom-textarea{ - font-size: calc(100vw / 85); + font-size: calc(100vw / 110); &::placeholder{ - font-size: calc(100vw / 85); + font-size: calc(100vw / 110); } } } diff --git a/src/custom.scss b/src/custom.scss index 7e5dd84..882c0ba 100644 --- a/src/custom.scss +++ b/src/custom.scss @@ -84,21 +84,7 @@ } .main { - background: linear-gradient( - 135deg, - hsla(0, 0%, 31%, 1) 0%, - hsla(0, 0%, 0%, 1) 100% - ); - background: -moz-linear-gradient( - 135deg, - hsla(0, 0%, 31%, 1) 0%, - hsla(0, 0%, 0%, 1) 100% - ); - background: -webkit-linear-gradient( - 135deg, - hsla(0, 0%, 31%, 1) 0%, - hsla(0, 0%, 0%, 1) 100% - ); + background: black; width: 100%; overflow-x: hidden; padding-top: 60px; @@ -186,6 +172,11 @@ } @media screen and (min-width: 641px) and (max-width: 1007px) { + .main{ + main { + max-width: 900px; + } + } .desktop{ display: none !important; } @@ -195,6 +186,11 @@ } @media screen and (max-width: 640px) { + .main{ + main { + max-width: 500px; + } + } .desktop{ display: none !important; } diff --git a/src/redux/actions-type/file.tsx b/src/redux/actions-type/file.tsx new file mode 100644 index 0000000..4611f83 --- /dev/null +++ b/src/redux/actions-type/file.tsx @@ -0,0 +1,21 @@ +interface fileUpload { + type : "file/upload" + data : any + params : any +} + +interface error{ + type : "file/error" + data : undefined + params : any +} + +interface loading{ + type : "file/loading" + data : undefined + params : any +} + +type FileAction = fileUpload | loading | error; + +export default FileAction; diff --git a/src/redux/actions-type/index.tsx b/src/redux/actions-type/index.tsx index d4d6cd3..ffb5beb 100644 --- a/src/redux/actions-type/index.tsx +++ b/src/redux/actions-type/index.tsx @@ -5,6 +5,8 @@ export type { default as BookAction } from "./book"; export type { default as BlogAction } from "./blog"; export type { default as productAction } from "./product"; export type { default as FaqAction } from "./faq"; +export type { default as FileAction } from "./file"; + diff --git a/src/redux/actions-type/public.tsx b/src/redux/actions-type/public.tsx index 5715dec..26a6e9c 100644 --- a/src/redux/actions-type/public.tsx +++ b/src/redux/actions-type/public.tsx @@ -1,44 +1,61 @@ interface getHomeData { - type : "public/homePage" - data : any + type: "public/homePage"; + data: any; } -interface getBlogList{ - type : "public/blogList" - data : any +interface getBlogList { + type: "public/blogList"; + data: any; } -interface getBlogInfo{ - type : "public/blogInfo" - data : any +interface getBlogInfo { + type: "public/blogInfo"; + data: any; } -interface setFaqActive{ - type : "public/faq/activate" - data : any +interface setFaqActive { + type: "public/faq/activate"; + data: any; } -interface setSubscribe{ - type: "public/setSubscribe" - data: any +interface setSubscribe { + type: "public/setSubscribe"; + data: any; } -interface error{ - type : "error" - data : undefined +interface getProvince { + type: "public/province"; + data: any; } -interface loading{ - type : "loading" - data : undefined +interface getCity { + type: "public/city"; + data: any; } +interface error { + type: "error"; + data: undefined; +} + +interface loading { + type: "loading"; + data: undefined; +} // interface filterNewProducts{ // } - -type PublicAction = getBlogList | getBlogInfo | setSubscribe | getHomeData | setFaqActive | loading | error; +type PublicAction = + | getBlogList + | getBlogInfo + | setSubscribe + | getHomeData + | setFaqActive + | getProvince + | getCity + | loading + | error; export default PublicAction; diff --git a/src/redux/actions/file.js b/src/redux/actions/file.js new file mode 100644 index 0000000..02090a1 --- /dev/null +++ b/src/redux/actions/file.js @@ -0,0 +1,22 @@ +import proxy from "../proxy"; +const file = { + upload: + (data = {}) => + async (dispatch) => { + var formData = new FormData(); + for (let key in data) formData.append(key, data[key]); + return await proxy.post( + "file/upload", + formData, + { + dispatch, + headers: { + "Content-Type": "multipart/form-data", + }, + }, + data + ); + }, +}; + +export default file; diff --git a/src/redux/actions/index.tsx b/src/redux/actions/index.tsx index 91b6719..9fd9385 100644 --- a/src/redux/actions/index.tsx +++ b/src/redux/actions/index.tsx @@ -8,6 +8,8 @@ export { default as userFactor } from "./userFactor"; export { default as userProduct } from "./userProduct"; export { default as content } from "./content"; export { default as faq } from "./faq"; +export { default as file } from "./file"; + diff --git a/src/redux/actions/public.tsx b/src/redux/actions/public.tsx index 8295be0..3dce707 100644 --- a/src/redux/actions/public.tsx +++ b/src/redux/actions/public.tsx @@ -28,6 +28,10 @@ const publicApi = { await proxy.get("public/blogInfo", data, { dispatch }), setSubscribe : (data: Object) => async (dispatch: Dispatch) => await dispatch({type : "public/setSubscribe", data : data}), + getProvince: (data = {}) => async (dispatch : Dispatch) => + await proxy.get("public/province", data, { dispatch }), + getCity: (data = {}) => async (dispatch : Dispatch) => + await proxy.get("public/city", data, { dispatch }), // filterNewProducts: (data: Object) => async (dispatch: Dispatch) => // await dispatch({ type: "public/filter", data: data }), }; diff --git a/src/redux/reducers/file.tsx b/src/redux/reducers/file.tsx new file mode 100644 index 0000000..c4cd6a0 --- /dev/null +++ b/src/redux/reducers/file.tsx @@ -0,0 +1,27 @@ +import {FileAction} from '../actions-type'; +const initialState = { + loading: false, + error: null, + uploads: {}, + lastUpload: null, +}; + +export default function file(state = initialState, action : FileAction) { + let { type, data, params } = action; + switch (type) { + case "file/upload": + return { + ...state, + loading: false, + error: null, + uploads: { ...state.uploads, [params?.target || "last"]: data.id }, + lastUpload: data.id, + }; + case "file/loading": + return { ...state, loading: true }; + case "file/error": + return { ...state, loading: false, error: data.message }; + default: + return state; + } +} diff --git a/src/redux/reducers/index.tsx b/src/redux/reducers/index.tsx index 9482a60..643033b 100644 --- a/src/redux/reducers/index.tsx +++ b/src/redux/reducers/index.tsx @@ -5,3 +5,5 @@ export { default as book } from "./book"; export { default as blog } from "./blog"; export { default as product } from "./product"; export { default as faq } from "./faq"; +export { default as file } from "./file"; + diff --git a/src/redux/reducers/public.tsx b/src/redux/reducers/public.tsx index a1c9806..203acf1 100644 --- a/src/redux/reducers/public.tsx +++ b/src/redux/reducers/public.tsx @@ -1,7 +1,6 @@ import { PublicAction } from "../actions-type"; import proxy from '../proxy'; const initialState = { - status : proxy.status(), homeData: [], newProducts: [], levels: [], @@ -11,6 +10,8 @@ const initialState = { arList: [], blogList: [], blog: null, + province : null, + city : null, mockSubscribes: [ { id: 0, @@ -261,6 +262,10 @@ export default function publicApi(state = initialState, action: PublicAction) { return { ...state, loading: false, error: null, blog: data }; case "public/setSubscribe": return { ...state, loading: false, error: null, selectedSubscribe : data }; + case "public/province": + return { ...state, loading: false, error: null, province: data }; + case "public/city": + return { ...state, loading: false, error: null, city: data }; case "loading": return { ...state, loading: true }; case "error": diff --git a/src/router.js b/src/router.js index 536f281..e9b7d76 100644 --- a/src/router.js +++ b/src/router.js @@ -19,7 +19,7 @@ import proxy from "./redux/proxy"; function router({ status }) { const home = ( - {proxy.status() ? : } + {status ? : } ); return ( @@ -62,5 +62,5 @@ function router({ status }) { } export default connect((state) => ({ - status: state.publicApi.status, + status: state.user.status, }))(router); diff --git a/src/views/Auth/Login/index.tsx b/src/views/Auth/Login/index.tsx index 9aab3fa..3460013 100644 --- a/src/views/Auth/Login/index.tsx +++ b/src/views/Auth/Login/index.tsx @@ -27,8 +27,8 @@ function Login(props: any) { const onChange = (name: string, value: string) => { setSignUpFiels({ ...loginFields, [name]: value }); }; - const usernameInput = useRef(); - const passwordInput = useRef(); + // const usernameInput = useRef(); + // const passwordInput = useRef(); useEffect(() => { @@ -57,7 +57,7 @@ function Login(props: any) { align="left" onInput={onInput.englishAndNumberWithoutSpace} onChange={onChange} - ref={usernameInput} + // ref={usernameInput} />
diff --git a/src/views/Auth/Profile/Birthdate/index.js b/src/views/Auth/Profile/Birthdate/index.js new file mode 100644 index 0000000..8fbc0dd --- /dev/null +++ b/src/views/Auth/Profile/Birthdate/index.js @@ -0,0 +1,61 @@ +import React, { useState } from "react"; +import onInput from "~/util/onInput"; +import Input from "../../../../components/Input/index"; +import "./index.scss"; +import moment from "jalali-moment"; +export default function Birthdate(props) { + const { defaultValue, parent, name } = props; + let momentDate = moment(defaultValue[name]); + let isvalid = momentDate.isValid(); + const day = isvalid ? momentDate.format("jDD") : null, + month = isvalid ? momentDate.format("jMM") : null, + year = isvalid ? momentDate.format("jYYYY") : null; + const [state, setState] = useState({ day, month, year }); + const onChange = (_name, value) => { + let _state = { ...state, [_name]: value }; + setState(_state); + + parent.onChange( + name, + moment + .from(`${_state.year}/${_state.month}/${_state.day}`, "fa", "YYYY/M/D") + .locale("en") + ); + }; + return ( +
+ +
+ + / + + / + +
+
+ ); +} diff --git a/src/views/Auth/Profile/Birthdate/index.scss b/src/views/Auth/Profile/Birthdate/index.scss new file mode 100644 index 0000000..2ceef16 --- /dev/null +++ b/src/views/Auth/Profile/Birthdate/index.scss @@ -0,0 +1,85 @@ +.birthdate { + width: 100%; + border-radius: 10px; + padding: 0px 10px; + border: 1px solid #777; + margin: 10px 0px; + label { + width: fit-content; + color: #ccc; + font-weight: 100; + } + span { + color: #bfbfbf; + } + + input { + border: 0px; + background-color: rgba(204, 204, 204, 0.098); + font-family: numeralLight; + color: #84de56; + max-width: 40px; + text-align: center !important; + direction: ltr; + margin: 0px 5px; + border: none; + &:focus { + outline: 0px; + border: 0px; + } + &::placeholder { + color: #bfbfbf; + } + } + + +} + +@media screen and (max-width: 1000px) { + span { + font-size: 14px; + } + input { + font-size: 14px; + + &::placeholder { + font-size: 15px; + } + } +} + +@media screen and (min-width: 6401px) and (max-width: 1007px) { + .birthdate { + label { + font-size: calc(100vw / 40) !important; + } + span { + font-size: calc(100vw / 35); + } + input { + font-size: calc(100vw / 20); + margin: 0px 5px !important; + &::placeholder { + font-size: calc(100vw / 30); + } + } + } +} + +@media screen and (max-width: 640px) { + .birthdate { + label { + font-size: calc(100vw / 35) !important; + } + span { + font-size: calc(100vw / 35); + } + input { + font-size: calc(100vw / 20); + + &::placeholder { + font-size: calc(100vw / 30); + } + } + } +} \ No newline at end of file diff --git a/src/views/Auth/Profile/Document/index.js b/src/views/Auth/Profile/Document/index.js new file mode 100644 index 0000000..92fd674 --- /dev/null +++ b/src/views/Auth/Profile/Document/index.js @@ -0,0 +1,111 @@ +import React from "react"; +import "./index.scss"; + +const maxDesktopSize = 1250; +const maxMobileSize = 550; + +const fontSize = { + desktop: { + span: window.innerWidth > maxDesktopSize ? 14 : window.innerWidth / 80, + }, + mobile: { + span: window.innerWidth > maxMobileSize ? 14 : window.innerWidth / 30, + }, +}; + +export default function Document(props) { + const { parent, name } = props; + return ( + <> + {window.innerWidth < 1000 ? ( +
+ {parent.state[name] === "" ? ( + <> + + parent.onChange(e.target.name, e.target.files[0]) + } + /> + + گواهی تدریس خود را آپلود کنید. + + + ) : ( + <> + + parent.onChange(e.target.name, e.target.files[0]) + } + /> + + {parent.state[name].name || + "گواهی تدریس ثبت شده و درحال بررسی می باشد"} + + + )} +
+ ) : null} + {window.innerWidth > 1000 ? ( +
+ {parent.state[name] === "" ? ( + <> + + parent.onChange(e.target.name, e.target.files[0]) + } + /> + + گواهی تدریس خود را آپلود کنید. + + + ) : ( + <> + + parent.onChange(e.target.name, e.target.files[0]) + } + name={props.name} + defaultValue="" + type="file" + /> + + {parent.state[name].name || + "گواهی تدریس ثبت شده و درحال بررسی می باشد"} + + + )} +
+ ) : null} + + ); +} diff --git a/src/views/Auth/Profile/Document/index.scss b/src/views/Auth/Profile/Document/index.scss new file mode 100644 index 0000000..e31bad8 --- /dev/null +++ b/src/views/Auth/Profile/Document/index.scss @@ -0,0 +1,28 @@ +.mobile-auth-profile { + &__document { + margin: 10px auto; + width: 100%; + height: 50px; + border-radius: 10px; + border: 2px dashed rgb(209, 209, 209); + position: relative; + input { + width: 100%; + height: 100%; + position: absolute; + left: 0px; + top: 0px; + opacity: 0; + } + img { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 50%; + } + span { + color: #afafaf; + font-family: numeralLight; + } + } +} diff --git a/src/views/Auth/Profile/GenderSwitch/index.js b/src/views/Auth/Profile/GenderSwitch/index.js new file mode 100644 index 0000000..cd647d6 --- /dev/null +++ b/src/views/Auth/Profile/GenderSwitch/index.js @@ -0,0 +1,28 @@ +import React from "react"; + +import "./index.scss"; + +export default function GenderSwitch({ + onChange, + name, + options, + selectedOption, + label, +}) { + return ( +
+
onChange(name, 2)} + > + {options[0]} +
+
onChange(name, 1)} + > + {options[1]} +
+
+ ); +} diff --git a/src/views/Auth/Profile/GenderSwitch/index.scss b/src/views/Auth/Profile/GenderSwitch/index.scss new file mode 100644 index 0000000..0060721 --- /dev/null +++ b/src/views/Auth/Profile/GenderSwitch/index.scss @@ -0,0 +1,44 @@ +.gender { + width: 100%; + margin-bottom: 10px; + div { + border-radius: 10px; + font-family: numeralLight; + padding: 13px 0px; + width: 45%; + text-align: center; + cursor: pointer; + color: #ccc; + background-color: black; + border: 1px solid #777; + } + &__active{ + background-color: #84de56 !important; + color: white !important; + border: none !important; + } +} + +@media screen and (min-width: 1441px) { + .gender{ + font-size: 16px; + } +} + +@media screen and (min-width: 1008px) and (max-width: 1440px) { + .gender{ + font-size: calc(100vw / 90); + } +} + +@media screen and (min-width: 641px) and (max-width: 1007px) { + .gender{ + font-size: calc(100vw / 40); + } +} + +@media screen and (max-width: 640px) { + .gender{ + font-size: calc(100vw / 30); + } +} diff --git a/src/views/Auth/Profile/MultipleSelector/index.js b/src/views/Auth/Profile/MultipleSelector/index.js new file mode 100644 index 0000000..029e696 --- /dev/null +++ b/src/views/Auth/Profile/MultipleSelector/index.js @@ -0,0 +1,96 @@ +import React from "react"; +import Select from "@mui/material/Select"; +import { makeStyles } from "@mui/styles"; +import Input from "@mui/material/Input"; +import InputLabel from "@mui/material/InputLabel"; +import MenuItem from "@mui/material/MenuItem"; +import FormControl from "@mui/material/FormControl"; +import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; + +import "./index.scss"; +export default function MultipleSelector(props) { + const useStyles = makeStyles((theme) => ({ + root: { + "& .MuiTextField-root": { + width: "100%", + position: "relative", + marginRight: 10, + "& input": { + textAlign: props.align, + direction: props.align === "right" ? "rtl" : "ltr", + }, + }, + }, + })); + + const classes = useStyles(); + const { parent, defaultValue, name, label, options, selectedOptions } = props; + return ( + <> + {window.innerWidth < 1000 ? ( + + {label} + } + variant="outlined" + > + {options.map((name, i) => ( + + {name} + + ))} + + + + ) : null} + {window.innerWidth > 1000 ? ( + + {label} + } + variant="outlined" + > + {options.map((name, i) => ( + + {name} + + ))} + + + + ) : null} + + ); +} diff --git a/src/views/Auth/Profile/MultipleSelector/index.scss b/src/views/Auth/Profile/MultipleSelector/index.scss new file mode 100644 index 0000000..5578cc0 --- /dev/null +++ b/src/views/Auth/Profile/MultipleSelector/index.scss @@ -0,0 +1,10 @@ +.mobile-multiple-selector { + width: 100%; + border-radius: 10px; + padding: 9px 10px; + border: 1px solid #ccc !important; + margin: 0px !important; + .MuiInput-formControl { + margin: 9px 0px 8px !important; + } +} diff --git a/src/views/Auth/Profile/Upload/index.js b/src/views/Auth/Profile/Upload/index.js new file mode 100644 index 0000000..18b52d9 --- /dev/null +++ b/src/views/Auth/Profile/Upload/index.js @@ -0,0 +1,29 @@ +import React from "react"; +import AddAPhotoIcon from "@mui/icons-material/AddAPhoto"; +import './index.scss'; + +export default function Upload({ name, value, onChange, label }) { + return ( +
+ <> + {value === null ? ( + + ) : ( + {"کاربر"} + )} + onChange(e.target.name, e.target.files[0])} + /> + +
+ ); +} diff --git a/src/views/Auth/Profile/Upload/index.scss b/src/views/Auth/Profile/Upload/index.scss new file mode 100644 index 0000000..eb41ed6 --- /dev/null +++ b/src/views/Auth/Profile/Upload/index.scss @@ -0,0 +1,55 @@ +.profile-upload { + width: 100px; + height: 100px; + border-radius: 50%; + margin-top: 15px auto 0px; + // border: 2px dotted #ccc; + position: relative; + background-color: #272727; + input { + width: 100%; + height: 100%; + opacity: 0; + position: absolute; + left: 0px; + top: 0px; + z-index: 50; + } + span { + color: #505a82; + font-family: numeralLight; + height: 20px; + position: absolute; + left: 0px; + top: calc(50% - 10px); + width: 100%; + text-align: center; + z-index: 10; + } +} + +@media screen and (min-width: 1441px) { + .profile-upload { + + } +} + +@media screen and (min-width: 1008px) and (max-width: 1440px) { + .profile-upload { + + } +} + +@media screen and (min-width: 641px) and (max-width: 1007px) { + .profile-upload { + width: 80px; + height: 80px; + } +} + +@media screen and (max-width: 640px) { + .profile-upload { + width : 80px; + height : 80px; + } +} diff --git a/src/views/Auth/Profile/index.scss b/src/views/Auth/Profile/index.scss new file mode 100644 index 0000000..61be694 --- /dev/null +++ b/src/views/Auth/Profile/index.scss @@ -0,0 +1,422 @@ +.MuiOutlinedInput-input { + font-family: numeralLight !important; +} + +.profile { + scrollbar-width: 0px; + padding: 50px 20px 0px; + &::-webkit-scrollbar { + display: none; + } + header { + margin: 30px 0px; + h1 { + margin-top: 15px; + font-family: numeralMedium; + color: white; + letter-spacing: -1px; + } + p { + font-family: numeralLight; + color: white; + text-align: justify; + } + } + &__box { + width: 100%; + border: 1px solid #777; + border-radius: 20px; + &--section { + width: 45%; + } + + .MuiMenu-list, + .MuiFormControl-root { + width: 100%; + margin: 10px auto !important; + scrollbar-width: 0px !important; + &::-webkit-scrollbar { + display: none !important; + width: 0px !important; + } + option { + font-family: numeralLight !important; + } + .MuiSelect-iconOutlined { + display: none; + } + .MuiSelect-outlined.MuiSelect-outlined { + padding-right: 15px; + } + color: #797979 !important; + } + + button { + margin-top: 20px; + margin-bottom: 50px; + font-family: numeralLight; + border: 0px; + background-color: #00cc69; + border-radius: 7px; + color: white; + padding: 12px 0px; + width: 100%; + } + } +} + +@media screen and (min-width: 1441px) { + .profile { + button { + font-size: 21px; + } + header { + } + &__box { + flex-direction: row; + justify-content: space-around; + padding: 30px 10px; + } + } + .MuiFormControl-root { + width: 100%; + margin: 10px auto !important; + .MuiSelect-iconOutlined { + display: none; + } + .MuiSelect-outlined.MuiSelect-outlined { + padding-right: 15px; + } + color: #797979 !important; + } + .MuiOutlinedInput-notchedOutline { + top: 0px !important; + } + .MuiOutlinedInput-notchedOutline { + border-color: #666666 !important; + border-width: 1px !important; + color: green !important; + border-radius: 10px !important; + } + + .MuiOutlinedInput-input { + padding: 15px 14px !important; + font-family: numeralLight; + font-size: 20px; + color: #84de56 !important; + &:focus { + border: 0.2px solid #84de56 !important; + border-radius: 10px; + transform: translateY(0.5px); + border-radius: 10px !important; + } + } + .MuiInputLabel-outlined { + font-family: numeralLight !important; + display: inline !important; + position: absolute; + text-align: right !important; + right: 15px !important; + top: 50% !important; + padding: 0px !important; + transform: translate(0px, -50%) scale(1) !important; + } + .MuiInputLabel-shrink { + text-align: center !important; + display: inline; + position: absolute; + right: 0px !important; + top: -8px !important; + transform: translate(0px, 0px) scale(0.85) !important; + padding: 0px 10px !important; + } + + label { + background-color: black; + width: fit-content; + text-align: center; + color: #b5b5b5 !important; + letter-spacing: -1px; + font-size: 14px !important; + } + .Mui-focused { + color: rgba(0, 0, 0, 1) !important; + border-color: #84de56 !important; + // background-color: white; + color: #84de56 !important; + } + + .MuiInputBase-input { + height: auto !important; + } +} + +@media screen and (min-width: 1008px) and (max-width: 1440px) { + .profile { + button { + font-size: calc(100vw / 70); + } + &__box { + padding: 30px 10px; + flex-direction: row; + justify-content: space-around; + } + } + .MuiFormControl-root { + width: 100%; + margin: 10px auto !important; + .MuiSelect-iconOutlined { + display: none; + } + .MuiSelect-outlined.MuiSelect-outlined { + padding-right: 15px; + } + color: #797979 !important; + } + .MuiOutlinedInput-notchedOutline { + top: 0px !important; + } + .MuiOutlinedInput-notchedOutline { + border-color: #666666 !important; + border-width: 1px !important; + color: green !important; + border-radius: 10px !important; + } + + .MuiOutlinedInput-input { + padding: 15px 14px !important; + font-family: numeralLight; + font-size: calc(100vw / 80) !important; + color: #84de56 !important; + &:focus { + border: 0.2px solid #84de56 !important; + border-radius: 10px; + transform: translateY(0px); + z-index: 100; + border-radius: 10px !important; + } + } + .MuiInputLabel-outlined { + font-family: numeralLight !important; + display: inline !important; + position: absolute; + text-align: right !important; + right: 10px !important; + top: 50% !important; + padding: 0px !important; + transform: translate(0px, -50%) scale(1) !important; + } + .MuiInputLabel-shrink { + text-align: center !important; + display: inline; + position: absolute; + right: 0px !important; + top: -5px !important; + transform: translate(0px, 0px) scale(0.85) !important; + padding: 0px 10px !important; + z-index: 120 !important; + } + + label { + background-color: black; + width: fit-content; + text-align: center; + color: #b5b5b5 !important; + letter-spacing: -1px; + font-size: calc(100vw / 110) !important; + z-index: 120; + } + .Mui-focused { + color: rgba(0, 0, 0, 1) !important; + border-color: #84de56 !important; + // background-color: white; + color: #84de56 !important; + } + + .MuiInputBase-input { + height: auto !important; + } +} + +@media screen and (min-width: 641px) and (max-width: 1007px) { + .profile { + padding: 50px 100px 10px; + header { + margin: 0px; + margin-top: 30px; + } + &__box { + flex-direction: column; + border: none; + &--section { + width: 100%; + } + } + .MuiFormControl-root { + width: 100%; + margin: 10px auto !important; + .MuiSelect-iconOutlined { + display: none; + } + .MuiSelect-outlined.MuiSelect-outlined { + padding-right: 15px; + } + color: #797979 !important; + } + .MuiOutlinedInput-notchedOutline { + top: 0px !important; + } + .MuiOutlinedInput-notchedOutline { + border-color: #666666 !important; + border-width: 1px !important; + color: green !important; + border-radius: 10px !important; + } + + .MuiOutlinedInput-input { + padding: 15px 14px !important; + font-family: numeralLight; + font-size: calc(100vw / 40); + background-color: inherit; + color: #84de56; + &:focus { + border: 0.2px solid #84de56 !important; + border-radius: 10px; + transform: translateY(0px); + z-index: 100; + border-radius: 10px !important; + } + } + .MuiInputLabel-outlined { + font-family: numeralLight !important; + display: inline !important; + position: absolute; + text-align: right !important; + right: 15px; + top: calc(50%); + padding: 0px !important; + transform: translate(0px, -50%) scale(1) !important; + } + .MuiInputLabel-shrink { + text-align: center !important; + display: inline; + position: absolute; + right: 0px; + top: -10px; + transform: translate(0px, 0px) scale(0.85) !important; + padding: 0px 10px !important; + } + + label { + background-color: black; + width: fit-content; + text-align: center; + color: #b5b5b5 !important; + letter-spacing: -1px; + font-size: calc(100vw / 40); + z-index: 110; + } + .Mui-focused { + color: rgba(0, 0, 0, 1) !important; + border-color: #84de56 !important; + // background-color: white; + color: #84de56 !important; + } + + .MuiInputBase-input { + height: auto !important; + } + } +} + +@media screen and (max-width: 640px) { + .profile { + padding: 0px 10px; + header { + margin: 0px; + margin-top: 70px; + } + &__box { + flex-direction: column; + border: none; + &--section { + width: 100%; + } + } + .MuiFormControl-root { + width: 100%; + margin: 10px auto !important; + .MuiSelect-iconOutlined { + display: none; + } + .MuiSelect-outlined.MuiSelect-outlined { + padding-right: 15px; + } + color: #797979 !important; + } + .MuiOutlinedInput-notchedOutline { + top: 0px !important; + } + .MuiOutlinedInput-notchedOutline { + border-color: #666666 !important; + border-width: 1px !important; + color: green !important; + border-radius: 10px !important; + } + + .MuiOutlinedInput-input { + padding: 15px 14px !important; + font-family: numeralLight; + font-size: calc(100vw / 30); + background-color: inherit; + border-radius: 10px; + color: #84de56 !important; + + &:focus { + border: 0.2px solid #84de56 !important; + border-radius: 10px; + transform: translateY(0px); + z-index: 100; + } + } + .MuiInputLabel-outlined { + font-family: numeralLight !important; + display: inline !important; + position: absolute; + text-align: right !important; + right: 15px; + top: calc(50%); + padding: 0px !important; + transform: translate(0px, -50%) scale(1) !important; + } + .MuiInputLabel-shrink { + text-align: center !important; + display: inline; + position: absolute; + right: 0px; + top: -10px; + transform: translate(0px, 0px) scale(0.7) !important; + padding: 0px 10px !important; + } + + label { + background-color: black; + width: fit-content; + text-align: center; + color: #b5b5b5 !important; + letter-spacing: -1px; + font-size: calc(100vw / 25); + z-index: 110; + } + .Mui-focused { + color: rgba(0, 0, 0, 1) !important; + border-color: #84de56 !important; + // background-color: white; + color: #84de56 !important; + } + + .MuiInputBase-input { + height: auto !important; + } + } +} diff --git a/src/views/Auth/Profile/index.tsx b/src/views/Auth/Profile/index.tsx index 01c14ff..2377cec 100644 --- a/src/views/Auth/Profile/index.tsx +++ b/src/views/Auth/Profile/index.tsx @@ -1,9 +1,459 @@ -import React from 'react' +import React, { useState, useEffect } from "react"; +import onInput from "../../../util/onInput"; +import { user, file, publicApi } from "../../../redux/actions"; +import { connect } from "react-redux"; + +import Select from "../../../components/Select/index"; +import Input from "../../../components/Input/index"; +import TextArea from "../../../components/Textarea/index"; +import Upload from "./Upload/index"; +import Gender from "./GenderSwitch/index"; +import Birthdate from "./Birthdate/index"; +import MultipleSelector from "./MultipleSelector/index"; +import Document from "./Document/index"; +import "./index.scss"; +import { useHistory } from "react-router-dom"; +import Navbar from "../../../components/Navbar/index"; +import Footer from "../../Home/Footer/index"; +function Navigate({ path }: any) { + let history = useHistory(); + return <>{history.push(path)}; +} + +const maxDesktopSize = 1250; +const maxMobileSize = 550; + +const fontSize = { + desktop: { + h1: window.innerWidth > maxDesktopSize ? 25 : window.innerWidth / 55, + p: window.innerWidth > maxDesktopSize ? 14 : window.innerWidth / 90, + }, + mobile: { + h1: window.innerWidth > maxMobileSize ? 20 : window.innerWidth / 18, + p: window.innerWidth > maxMobileSize ? 14 : window.innerWidth / 28, + }, +}; + +function Profile({ + profile, + uploads, + getProvince, + getCity, + setDone, + upload, + setProfile, + province, + provinceList, + cityList, +}: any) { + const [render, setRender] = useState(false); + const [formData, setFormData] = useState({ + file: uploads["file"] || profile.picFileId || null, + picFileId: uploads["file"] || profile.picFileId || null, + docFileIds: uploads["docFileIds"] || profile.docFileIds || "", + firstName: "", + lastName: "", + password: "", + username: "", + address: "", + email: "", + birthDate: "", + gender: profile.gender || 1, + status: profile.status || 1, + nationalId: "", + phone: "", + schools: null, + zoneId: "", + schoolId: "", + postalCode: "", + gradeIds: profile.gradeIds, + provinceId: profile.provinceId, + cityId: profile.cityId, + }); + + useEffect(() => { + getProvince(); + getCity({ provinceId: profile.provinceId }); + }, []); + + const grades= [ + { + name : 'پیش دبستانی', + value : 0, + }, + { + name: "اول", + value: 1, + }, + { + name: "دوم", + value: 2, + }, + { + name: "سوم", + value: 3, + }, + { + name: "چهارم", + value: 4, + }, + { + name: "پنجم", + value: 5, + }, + { + name: "ششم", + value: 6, + }, + { + name: "هفتم", + value: 7, + }, + { + name: "هشتم", + value: 8, + }, + { + name: "نهم", + value: 9, + }, + { + name: "دهم", + value: 10, + }, + { + name: "یازدهم", + value: 11, + }, + { + name: "دوازدهم", + value: 12, + }, + ]; + + const onChange = (name: string, value: any) => { + if (name === "provinceId") { + getCity({ provinceId: value }); + setFormData({ ...formData, cityId: null, [name]: value }); + } else if (name === "status") { + setFormData({ + ...formData, + gradeIds: formData.gradeIds.slice(0, 1) || [], + [name]: value, + }); + } else if (name === "docFileIds") { + upload({ file: value, target: name }); + setFormData({ ...formData, [name]: value }); + } else if (name === "file") { + upload({ file: value, target: name }); + setFormData({ ...formData, [name]: value }); + } else { + setFormData({ ...formData, [name]: value }); + } + }; + + const onSubmit = async () => { + const { + firstName, + lastName, + username, + //cellphone, + password, + postalCode, + address, + email, + phone, + picFileId, + gender, + nationalId, + birthDate, + schools, + gradeIds, + status, + provinceId, + cityId, + docFileIds, + } = formData; + const data = { + firstName: firstName || profile.firstName, + lastName: lastName || profile.lastName, + username: username || profile.username, + cellphone: profile.cellphone, + password: password || profile.password, + postalCode: postalCode || profile.postalCode, + address: address || profile.address, + email: email || profile.email, + phone: phone || profile.phone, + nationalId: nationalId || profile.nationalId, + picFileId: String(uploads["file"] || picFileId || profile.picFileId), + gender: gender || profile.gender, + birthDate: birthDate || profile.birthDate, + schools: schools || profile.schools, + gradeIds: String(gradeIds || profile.gradeIds), + status: status || profile.status, + provinceId: provinceId || profile.provinceId, + cityId: cityId || profile.cityId, + docFileIds: String( + uploads["docFileIds"] || docFileIds || profile.docFileIds + ), + }; + await setProfile(data); + }; + + // if (setDone) return ; -export default function Profile() { return ( -
- +
+ +
+
+
+

حساب کاربری

+

لطفا مشخصات خود را به صورت کامل نمایید.

+
+
+ +
+
+
onSubmit()}> +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+ {formData.status === 1 ? ( +
+ +
+ ) : null} + {console.log(province)} +
+ +
+ {/*
+ +
+ ) : null} + {formData.status == 2 ? ( +
+ +
+ ) : null} + {formData.status == 2 ? : null} +
+ +
+
+