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.js b/src/Redux/actions/index.js index d4f95ac..7fb3969 100644 --- a/src/Redux/actions/index.js +++ b/src/Redux/actions/index.js @@ -11,3 +11,4 @@ export { default as userFactor } from "./userFactor.js"; export { default as transport } from "./transport.js"; export { default as comment } from "./comment.js"; export { default as activation } from "./activation.js"; +export { default as file } from "./file.js"; diff --git a/src/Redux/actions/public.js b/src/Redux/actions/public.js index 1cd07ae..6b723bf 100644 --- a/src/Redux/actions/public.js +++ b/src/Redux/actions/public.js @@ -20,6 +20,10 @@ const publicApi = { await proxy.get("public/blogInfo", data, { history, dispatch }), filterNewProducts: (data, history) => async (dispatch) => await dispatch({ type: "public/filter", data: data }), + getProvince: (data, history) => async (dispatch) => + await proxy.get("public/province", data, { history, dispatch }), + getCity: (data, history) => async (dispatch) => + await proxy.get("public/city", data, { history, dispatch }), }; export default publicApi; diff --git a/src/Redux/proxy.js b/src/Redux/proxy.js index 6058c2e..de7f256 100644 --- a/src/Redux/proxy.js +++ b/src/Redux/proxy.js @@ -3,7 +3,9 @@ import axios from "axios"; let { baseUrl } = ApiConfig; let access = window.localStorage.getItem("access"); +window.baseURL = baseUrl; baseUrl = baseUrl + "/"; + const Axios = axios.create({ withCredentials: true, validateStatus: null, @@ -11,41 +13,53 @@ const Axios = axios.create({ //headers: access ? { Authorization: `Bearer ${access}` } : {}, }); class Proxy { - get = async (url, params, opt = {}) => + get = async (url, params, opt = {}, data) => + await this.check( + url, + opt, + async () => await Axios.get(url, { params, ...opt }), + data || params + ); + post = async (url, params, opt = {}, data) => + await this.check( + url, + opt, + async () => await Axios.post(url, params, opt), + data || params + ); + put = async (url, params, opt = {}, data) => await this.check( url, opt, - async () => await Axios.get(url, { params, ...opt }) + async () => await Axios.put(url, params, opt), + data || params ); - post = async (url, params, opt = {}) => - await this.check(url, opt, async () => await Axios.post(url, params, opt)); - put = async (url, params, opt = {}) => - await this.check(url, opt, async () => await Axios.put(url, params, opt)); - delete = async (url, params, opt = {}) => { + delete = async (url, params, opt = {}, data) => { await this.check( url, opt, - async () => await Axios.delete(url, { ...opt, data: params }) + async () => await Axios.delete(url, { ...opt, data: params }), + data || params ); }; - check = async (url, { dispatch }, fetch) => { + check = async (url, { dispatch }, fetch, params) => { dispatch = dispatch || (() => {}); dispatch({ type: "loading" }); let response = await fetch(); switch (response.status) { case 200: - dispatch({ type: url, data: response.data.data }); + dispatch({ type: url, data: response.data.data, params }); return response.data.data; case 401: if (await this.refresh()) { let response = await fetch(); - dispatch({ type: url, data: response.data.data }); + dispatch({ type: url, data: response.data.data, params }); return response.data.data; } break; default: - dispatch({ type: "error", data: response.data }); + dispatch({ type: "error", data: response.data, params }); } return false; }; diff --git a/src/Redux/reducers/file.js b/src/Redux/reducers/file.js new file mode 100644 index 0000000..b09142b --- /dev/null +++ b/src/Redux/reducers/file.js @@ -0,0 +1,26 @@ +const initialState = { + loading: false, + error: null, + uploads: {}, + lastUpload: null, +}; + +export default function file(state = initialState, action) { + 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 "loading": + return { ...state, loading: true }; + case "error": + return { ...state, loading: false, error: data.message }; + default: + return state; + } +} diff --git a/src/Redux/reducers/index.js b/src/Redux/reducers/index.js index 9bc1d52..0c032e8 100644 --- a/src/Redux/reducers/index.js +++ b/src/Redux/reducers/index.js @@ -11,3 +11,4 @@ export { default as userFactor } from "./userFactor.js"; export { default as transport } from "./transport.js"; export { default as comment } from "./comment.js"; export { default as activation } from "./activation.js"; +export { default as file } from "./file.js"; diff --git a/src/Redux/reducers/public.js b/src/Redux/reducers/public.js index e444d63..91e63c0 100644 --- a/src/Redux/reducers/public.js +++ b/src/Redux/reducers/public.js @@ -10,6 +10,8 @@ const initialState = { arList: [], blogList: [], blog: null, + province: [], + city: [], }; const grades = [ @@ -130,6 +132,10 @@ export default function publicApi(state = initialState, action) { }; case "faq/list": return { ...state, loading: false, error: null, faqList: data }; + case "public/province": + return { ...state, loading: false, error: null, province: data }; + case "public/city": + return { ...state, loading: false, error: null, city: data }; case "public/faq/activate": return { ...state, diff --git a/src/Redux/reducers/user.js b/src/Redux/reducers/user.js index 4dca89f..34b0641 100644 --- a/src/Redux/reducers/user.js +++ b/src/Redux/reducers/user.js @@ -8,6 +8,7 @@ const initialState = { domains: [], mothers: [], profileStatus: false, + setDone: false, }; export default function user(state = initialState, action) { let { type, data } = action; @@ -28,7 +29,13 @@ export default function user(state = initialState, action) { }; case "user/getProfile": localStorage.setItem("userData", JSON.stringify(data)); - return { ...state, loading: false, status: data, error: null }; + return { + ...state, + loading: false, + status: data, + error: null, + setDone: false, + }; case "user/logout": return { ...state, loading: false, status: proxy.status(), error: null }; case "user/getUserRole": @@ -40,11 +47,7 @@ export default function user(state = initialState, action) { case "mothers/list": return { ...state, loading: false, mothers: data, error: null }; case "user/setProfile": - toast.success("تغییرات اعمال شد."); - setTimeout(() => { - window.location = "/"; - }, 500); - return { ...state, loading: false, error: null }; + return { ...state, loading: false, error: null, setDone: true }; case "loading": return { ...state, loading: true }; case "error": diff --git a/src/constants/defaultValues.js b/src/constants/defaultValues.js index 2591544..37f0379 100644 --- a/src/constants/defaultValues.js +++ b/src/constants/defaultValues.js @@ -1,9 +1,9 @@ export const ApiConfig = { - apiKey: 'AIzaSyBBksq-Asxq2M4Ot-75X19IyrEYJqNBPcg', - authDomain: 'dnvn.ir', - baseUrl: 'https://dnvn.ir/api/v1', + apiKey: "AIzaSyBBksq-Asxq2M4Ot-75X19IyrEYJqNBPcg", + authDomain: "dnvn.ir", + baseUrl: "https://dnvn.ir/api/v1/", //baseUrl: 'http://localhost:3030/api/v1', - loginURL: 'user/login', - otploginURL: 'user/otp/login', - logoutURL: 'user/logout', -}; \ No newline at end of file + loginURL: "user/login", + otploginURL: "user/otp/login", + logoutURL: "user/logout", +}; diff --git a/src/views/Auth/Profile/Birthdate/index.js b/src/views/Auth/Profile/Birthdate/index.js index 5fe097a..e9e60a5 100644 --- a/src/views/Auth/Profile/Birthdate/index.js +++ b/src/views/Auth/Profile/Birthdate/index.js @@ -1,16 +1,26 @@ -import React from "react"; +import React, { useState } from "react"; import onInput from "~/util/onInput"; - +import Input from "../Input/index"; import "./index.scss"; - -const maxMobileSize = 550; -const maxDesktopSize = 1250; - -const fontSize = { - // desktop : -}; - +import moment from "jalali-moment"; export default function Birthdate(props) { + const { defaultValue, parent, name } = props; + const momentDate = moment(defaultValue[name]); + const day = momentDate.format("jDD"), + month = momentDate.format("jMM"), + year = momentDate.format("jYYYY"); + 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 ( <> {window.innerWidth < 1000 ? ( @@ -18,24 +28,33 @@ export default function Birthdate(props) {
/ /
@@ -44,28 +63,38 @@ export default function Birthdate(props) {
- + / - + / - +
) : null} ); } - -const Input = (props) => { - const { name, placeholder, maxLength, onInput } = props; - return ( - (e.target.value = onInput(e.target.value))} - /> - ); -}; diff --git a/src/views/Auth/Profile/Birthdate/index.scss b/src/views/Auth/Profile/Birthdate/index.scss index 75a3600..06c55f4 100644 --- a/src/views/Auth/Profile/Birthdate/index.scss +++ b/src/views/Auth/Profile/Birthdate/index.scss @@ -12,13 +12,14 @@ span { color: #bfbfbf; } + input { border: 0px; background-color: white; font-family: numeralLight; color: #4d4d4d; width: 42px; - text-align: center; + text-align: center !important; direction: ltr; &:focus { outline: 0px; @@ -73,7 +74,7 @@ font-family: numeralLight; color: #4d4d4d; width: 42px; - text-align: center; + text-align: center !important; direction: ltr; &:focus { outline: 0px; diff --git a/src/views/Auth/Profile/GenderSwitch/index.js b/src/views/Auth/Profile/GenderSwitch/index.js index 915d866..9b29f46 100644 --- a/src/views/Auth/Profile/GenderSwitch/index.js +++ b/src/views/Auth/Profile/GenderSwitch/index.js @@ -14,17 +14,17 @@ export default function GenderSwitch(props) { const styles = { girl: { fontSize: window.innerWidth > 1000 ? fontSize.desktop : fontSize.mobile, - color: selectedOption === options[1] ? "white" : "grey", - backgroundColor: selectedOption === options[1] ? "#128c7e" : "white", - border: selectedOption === options[1] ? "0px" : "1px solid #ccc", + color: selectedOption === 1 ? "white" : "grey", + backgroundColor: selectedOption === 1 ? "#128c7e" : "white", + border: selectedOption === 1 ? "0px" : "1px solid #ccc", borderTopLeftRadius: 10, borderBottomLeftRadius: 10, }, boy: { fontSize: window.innerWidth > 1000 ? fontSize.desktop : fontSize.mobile, - color: selectedOption === options[0] ? "white" : "grey", - backgroundColor: selectedOption === options[0] ? "#128c7e" : "white", - border: selectedOption === options[0] ? "0px" : "1px solid #ccc", + color: selectedOption === 2 ? "white" : "grey", + backgroundColor: selectedOption === 2 ? "#128c7e" : "white", + border: selectedOption === 2 ? "0px" : "1px solid #ccc", borderTopRightRadius: 10, borderBottomRightRadius: 10, borderLeft: window.innerWidth > 1000 ? "1px solid #ccc" : "0px", @@ -34,32 +34,20 @@ export default function GenderSwitch(props) { <> {window.innerWidth > 1000 ? (
-
parent.onChange(name, options[0])} - > +
parent.onChange(name, 2)}> {options[0]}
-
parent.onChange(name, options[1])} - > +
parent.onChange(name, 1)}> {options[1]}
) : null} {window.innerWidth < 1000 ? (
-
parent.onChange(name, options[0])} - > +
parent.onChange(name, 2)}> {options[0]}
-
parent.onChange(name, options[1])} - > +
parent.onChange(name, 1)}> {options[1]}
diff --git a/src/views/Auth/Profile/Input/index.js b/src/views/Auth/Profile/Input/index.js index 678a36d..878d1ad 100644 --- a/src/views/Auth/Profile/Input/index.js +++ b/src/views/Auth/Profile/Input/index.js @@ -19,7 +19,8 @@ export default function FormPropsTextFields(props) { })); const classes = useStyles(); - const { parent, defaultValue, maxLength, inputMode, onInput } = props; + const { parent, defaultValue, maxLength, inputMode, onInput, variant } = + props; return (
@@ -27,11 +28,15 @@ export default function FormPropsTextFields(props) { id="outlined-basic" name={props.name} label={props.label} - variant="outlined" + variant={variant || "outlined"} onChange={(e) => parent.onChange(e.target.name, e.target.value)} defaultValue={defaultValue[props.name] || ""} - maxLength={maxLength} - onInput={(e) => (e.target.value = onInput(e.target.value))} + inputProps={{ maxLength }} + onInput={ + onInput + ? (e) => (e.target.value = onInput(e.target.value)) + : () => {} + } />
diff --git a/src/views/Auth/Profile/MultipleSelector/index.js b/src/views/Auth/Profile/MultipleSelector/index.js index 8cd0744..5e39055 100644 --- a/src/views/Auth/Profile/MultipleSelector/index.js +++ b/src/views/Auth/Profile/MultipleSelector/index.js @@ -37,13 +37,13 @@ export default function MultipleSelector(props) { labelId="demo-mutiple-name-label" id="demo-mutiple-name" multiple - value={selectedOptions} - onChange={(e) => parent.onChange(name, e.target.value)} + value={selectedOptions.split(",")} + onChange={(e) => parent.onChange(name, e.target.value.join(","))} input={} variant="outlined" > - {options.map((name) => ( - + {options.map((name, i) => ( + {name} ))} @@ -69,13 +69,13 @@ export default function MultipleSelector(props) { labelId="demo-mutiple-name-label" id="demo-mutiple-name" multiple - value={selectedOptions} - onChange={(e) => parent.onChange(name, e.target.value)} + value={selectedOptions.split(",")} + onChange={(e) => parent.onChange(name, e.target.value.join(","))} input={} variant="outlined" > - {options.map((name) => ( - + {options.map((name, i) => ( + {name} ))} diff --git a/src/views/Auth/Profile/Select/index.js b/src/views/Auth/Profile/Select/index.js index 9aa4bd6..a00de7d 100644 --- a/src/views/Auth/Profile/Select/index.js +++ b/src/views/Auth/Profile/Select/index.js @@ -17,7 +17,7 @@ const useStyles = makeStyles((theme) => ({ export default function CustomizedSelects(props) { const classes = useStyles(); - const { parent } = props; + const { parent, selectedOptions } = props; return ( <> {window.innerWidth < 1000 ? ( @@ -29,12 +29,12 @@ export default function CustomizedSelects(props) { parent.onChange(props.name, e.target.value)} > {/* 09366858119 */} {props.options.map((item, i) => ( - ))} diff --git a/src/views/Auth/Profile/TextArea/index.js b/src/views/Auth/Profile/TextArea/index.js index 7329408..a9432c9 100644 --- a/src/views/Auth/Profile/TextArea/index.js +++ b/src/views/Auth/Profile/TextArea/index.js @@ -14,7 +14,7 @@ const useStyles = makeStyles((theme) => ({ export default function MultilineTextFields(props) { const classes = useStyles(); const [value, setValue] = React.useState("Controlled"); - const { parent } = props; + const { parent, defaultValue } = props; return (
parent.onChange(e.target.name, e.target.value)} + defaultValue={defaultValue[props.name] || ""} name={props.name} - defaultValue="" variant="outlined" /> diff --git a/src/views/Auth/Profile/Upload/index.js b/src/views/Auth/Profile/Upload/index.js index 887a416..72a7b50 100644 --- a/src/views/Auth/Profile/Upload/index.js +++ b/src/views/Auth/Profile/Upload/index.js @@ -11,49 +11,40 @@ const fontSize = { }; export default function Upload(props) { - const { parent } = props; + let { parent, name } = props; return ( <> {window.innerWidth < 1000 ? (
- {parent.state.file === null ? ( - <> - - parent.onChange(e.target.name, e.target.files[0]) - } - /> + <> + {parent.state.file === null ? ( - - ) : ( - <> - - parent.onChange(e.target.name, e.target.files[0]) + ) : ( + {"کاربر"} - {/* {"کاربر"} */} - - )} + )} + + parent.onChange(e.target.name, e.target.files[0]) + } + /> +
) : null} {window.innerWidth > 1000 ? (
- {parent.state.file === "" ? ( - <> - parent.onChange(e.target.name, e.target.value)} - name={props.name} - defaultValue="" - type="file" - /> + <> + {parent.state.file === null ? ( - - ) : ( - <> - parent.onChange(e.target.name, e.target.value)} - name={props.name} - defaultValue="" - type="file" + ) : ( + {"کاربر"} - - {parent.state.file.name} - - - )} + )} + + parent.onChange(e.target.name, e.target.files[0]) + } + name={props.name} + defaultValue="" + type="file" + /> +
) : null} diff --git a/src/views/Auth/Profile/index.js b/src/views/Auth/Profile/index.js index 711b456..1647f0e 100644 --- a/src/views/Auth/Profile/index.js +++ b/src/views/Auth/Profile/index.js @@ -1,6 +1,6 @@ import React, { Component } from "react"; import onInput from "~/util/onInput"; -import { user } from "~/Redux/actions"; +import { user, file } from "~/Redux/actions"; import { connect } from "react-redux"; import Select from "./Select/index"; @@ -14,8 +14,12 @@ import Loader from "~/components/Loader/index"; import Document from "./Document/index"; import logo from "../../../assets/icons/logo.png"; import pic from "../../../assets/images/pic.png"; - +import { useHistory } from "react-router-dom"; import "./index.scss"; +function Navigate({ path }) { + let history = useHistory(); + return <>{history.push(path)}; +} const maxDesktopSize = 1250; const maxMobileSize = 550; @@ -40,7 +44,9 @@ const toastMessages = { class Profile extends Component { state = { render: false, - file: null, + file: this.props.uploads["file"] || this.props.profile.picFileId || null, + picFileId: + this.props.uploads["file"] || this.props.profile.picFileId || null, docFileIds: "", firstName: "", lastName: "", @@ -48,8 +54,9 @@ class Profile extends Component { username: "", address: "", email: "", - gender: "دختر", - userRoleId: "دانش آموز", + birthDate: "", + gender: this.props.profile.gender || 1, + status: this.props.profile.status || 1, nationalId: "", provinceId: "", phone: "", @@ -57,7 +64,8 @@ class Profile extends Component { zoneId: "", schoolId: "", postalCode: "", - gradeId: [], + gradeIds: this.props.profile.gradeIds, + validation: { firstName: "", lastName: "", @@ -74,14 +82,19 @@ class Profile extends Component { } onChange = (name, value) => { - if (name === "gardeId" && this.state.userRoleId === "معلم") { + // if (name === "gradeIds" && this.state.status == 2) { + // this.setState((prevState) => ({ + // gradeIds: [...prevState.gradeIds.split(","), value], + // })); + // } else + if (name === "status") { this.setState((prevState) => ({ - gradeId: [...prevState.gradeId, value], + gradeIds: prevState.gradeIds.slice(0, 1) || [], + [name]: value, })); - } - if (name === "userRoleId") { + } else if (name === "file") { + this.props.upload({ file: value, target: name }); this.setState({ - gradeId: [], [name]: value, }); } else { @@ -96,12 +109,19 @@ class Profile extends Component { firstName, lastName, username, - cellphone, + //cellphone, password, postalCode, address, email, phone, + picFileId, + gender, + nationalId, + birthDate, + schools, + gradeIds, + status, } = this.state; const { profile, setProfile } = this.props; const data = { @@ -114,11 +134,21 @@ class Profile extends Component { address: address || profile.address, email: email || profile.email, phone: phone || profile.phone, + nationalId: nationalId || profile.nationalId, + picFileId: String( + this.props.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, }; await setProfile(data); }; render() { + if (this.props.setDone) return ; const grades = [ "پیش دبستان", "اول", @@ -134,7 +164,7 @@ class Profile extends Component { "یازدهم", "دوازدهم", ]; - const { user, profile } = this.props; + const { profile } = this.props; return ( <> {window.innerWidth > 1000 ? ( @@ -145,7 +175,7 @@ class Profile extends Component {

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

-
this.onSubmit(e)} > @@ -159,6 +189,7 @@ class Profile extends Component { label="نام" parent={this} defaultValue={profile} + onInput={onInput.persianOnly} />
@@ -167,6 +198,7 @@ class Profile extends Component { label="نام خانوادگی" parent={this} defaultValue={profile} + onInput={onInput.persianOnly} />
@@ -176,6 +208,7 @@ class Profile extends Component { parent={this} defaultValue={profile} align="left" + onInput={onInput.englishAndNumberWithoutSpace} />
@@ -190,14 +223,20 @@ class Profile extends Component {
- +
{/*
@@ -208,35 +247,36 @@ class Profile extends Component {
- {this.state.userRoleId === "دانش آموز" ? ( + {this.state.status === 1 ? (
) : null} @@ -271,31 +311,33 @@ class Profile extends Component { label={"شهرستان"} />
-
+ {/*
) : null} - {this.state.userRoleId === "معلم" ? ( + {this.state.status === "معلم" ? (
) : null} @@ -305,7 +347,10 @@ class Profile extends Component { name="postalCode" label={"کد پستی"} align="left" + maxLength={10} + inputMode="numeric" defaultValue={profile} + onInput={onInput.numberOnly} />
@@ -313,13 +358,14 @@ class Profile extends Component { parent={this} label={"آدرس محل سکونت"} name="address" + defaultValue={profile} />
- +
- +
) : ( @@ -383,32 +429,37 @@ class Profile extends Component { inputMode="numeric" onInput={onInput.numberOnly} /> - + - {this.state.userRoleId === "دانش آموز" ? ( + {this.state.status === 1 ? ( ) : null} @@ -437,31 +488,31 @@ class Profile extends Component { name="cityId" label={"شهرستان"} /> - ) : null} - {this.state.userRoleId === "معلم" ? ( + {this.state.status === "معلم" ? ( ) : null} - {this.state.userRoleId === "معلم" ? ( + {this.state.status === "معلم" ? ( ) : null} -