diff --git a/src/components/Input/index.js b/src/components/Input/index.js new file mode 100644 index 0000000..1c74aed --- /dev/null +++ b/src/components/Input/index.js @@ -0,0 +1,51 @@ +import React from "react"; +import TextField from "@material-ui/core/TextField"; +import { makeStyles } from "@material-ui/core/styles"; + +export default function FormPropsTextFields(props) { + const useStyles = makeStyles((theme) => ({ + root: { + "& .MuiTextField-root": { + width: "100%", + position: "relative", + marginRight: 10, + "& input": { + textAlign: props.align, + direction: props.align === "right" ? "rtl" : "ltr", + }, + fontFamily: "numeralLight", + }, + }, + })); + + const classes = useStyles(); + const { defaultValue, maxLength, inputMode, onInput, variant, onChange } = + props; + return ( +
+ ); +} + +FormPropsTextFields.defaultProps = { + align: "right", + maxLength: "", + inputMode: "numeric", + defaultValue: "", +}; diff --git a/src/redux/actions-type/blog.tsx b/src/redux/actions-type/blog.tsx new file mode 100644 index 0000000..e8e353f --- /dev/null +++ b/src/redux/actions-type/blog.tsx @@ -0,0 +1,18 @@ +interface list { + type : "public/blogList" + data : any +} + +interface error{ + type : "blog/error" + data : undefined +} + +interface loading{ + type : "blog/loading" + data : undefined +} + +type BlogAction = list | loading | error; + +export default BlogAction; diff --git a/src/redux/actions-type/book.tsx b/src/redux/actions-type/book.tsx new file mode 100644 index 0000000..6d56d31 --- /dev/null +++ b/src/redux/actions-type/book.tsx @@ -0,0 +1,24 @@ +interface list { + type : "book/list" + data : any +} + +interface info{ + type : "book/info" + data : any +} + +interface error{ + type : "book/error" + data : undefined +} + +interface loading{ + type : "book/loading" + data : undefined +} + + +type BookAction = list | info | loading | error; + +export default BookAction; diff --git a/src/redux/actions-type/index.tsx b/src/redux/actions-type/index.tsx index 4713c1f..a10a02f 100644 --- a/src/redux/actions-type/index.tsx +++ b/src/redux/actions-type/index.tsx @@ -1,3 +1,7 @@ // @create-index export type { default as PublicAction } from "./public"; export type { default as UserAction } from "./user"; +export type { default as BookAction } from "./book"; +export type { default as BlogAction } from "./blog"; + + diff --git a/src/redux/actions-type/public.tsx b/src/redux/actions-type/public.tsx index 32c4d48..37dc593 100644 --- a/src/redux/actions-type/public.tsx +++ b/src/redux/actions-type/public.tsx @@ -28,6 +28,6 @@ interface loading{ // } -type PublicAction =getBlogList | getBlogInfo | getHomeData | loading | error; +type PublicAction = getBlogList | getBlogInfo | getHomeData | loading | error; export default PublicAction; diff --git a/src/redux/actions/blog.tsx b/src/redux/actions/blog.tsx new file mode 100644 index 0000000..403b8c0 --- /dev/null +++ b/src/redux/actions/blog.tsx @@ -0,0 +1,28 @@ +import proxy from "../proxy"; +import { Dispatch } from "redux"; +const blog = { + list: + (data = {}) => + async (dispatch : Dispatch) => + await proxy.get("public/blogList", data, { dispatch }), + // update: + // (data = {}, data2 = {}) => + // async (dispatch : Dispatch) => { + // await proxy.put("blog/update", data); + // await proxy.get("blog/list", data2, { dispatch }); + // }, + // add: + // (data = {}, data2 = {}) => + // async (dispatch : Dispatch) => { + // await proxy.post("blog/add", data); + // await proxy.get("blog/list", data2, { dispatch }); + // }, + // del: + // (data = {}, data2 = {}) => + // async (dispatch : Dispatch) => { + // await proxy.delete("blog/delete", data); + // await proxy.get("blog/list", data2, { dispatch }); + // }, +}; + +export default blog; diff --git a/src/redux/actions/book.tsx b/src/redux/actions/book.tsx new file mode 100644 index 0000000..853e8a9 --- /dev/null +++ b/src/redux/actions/book.tsx @@ -0,0 +1,38 @@ +import proxy from "../proxy"; +import { Dispatch } from "redux"; +const book = { + list: + (data = {}) => + async (dispatch : Dispatch) => + await proxy.get("book/list", data, { dispatch }), + info: + (data = {}) => + async (dispatch : Dispatch) => + await proxy.get("book/info", data, { dispatch }), + // update: + // (data = {}, data2 = {}) => + // async (dispatch : Dispatch) => { + // await proxy.put("book/update", data); + // await proxy.get("book/list", data2, { dispatch }); + // }, + // add: + // (data = {}, data2 = {}) => + // async (dispatch) => { + // await proxy.post("book/add", data); + // await proxy.get("book/list", data2, { dispatch }); + // }, + // del: + // (data = {}, data2 = {}) => + // async (dispatch) => { + // await proxy.delete("book/delete", data); + // await proxy.get("book/list", data2, { dispatch }); + // }, + // searchBook: (data) => async (dispatch) => { + // dispatch({ type: "book/search", data: data }); + // }, + // filterBook: (data) => async (dispatch) => { + // dispatch({ type: "book/filter", data: data }); + // }, +}; + +export default book; diff --git a/src/redux/actions/index.tsx b/src/redux/actions/index.tsx index a305439..9126156 100644 --- a/src/redux/actions/index.tsx +++ b/src/redux/actions/index.tsx @@ -1,4 +1,8 @@ // @create-index export { default as publicApi } from "./public"; export { default as user } from "./user"; +export { default as book } from "./book"; +export { default as blog } from "./blog"; + + diff --git a/src/redux/reducers/blog.tsx b/src/redux/reducers/blog.tsx new file mode 100644 index 0000000..9191318 --- /dev/null +++ b/src/redux/reducers/blog.tsx @@ -0,0 +1,29 @@ +import { toast } from "react-toastify"; +import {BlogAction} from '../actions-type'; + +const initialState = { + loading: false, + error: null, + list: [], +}; +export default function blog(state = initialState, action : BlogAction) { + let { type, data } = action; + switch (type) { + case "public/blogList": + return { ...state, loading: false, list: data, error: null }; + // case "blog/update": + // return { ...state, loading: false, error: null }; + // case "blog/add": + // return { ...state, loading: false, error: null }; + // case "blog/delete": + // return { ...state, loading: false, error: null }; + ///////////// + case "blog/loading": + return { ...state, loading: true }; + case "blog/error": + toast.error(data.message); + return { ...state, loading: false, error: data.message }; + default: + return state; + } +} diff --git a/src/redux/reducers/book.tsx b/src/redux/reducers/book.tsx new file mode 100644 index 0000000..4fd7800 --- /dev/null +++ b/src/redux/reducers/book.tsx @@ -0,0 +1,129 @@ +import { toast } from "react-toastify"; +import { BookAction } from "../actions-type"; + +const initialState = { + loading: false, + error: null, + list: [], + info: null, + searchResult: [], + filterResult: [], + subjects: [], + levels: [], + sortFilters: ["مرتب سازی", "محبوب ترین", "جدیدترین"], +}; + +const grades = [ + "پیش دبستان", + "اول", + "دوم", + "سوم", + "چهارم", + "پنجم", + "ششم", + "هفتم", + "هشتم", + "نهم", + "دهم", + "یازدهم", + "دوازدهم", +]; + +export default function book(state = initialState, action : BookAction) { + let { type, data } = action; + switch (type) { + case "book/list": + let itemsSubject = (Array.isArray(data) ? data : []).map( + (item, index) => item.name + ); + if (window.innerWidth < 1000) { + itemsSubject.unshift("نام کتاب"); + } + let itemsLevel = (Array.isArray(data) ? data : []) + .map((item) => item.gradeId * 1) + .sort((a, b) => a - b) + .map((e) => grades[e]); + if (window.innerWidth < 1000) { + itemsLevel.unshift("پایه تحصیلی"); + } + return { + ...state, + loading: false, + list: data, + subjects: Array.from(new Set(itemsSubject)), + levels: Array.from(new Set(itemsLevel)), + filterResult: data, + error: null, + }; + case "book/info": + return { ...state, loading: false, info: data, error: null }; + // case "book/update": + // return { ...state, loading: false, error: null }; + // case "book/add": + // return { ...state, loading: false, error: null }; + // case "book/delete": + // return { ...state, loading: false, error: null }; + // case "book/search": + // return { ...state }; + // case "book/filter": + // const realList = state.list; + // const level = data.level; + // const subject = data.subject; + // const sort = data.sort; + // const search = data.search; + // if (level.length > 0 || subject.length > 0 || sort || search) { + // localStorage.setItem("filter", "ON"); + // } + // let finalSort; + // let byLevelFilter = []; + // if (level.length > 0) { + // level.map((item1) => { + // for (let i = 0; i < realList.length; i++) { + // if (grades[realList[i].gradeId] === item1) { + // byLevelFilter.push(realList[i]); + // } + // } + // }); + // } else { + // byLevelFilter = realList; + // } + + // let bySubjectFilter = []; + // if (subject.length > 0) { + // subject.map((item1) => { + // for (let i = 0; i < byLevelFilter.length; i++) { + // if (byLevelFilter[i].name === item1) { + // bySubjectFilter.push(byLevelFilter[i]); + // } + // } + // }); + // } else { + // bySubjectFilter = byLevelFilter; + // } + + // const bySearchFilter = search + // ? bySubjectFilter.filter((item1) => item1.name.indexOf(search) !== -1) + // : bySubjectFilter; + + // if (sort === "گران ترین") { + // finalSort = bySearchFilter.sort((item1, item2) => { + // return item1.product[0].price - item2.product[0].price; + // }); + // } else { + // finalSort = bySearchFilter; + // } + // return { + // ...state, + // loading: false, + // error: null, + // filterResult: finalSort, + // }; + case "book/loading": + return { ...state, loading: true }; + case "book/error": + toast.error(data.message); + 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 d34f1e3..0ff37fc 100644 --- a/src/redux/reducers/index.tsx +++ b/src/redux/reducers/index.tsx @@ -1,3 +1,7 @@ // @create-index export { default as publicApi } from "./public"; export { default as user } from "./user"; +export { default as book } from "./book"; +export { default as blog } from "./blog"; + + diff --git a/src/util/onInput.js b/src/util/onInput.js index a42c2f8..9f64e8f 100644 --- a/src/util/onInput.js +++ b/src/util/onInput.js @@ -72,7 +72,7 @@ class onInput { newText = newText.replace(/N/g, ""); newText = newText.replace(/M/g, ""); newText = newText.replace(/\?/g, ""); - if (!newText) { + if (!newText && newText.length !== 0) { toast.info("از کاراکتر فارسی استفاده کنید"); } return newText; @@ -131,7 +131,7 @@ class onInput { newText = newText.replace(/ه/g, ""); newText = newText.replace(/ی/g, ""); newText = newText.replace(/\?/g, ""); - if (!newText) { + if (!newText && newText.length !== 0) { toast.info("از کاراکتر انگلیسی واعداداستفاده کنید"); } return newText; @@ -238,7 +238,7 @@ class onInput { newText = newText.replace(/B/g, ""); newText = newText.replace(/N/g, ""); newText = newText.replace(/M/g, ""); - if (!newText) { + if (!newText && newText.length !== 0) { toast.info("از اعداداستفاده کنید"); } return newText; @@ -267,6 +267,14 @@ class onInput { } return newNum; }; + phonenumber = (value) => { + let formattedValue = value + .replace(/[\u0660-\u0669\u06f0-\u06f9]/g, function (c) { + return c.charCodeAt(0) & 0xf; + }) + .replace(/[^\d]/, ""); + return formattedValue; + }; } const _onInput = new onInput(); diff --git a/src/views/Auth/Login/index.scss b/src/views/Auth/Login/index.scss new file mode 100644 index 0000000..2d714f5 --- /dev/null +++ b/src/views/Auth/Login/index.scss @@ -0,0 +1,280 @@ +.login { + width: 100%; + height: 100vh; + position: relative; + font-family: numeralLight; + &__options{ + color: #B5B5B5; + a { + color: #84de56; + } + } + img { + transform: rotate(-90deg); + } + .MuiButtonBase-root{ + padding: 0px !important; + } + 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% + ); + .footer { + position: fixed; + bottom: 0px; + left: 0px; + } +} + +@media screen and (min-width: 1441px) { + .login { + section { + width: 410px; + b { + color: white; + font-size: 20px; + margin-bottom: 30px; + font-weight: 500; + p { + font-size: 16px; + } + } + + button { + margin-top: 25px; + background-color: #84de56; + color: white; + font-size: 20px; + padding: 10px 0px; + border: 0px; + border-radius: 10px; + } + } + &__info { + width: 350px; + margin: 40px auto 0px; + text-align: center; + color: white; + font-size: 14px; + a { + color: #84de56; + } + } + &__back { + margin-bottom: 60px; + a { + color: white; + font-size: 13px; + } + } + &__options{ + div{ + font-size: 13px; + } + a{ + font-size: 15px; + } + } + .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; + &:focus{ + border: 0.2px solid #84de56 !important; + border-radius: 10px; + transform : translateY(0.5px); + } + } + .MuiInputLabel-outlined { + font-family: numeralLight !important; + display: inline !important; + position: absolute; + text-align: right !important; + right: 15px; + top: 22px; + padding: 0px !important; + transform: translate(0px, 0px) scale(1) !important; + } + .MuiInputLabel-shrink { + text-align: center !important; + display: inline; + position: absolute; + right: 0px; + top: -8px; + transform: translate(0px, 0px) scale(0.85) !important; + padding: 0px 10px !important; + } + + label { + background-color: #2F2F2F; + width: fit-content; + text-align: center; + color: #B5B5B5 !important; + letter-spacing: -1px; + font-size: 16px; + } + .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) { + .login { + section { + width: 350px; + transform: scale(0.9); + b { + color: white; + font-size: calc(100vw / 80); + margin-bottom: 30px; + font-weight: 500; + } + + button { + margin-top: 25px; + background-color: #84de56; + color: white; + font-size: calc(100vw / 80); + padding: 10px 0px; + border: 0px; + border-radius: 10px; + } + } + &__info { + width: 300px; + margin: 40px auto 0px; + text-align: center; + color: white; + font-size: calc(100vw / 110); + a { + color: #84de56; + } + } + &__back { + margin-bottom: 40px; + a { + color: white; + font-size: calc(100vw / 110); + } + } + &__options{ + div{ + font-size: calc(100vw / 110); + } + a{ + font-size: calc(100vw / 110); + } + } + .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: 10px 14px !important; + font-family: numeralLight; + font-size: calc(100vw / 80); + &: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: -8px; + transform: translate(0px, 0px) scale(0.85) !important; + padding: 0px 10px !important; + } + + label { + background-color: #2F2F2F; + width: fit-content; + text-align: center; + color: #B5B5B5 !important; + letter-spacing: -1px; + font-size: calc(100vw / 100); + 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/Login/index.tsx b/src/views/Auth/Login/index.tsx index 60106d1..80fcd7f 100644 --- a/src/views/Auth/Login/index.tsx +++ b/src/views/Auth/Login/index.tsx @@ -1,9 +1,88 @@ -import React from 'react' +import React, { useState } from "react"; +import Navbar from "../../../components/Navbar/index"; +import Footer from "../../../views/Home/Footer/index"; +import Input from "../../../components/Input/index"; +import Checkbox from "@material-ui/core/Checkbox"; +import CheckBoxOutlineBlankTwoToneIcon from "@material-ui/icons/CheckBoxOutlineBlankTwoTone"; +import CheckBoxRoundedIcon from "@material-ui/icons/CheckBoxRounded"; -export default function Login() { +import { Link } from "react-router-dom"; +import arrow from "../../../assets/icons/dropdown.png"; +import onInput from "../../../util/onInput"; +import { connect, useSelector } from "react-redux"; +import { user } from "../../../redux/actions"; + +import "./index.scss"; + +interface LoginFields { + username?: string; + password?: string; +} + +function Login(props: any) { + const [loginFields, setSignUpFiels] = useStateprops.setPage("signup")}> + ساخت حساب کاربری +
+
با ثبت نام در سرویس ویدئویی دانوین قوانین
شرایط استفاده و حریم خصوصی
@@ -44,7 +86,7 @@ export default function SignUp() {
)}
{level === "otp" && (
- کد ارسال شده به شماره {signUpFiels?.phonenumber} را وارد کنید.
+ کد ارسال شده به شماره {signUpFields?.cellphone} را وارد کنید.
-
-
پیشنهادی برای شما
- پیشنهادی برای شما
+