diff --git a/package.json b/package.json index 7d9f7f9..8e8924f 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "@testing-library/user-event": "^12.1.10", "@trendyol-js/react-carousel": "^2.0.0", "axios": "^0.24.0", + "jalali-moment": "^3.3.10", "jol-player": "^2.5.0", "lodash": "^4.17.21", "react": "^17.0.2", diff --git a/src/App.js b/src/App.js index 56e18d6..3fada8a 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,7 @@ import "./App.scss"; import { Provider } from "react-redux"; +import { ToastContainer } from "react-toastify"; +import "react-toastify/dist/ReactToastify.css"; import store from "./redux/store"; import Router from "./router"; @@ -7,6 +9,18 @@ function App({theme}) { return ( + ); } diff --git a/src/App.scss b/src/App.scss index c612a88..fee89fa 100644 --- a/src/App.scss +++ b/src/App.scss @@ -91,3 +91,7 @@ max-width: 1480px; } } + +.Toastify *{ + font-size: 13px; +} diff --git a/src/assets/icons/arrow-left-green.png b/src/assets/icons/arrow-left-green.png new file mode 100644 index 0000000..4d07993 Binary files /dev/null and b/src/assets/icons/arrow-left-green.png differ diff --git a/src/assets/icons/arrow-left.png b/src/assets/icons/arrow-left.png new file mode 100644 index 0000000..70d90d4 Binary files /dev/null and b/src/assets/icons/arrow-left.png differ diff --git a/src/assets/icons/bottom-home-active.svg b/src/assets/icons/bottom-home-active.svg new file mode 100644 index 0000000..b5aa911 --- /dev/null +++ b/src/assets/icons/bottom-home-active.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/bottom-products-deactive.svg b/src/assets/icons/bottom-products-deactive.svg new file mode 100644 index 0000000..875ff38 --- /dev/null +++ b/src/assets/icons/bottom-products-deactive.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/icons/bottom-profile-deactive.svg b/src/assets/icons/bottom-profile-deactive.svg new file mode 100644 index 0000000..8a9ae83 --- /dev/null +++ b/src/assets/icons/bottom-profile-deactive.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/bottom-test-deactive.svg b/src/assets/icons/bottom-test-deactive.svg new file mode 100644 index 0000000..f040018 --- /dev/null +++ b/src/assets/icons/bottom-test-deactive.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/icons/bottom-video-deactive.svg b/src/assets/icons/bottom-video-deactive.svg new file mode 100644 index 0000000..4250b15 --- /dev/null +++ b/src/assets/icons/bottom-video-deactive.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/assets/icons/dropdown.png b/src/assets/icons/dropdown.png new file mode 100644 index 0000000..7d05d91 Binary files /dev/null and b/src/assets/icons/dropdown.png differ diff --git a/src/components/BottomNavigation/index.js b/src/components/BottomNavigation/index.js new file mode 100644 index 0000000..4de876c --- /dev/null +++ b/src/components/BottomNavigation/index.js @@ -0,0 +1,91 @@ +import React, { useState } from "react"; +import { Link } from "react-router-dom"; +import { connect } from "react-redux"; +import activeHomeIcon from "../../assets/icons/bottom-home-active.svg"; +import deactiveProductsIcon from "../../assets/icons/bottom-products-deactive.svg"; +import deactiveVideoIcon from "../../assets/icons/bottom-video-deactive.svg"; +import deactiveProfileIcon from "../../assets/icons/bottom-profile-deactive.svg"; +import deactiveTestIcon from "../../assets/icons/bottom-test-deactive.svg"; + +export const BottomNavigation = ({ pages, isDark }) => { + const [activeLink, setActiveLink] = useState("/"); + + const Tab = ({ page }) => { + return ( + setActiveLink(page.link)} + > + + + {page.name} + + + ); + }; + return ( + <> + + + ); +}; + +const mapStateToProps = (state) => ({ + isDark: state.publicApi.isDark, +}); + +const mapDispatchToProps = {}; + +export default connect(mapStateToProps, mapDispatchToProps)(BottomNavigation); + +BottomNavigation.defaultProps = { + pages: [ + { + id: 0, + name: "صفحه اصلی", + link: "/", + activeIcon: activeHomeIcon, + deactiveIcon: "", + }, + { + id: 1, + name: "محصولات", + link: "/products", + activeIcon: "", + deactiveIcon: deactiveProductsIcon, + }, + { + id: 2, + name: "ویدئو", + link: "/vod", + activeIcon: "", + deactiveIcon: deactiveVideoIcon, + }, + { + id: 3, + name: "آزمون", + link: "/test", + activeIcon: "", + deactiveIcon: deactiveTestIcon, + }, + { + id: 4, + name: "حساب کاربری", + link: "/profile", + activeIcon: "", + deactiveIcon: deactiveProfileIcon, + }, + ], +}; diff --git a/src/components/Button/index.js b/src/components/Button/index.js index ca558a3..ac65d92 100644 --- a/src/components/Button/index.js +++ b/src/components/Button/index.js @@ -7,6 +7,7 @@ export default function Button({ border, width, bgOpacity, + onClick, }) { return ( diff --git a/src/components/Input/danger.png b/src/components/Input/danger.png new file mode 100644 index 0000000..0bb622e Binary files /dev/null and b/src/components/Input/danger.png differ diff --git a/src/components/Input/index.js b/src/components/Input/index.js new file mode 100644 index 0000000..004f9eb --- /dev/null +++ b/src/components/Input/index.js @@ -0,0 +1,171 @@ +import React, { useState } from "react"; +import _ from "lodash"; +import "./index.scss"; + +import tick from "./tick.png"; +import danger from "./danger.png"; + +const langDetector = (lang, option1, option2) => { + return lang === "fa" ? option1 : option2; +}; + +const inputStatusHandler = (value, focus, status, primary, success, danger) => { + if (!focus) { + return ""; + } else { + if (!value) { + return primary; + } else { + if (status) { + return success; + } else { + return danger; + } + } + } +}; + +export default function Input(props) { + const [value, setValue] = useState(""); + const [focusToggle, setFocusToggle] = useState(false); + + const { lang, theme, inputMode, label, status, maxLength, message } = props; + + const onChange = (val) => { + setValue(val); + }; + + return ( +
+ + onChange(e.target.value)} + value={value} + onFocus={() => setFocusToggle(true)} + onBlur={() => !value ? setFocusToggle(false) : setFocusToggle(true)} + maxLength={maxLength} + /> + {!status && value && ( + {langDetector(lang, + )} + {status && value && ( + {langDetector(lang, + )} + + {value && !status && ( + + {message} + + )} + {value && ( + + {value.length + "/" + maxLength} + + )} +
+ ); +} + +Input.defaultProps = { + lang : 'fa', + inputMode : 'numeric', + label : 'label', + status : '', + maxLength : '', + message : '', +} \ No newline at end of file diff --git a/src/components/Input/index.scss b/src/components/Input/index.scss new file mode 100644 index 0000000..9b0bf19 --- /dev/null +++ b/src/components/Input/index.scss @@ -0,0 +1,60 @@ +$primary: #196EC0; +$gray: #dbdbdb; +$danger: #E00A0A; +$success: #23C933; + +.input { + &__labelFocus{ + top: 0px !important; + font-size: 9px !important; + color: $primary !important; + } + &__labelDanger{ + top: 0px !important; + font-size: 9px !important; + color: $danger !important; + } + &__labelSuccess{ + top: 0px !important; + font-size: 9px !important; + color: $success !important; + } + + + &__inputActive{ + border-color: $primary !important; + } + &__inputSuccess{ + border-color: $success !important; + } + &__inputDanger{ + border-color: $danger !important; + } + + &__message{ + &Success{ + color: $success; + } + &Danger{ + color: $danger; + } + } + &__length{ + &Success{ + color: $success; + } + &Danger{ + color: $danger; + } + } +} + +.en { + direction: ltr; + text-align: left; +} + +.fa { + direction: rtl; + text-align: right; +} \ No newline at end of file diff --git a/src/components/Input/tick.png b/src/components/Input/tick.png new file mode 100644 index 0000000..805f74a Binary files /dev/null and b/src/components/Input/tick.png differ diff --git a/src/components/Navbar/index.js b/src/components/Navbar/index.js index 757a8cb..2aae4ce 100644 --- a/src/components/Navbar/index.js +++ b/src/components/Navbar/index.js @@ -12,7 +12,7 @@ import arBlueIcon from "../../assets/icons/ar-blue.svg"; import hamburgerIcon from "../../assets/icons/hamburger.svg"; import hamburgerBlueIcon from "../../assets/icons/hamburger-blue.svg"; -function Navbar({ pages, isDark, isLogin }) { +function Navbar({ pages, isDark}) { const [top, setTop] = useState(false); useEffect(() => { if (window.scrollY === 0) { @@ -80,57 +80,55 @@ function Navbar({ pages, isDark, isLogin }) { > - {isLogin && ( -
- - - - - - -
- )} + +
+ + + + + + +
- {/* portrait end */} + ){/* portrait end */} ); } const mapStateToProps = (state) => ({ isDark: state.publicApi.isDark, - isLogin: state.user.status, }); export default connect(mapStateToProps, {})(Navbar); diff --git a/src/components/PrivateRouter/index.js b/src/components/PrivateRouter/index.js new file mode 100644 index 0000000..017d7c6 --- /dev/null +++ b/src/components/PrivateRouter/index.js @@ -0,0 +1,32 @@ +import React from "react"; +import { Route, Redirect } from "react-router-dom"; +import { connect } from "react-redux"; + +const PrivateRouter = ({ + component: Component, + restricted, + status, + customPage, + ...rest +}) => { + return ( + + restricted ? ( + + ) : ( + + + ) + } + /> + ); +}; + +export default connect( + (state) => ({ + status: state.user.status, + }), + {} +)(PrivateRouter); diff --git a/src/components/Textarea/index.js b/src/components/Textarea/index.js new file mode 100644 index 0000000..72573ce --- /dev/null +++ b/src/components/Textarea/index.js @@ -0,0 +1,21 @@ +import React from "react"; +import _ from "lodash"; + +export default function Textarea({ placeholder, theme }) { + const light = theme === "light"; + return ( + <> +