drawer - some api - headerOption added

temp
Reza_ashrafi 3 years ago
parent f309ac09a0
commit fb80e688ab
  1. 1
      package.json
  2. 3
      src/App.js
  3. 8
      src/assets/icons/bookmark-deactive-dark.svg
  4. 8
      src/assets/icons/bookmark-deactive-light.svg
  5. 10
      src/assets/icons/dots-menu-dark.svg
  6. 10
      src/assets/icons/dots-menu-light.svg
  7. 8
      src/components/BottomNavigation/index.js
  8. 14
      src/components/Button/index.js
  9. 17
      src/components/Drawer/index.js
  10. 4
      src/components/Header/index.js
  11. 74
      src/components/Navbar/index.js
  12. 14
      src/redux/actions/public.js
  13. 13
      src/redux/reducers/public.js
  14. 85
      src/router.js
  15. 20
      src/views/Auth/SignUp/index.js
  16. 27
      src/views/Auth/index.js
  17. 2
      src/views/Home/Portrait/Private/Blogs/index.js
  18. 4
      src/views/Home/Portrait/Private/MyBooks/index.js
  19. 2
      src/views/Home/Portrait/Private/Videos/index.js
  20. 9
      src/views/Home/Portrait/index.js
  21. 24
      src/views/Home/index.js
  22. 40
      src/views/Product/index.js
  23. 6
      src/views/Products/index.js
  24. 31
      src/views/ShoppingCart/Code/index.js
  25. 72
      src/views/ShoppingCart/Product/index.js
  26. 26
      src/views/ShoppingCart/index.js
  27. 5
      yarn.lock

@ -15,6 +15,7 @@
"lodash": "^4.17.21",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-modern-drawer": "^1.0.1",
"react-redux": "^7.2.6",
"react-router-dom": "^6.0.2",
"react-scripts": "4.0.3",

@ -2,6 +2,7 @@ import "./App.scss";
import { Provider } from "react-redux";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import "react-modern-drawer/dist/index.css";
import store from "./redux/store";
import Router from "./router";
@ -12,7 +13,7 @@ function App({theme}) {
<ToastContainer
position="top-right"
theme="colored"
autoClose={2000}
autoClose={4000}
hideProgressBar={true}
newestOnTop={true}
closeOnClick

@ -0,0 +1,8 @@
<svg id="vuesax_linear_archive-add" data-name="vuesax/linear/archive-add" xmlns="http://www.w3.org/2000/svg" width="29.778" height="29.778" viewBox="0 0 29.778 29.778">
<g id="archive-add" transform="translate(0)">
<path id="Vector" d="M6.2,0H0" transform="translate(11.787 13.214)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-2" data-name="Vector" d="M0,0V6.2" transform="translate(14.889 10.187)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-3" data-name="Vector" d="M16.75,0H4.789A4.8,4.8,0,0,0,0,4.789V22.272c0,2.233,1.6,3.176,3.561,2.1l6.055-3.362a2.628,2.628,0,0,1,2.32,0l6.055,3.362c1.96,1.092,3.561.149,3.561-2.1V4.789A4.819,4.819,0,0,0,16.75,0Z" transform="translate(4.119 2.482)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-4" data-name="Vector" d="M0,0H29.778V29.778H0Z" fill="none" opacity="0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1,8 @@
<svg id="vuesax_linear_archive-add" data-name="vuesax/linear/archive-add" xmlns="http://www.w3.org/2000/svg" width="29.778" height="29.778" viewBox="0 0 29.778 29.778">
<g id="archive-add" transform="translate(0)">
<path id="Vector" d="M6.2,0H0" transform="translate(11.787 13.214)" fill="none" stroke="#196ec0" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-2" data-name="Vector" d="M0,0V6.2" transform="translate(14.889 10.187)" fill="none" stroke="#196ec0" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-3" data-name="Vector" d="M16.75,0H4.789A4.8,4.8,0,0,0,0,4.789V22.272c0,2.233,1.6,3.176,3.561,2.1l6.055-3.362a2.628,2.628,0,0,1,2.32,0l6.055,3.362c1.96,1.092,3.561.149,3.561-2.1V4.789A4.819,4.819,0,0,0,16.75,0Z" transform="translate(4.119 2.482)" fill="none" stroke="#196ec0" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-4" data-name="Vector" d="M0,0H29.778V29.778H0Z" fill="none" opacity="0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="29.778" height="29.778" viewBox="0 0 29.778 29.778">
<g id="vuesax_linear_more" data-name="vuesax/linear/more" transform="translate(29.778) rotate(90)">
<g id="more">
<path id="Vector" d="M2.482,0A2.482,2.482,0,1,0,4.963,2.482,2.489,2.489,0,0,0,2.482,0Z" transform="translate(3.722 12.408)" fill="#fff"/>
<path id="Vector-2" data-name="Vector" d="M2.482,0A2.482,2.482,0,1,0,4.963,2.482,2.489,2.489,0,0,0,2.482,0Z" transform="translate(21.093 12.408)" fill="#fff"/>
<path id="Vector-3" data-name="Vector" d="M2.482,0A2.482,2.482,0,1,0,4.963,2.482,2.489,2.489,0,0,0,2.482,0Z" transform="translate(12.408 12.408)" fill="#fff"/>
<path id="Vector-4" data-name="Vector" d="M0,0H29.778V29.778H0Z" transform="translate(0 0)" fill="#fff" opacity="0"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 843 B

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="29.778" height="29.778" viewBox="0 0 29.778 29.778">
<g id="vuesax_linear_more" data-name="vuesax/linear/more" transform="translate(29.778) rotate(90)">
<g id="more">
<path id="Vector" d="M2.482,0A2.482,2.482,0,1,0,4.963,2.482,2.489,2.489,0,0,0,2.482,0Z" transform="translate(3.722 12.408)" fill="#196ec0"/>
<path id="Vector-2" data-name="Vector" d="M2.482,0A2.482,2.482,0,1,0,4.963,2.482,2.489,2.489,0,0,0,2.482,0Z" transform="translate(21.093 12.408)" fill="#196ec0"/>
<path id="Vector-3" data-name="Vector" d="M2.482,0A2.482,2.482,0,1,0,4.963,2.482,2.489,2.489,0,0,0,2.482,0Z" transform="translate(12.408 12.408)" fill="#196ec0"/>
<path id="Vector-4" data-name="Vector" d="M0,0H29.778V29.778H0Z" transform="translate(0 0)" fill="#196ec0" opacity="0"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 855 B

@ -1,5 +1,5 @@
import React, { useState } from "react";
import { Link } from "react-router-dom";
import { NavLink } 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";
@ -12,7 +12,7 @@ export const BottomNavigation = ({ pages, isDark }) => {
const Tab = ({ page }) => {
return (
<Link
<NavLink
to={page.link}
className="flex flex-col justify-center itemms-center"
onClick={() => setActiveLink(page.link)}
@ -25,14 +25,14 @@ export const BottomNavigation = ({ pages, isDark }) => {
<span className="text-blueB9 text-xs text-center font-bold mt-1">
{page.name}
</span>
</Link>
</NavLink>
);
};
return (
<>
<footer
className="w-full flex flex-row justify-around items-center fixed bottom-0 left-0 py-2 z-20 lg:hidden"
style={{ background: isDark ? "hsla(209, 39%, 28%, 1)" : "#E8FCFF" }}
style={{ background: isDark ? "hsla(209, 39%, 28%, 0.96)" : "#E8FCFFEE" }}
>
{pages.map((page, index) => (
<Tab page={page} key={index} />

@ -8,12 +8,22 @@ export default function Button({
width,
bgOpacity,
onClick,
selectable,
active,
}) {
return (
<button
className={`rounded-md py-3 justify-center text-sm ${backgroundColor} ${color} ${bgOpacity}`}
className={`rounded-md py-3 justify-center text-sm ${
selectable ? (active ? "bg-black" : backgroundColor) : backgroundColor
} ${selectable ? (active ? "text-blueC0" : color) : color} ${
selectable ? (active ? "bg-opacity-10" : bgOpacity) : bgOpacity
} `}
style={{
border: `${border.width} solid ${border.color}`,
border: `${
selectable ? (active ? "2px" : border.width) : border.width
} solid ${
selectable ? (active ? "#196EC0" : border.color) : border.color
}`,
width: width,
}}
onClick={() => onClick()}

@ -0,0 +1,17 @@
import React from "react";
import Drawer from "react-modern-drawer";
const MyDrawer = ({ drawerOpen, setDrawerOpen }) => {
return (
<Drawer
open={drawerOpen}
onClose={() => setDrawerOpen(() => !drawerOpen)}
size={'80%'}
direction="right"
>
</Drawer>
);
};
export default MyDrawer;

@ -10,11 +10,11 @@ function Header({ title, link, isDark }) {
<strong className="text-blueC0 dark:text-white font-semibold text-sm">
{title}
</strong>
<Link to={link}>
<Link to={link} className="ml-1">
<img
src={isDark ? arrowWhiteIcon : arrowBlueIcon}
alt=""
className={`transform ${isDark ? "w-5" : "w-5 rotate-180"}`}
className={`transform ${isDark ? "w-6" : "w-6 rotate-180"}`}
/>
</Link>
</header>

@ -1,7 +1,9 @@
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { Link, useNavigate } from "react-router-dom";
import { connect } from "react-redux";
import _ from "lodash";
import Drawer from "../Drawer";
//assets
import grayBagIcon from "../../assets/icons/gray-bag.svg";
import graySearchIcon from "../../assets/icons/gray-search.svg";
import logoIcon from "../../assets/icons/logo.svg";
@ -11,9 +13,20 @@ import arIcon from "../../assets/icons/ar-white.svg";
import arBlueIcon from "../../assets/icons/ar-blue.svg";
import hamburgerIcon from "../../assets/icons/hamburger.svg";
import hamburgerBlueIcon from "../../assets/icons/hamburger-blue.svg";
import arrowBlueIcon from "../../assets/icons/arrow-right-blue.svg";
import arrowWhiteIcon from "../../assets/icons/arrow-left-white.svg";
import dotsMenuDarkIcon from "../../assets/icons/dots-menu-dark.svg";
import bookmarkDeactiveDarkIcon from "../../assets/icons/bookmark-deactive-dark.svg";
import dotsMenuLightIcon from "../../assets/icons/dots-menu-light.svg";
import bookmarkDeactiveLightIcon from "../../assets/icons/bookmark-deactive-light.svg";
function Navbar({ pages, isDark, headerOptions }) {
const navigation = useNavigate();
const { logo, hamburgerMenu, qr, shown, menu, title, back, bookmark } =
headerOptions;
function Navbar({ pages, isDark}) {
const [top, setTop] = useState(false);
const [drawerOpen, setDrawerOpen] = useState(false);
useEffect(() => {
if (window.scrollY === 0) {
setTop(() => true);
@ -65,23 +78,45 @@ function Navbar({ pages, isDark}) {
</div>
{/* landscape end */}
{/* portrait start */}
<div className="w-full h-full relative flex flex-row items-center justify-between lg:hidden pt-6 pb-2 px-4">
<div className="w-full h-full relative flex flex-row items-center justify-between lg:hidden py-3 px-4">
<div className="relative">
{hamburgerMenu && (
<>
<span className="w-2.5 h-2.5 rounded-full bg-redFF1 absolute -left-1 -top-1 animate-bounce"></span>
<img
onClick={() => setDrawerOpen((prevState) => !prevState)}
src={isDark ? hamburgerIcon : hamburgerBlueIcon}
alt=""
className="w-7 h-7.5"
/>
</>
)}
{!title && back ? (
<img
src={isDark ? arrowWhiteIcon : arrowBlueIcon}
alt="back"
className={`w-6 ${isDark ? "transform rotate-180" : ""}`}
onClick={() => navigation(-1)}
/>
) : null}
{title && (
<strong className="text-blueC0 text-lg font-semibold dark:text-white">
{title}
</strong>
)}
</div>
{logo && (
<Link
to="/"
className="absolute left-1/2 transform -translate-y-1/2 top-1/2 -translate-x-1/2"
>
<img src={logoIcon} className="w-6 h-8" />
</Link>
)}
<div className="flex flex-row items-center">
{qr && (
<>
<Link
to="/qr"
className={_.join(
@ -120,15 +155,43 @@ function Navbar({ pages, isDark}) {
className={_.join(["w-6"], " ")}
/>
</Link>
</>
)}
{bookmark && (
<img
src={
isDark ? bookmarkDeactiveDarkIcon : bookmarkDeactiveLightIcon
}
alt="bookmark"
className="w-7 ml-2"
/>
)}
{menu && (
<img
src={isDark ? dotsMenuDarkIcon : dotsMenuLightIcon}
alt="menu"
className="w-7"
/>
)}
{title && back ? (
<img
src={isDark ? arrowWhiteIcon : arrowBlueIcon}
alt="back"
className={`w-6 ${isDark ? "" : "transform -rotate-180"}`}
onClick={() => navigation(-1)}
/>
) : null}
</div>
</div>
){/* portrait end */}
<Drawer drawerOpen={drawerOpen} setDrawerOpen={setDrawerOpen} />
{/* portrait end */}
</div>
);
}
const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark,
headerOptions: state.publicApi.headerOptions,
});
export default connect(mapStateToProps, {})(Navbar);
@ -160,4 +223,7 @@ Navbar.defaultProps = {
name: "وبلاگ",
},
],
logo: true,
hamburgerMenu: true,
qr: true,
};

@ -1,12 +1,14 @@
import proxy from "../proxy";
const publicApi = {
setHeaderOptions: (data) => async (dispatch) =>
await dispatch({ type: "public/setHeaderOptions", data }),
setIsDark: (data) => async (dispatch) =>
await dispatch({ type: "public/setIsDark", data: data }),
await dispatch({ type: "public/setIsDark", data }),
getHomeData: (data) => async (dispatch) =>
await proxy.get("public/homePage", data, { dispatch }),
setFaqActive: (data) => async (dispatch) =>
await dispatch({ type: "public/faq/activate", data: data }),
await dispatch({ type: "public/faq/activate", data }),
bookInfo:
(data = {}) =>
async (dispatch) =>
@ -26,7 +28,7 @@ const publicApi = {
getBlogInfo: (data) => async (dispatch) =>
await proxy.get("public/blogInfo", data, { dispatch }),
setSubscribe: (data) => async (dispatch) =>
await dispatch({ type: "public/setSubscribe", data: data }),
await dispatch({ type: "public/setSubscribe", data }),
getProvince:
(data = {}) =>
async (dispatch) =>
@ -36,15 +38,15 @@ const publicApi = {
async (dispatch) =>
await proxy.get("public/city", data, { dispatch }),
selectMenu: (data) => async (dispatch) =>
await dispatch({ type: "public/selectMenu", data: data }),
await dispatch({ type: "public/selectMenu", data }),
getHeader:
(data = {}) =>
async (dispatch) =>
await proxy.get("public/VOD/homePage", data, { dispatch }),
activeCategory: (data) => async (dispatch) =>
await dispatch({ type: "active/category", data: data }),
await dispatch({ type: "active/category", data }),
setVideoActive: (data) => async (dispatch) =>
await dispatch({ type: "active/video", data: data }),
await dispatch({ type: "active/video", data }),
};
export default publicApi;

@ -1,7 +1,7 @@
import location from "../../utils/location";
const initialState = {
isDark: localStorage.getItem("isDark") || false,
isDark: localStorage.getItem("isDark") || true,
homeData: [],
newProducts: [],
levels: [],
@ -50,6 +50,15 @@ const initialState = {
11: "یازدهم",
12: "دوازدهم",
},
headerOptions : {
shown : false,
logo : false,
hamburgerMenu :false,
qr : false,
menu : false,
back : false,
title : false,
}
};
const grades = [
@ -70,6 +79,8 @@ const grades = [
export default function publicApi(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "public/setHeaderOptions":
return {...state, headerOptions : data};
case "public/setIsDark":
localStorage.setItem("isDark", data);
return { ...state, location: false, error: null, isDark: data };

@ -13,30 +13,96 @@ import Product from "./views/Product";
import ShoppingCart from "./views/ShoppingCart";
// import VideoTube from "./views/Home/VideoTube";
function Router({ isDark, isLogin }) {
function Router({ isDark, isLogin, headerOptions }) {
return (
<div className={_.join([isDark ? "dark" : ""], " ")}>
<div
className={_.join(
[
"min-h-screen min-w-screen rtl overflow-x-hidden py-20 lg:py-0",
"min-h-screen min-w-screen rtl overflow-x-hidden pb-20 lg:py-0",
isDark ? "" : "bg-white",
headerOptions?.shown ? "pt-16" : "pt-4",
],
" "
)}
>
<BrowserRouter>
<Navbar />
{headerOptions?.shown && <Navbar headerOptions={headerOptions} />}
<BG />
<BottomNavigation />
<Routes>
<Route path="/" exact element={<Home />} />
<Route
path="/"
exact
element={
<Home
headerOptions={{
logo: true,
hamburgerMenu: true,
qr: true,
title: false,
back: false,
shown: true,
menu: false,
}}
/>
}
/>
<Route path="/login" exact element={<Auth page="login" />} />
<Route path="/signup" exact element={<Auth page="signup" />} />
<Route
path="/signup"
exact
element={
<Auth
page="signup"
headerOptions={{
logo: true,
hamburgerMenu: true,
qr: true,
title: false,
back: false,
shown: true,
menu: false,
}}
/>
}
/>
<Route path="/profile" exact element={<Auth page="profile" />} />
<Route path="/products" exact element={<Products />} />
<Route path="/cart" exact element={<ShoppingCart />} />
<Route path="/products/:id" exact element={<Product />} />
<Route
path="/products"
exact
element={<Products headerOptions={{ shown: false }} />}
/>
<Route
path="/cart"
exact
element={
<ShoppingCart
headerOptions={{
shown: true,
title: "سبد خرید",
back: true,
}}
/>
}
/>
<Route
path="/products/:id"
exact
element={
<Product
headerOptions={{
shown: true,
logo: false,
hamburgerMenu: false,
title: false,
back: true,
menu: true,
bookmark: true,
}}
/>
}
/>
<Route
path="*"
element={
@ -54,7 +120,8 @@ function Router({ isDark, isLogin }) {
const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark,
isLogin: state.user.status
isLogin: state.user.status,
headerOptions: state.publicApi.headerOptions,
});
export default connect(mapStateToProps, {})(Router);

@ -7,12 +7,19 @@ import onInput from "../../../utils/onInput";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import { user } from "../../../redux/actions";
import { user, publicApi } from "../../../redux/actions";
import _ from "lodash";
//assets
import logoIcon from "./assets/logo.svg";
function SignUp({ sendOtp, sendPhoneNumber, loginFlag, theme }) {
function SignUp({
sendOtp,
sendPhoneNumber,
loginFlag,
theme,
headerOptions,
setHeaderOptions,
}) {
const [level, setLevel] = useState("phonenumber");
const [signUpFields, setSignUpFiels] = useState({});
const [error, setError] = useState("");
@ -73,7 +80,12 @@ function SignUp({ sendOtp, sendPhoneNumber, loginFlag, theme }) {
};
const checkOtp = () => {
if (signUpFields?.otp1 && signUpFields?.otp2 && signUpFields?.otp3 && signUpFields?.otp4) {
if (
signUpFields?.otp1 &&
signUpFields?.otp2 &&
signUpFields?.otp3 &&
signUpFields?.otp4
) {
sendOtp({
cellphone: signUpFields?.cellphone,
otp:
@ -94,6 +106,7 @@ function SignUp({ sendOtp, sendPhoneNumber, loginFlag, theme }) {
useEffect(() => {
// numberInput.current.focus();
setHeaderOptions(headerOptions);
}, []);
useEffect(() => {
@ -270,5 +283,6 @@ export default connect(
{
sendOtp: user.otp_login,
sendPhoneNumber: user.otp,
setHeaderOptions: publicApi.setHeaderOptions,
}
)(SignUp);

@ -1,9 +1,8 @@
import React, {useState, useEffect} from 'react';
import SignUp from './SignUp/index';
import Profile from './Profile/index';
import Login from './Login/index';
import {connect} from 'react-redux';
import React, { useState, useEffect } from "react";
import SignUp from "./SignUp/index";
import Profile from "./Profile/index";
import Login from "./Login/index";
import { connect } from "react-redux";
function Auth(props) {
const [page, setPage] = useState(props.page);
@ -12,11 +11,19 @@ function Auth(props) {
}, [props.page]);
return (
<>
{ page === 'signup' && <SignUp theme={props.theme} /> }
{ page === 'login' && <Login theme={props.theme} setPage={setPage} /> }
{ page === 'profile' && <Profile theme={props.theme} /> }
{page === "signup" && (
<SignUp theme={props.theme} headerOptions={props.headerOptions} />
)}
{page === "login" && (
<Login
theme={props.theme}
setPage={setPage}
headerOptions={props.headerOptions}
/>
)}
{page === "profile" && <Profile theme={props.theme} />}
</>
)
);
}
export default connect((state) => ({

@ -14,7 +14,7 @@ function Blogs({ list, getList, isDark }) {
<div className="w-full pr-4">
<div className="w-full flex flex-col rounded-md py-4 overflow-hidden">
<header className="w-full flex flex-row justify-between items-center">
<strong className="text-blueC0 dark:text-white font-bold text-lg">
<strong className="text-blueC0 dark:text-white font-bold text-sm">
خواندنیها
</strong>
<img

@ -11,7 +11,7 @@ function MyBooks({ list, getList, grades }) {
return (
<div className="w-full px-4 mb-5">
<div className="w-full flex flex-col rounded-md pt-4 px-2 bg-blueFF1 dark:bg-gray2077 overflow-hidden">
<strong className="text-blueC0 dark:text-white font-bold text-lg">کتابهای من</strong>
<strong className="text-blueC0 dark:text-white font-bold text-sm">کتابهای من</strong>
<ul className="list-none w-full overflow-x-scroll pt-2 flex flex-row">
{list.map((book, index) => (
<Book book={book} key={index} grades={grades} />
@ -25,7 +25,7 @@ function MyBooks({ list, getList, grades }) {
const Book = ({ book, grades }) => {
return (
<li className="flex flex-col ml-3">
<Link to={"/products/" + book.name}>
<Link to={"/products/" + book.id}>
<img
src={`https://dnvn.ir/api/v1/file/${book.fileIds}`}
alt=""

@ -14,7 +14,7 @@ function Videos({ list, getList, grades, isDark }) {
<div className="w-full px-4">
<div className="w-full flex flex-col rounded-md py-4 overflow-hidden">
<header className="w-full flex flex-row justify-between items-center">
<strong className="text-blueC0 dark:text-white font-bold text-lg">
<strong className="text-blueC0 dark:text-white font-bold text-sm">
دورههای ویدئویی شما
</strong>
<img

@ -1,9 +1,8 @@
import React from "react";
import React, { useEffect } from "react";
import { connect } from "react-redux";
import Public from "./Public";
import Private from "./Private";
function Portrait({ isLogin }) {
return (
<div className="w-full min-h-screen lg:hidden z-10">
@ -16,4 +15,8 @@ const mapStateToProps = (state) => ({
isLogin: state.user.status,
});
export default connect(mapStateToProps, {})(Portrait);
const mapDispatchToProps = {
};
export default connect(mapStateToProps, mapDispatchToProps)(Portrait);

@ -1,13 +1,25 @@
import React from 'react';
import Landscape from './Landscape';
import Portrait from './Portrait';
import React, { useEffect } from "react";
import { connect } from "react-redux";
import Landscape from "./Landscape";
import Portrait from "./Portrait";
import { publicApi } from "../../redux/actions";
export default function Home() {
function Home({ setHeaderOptions, headerOptions }) {
useEffect(() => {
setHeaderOptions(headerOptions);
}, []);
return (
<>
<Portrait />
<Landscape />
</>
)
);
}
const mapStateToProps = (state) => ({});
const mapDispatchToProps = {
setHeaderOptions: publicApi.setHeaderOptions,
};
export default connect(mapStateToProps, mapDispatchToProps)(Home);

@ -1,7 +1,7 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { toast } from "react-toastify";
import { book, userProduct } from "../../redux/actions";
import { book, userProduct, publicApi } from "../../redux/actions";
import proxy from "../../redux/proxy";
import location from "../../utils/location";
import Button from "../../components/Button";
@ -17,9 +17,14 @@ export const Product = ({
isDark,
userId,
pushToCart,
headerOptions,
setHeaderOptions,
}) => {
const [type, setType] = useState("physical");
useEffect(() => {
getInfo({ id: location.getId() });
setHeaderOptions(headerOptions);
}, []);
return (
<>
@ -37,7 +42,9 @@ export const Product = ({
/>
<div className="flex flex-1 flex-col pr-2 pt-2">
<h1 className="text-blue5F mb-3 font-semibold text-sm dark:text-white">
{book?.name}
{type === "digital"
? book?.product[0]?.name
: book?.product[1]?.name}
</h1>
<div className="text-blueC0 text-xs dark:text-greenBA">
{"پایه" + " " + grades[book?.gradeId]}
@ -58,7 +65,7 @@ export const Product = ({
{book?.rate} <br /> امتیاز
</li>
</ul>
<h2 className="text-blueC0 text-sm font-light mt-5 dark:text-greenBA">
<h2 className="text-blueC0 text-sm font-semibold mt-7 dark:text-greenBA">
نسخه محصول را انتخاب کنید
</h2>
<div className="w-full flex flex-row justify-between items-center mt-4">
@ -68,13 +75,19 @@ export const Product = ({
border={{ color: isDark ? "#ffffff55" : "#196EC055", width: "1px" }}
width="49%"
color={isDark ? "text-white" : "text-blueC0"}
active={type === "physical"}
selectable={true}
onClick={() => setType("physical")}
/>
<Button
title="نسخه دیجیتال"
backgroundColor={isDark ? "bg-transparent" : "bg-white"}
border={{ color: isDark ? "#ffffff55" : "#196EC055", width: "1px" }}
width="49%"
selectable={true}
active={type === "digital"}
color={isDark ? "text-white" : "text-blueC0"}
onClick={() => setType("digital")}
/>
</div>
<div className="w-full flex flex-row justify-between items-center mt-4">
@ -82,13 +95,24 @@ export const Product = ({
onClick={() =>
proxy.status()
? pushToCart({
productId: book.product[1].id,
productId:
type === "digital"
? book?.product[0]?.id
: book?.product[1]?.id,
userId: userId,
count: 1,
})
: toast.info("ابتدا وارد حساب کاربری خود شوید.")
}
title="خرید با قیمت 245.000 تومان"
title={
"خرید با قیمت" +
" " +
(type === "digital"
? book?.product[0]?.price
: book?.product[1]?.price) +
" " +
"تومان"
}
backgroundColor="bg-blueC0"
border={{ color: "#196EC055", width: "1px" }}
width="65%"
@ -149,7 +173,11 @@ const mapStateToProps = (state) => ({
userId: state.user.status.id,
});
const mapDispatchToProps = { getInfo: book.info, pushToCart: userProduct.add };
const mapDispatchToProps = {
getInfo: book.info,
pushToCart: userProduct.add,
setHeaderOptions: publicApi.setHeaderOptions,
};
export default connect(mapStateToProps, mapDispatchToProps)(Product);

@ -3,7 +3,7 @@ import { Link } from "react-router-dom";
import { connect } from "react-redux";
import Search from "../../components/Search";
import Select from "../../components/Select";
import { book } from "../../redux/actions";
import { book, publicApi } from "../../redux/actions";
//assets
import searchLight from "../../assets/icons/search-light.svg";
@ -65,6 +65,8 @@ export const Products = ({
gradeFilter,
selectedGrade,
gradeFilterBooks,
setHeaderOptions,
headerOptions,
}) => {
const [filter, setFilter] = useState({
search: "",
@ -78,6 +80,7 @@ export const Products = ({
useEffect(() => {
getList();
setHeaderOptions(headerOptions);
}, []);
useEffect(() => {
@ -154,6 +157,7 @@ const mapStateToProps = (state) => ({
const mapDispatchToProps = {
getList: book.list,
gradeFilter: book.gradeFilter,
setHeaderOptions: publicApi.setHeaderOptions,
};
export default connect(mapStateToProps, mapDispatchToProps)(Products);

@ -1,14 +1,37 @@
import React from "react";
import React, {useState} from "react";
import { connect } from "react-redux";
import { userFactor } from "../../../redux/actions";
function Code({ codeId, setCodeId, userId, factorId }) {
const [value, setValue] = React.useState(codeId || "");
const setOff = () => {
setCodeId({ offCodeValue: value, userId: userId, id: factorId });
}
export default function Code({}) {
return (
<form className="flex w-full flex-row border border-blueC0 border-solid rounded-md mt-3 overflow-hidden">
<input
type="text"
className="border-0 flex-1 text-right pr-3 font-medium text-xs dark:bg-gray2077 placeholder:text-blue5F"
className="border-0 flex-1 text-right pr-3 font-medium text-xs dark:bg-gray2077 placeholder:text-blue5F dark:text-white"
placeholder={"کد تخفیف دارید ؟"}
/>
<button className={"py-3 px-4 text-xs bg-blueC0 text-white border border-blueC0 border-solid"}>ثبت کد</button>
<button className={"py-3 px-4 text-xs bg-blueC0 text-white border border-blueC0 border-solid"} onClick={setOff}>ثبت کد</button>
</form>
);
}
const mapStateToProps = (state) => ({
codeId: state.userFactor.info?.codeId,
userId: state.user.status.id,
factorId: state.userFactor.info?.id,
});
const mapDispatchToProps = {
setCodeId: userFactor.update,
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Code);

@ -1,43 +1,95 @@
import React from "react";
import { connect } from "react-redux";
import { userProduct } from "../../../redux/actions";
// assets
import bookImage from "../../../assets/images/zist-11.svg";
import exitIcon from "../../../assets/icons/exit.svg";
export default function Product({ product }) {
function Product({ product, grades, pushToCart }) {
return (
<div className="flex flex-row justify-between py-5 border-b border-solid border-grayDB dark:border-gray45">
<div className="flex flex-row">
<img src={bookImage} className="rounded-md w-20" />
<img
src={"https://dnvn.ir/api/v1/file/" + product.product.book.fileIds}
className="rounded-md w-20"
/>
<div className="flex flex-col pr-2">
<strong className="text-sm text-blue5F mb-1 dark:text-white">
علوم اجتماعی
{product.product.book.name}
</strong>
<span className="text-gray70 text-xs mb-1 dark:text-greenBA">
پایه دوم
{"پایه" + " " + grades[product.product.book.gradeId]}
</span>
<span className="text-gray70 text-xs mb-1 dark:text-greenBA">
نسخه فیزیکی
{product.productType === 2 ? "نسخه فیزیکی" : "نسخه دیجیتال"}
</span>
</div>
</div>
<div className={"flex flex-col justify-between items-end"}>
<img src={exitIcon} className="w-4" alt="" />
<img
src={exitIcon}
className="w-4"
alt=""
onClick={() =>
pushToCart(
{
productId: product?.productId,
userId: product?.userId,
count: product?.productType === 1 ? -1 : -product?.count,
},
{},
{id : product?.factorId}
)
}
/>
<div className="flex flex-col items-center">
{product.productType === 2 && (
<div className="flex flex-row items-center mb-3">
<button className="rounded-md pt-2 pb-1.5 px-3 border border-solid border-blueC0 text-blueC0">
<button
className="rounded-md pt-2 pb-1.5 px-3 border border-solid border-blueC0 text-blueC0"
onClick={() =>
pushToCart({
productId: product?.productId,
userId: product?.userId,
count: 1,
})
}
>
+
</button>
<span className="mx-2.5 font-semibold text-md text-blueC0">1</span>
<button className="rounded-md pt-2 pb-1.5 px-3 border border-solid border-grayDB text-grayDB dark:border-blueC0 dark:text-blueC0">
<span className="mx-2.5 font-semibold text-md text-blueC0">
{product.count}
</span>
<button
className="rounded-md pt-2 pb-1.5 px-3 border border-solid border-grayDB text-grayDB dark:border-blueC0 dark:text-blueC0"
onClick={() =>
pushToCart({
productId: product?.productId,
userId: product?.userId,
count: -1,
})
}
>
-
</button>
</div>
)}
<strong className="font-bold text-md text-blue5F dark:text-white">
145.000
{product.product.price}&nbsp;تومان
</strong>
</div>
</div>
</div>
);
}
const mapStateToProps = (state) => ({
grades: state.publicApi.grades,
});
const mapDispatchToProps = {
pushToCart: userProduct.add,
};
export default connect(mapStateToProps, mapDispatchToProps)(Product);

@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react";
import { userProduct, userFactor } from "../../redux/actions";
import { userProduct, userFactor, publicApi } from "../../redux/actions";
import Product from "./Product";
import Code from "./Code";
@ -15,12 +15,12 @@ const PriceStatus = ({ name, value, type, isDark }) => {
<div className="w-full flex flex-row justify-between py-2">
<strong className="font-light text-sm dark:text-white">{name}</strong>
<span
className="font-normal text-xs dark:text-white"
className="font-bold text-xs dark:text-white"
style={{
color: !isDark ? (type === "error" ? "#F1420D" : "#246E8A") : "",
}}
>
{value}
{value + " " + "تومان"}
</span>
</div>
);
@ -36,33 +36,37 @@ function ShoppingCart({
getList,
getInfo,
getFactorInfo,
payFactor
payFactor,
headerOptions,
setHeaderOptions,
}) {
useEffect(() => {
getList();
getFactorInfo({ userId });
setHeaderOptions(headerOptions);
}, []);
return (
<div className="w-full flex flex-col px-4">
{[0, 1].map((product, index) => (
{list.map((product, index) => (
<Product key={index} product={product} />
))}
<Code />
<div className="flex flex-col w-full border-t py-2 border-gray-300 border-b mt-6">
<PriceStatus
name="مبلغ سبد خرید"
value="265000 تومان"
value={factorInfo?.sumPrice}
type="normal"
isDark={isDark}
/>
<PriceStatus
name="میزان تخفیف"
value="0 تومان"
value={factorInfo?.offPrice}
type="error"
isDark={isDark}
/>
<PriceStatus
name="مالیات بر ارزش افزوده"
value="0 تومان"
value={factorInfo?.sumPrice * 0.009}
type="error"
isDark={isDark}
/>
@ -72,7 +76,7 @@ function ShoppingCart({
جمع کل سبد خرید
</strong>
<p className="font-medium text-greenBA text-xs dark:text-white">
235.000 تومان
{factorInfo?.payPrice + " " + "تومان"}
</p>
</div>
<div
@ -90,6 +94,7 @@ function ShoppingCart({
border={{ color: "#196EC055", width: "1px" }}
width="100%"
color="text-white"
// onClick={() => }
/>
</div>
);
@ -109,6 +114,7 @@ const mapDispatchToProps = {
getInfo: userProduct.info,
getFactorInfo: userFactor.info,
payFactor: userFactor.payment,
setHeaderOptions: publicApi.setHeaderOptions,
};
export default connect(mapStateToProps, mapDispatchToProps)(ShoppingCart);

@ -9422,6 +9422,11 @@ react-is@^17.0.1, react-is@^17.0.2:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
react-modern-drawer@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/react-modern-drawer/-/react-modern-drawer-1.0.1.tgz#a400c551216b3dffadf93e80f7cc313d30434d13"
integrity sha512-Stswd8ETIRTGLJl7aFtu92kXb+7UCPn2mzTvpGWsE1kMXco3dK+PZyw/4NGGwDpesZvwPsz3PFlO1BuVqBZpCg==
react-redux@^7.2.6:
version "7.2.6"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.6.tgz#49633a24fe552b5f9caf58feb8a138936ddfe9aa"

Loading…
Cancel
Save