reza added something

temp
Reza_ashrafi 3 years ago
parent 503bf41a3d
commit 8d372deb20
  1. 10
      src/assets/icons/ar-blue.svg
  2. 8
      src/assets/icons/hamburger-blue.svg
  3. 8
      src/assets/icons/qr-blue.svg
  4. 2
      src/components/Drawer/index.js
  5. 26
      src/components/Header/index.js
  6. 9
      src/components/Input/index.js
  7. 4
      src/components/Navbar/index.js
  8. 10
      src/components/Progress/index.js
  9. 33
      src/components/Search/index.js
  10. 4
      src/components/Select/index.js
  11. 1
      src/redux/reducers/book.js
  12. 2
      src/redux/reducers/public.js
  13. 4
      src/router.js
  14. 39
      src/views/Home/Portrait/Private/Blogs/index.js
  15. 18
      src/views/Home/Portrait/Private/MyBooks/index.js
  16. 25
      src/views/Home/Portrait/Private/Shop/index.js
  17. 30
      src/views/Home/Portrait/Private/Videos/index.js
  18. 46
      src/views/Home/Portrait/Private/index.js
  19. 4
      src/views/Home/Portrait/Public/GradiantText/index.js
  20. 96
      src/views/Products/index.js
  21. 9
      src/views/Products/layouts/Desktop/Main.js
  22. 9
      src/views/Products/layouts/Desktop/Sidebar.js
  23. 69
      src/views/Products/layouts/Mobile/Header.js
  24. 164
      src/views/Products/layouts/Mobile/Main.js

@ -1,9 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="28.908" height="28.908" viewBox="0 0 28.908 28.908">
<g id="Group_419" data-name="Group 419" transform="translate(-11 -20.092)">
<path id="Path_1864" data-name="Path 1864" d="M1.694,1.694H6.775V0H0V6.775H1.694Zm0,0" transform="translate(11 20.092)" fill="#196ec0"/>
<path id="Path_1863" data-name="Path 1863" d="M392,0V1.694h5.081V6.775h1.694V0Zm0,0" transform="translate(-358.868 20.092)" fill="#196ec0"/>
<path id="Path_1862" data-name="Path 1862" d="M397.081,397.081H392v1.694h6.775V392h-1.694Zm0,0" transform="translate(-358.868 -349.775)" fill="#196ec0"/>
<path id="Path_1861" data-name="Path 1861" d="M1.694,392H0v6.775H6.775v-1.694H1.694Zm0,0" transform="translate(11 -349.775)" fill="#196ec0"/>
<text id="AR" transform="translate(26 39.092)" fill="#196ec0" font-size="14" font-family="IRANSansX-Light, IRANSansX" font-weight="300"><tspan x="-8.841" y="0">AR</tspan></text>
<path id="Path_1864" data-name="Path 1864" d="M1.694,1.694H6.775V0H0V6.775H1.694Zm0,0" transform="translate(11 20.092)" fill="rgb(19, 123, 79)"/>
<path id="Path_1863" data-name="Path 1863" d="M392,0V1.694h5.081V6.775h1.694V0Zm0,0" transform="translate(-358.868 20.092)" fill="rgb(19, 123, 79)"/>
<path id="Path_1862" data-name="Path 1862" d="M397.081,397.081H392v1.694h6.775V392h-1.694Zm0,0" transform="translate(-358.868 -349.775)" fill="rgb(19, 123, 79)"/>
<path id="Path_1861" data-name="Path 1861" d="M1.694,392H0v6.775H6.775v-1.694H1.694Zm0,0" transform="translate(11 -349.775)" fill="rgb(19, 123, 79)"/>
<text id="AR" transform="translate(26 39.092)" fill="rgb(19, 123, 79)" font-size="14" font-family="IRANSansX-Light, IRANSansX" font-weight="300"><tspan x="-8.841" y="0">AR</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 964 B

After

Width:  |  Height:  |  Size: 1009 B

@ -1,8 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="31.567" height="28.996" viewBox="0 0 31.567 28.996">
<g id="textalign-justifycenter" transform="translate(-367.969 -188.141)">
<path id="Vector" d="M0,0H29.567" transform="translate(368.969 189.141)" fill="none" stroke="#196ec0" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
<path id="Vector-2" data-name="Vector" d="M0,0H29.567" transform="translate(368.969 198.14)" fill="none" stroke="#196ec0" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
<path id="Vector-3" data-name="Vector" d="M0,0H29.567" transform="translate(368.969 207.139)" fill="none" stroke="#196ec0" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
<path id="Vector-4" data-name="Vector" d="M0,0H29.567" transform="translate(368.969 216.137)" fill="none" stroke="#196ec0" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
<path id="Vector" d="M0,0H29.567" transform="translate(368.969 189.141)" fill="none" stroke="rgb(19, 123, 79)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
<path id="Vector-2" data-name="Vector" d="M0,0H29.567" transform="translate(368.969 198.14)" fill="none" stroke="rgb(19, 123, 79)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
<path id="Vector-3" data-name="Vector" d="M0,0H29.567" transform="translate(368.969 207.139)" fill="none" stroke="rgb(19, 123, 79)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
<path id="Vector-4" data-name="Vector" d="M0,0H29.567" transform="translate(368.969 216.137)" fill="none" stroke="rgb(19, 123, 79)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 940 B

After

Width:  |  Height:  |  Size: 976 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

@ -41,7 +41,7 @@ const MyDrawer = ({
onClick={(e) => e.stopPropagation()}
>
<header
class="flex flex-col justify-between h-1/6 pt-3 px-3 bg-blueEB dark:bg-blue90"
className="flex flex-col justify-between h-1/6 pt-3 px-3 bg-green-500 dark:bg-blue90"
style={{ minHeight: "calc(100vh / 6)" }}
>
<div className="flex flex-row justify-between">

@ -1,32 +1,38 @@
import React from "react";
import { Link } from "react-router-dom";
import {connect} from 'react-redux';
import arrowBlueIcon from "../../assets/icons/arrow-right-blue.svg";
import { connect } from "react-redux";
import arrowGreenIcon from "../../assets/icons/dropdown-blue.svg";
import arrowWhiteIcon from "../../assets/icons/arrow-left-white.svg";
function Header({ title, link, isDark }) {
return (
<header className="w-full flex flex-row justify-between items-center pl-0">
<strong className="text-blueC0 dark:text-white font-semibold text-sm">
<strong className="text-green7B dark:text-white font-semibold text-base lg:text-sm">
{title}
</strong>
<Link to={link} className="ml-2">
{isDark ? (
<img
src={isDark ? arrowWhiteIcon : arrowBlueIcon}
src={arrowWhiteIcon}
alt=""
className={`transform ${isDark ? "w-6" : "w-6 rotate-180"}`}
className={`transform ${"w-6"}`}
/>
) : (
<img
src={arrowGreenIcon}
alt=""
className={`transform rotate-90 w-2}`}
/>
)}
</Link>
</header>
);
}
const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark
})
isDark: state.publicApi.isDark,
});
const mapDispatchToProps = {
}
const mapDispatchToProps = {};
export default connect(mapStateToProps, mapDispatchToProps)(Header);

@ -49,7 +49,10 @@ export default function Input(props) {
return (
<div
className={_.join(
["input flex flex-col relative my-2 dark:bg-opacity-10 w-full", langDetector(lang, "fa", "en")],
[
"input flex flex-col relative my-2 dark:bg-opacity-10 w-full",
langDetector(lang, "fa", "en"),
],
" "
)}
style={{ width }}
@ -80,7 +83,9 @@ export default function Input(props) {
placeholder={label}
className={_.join(
[
`flex-1 border border-gray-300 dark:bg-opacity-10 bg-transparent rounded-md outline-none py-3 px-4 text-tiny ${backgroundColor} ${align}`,
`flex-1 border border-gray-300 dark:bg-opacity-10 rounded-md outline-none py-3 px-4 text-tiny ${
backgroundColor ? backgroundColor : "bg-transparent"
} ${align}`,
inputStatusHandler(
value,
focusToggle,

@ -129,7 +129,7 @@ function Navbar({
className={_.join(
[
"rounded-sm p-1.5",
isDark ? "bg-gray36 ml-2" : "bg-blueFF1 ml-3 shadow-sm",
isDark ? "bg-blueC0 bg-opacity-10 ml-2" : " ml-3 shadow-sm",
],
" "
)}
@ -148,7 +148,7 @@ function Navbar({
className={_.join(
[
"rounded-sm p-1.5",
isDark ? "bg-gray36" : "bg-blueFF1 shadow-sm",
isDark ? "bg-blueC0 bg-opacity-10" : " shadow-sm",
],
" "
)}

@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react";
function Progress({ percent, deskTop }) {
function Progress({ percent, deskTop, direction = "float-left" }) {
const [delayPercent, setDelayPercent] = useState(0);
useEffect(() => {
setTimeout(() => {
@ -8,9 +8,13 @@ function Progress({ percent, deskTop }) {
}, 1000);
}, [percent]);
return (
<div className={`flex-1 ${deskTop ? 'h-3' : 'h-1.5'} rounded-full overflow-hidden my-3 bg-blueC0 bg-opacity-10`}>
<div
className="h-full bg-blueC0 float-left transition-all duration-500 rounded-full"
className={`flex-1 ${
deskTop ? "h-3" : "h-1.5"
} rounded-full overflow-hidden my-3 bg-blueC0 bg-opacity-10`}
>
<div
className={`h-full bg-blueC0 transition-all ${direction} duration-500 rounded-full`}
style={{ width: delayPercent + "%" }}
></div>
</div>

@ -1,10 +1,10 @@
import React from "react";
import {connect} from 'react-redux';
import { connect } from "react-redux";
import { publicApi } from "../../redux/actions";
import _ from "lodash";
import searchIcon from "./search.png";
const langDetector = (lang = 'fa', option1, option2) => {
const langDetector = (lang = "fa", option1, option2) => {
return lang === "fa" ? option1 : option2;
};
@ -12,7 +12,15 @@ function Search(props) {
return (
<div className="flex items-center justify-center w-full my-3 bg-white z-50 overflow-hidden rounded-md">
<div className="relative text-gray-600 focus-within:text-gray-400 w-full">
<span className={_.join(["absolute inset-y-0 flex items-center pl-2", langDetector(props.lang, "left-0", "right-0")], " ")}>
<span
className={_.join(
[
"absolute inset-y-0 flex items-center pl-2",
langDetector(props.lang, "left-0", "right-0"),
],
" "
)}
>
<button
type="submit"
className="p-1 focus:outline-none focus:shadow-outline"
@ -23,8 +31,15 @@ function Search(props) {
<input
type="search"
name={props.name}
className="z-50 w-full py-3 text-sm lg:text-tiny lg:font-semibold text-gray1 border border-solid border-gray-200 rounded-md pr-5 pl-14 outline-none focus:ring-1 focus:text-gray-900 "
placeholder={_.join([langDetector(props.lang , "جستجو...", "Search...")], " ")}
className={`z-50 w-full py-3 text-base lg:text-tiny lg:font-semibold ${
props.backgroundColor
} ${
props.textColor ? props.textColor : "text-gray1"
} border border-solid border-gray-200 rounded-md pr-5 pl-14 outline-none focus:ring-1 focus:text-gray-900 `}
placeholder={_.join(
[langDetector(props.lang, "جستجو...", "Search...")],
" "
)}
autoComplete="off"
onChange={(e) => props.onChange(e.target.value)}
onFocus={() => props.setOverLayer(true)}
@ -35,12 +50,10 @@ function Search(props) {
);
}
const mapStateToProps = (state) => ({
})
const mapStateToProps = (state) => ({});
const mapDispatchToProps = {
setOverLayer : publicApi.setOverLayer
}
setOverLayer: publicApi.setOverLayer,
};
export default connect(mapStateToProps, mapDispatchToProps)(Search);

@ -12,10 +12,10 @@ function Select({
}) {
return (
<div
className={`inline-block w-1/2 relative group ${margin} ${backgroundColor}`}
className={`inline-block w-1/2 relative group rounded-md overflow-hidden ${margin} bg-transparent`}
>
<select
className={`text-gray70 text-tiny block appearance-none bg-transparent w-full border border-solid px-4 py-3 pr-3 rounded-md leading-tight focus:outline-none focus:border-blueC0 focus:text-blueC0 ${borderColor}`}
className={`text-gray70 text-base lg:text-tiny block appearance-none ${backgroundColor} w-full border border-solid px-4 py-3 pr-3 rounded-md leading-tight focus:outline-none focus:border-blueC0 focus:text-blueC0 ${borderColor}`}
onChange={(e) => onChange(name, e.target.value)}
>
{options.map((option, index) => (

@ -28,6 +28,7 @@ const initialState = {
productType: null,
available: false,
sort: null,
search : "",
},
};

@ -1,7 +1,7 @@
import location from "../../utils/location";
const initialState = {
isDark: false,
isDark: localStorage.getItem("isDark") || false,
isMobile: window.innerWidth < 1024,
homeData: [],
newProducts: [],

@ -59,9 +59,9 @@ function Router({
<div
className={_.join(
[
"min-h-screen min-w-screen rtl overflow-x-hidden pb-20 lg:py-0",
"min-h-screen min-w-screen rtl overflow-x-hidden lg:pb-20 lg:py-0",
isDark ? "" : "bg-white",
headerOptions?.shown ? "pt-16" : "pt-4",
headerOptions?.shown ? "pt-16" : "pt-0",
],
" "
)}

@ -1,29 +1,33 @@
import React, { useEffect } from "react";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import { blog } from "../../../../../redux/actions";
import _ from "lodash";
import arrowBlueIcon from "../../../../../assets/icons/arrow-right-blue.svg";
import arrowGreenIcon from "../../../../../assets/icons/dropdown-blue.svg";
import arrowWhiteIcon from "../../../../../assets/icons/arrow-left-white.svg";
function Blogs({ list, getList, isDark }) {
useEffect(() => {
getList();
}, []);
function Blogs({ list, isDark }) {
return (
<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-sm">
<strong className="text-green7B dark:text-white font-bold text-base lg:text-sm">
خواندنیها
</strong>
{isDark ? (
<img
src={isDark ? arrowWhiteIcon : arrowBlueIcon}
src={ arrowWhiteIcon}
alt=""
className={`transform ml-4 ${isDark ? "w-7" : "rotate-180"}`}
className={`transform ml-4 w-7`}
/>
) : (
<img
src={arrowGreenIcon}
alt=""
className={`transform ml-4 rotate-90`}
/>
)}
</header>
<ul className="list-none w-full overflow-x-scroll pt-3 flex flex-row pb-10">
<ul className="list-none w-full overflow-x-scroll pt-3 flex flex-row pb-10 no-scrollbar">
{list.map((blog, index) => (
<Blog blog={blog} key={index} />
))}
@ -43,8 +47,12 @@ const Blog = ({ blog }) => {
background: `url(https://dnvn.ir/api/v1/file/${blog?.fileIds})`,
backgroundPosition: "contain",
backgroundSize: "100% 100%",
width: 280,
minHeight: 220,
minWidth: 200,
width: 'calc(100vw / 1.6)',
maxWidth: 350,
minHeight : 160,
height : 'calc(100vw / 1.6 * 3 / 4)',
maxHeight : 300
}}
>
<div className="w-11/12 bg-white rounded-md shadow-md flex flex-col transform translate-y-1/2 p-2 dark:bg-gray36">
@ -58,12 +66,12 @@ const Blog = ({ blog }) => {
alt=""
className="w-5 h-5 rounded-full ml-2"
/>
<span className="text-blueC0 text-xs font-light dark:text-greenBA">
<span className="text-green7B text-xs font-light dark:text-greenBA">
{"حامد دژبانی نسب"}
</span>
</div>
<div className="flex flex-row items-center">
<span className="text-xs font-light dark:text-greenBA">
<span className="text-xs font-light text-gray70 dark:text-greenBA">
{_.join(["زمان مناسب", "30"], " ")}
</span>
</div>
@ -75,8 +83,7 @@ const Blog = ({ blog }) => {
};
const mapStateToProps = (state) => ({
list: state.publicApi.blogList,
isDark: state.publicApi.isDark,
});
export default connect(mapStateToProps, { getList: blog.list })(Blogs);
export default connect(mapStateToProps, {})(Blogs);

@ -1,10 +1,10 @@
import React, { useEffect } from "react";
import React from "react";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import { ScrollingCarousel } from "@trendyol-js/react-carousel";
import Progress from "../../../../../components/Progress";
function MyBooks({ books, getList, grades, isMobile }) {
function MyBooks({ books, grades, isMobile }) {
const Book = ({ book }) => {
return (
<li className="flex flex-col lg:ml-6 lg:p-2 lg:border lg:border-solid lg:border-green-200 lg:rounded-md lg:pt-4">
@ -18,15 +18,17 @@ function MyBooks({ books, getList, grades, isMobile }) {
width: isMobile ? "" : "calc(100vh / 5 * 3 / 4)",
minHeight: isMobile ? "calc(100vh / 5)" : "",
minWidth: isMobile ? "calc(100vh / 5 * 3 / 4)" : "",
maxHeight: isMobile ? 100 : "",
maxWidth: isMobile ? 70 : ""
}}
/>
<h2 className="mt-2 text-sm lg:text-tiny font-semibold text-blue5F dark:text-white lg:mt-4">
<h2 className="mt-2 text-tiny lg:text-tiny font-semibold text-blue5F dark:text-white lg:mt-4">
{book.name}
</h2>
<p className="font-medium text-green7B dark:text-greenBA text-xs lg:text-sm mt-1 lg:mt-2">{`پایه ${
<p className="font-medium text-green7B dark:text-greenBA text-sm lg:text-sm mt-2 lg:mt-2">{`پایه ${
grades[book.gradeId]
}`}</p>
<Progress percent={60} />
<Progress percent={60} direction="float-right" />
</Link>
</li>
);
@ -34,12 +36,12 @@ function MyBooks({ books, getList, grades, isMobile }) {
return (
<div className="px-4 mb-5 lg:mb-0" style={{maxWidth: '100%'}}>
<div className="w-full flex flex-col rounded-md pt-4 lg:py-5 px-2 lg:px-4 bg-blueC0 bg-opacity-5 border border-green-200 border-solid dark:bg-gray2077 overflow-hidden">
<strong className="text-green7B dark:text-white font-bold text-sm lg:text-base">
<div className="w-full flex flex-col rounded-md pt-4 lg:py-5 px-2 lg:px-4 bg-blueC0 bg-opacity-5 border border-green-200 border-solid dark:bg-gray2077 dark:border-opacity-40 overflow-hidden">
<strong className="text-green7B dark:text-white font-bold text-base lg:text-base mb-2">
کتابهای من
</strong>
{isMobile ? (
<ul className="list-none w-full overflow-x-scroll pt-2 flex flex-row lg:pt-5 lg:flex-wrap lg:overflow-y-scroll gap-3 lg:gap-10">
<ul className="list-none w-full overflow-x-scroll pt-2 flex flex-row lg:pt-5 lg:flex-wrap lg:overflow-y-scroll gap-3 lg:gap-10 no-scrollbar">
{books?.slice(0, 5)?.map((book, index) => (
<Book book={book} key={index} />
))}

@ -3,22 +3,18 @@ import { Link } from "react-router-dom";
import { connect } from "react-redux";
import { book } from "../../../../../redux/actions";
import Header from '../../../../../components/Header'
// assets
import arrowBlueIcon from "../../../../../assets/icons/arrow-right-blue.svg";
import arrowWhiteIcon from "../../../../../assets/icons/arrow-left-white.svg";
function Shop({ list, getList, grades, isDark }) {
useEffect(() => {
getList();
}, []);
function Shop({ list, grades }) {
return (
<div className="w-full pr-4">
<div className="w-full flex flex-col rounded-md py-4 overflow-hidden">
<Header title="فروشگاه" link="/products" />
<ul
className="list-none w-full overflow-x-scroll mt-3 flex flex-col flex-wrap"
className="list-none w-full overflow-x-scroll mt-3 flex flex-col flex-wrap no-scrollbar"
style={{
height: 320,
height: 'calc(100vh / 4)',
}}
>
{list.map((book, index) => (
@ -45,18 +41,20 @@ const Book = ({ book, index }) => {
alt=""
className="rounded-sm"
style={{
width: 200,
height: 303,
width: 'calc(100vh / 4 * 3 / 4.3 )',
height: 'calc(100vh / 4)',
maxWidth: 200,
maxHeight: 275
}}
/>
) : (
<img
src={`https://dnvn.ir/api/v1/file/${book.fileIds}`}
alt=""
className="rounded-sm"
className="rounded-sm mb-0"
style={{
width: 100,
height: 148,
width: 'calc(100vh / 4 / 2 * 3 / 4.3)',
height: 'calc(100vh / 4 / 2 - 4px)',
marginBottom: index % 2 !== 0 ? "8px" : "0px",
}}
/>
@ -67,7 +65,6 @@ const Book = ({ book, index }) => {
};
const mapStateToProps = (state) => ({
list: state.book.list,
isDark: state.publicApi.isDark,
});

@ -3,7 +3,9 @@ import { Link } from "react-router-dom";
import { ScrollingCarousel } from "@trendyol-js/react-carousel";
import { connect } from "react-redux";
import Progress from "../../../../../components/Progress";
import arrowBlueIcon from "../../../../../assets/icons/arrow-right-blue.svg";
//assets
import arrowGreenIcon from "../../../../../assets/icons/dropdown-blue.svg";
import arrowWhiteIcon from "../../../../../assets/icons/arrow-left-white.svg";
function Videos({ videos, grades, isDark, isMobile }) {
@ -12,7 +14,7 @@ function Videos({ videos, grades, isDark, isMobile }) {
<li className="flex flex-col lg:ml-6 lg:p-2 lg:border lg:border-solid lg:border-green-200 lg:rounded-md">
<Link to={"/products/" + video.id}>
<img
src={`https://dnvn.ir/api/v1/file/${video.posterId}`}
src={`https://dnvn.ir/api/v1/file/${video?.fileIds}`}
alt=""
className="rounded-sm"
style={{
@ -22,13 +24,13 @@ function Videos({ videos, grades, isDark, isMobile }) {
minWidth: isMobile ? "calc(100vw / 2)" : "",
}}
/>
<h2 className="mt-2 text-sm font-normal text-blue5F dark:text-white lg:mt-4 lg:text-tiny lg:mb-5">
{"دوره ویدئویی" + " " + video.name}
<h2 className="mt-3 mb-4 text-sm font-semibold text-blue5F dark:text-white lg:mt-4 lg:text-tiny lg:mb-5">
{"دوره ویدئویی" + " " + video?.product[2]?.name}
</h2>
{/* <p className="font-medium text-blueC0 dark:text-greenBA text-xs mt-1 lg:mt-2 lg:text-sm">{`پایه ${
grades[video.gradeId]
}`}</p> */}
<Progress percent={60} />
<Progress percent={60} direction="float-right" />
</Link>
</li>
);
@ -37,18 +39,26 @@ function Videos({ videos, grades, isDark, isMobile }) {
<div className="w-full px-4 lg:py-4">
<div className="w-full flex flex-col py-4 lg:px-3 overflow-hidden lg:border lg:border-solid lg:border-gray-200 rounded-md lg:bg-blueC0 lg:bg-opacity-5">
<header className="w-full flex flex-row justify-between items-center">
<strong className="text-green7B dark:text-white font-bold text-sm lg:text-base mt-2">
<strong className="text-green7B dark:text-white font-bold text-base lg:text-base mt-2">
دورههای ویدئویی شما
</strong>
{isDark ? (
<img
src={arrowWhiteIcon}
alt=""
className={`transform lg:hidden w-7`}
/>
) : (
<img
src={isDark ? arrowWhiteIcon : arrowBlueIcon}
src={arrowGreenIcon}
alt=""
className={`transform lg:hidden ${isDark ? "w-7" : "rotate-180"}`}
className={`transform lg:hidden rotate-90`}
/>
)}
</header>
{isMobile ? (
<ul className="list-none w-full overflow-x-scroll pt-3 gap-3 lg:gap-5 flex flex-row lg:pt-5 lg:flex-wrap lg:overflow-y-scroll">
{videos.slice(0, 5)?.map((video, index) => (
<ul className="list-none w-full overflow-x-scroll pt-3 gap-3 lg:gap-5 flex flex-row lg:pt-5 lg:flex-wrap lg:overflow-y-scroll no-scrollbar">
{videos?.slice(0, 5)?.map((video, index) => (
<Video video={video} key={index} />
))}
</ul>

@ -1,18 +1,40 @@
import React from 'react';
import MyBooks from './MyBooks';
import Shop from './Shop';
import Videos from './Videos';
import Blogs from './Blogs';
import React, { useEffect } from "react";
import { connect } from "react-redux";
import { book, blog } from "../../../../redux/actions";
import MyBooks from "./MyBooks";
import Shop from "./Shop";
import Videos from "./Videos";
import Blogs from "./Blogs";
function Private() {
function Private({ getList, products, blogs, getBlogList, grades }) {
useEffect(() => {
if (products.length === 0) {
getList({ vod: true });
}
if(blogs.length === 0){
getBlogList();
}
// console.log(getBlogList());
}, []);
return (
<div className="w-full flex-1 pb-6">
<MyBooks />
<Shop />
<Videos />
<Blogs />
<MyBooks books={products} grades={grades} />
<Shop list={products} grades={grades} />
<Videos videos={products} grades={grades} />
<Blogs list={blogs} />
</div>
)
);
}
export default Private;
const mapStateToProps = (state) => ({
products: state.book.list,
blogs: state.blog.list,
grades: state.publicApi.grades
});
const mapDispatchToProps = {
getList: book.list,
getBlogList: blog.list
};
export default connect(mapStateToProps, mapDispatchToProps)(Private);

@ -7,10 +7,10 @@ function GradiantText() {
className="w-full flex flex-col items-center py-10"
style={{ background: `url(${phraseImage})` }}
>
<h2 class="text-3xl font-extrabold text-transparent bg-clip-text bg-gradient-to-br from-blue-900 to-blue-300">
<h2 className="text-3xl font-extrabold text-transparent bg-clip-text bg-gradient-to-br from-blue-900 to-blue-300">
یادگیری بدون وقفه
</h2>
<h2 class="text-3xl font-extrabold text-transparent bg-clip-text bg-gradient-to-br from-blue-300 to-blue-900">
<h2 className="text-3xl font-extrabold text-transparent bg-clip-text bg-gradient-to-br from-blue-300 to-blue-900">
لذت یادگیری هوشمند
</h2>
</div>

@ -1,14 +1,14 @@
import React, { useState, useEffect, useCallback } from "react";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import Search from "../../components/Search";
import Select from "../../components/Select";
import Sidebar from "./layouts/Sidebar";
import Main from "./layouts/Main";
import Sidebar from "./layouts/Desktop/Sidebar";
import Main from "./layouts/Desktop/Main";
import Header from "./layouts/Mobile/Header";
import MobileMain from "./layouts/Mobile/Main";
import { book, publicApi } from "../../redux/actions";
//assets
import searchLight from "../../assets/icons/search-light.svg";
export const Products = ({
isDark,
@ -16,32 +16,15 @@ export const Products = ({
books,
getList,
grades,
gradeFilter,
selectedGrade,
gradeFilterBooks,
setHeaderOptions,
headerOptions,
desktopContentTransform,
}) => {
const [filter, setFilter] = useState({
search: "",
grade: "",
productsType: "کتاب",
});
const onChange = (name, value) => {
setFilter({ ...filter, [name]: value });
};
useEffect(() => {
getList({ vod: true });
setHeaderOptions(headerOptions);
}, []);
useEffect(() => {
gradeFilter(filter.grade);
}, [filter]);
const Product = ({ productsType, product, index }) => {
return (
<>
@ -97,73 +80,21 @@ export const Products = ({
{/* Portrait */}
<div
className={`w-full flex flex-col bg-transparent relative ${
desktopContentTransform ? "top-24 z-10" : ""
desktopContentTransform ? "lg:top-24 z-10" : ""
}`}
>
{isMobile ? (
<>
<header className="w-full px-4">
<Search
backgroundColor="bg-grayF9 dark:bg-gray2077"
borderColor="border-grayDB dark:border-gray45"
textColor="text-blueC0 dark:text-white"
icon={searchLight}
/>
<div className="w-full flex flex-row justify-between mt-3">
<Select
margin="ml-1"
fill="fill-blueC0 dark:fill-white"
borderColor="border-grayDB dark:border-gray45"
backgroundColor="bg-grayF9 dark:bg-gray2077"
onChange={onChange}
name="productsType"
options={["کتاب", "ویديو", "اشتراک"]}
// hoverFill="fill-greenBA"
/>
<Select
margin="mr-1"
fill="fill-blueC0 dark:fill-white"
borderColor="border-grayDB dark:border-gray45"
backgroundColor="bg-grayF9 dark:bg-gray2077"
onChange={onChange}
name="grade"
options={Object.values(grades)}
// hoverFill="fill-grayBA"
/>
</div>
</header>
<div className="w-full flex flex-row flex-wrap mt-3">
{selectedGrade
? gradeFilterBooks?.map((product, index) => (
<Product
key={index}
productsType={filter.productsType}
product={product}
index={Number(index)}
grades={grades}
/>
))
: books?.map((product, index) => (
<Product
key={index}
productsType={filter.productsType}
product={product}
index={Number(index)}
/>
))}
<div className="h-screen w-full overflow-hidden">
<Header />
<MobileMain books={books} grades={grades} />
</div>
</>
) : (
<div
className={`w-full flex flex-row gap-10 px-5 overflow-y-hidden mt-3 justify-center lg:pt-24 lg:mt-0`}
>
<div className="w-11/12 flex flex-row gap-5 justify-end">
<Sidebar onChange={onChange} />
<Main
filter={filter}
books={books}
grades={grades}
/>
<Sidebar />
<Main books={books} grades={grades} />
</div>
</div>
)}
@ -176,10 +107,8 @@ const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark,
isMobile: state.publicApi.isMobile,
books: state.book.list,
listVOD: state.product.listVOD,
grades: state.publicApi.grades,
gradeFilterBooks: state.book.gradeFilterBooks,
selectedGrade: state.book.selectedGrade,
filterOptions: state.book.filterOptions,
desktopContentTransform: state.publicApi.desktopContentTransform,
});
@ -187,6 +116,7 @@ const mapDispatchToProps = {
getList: book.list,
gradeFilter: book.gradeFilter,
setHeaderOptions: publicApi.setHeaderOptions,
setFilterOptions: book.setFilterOptions,
};
export default connect(mapStateToProps, mapDispatchToProps)(Products);

@ -3,10 +3,10 @@ import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { ScrollingCarousel } from "@trendyol-js/react-carousel";
import Product from "../../../components/Product";
import VodProduct from "../../../components/VodProduct";
import Loading from "../../../components/Loading";
import { book, publicApi } from "../../../redux/actions";
import Product from "../../../../components/Product";
import VodProduct from "../../../../components/VodProduct";
import Loading from "../../../../components/Loading";
import { book, publicApi } from "../../../../redux/actions";
export const Main = ({ books, grades, sortMethods, filterOptions }) => {
const [filterLoading, setFilterLoading] = useState(false);
@ -201,7 +201,6 @@ const mapStateToProps = (state) => ({
isMobile: state.publicApi.isMobile,
sortMethods: state.book.sortMethods,
filterOptions: state.book.filterOptions,
filterResult: state.book.filterResult,
});
const mapDispatchToProps = {

@ -1,14 +1,13 @@
import React, { useState, useMemo } from "react";
import { connect } from "react-redux";
import { book } from "../../../redux/actions";
import Checkbox from "../../../components/Checkbox";
import Switch from "../../../components/Switch";
import { book } from "../../../../redux/actions";
import Checkbox from "../../../../components/Checkbox";
import Switch from "../../../../components/Switch";
//assets
import dropdownIcon from "../../../assets/icons/dropdown-blue.svg";
import dropdownIcon from "../../../../assets/icons/dropdown-blue.svg";
export const Sidebar = ({
onChange,
levels,
subjects,
productTypes,

@ -0,0 +1,69 @@
import React from "react";
import { connect } from "react-redux";
import { book } from "../../../../redux/actions";
import _ from "lodash";
import Search from "../../../../components/Search";
import Select from "../../../../components/Select";
import searchLight from "../../../../assets/icons/search-light.svg";
export const Header = ({
setFilterOptions,
filterOptions,
levels,
productTypes,
isDark
}) => {
return (
<header className="w-full px-4 fixed top-0 left-0 pb-5 z-10" style={{backgroundColor: isDark ? '#061B30' : 'white'}}>
<Search
backgroundColor="bg-gray-100 dark:bg-blueC0 dark:bg-opacity-70"
borderColor="border-grayDB dark:border-gray45"
textColor="text-black dark:text-white"
icon={searchLight}
onChange={_.debounce(
(val) => setFilterOptions({ ...filterOptions, search: val }),
700
)}
/>
<div className="w-full flex flex-row justify-between mt-3">
<Select
margin="ml-1"
fill="fill-green-700 dark:fill-white"
borderColor="border-grayDB dark:border-gray45"
backgroundColor="bg-gray-100"
onChange={(name, value) =>
setFilterOptions({ ...filterOptions, [name]: value })
}
name="productType"
options={productTypes}
/>
<Select
margin="mr-1"
fill="fill-green-700 dark:fill-white"
borderColor="border-grayDB dark:border-gray45"
backgroundColor="bg-gray-100"
onChange={(name, value) =>
setFilterOptions({ ...filterOptions, [name]: value })
}
name="grade"
options={Object.values(levels)}
/>
</div>
</header>
);
};
const mapStateToProps = (state) => ({
levels: state.publicApi.grades,
productTypes: state.book.productTypes,
filterOptions: state.book.filterOptions,
isDark: state.publicApi.isDark
});
const mapDispatchToProps = {
setFilterOptions: book.setFilterOptions,
};
export default connect(mapStateToProps, mapDispatchToProps)(Header);

@ -0,0 +1,164 @@
import React, { useEffect, useState } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import Loading from "../../../../components/Loading";
//assets
import whitePlayIcon from "../../../../components/VodProduct/white-play-button-icon.svg";
export const Main = ({ books, filterOptions, grades }) => {
const [filterLoading, setFilterLoading] = useState(false);
useEffect(() => {
setFilterLoading(() => true);
setTimeout(() => {
setFilterLoading(() => false);
}, 500);
}, [filterOptions]);
const Items = (type) => {
const { grade, subject, available, sort, productType, search } =
filterOptions;
let byGradeFilter;
let bySubjectFilter;
let byAvailableFilter;
let bySearchFilter;
if (grade) {
byGradeFilter = books?.filter((book) => grades[book?.gradeId] === grade);
} else {
byGradeFilter = books;
}
if (subject) {
bySubjectFilter = byGradeFilter?.filter(
(book) =>
book?.product[type]?.name?.indexOf(subject) !== -1 ||
book?.name.indexOf(subject) !== -1
);
} else {
bySubjectFilter = byGradeFilter;
}
if (available) {
byAvailableFilter = bySubjectFilter?.filter(
(book) => book.product[type].price
);
} else {
byAvailableFilter = bySubjectFilter;
}
if (search) {
bySearchFilter = byAvailableFilter?.filter(
(book) =>
book?.product[type]?.name?.indexOf(search) !== -1 ||
book?.name.indexOf(search) !== -1
);
} else {
bySearchFilter = byAvailableFilter;
}
return filterOptions.productType === "دوره ویدئویی"
? bySearchFilter?.map((product, index) => (
<Link
to={"/products" + product?.id}
className={`w-full flex flex-col border-grayDB dark:border-gray45 p-3 border-solid mb-5 shadow-md mx-4`}
key={index}
>
<div
className="relative w-full mb-2"
style={{ height: "calc(100vh / 5)" }}
>
<img
src={"https://dnvn.ir/api/v1/file/" + product?.fileIds}
className="w-full rounded-md h-full"
/>
<div
className={`absolute left-1/2 top-1/2 rounded-full p-4 group-hover:scale-125 transform -translate-x-1/2 -translate-y-1/2 duration-300 bg-playButtonIcon bg-black bg-opacity-20 backdrop-filter backdrop-blur-md`}
>
<img src={whitePlayIcon} alt="" className="w-5 h-5" />
</div>
</div>
<strong className="text-blue5F dark:text-white text-lg lg:text-tiny font-bold mb-2">
{product?.name}
</strong>
<span className="text-tiny lg:text-sm text-green7B dark:text-white font-light mb-4">
{"پایه" + " " + grades[product?.gradeId]}
</span>
<div className="w-full flex flex-row justify-center font-bold lg:font-medium text-lg lg:text-tiny text-blue5F dark:text-white">
{product?.product[2]?.price + " " + "تومان"}
</div>
</Link>
))
: bySearchFilter?.map((product, index) => (
<>
{(productType ? productType === "کتاب دیجیتال" : true) && (
<Link
key={index}
to={"/products/" + product?.id}
className={`w-1/2 flex flex-col border-t border-grayDB dark:border-gray45 p-3 border-solid ${
index % 2 === 0 ? "border-l" : ""
}`}
>
<img
src={"https://dnvn.ir/api/v1/file/" + product?.fileIds}
className="w-full rounded-md mb-2"
/>
<strong className="text-blue5F dark:text-white text-base lg:text-sm font-medium mb-2">
{"کتاب دیجیتال" + " " + product?.name}
</strong>
<span className="text-tiny lg:text-xs text-green7B dark:text-white font-light mb-4">
{"پایه" + " " + grades[product?.gradeId]}
</span>
<div className="w-full flex flex-row justify-center font-bold lg:font-medium text-lg lg:text-sm text-blue5F dark:text-white">
{product?.product[0]?.price + " " + "تومان"}
</div>
</Link>
)}
{(productType ? productType === "کتاب فیزیکی" : true) && (
<Link
key={index}
to={"/products/" + product?.id}
className={`w-1/2 flex flex-col border-t border-grayDB dark:border-gray45 p-3 border-solid ${
index % 2 === 0 ? "border-l" : ""
}`}
>
<img
src={"https://dnvn.ir/api/v1/file/" + product?.fileIds}
className="w-full rounded-md mb-2"
/>
<strong className="text-blue5F dark:text-white text-lg lg:text-sm font-medium mb-2">
{"کتاب فیزیکی" + " " + product?.name}
</strong>
<span className="text-tiny lg:text-xs text-green7B dark:text-white font-light mb-4">
{"پایه" + " " + grades[product?.gradeId]}
</span>
<div className="w-full flex flex-row justify-center font-bold lg:font-medium text-lg lg:text-sm text-blue5F dark:text-white">
{product?.product[1]?.price + " " + "تومان"}
</div>
</Link>
)}
</>
));
};
return (
<div className="h-full overflow-y-scroll w-full flex flex-wrap py-32">
{filterOptions?.productType === "دوره ویدئویی" && Items(2)}
{filterOptions?.productType === "کتاب دیجیتال" && Items(0)}
{filterOptions?.productType === "کتاب فیزیکی" && Items(1)}
{!filterOptions?.productType && Items(0)}
{filterLoading && (
<div className="w-full h-screen flex justify-center items-center bg-white bg-opacity-20 backdrop-filter backdrop-blur-xl fixed left-0 top-0">
<Loading size={4} color="bg-green-400" />
</div>
)}
</div>
);
};
const mapStateToProps = (state) => ({
filterOptions: state.book.filterOptions,
});
const mapDispatchToProps = {};
export default connect(mapStateToProps, mapDispatchToProps)(Main);
Loading…
Cancel
Save