temp
Pedram Keshavarzi 3 years ago
commit 2ac53fc232
  1. 10
      public/index.html
  2. 8
      public/logo.svg
  3. 4
      src/App.scss
  4. 6
      src/assets/icons/dropdown-blue.svg
  5. 2
      src/components/Checkbox/index.js
  6. 198
      src/components/CourseChapter/index.js
  7. 8
      src/components/Footer/Bazar.svg
  8. 8
      src/components/Footer/IOS.svg
  9. 181
      src/components/Footer/index.js
  10. 5
      src/components/Input/index.js
  11. 6
      src/components/JolPlayer/index.js
  12. 112
      src/components/Navbar/SearchResult/index.js
  13. 216
      src/components/Navbar/index.js
  14. 28
      src/components/OverLayer/index.js
  15. 171
      src/components/Product/index.js
  16. 104
      src/components/ProductImage/index.js
  17. 40
      src/components/ProductStatusCard/index.js
  18. 32
      src/components/ProductSuggestion/index.js
  19. 4
      src/components/ProductTab/index.js
  20. 84
      src/components/SalesContainer/index.js
  21. 23
      src/components/Search/index.js
  22. 6
      src/components/Select/index.js
  23. 191
      src/components/VerticalExpandableProductFilter/index.js
  24. 102
      src/components/VodProduct/index.js
  25. 1
      src/redux/actions/index.js
  26. 2
      src/redux/actions/public.js
  27. 4
      src/redux/actions/user.js
  28. 33
      src/redux/actions/userAddress.js
  29. 23
      src/redux/reducers/content.js
  30. 2
      src/redux/reducers/index.js
  31. 25
      src/redux/reducers/public.js
  32. 2
      src/redux/reducers/user.js
  33. 35
      src/redux/reducers/userAddress.js
  34. 2
      src/router.js
  35. 4
      src/utils/comments.js
  36. 0
      src/utils/filter.js
  37. 30
      src/utils/onInput.js
  38. 2
      src/utils/scroll.js
  39. 12
      src/utils/separate.js
  40. 5
      src/views/404/index.js
  41. 2
      src/views/AR/index.js
  42. 4
      src/views/Activation/index.js
  43. 140
      src/views/Address/index.js
  44. 17
      src/views/Auth/Profile/index.js
  45. 26
      src/views/Auth/SignUp/index.js
  46. 124
      src/views/BugsAndProblems/data.js
  47. 66
      src/views/BugsAndProblems/index.js
  48. 2
      src/views/Contact/index.js
  49. 4
      src/views/Dashboard/index.js
  50. 46
      src/views/Dashboard/layouts/Main/UserItems/ProductSuggestion/index.js
  51. 30
      src/views/Dashboard/layouts/Main/UserItems/index.js
  52. 18
      src/views/Dashboard/layouts/Main/index.js
  53. 4
      src/views/DeliveryForm/Address/index.js
  54. 12
      src/views/DeliveryForm/index.js
  55. 4
      src/views/Faq/index.js
  56. 153
      src/views/Home/Desktop/Part2/index.js
  57. 206
      src/views/Home/Desktop/Part4/index.js
  58. 0
      src/views/Home/Desktop/SalesContainer/index.css
  59. 78
      src/views/Home/Desktop/SalesContainer/index.js
  60. 150
      src/views/Home/Desktop/index.js
  61. 57
      src/views/Home/Portrait/Private/MyBooks/index.js
  62. 54
      src/views/Home/Portrait/Private/Videos/index.js
  63. 2
      src/views/Orders/components/Order.js
  64. 2
      src/views/Orders/index.js
  65. 49
      src/views/Product/Desktop/ProductOverAll/index.js
  66. 281
      src/views/Product/index.js
  67. 23
      src/views/Products/index.js
  68. 230
      src/views/Products/layouts/Main.js
  69. 84
      src/views/Products/layouts/Sidebar.js
  70. 4
      src/views/QR/Content/index.js
  71. 2
      src/views/QR/Scan/index.js
  72. 13
      src/views/ShoppingCart/Product/index.js
  73. 205
      src/views/ShoppingCart/index.js
  74. 40
      src/views/Video/components/Desktop/Videos.js
  75. 74
      src/views/Video/components/Season.js
  76. 68
      src/views/Video/index.js
  77. 38
      src/views/VideoDisplay/Desktop/index.js
  78. 61
      src/views/VideoDisplay/index.js
  79. 21
      src/views/Videos/components/MostViewedVideo.js
  80. 46
      src/views/Videos/components/NewestVideo.js
  81. 15
      src/views/Videos/index.js

@ -2,19 +2,19 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="icon" href="%PUBLIC_URL%/logo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
content="فروشگاه کتاب کمک آموزشی دانوین"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.svg" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!-- <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> -->
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>دانوین</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

@ -18,6 +18,10 @@
direction: rtl;
}
.scrolling-carousel button{
display: none;
}
@font-face {
font-family: Black;
src: url("./assets/font/IranSansX/Farsi/Black.ttf");

@ -0,0 +1,6 @@
<svg id="vuesax_linear_arrow-down" data-name="vuesax/linear/arrow-down" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="arrow-down">
<path id="Vector" d="M15.84,0,9.32,6.52a1.986,1.986,0,0,1-2.8,0L0,0" transform="translate(4.08 8.95)" fill="none" stroke="#196ec0" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
<path id="Vector-2" data-name="Vector" d="M0,0H24V24H0Z" transform="translate(24 24) rotate(180)" fill="none" opacity="0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 516 B

@ -2,7 +2,7 @@ import React from "react";
import './index.css';
export default function Checkbox(props) {
console.log(props)
// console.log(props)
return (
<div>
<svg className="checkbox-symbol">

@ -1,112 +1,160 @@
import React, { useState } from "react";
import './index.css';
const CourseChapter = ({ chapters }) => {
const [selectedLesson, setSelectedLesson] = useState(null);
import { connect } from "react-redux";
import { publicApi } from "../../redux/actions";
import { toast } from "react-toastify";
import "./index.css";
const CourseChapter = ({
playList,
seasons,
book,
grades,
selectedVideo,
userId,
setVideoActive,
}) => {
const duration = (value) => {
const minute = value % 60;
const hour = Math.round(value / 60);
return (
(hour > 0
? (hour.toString().length === 1 ? "0" + hour.toString() : hour) + ""
: "") +
":" +
(minute.toString().length === 1 ? "0" + minute.toString() : minute)
);
};
return (
<section style={{ width: "40%" }} className="bg-white mx-auto my-20 p-4">
<div
className="rounded py-5 px-4 relative"
style={{ backgroundColor: "#196EC033", height: '530px'}}
>
{/* top */}
<div className="flex flex-row items-center justify-between">
<div>
<h2 className="text-blue-800 text-base">سرفصل دوره</h2>
</div>
<div className="flex flex-row-reverse items-center divide-x transform translate-x-2">
<span className="text-blue-800 text-sm px-2">علوم تجربی</span>
<span className="text-blue-800 text-sm px-2">پایه ششم</span>
</div>
<section
className="bg-blueFF1 py-5 pr-5 overflow-hidden flex flex-col"
style={{
width: "calc(100% / 12 * 3.5)",
height: "calc(100vh - 300px)",
}}
>
<div className="flex flex-row w-full items-center justify-between">
<div>
<h2 className="text-blue-800 text-base font-semibold">سرفصل دوره</h2>
</div>
{/* divider */}
<div className="border-b border-blue-300 border-solid bg-opacity-10 my-5"></div>
{/* course title */}
<div className="overflow-y-scroll w-full hasScrollbar" style={{
height: '430px'
}}>
{chapters.map((chapter, index) => (
<div className="flex flex-col" key={index}>
<div className="bg-blue-600 rounded-sm p-4 flex flex-row items-center justify-between">
<p className="text-sm text-white">{chapter.title}</p>
<span className="text-sm text-white">{chapter.duration}</span>
</div>
{/* course lessons */}
{chapter.lessons.map((lesson, i) => (
<div className="flex flex-row-reverse items-center divide-x divide-solid transform translate-x-2">
<span className="text-blue-800 text-sm px-2">{book?.name}</span>
<span className="text-blue-800 text-sm px-2">
{"پایه" + " " + grades[book?.gradeId]}
</span>
</div>
</div>
<span className="w-full h-px bg-blue-200 my-4"></span>
<div className="overflow-y-scroll w-full hasScrollbar flex-1 flex flex-col">
<div className="bg-blue-600 rounded-sm p-4 flex flex-row items-center justify-between mb-2">
{/* <p className="text-sm text-white">
{(seasons.length > 0 && playList.length > 0) &&
seasons?.filter((item) => item?.id === playList[0]?.categoryId)[0]
?.name}
</p> */}
{/* <span className="text-sm text-white">{video?.duration}</span> */}
</div>
{playList?.map((video, index) => (
<div className="flex flex-col pl-4" key={index}>
<div
className="flex flex-row items-center justify-around"
key={index}
>
{/* right div dot dot */}
<div
className="flex flex-row items-center justify-around"
key={i}
className="flex items-center justify-center relative flex-col h-full"
style={{ width: "10%" }}
>
{/* right div dot dot */}
<span
className={`w-px flex-1 transform -translate-x-0 ${
Number(index) !== 0 ? "border-dashed" : ""
} border-r border-blueC0`}
></span>
<span className={`w-4 h-4 rounded-full bg-blueC0`}></span>
<span
className={`w-px flex-1 transform -translate-x-0 ${
Number(index) !== playList?.length - 1
? "border-dashed"
: ""
} border-r border-blueC0`}
></span>
</div>
{/* left div content */}
<div className="py-1.5" style={{ width: "90%" }}>
<div
className="flex items-center relative flex-col "
style={{ width: "10%", transform: "translateY(30px)" }}
>
<div
className={`flex justify-center items-center w-4 h-4 rounded-full
${selectedLesson === lesson ? "bg-red-600" : "bg-blue-600"},
${lesson.passed ? "bg-blue-600" : "bg-gray-400"}
className={`w-full bg-white flex flex-col transition duration-400 hover:scale-95 shadow-md transform rounded-md
${
selectedVideo?.id === video?.id
? "bg-blue-600 text-white-700"
: "text-blue-500"
}
`}
></div>
<span
className="w-1"
style={{
borderRight: "2px dashed #86A0B9",
transform: "translateX(-1px)",
height: "65px",
}}
></span>
</div>
{/* left div content */}
<div
className={`mt-2 bg-white border border-blue-300 flex flex-col border border-solid cursor-pointer transition duration-200 ease-in-out group hover:bg-blue-600
${selectedLesson === lesson ? "bg-blue-600 text-white-700" : "text-blue-500"}`}
style={{ width: "80%" }}
onClick={() => setSelectedLesson(lesson)}
onClick={() =>
video?.isFreeVod || +userId === 140
? setVideoActive(video)
: toast.error("ابتدا محصول رو خریداری کن!")
}
disabled={true}
>
{/* top */}
<div className="flex flex-row items-center justify-between p-4 border-0 border-b border-solid border-blue-500">
<div className="flex flex-row items-center justify-between p-3 border-0 border-b border-solid border-blue-300">
<p
className={`text-sm group-hover:text-white
${selectedLesson === lesson ? "text-white" : ""}`}
className={`text-tiny
${selectedVideo?.id === video?.id ? "text-white" : ""}`}
>
{lesson.title}
{video?.name}
</p>
<span
className={`text-xs group-hover:text-white border-r border-solid border-blue-200 pr-1
${selectedLesson === lesson ? "text-white" : "text-blue-500"}`}
className={`text-sm border-r border-solid border-blue-200 pr-1
${
selectedVideo?.id === video?.id
? "text-white"
: "text-blue-500"
}`}
>
{lesson.duration}
{duration(video?.duration)}
</span>
</div>
{/* divider */}
<div
className={`border-t border-blue-600 group-hover:border-white ${
selectedLesson === lesson ? "border-red-600" : ""
className={`border-t border-blue-600 ${
selectedVideo?.id === video?.id ? "border-red-600" : ""
}`}
></div>
{/* bottom */}
<span
className={`text-xs text-center group-hover:text-white p-2
${selectedLesson === lesson ? "text-white" : "text-blue-500"}`}
className={`text-tiny text-center p-3
${
selectedVideo?.id === video?.id
? "text-white"
: "text-blue-500"
}`}
>
{lesson.play}
پخش
</span>
</div>
</div>
))}
</div>
</div>
))}
</div>
{/* blue left border */}
{/* <div className="absolute top-1/2 left-0.5 transform -translate-x-1/2 -translate-y-1/2 bg-blue-600 w-1 h-20 rounded"></div> */}
</div>
</section>
);
};
export default CourseChapter;
const mapStateToProps = (state) => ({
selectedVideo: state.publicApi.selectedVideo,
seasons: state.publicApi.bookInfo?.categories,
book: state.publicApi.bookInfo,
grades: state.publicApi.grades,
// vods: state.publicApi.bookSection?.vods,
userId: state?.user?.status?.id,
});
const mapDispatchToProps = {
setVideoActive: publicApi.setVideoActive,
};
export default connect(mapStateToProps)(CourseChapter);
CourseChapter.defaultProps = {
chapters: [

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.6 KiB

@ -1,59 +1,70 @@
import React from "react";
import { Link } from "react-router-dom";
import _ from "lodash";
// import enamadlogo from './enamad-pic.svg';
import callIcon from '../../assets/icons/vuesax-linear-call-calling.svg';
import samandehi from './samandehi-pic.svg';
import callIcon from "../../assets/icons/vuesax-linear-call-calling.svg";
import samandehi from "./samandehi-pic.svg";
import iosIcon from "./IOS.svg";
import bazarIcon from "./Bazar.svg";
import lightBlueLine from "./light-blue-line.svg";
const FooterDesign1 = ({ color, bg, links, hasHeader }) => {
const FooterDesign1 = ({ color, bg, items, hasHeader }) => {
const enamad =
'<a referrerpolicy="origin" target="_blank" href="https://trustseal.enamad.ir/?id=224965&amp;Code=x8oNSO7tTnqAniyPpPyN"><img referrerpolicy="origin" src="https://Trustseal.eNamad.ir/logo.aspx?id=224965&amp;Code=x8oNSO7tTnqAniyPpPyN" alt="" style="cursor:pointer" id="x8oNSO7tTnqAniyPpPyN"></a>';
return (
<>
{hasHeader ?
<div className=" bg-gray-100 flex items-center justify-center py-6 text-blue52">
{hasHeader ? (
<div className=" bg-gray-100 w-full">
<div className="w-11/12 mx-auto flex items-center justify-between py-6 text-blue52">
<div className="flex items-center">
<div className="flex items-center ml-8 ">
<img src={callIcon} className="p-2" />
<div>
<h1 className="text-2xl mb-4 font-bold">
<span className=" text-blueC0 font-black">7</span> روز هفته{" "}
<span className="text-blueC0 font-black">24</span> ساعته
</h1>
<p className="text-lg font-light text-blue5F">
منتظر شنیدن صدای گرمتان هستیم
</p>
</div>
</div>
<div className="flex items-center ml-8 ">
<img src={callIcon} className="p-2" />
<div>
<h1 className="text-2xl text-bold mb-2 font-black">
<span className=" text-blueC0">7</span> روز هفته <span className="font-black text-blueC0">24</span> ساعته
</h1>
<p className="text-lg font-light text-blue-700">منتظر شنیدن صدای گرمتان هستیم</p>
<div className="mr-8 text-lg font-black transform translate-y-0.5">
<h1 className="text-left mb-5">654412 021</h1>
<h1>Info[at]danovin.ir</h1>
</div>
</div>
<div className="flex items-center">
<img src={iosIcon} alt="" className="cursor-pointer" />
<a href="http://danovin.ir/app.apk" download>
<img src={bazarIcon} alt="" className="mr-6" />
</a>
</div>
</div>
<div className="mr-8 text-lg font-black">
<h1 className="text-left mb-2">654412 021</h1>
<h1>Info[at]danovin.ir</h1>
</div>
</div>
: null}
) : null}
<footer
className={`flex flex-col bg-gray-200 py-16 md:flex-row justify-around items-start md:items-start relative shadow-md ${bg}`}
>
<div className="w-11/12 flex justify-between">
<div className="flex items-start">
<>
{
links.map((section, index) => <ul className={index != 0 ? 'mr-16' : ''} key={index}>
{
section.map((link, index) => <li
className={`font-light text-md leading-7 hover:font-bold ${color}`}
key={index}
>
<a href="" className={`${index == 0 ? ' text-lg font-bold' : ''}`}>{link}</a>
</li>)
}
</ul>)
}
</>
<div className="flex flex-row gap-10">
{items.map((item, index) => (
<div className="flex flex-col" key={index}>
<strong className="text-xl text-gray70">{item.name}</strong>
<ul className="flex flex-col mt-0">
{item.links.map((link, index) => (
<li className="mt-6">
<Link className="text-gray70 text-base" to={link.link} key={index}>
{link.name}
</Link>
</li>
))}
</ul>
</div>
))}
</div>
<div className="flex items-center justify-between mt-10 md:mt-0">
<div
@ -61,10 +72,12 @@ const FooterDesign1 = ({ color, bg, links, hasHeader }) => {
__html: enamad,
}}
className="w-28 p-2 rounded-md bg-gray-300 mx-6"
>
</div>
<img src={samandehi} alt="" className="w-28 p-2 rounded-md bg-gray-300 mr-6" />
></div>
<img
src={samandehi}
alt=""
className="w-28 p-2 rounded-md bg-gray-300 mr-6"
/>
</div>
</div>
{/* line
@ -73,7 +86,6 @@ const FooterDesign1 = ({ color, bg, links, hasHeader }) => {
alt=""
className="hidden sm:block absolute bottom-5 left-20"
/> */}
</footer>
</>
);
@ -82,26 +94,71 @@ const FooterDesign1 = ({ color, bg, links, hasHeader }) => {
export default FooterDesign1;
FooterDesign1.defaultProps = {
links: [
["لینک های اصلی", "فروشگاه", "درباره ما", "پرسش های متوالی"],
[
"خدمات مشتریان",
"شرایط و ضوابط استفاده",
" راهنمای خرید",
"همکاری تجاری"
],
[
"کاربری",
"حساب کاربری",
"سبد خرید",
"داشبورد کاربری"
],
[
"رضایت مشتریان",
"رسیدگی به شکایات",
"پیگیری سفارشات"
],
items: [
{
name: "لینکهای اصلی",
links: [
{
name: "فروشگاه",
link: "/products",
},
{
name: "دربارهما",
link: "/about-us",
},
{
name: "پرسشهای متداول",
link: "/faq",
},
],
},
{
name: "خدمات مشتریان",
links: [
{
name: "شرایط و ضوابط استفاده",
link: "#",
},
{
name: "راهنمای خرید",
link: "#",
},
{
name: "همکاری تجاری",
link: "#",
},
],
},
{
name: "کاربری",
links: [
{
name: "حساب کاربری",
link: "#",
},
{
name: "سبد خرید",
link: "/cart",
},
{
name: "داشبورد کاربری",
link: "/dashboard",
},
],
},
{
name: "رضایت مشتریان",
links: [
{
name: "رسیدگی به شکایات",
link: "/contact-us",
},
{
name: "پیگیری سفارشات",
link: "/orders",
},
],
},
],
bg: "bg-white",
color: "text-gray-600",

@ -49,9 +49,10 @@ export default function Input(props) {
return (
<div
className={_.join(
["input flex flex-col relative my-2 dark:bg-opacity-10", langDetector(lang, "fa", "en")],
["input flex flex-col relative my-2 dark:bg-opacity-10 w-full", langDetector(lang, "fa", "en")],
" "
)}
style={{width}}
>
{/* <label
className={_.join(
@ -92,7 +93,7 @@ export default function Input(props) {
],
" "
)}
style={{ direction: direction, width , }}
style={{ direction: direction }}
onChange={(e) =>
onChange(name, (e.target.value = regex(e.target.value)))
}

@ -4,7 +4,6 @@ import JoLPlayer from "jol-player";
function Video({ fileIds, posterId, autoPlay }) {
const videoRef = useRef(null);
return (
<div
style={{
@ -20,7 +19,10 @@ function Video({ fileIds, posterId, autoPlay }) {
option={{
videoSrc: `https://dnvn.ir/api/v1/file/${fileIds}`,
width: "100%",
height: window.innerWidth > 1024 ? window.innerHeight - 200 : window.innerHeight / 3.6,
height:
window.innerWidth > 1024
? window.innerHeight - 300
: window.innerHeight / 3.6,
theme: "#4dd35b",
language: "en",
isShowMultiple: window.innerWidth > 700,

@ -0,0 +1,112 @@
import React, { useEffect, useState } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
const Pages = [
{
strings : 'خانه - home - Home - Landing - landing', link : '/', name : 'خانه'
},
{
strings : 'ورود - ثبت نام - لاگین - login - Login', link : '/signup', name : 'ورود یا ثبت نام'
},
{
strings : 'کتاب - محصول - ویدئو - book - video - books - videos - خرید - ریاضی - علوم - شیمی - زیست - محصولات - ویدئوها - کتابها', link : '/products', name : 'محصولات'
},
{
strings : 'آدرس - شماره تماس - ارتباط با ما - نقشه - تیکت - شکایت - address - map - phone number - contact us', link : '/contact-us', name : 'ارتباط با ما'
},
]
export const SearchResult = ({ text, books, setText }) => {
const [relatedBooks, setRelatedBooks] = useState([]);
const [relatedPages, setRelatedPages] = useState([]);
useEffect(() => {
if (text && books.length > 0) {
let list = books.filter(
(book) =>
book.product[0].name.indexOf(text) !== -1 ||
book.product[1].name.indexOf(text) !== -1
);
let pages = Pages.filter((page) => page.strings.indexOf(text) !== -1);
setRelatedPages(pages);
setRelatedBooks(list);
}
}, [text]);
return (
<div
className="w-full list-none relative z-50"
>
<div
onClick={(e) => e.stopPropagation()}
className="absolute -top-1 w-full left-0 px-6 pt-5 bg-white pb-5 shadow-lg rounded-md flex flex-col overflow-y-scroll z-50"
style={{ maxHeight: "calc(100vh / 1.5)", direction : 'ltr' }}
>
<header className="w-full flex flex-row-reverse items-center gap-4">
<strong className="text-greenBA font-normal text-sm">محصولات</strong>
<span
className="flex-1 bg-greenBA bg-opacity-30"
style={{ height: 1 }}
></span>
</header>
{relatedBooks.length > 0 ? (
<ul className="list-none p-0 m-0 mt-4 flex flex-col gap-3 divide-solid divide-y divide-gray-200">
{relatedBooks.map((book, index) => (
<Link
to={"/products/" + book.id}
className="flex flex-row-reverse w-full gap-4 items-center"
ley={index}
onClick={() => setText(null)}
>
<img
style={{
height: "calc(100vh / 17)",
width: "calc(100vh / 17 * 2 / 3)",
}}
className="rounded-sm"
src={`https://dnvn.ir/api/v1/file/${book.fileIds}`}
alt=""
></img>
<strong className="text-sm pt-2 text-blueC0 font-semibold">
{book.product[1].name}
</strong>
</Link>
))}
</ul>
) : <span style={{direction: "rtl"}} className="text-blueC0 text-sm text-right py-4 font-semibold">هیچ محصولی یافت نشد.</span>}
<header className="w-full flex flex-row-reverse items-center gap-4 mt-5">
<strong className="text-greenBA font-normal text-sm">صفحات</strong>
<span
className="flex-1 bg-greenBA bg-opacity-30"
style={{ height: 1 }}
></span>
</header>
{relatedPages.length > 0 ? (
<ul className="list-none p-0 m-0 mt-4 flex flex-col gap-3 divide-solid divide-y divide-gray-200">
{relatedPages.map((page, index) => (
<Link
to={page.link}
className="flex flex-row-reverse w-full gap-4 items-center text-green-800 text-tiny font-semibold underline"
ley={index}
onClick={() => setText(null)}
>
{page.name}
</Link>
))}
</ul>
) : <span style={{direction: "rtl"}} className="text-blueC0 text-sm text-right py-4 font-semibold">هیچ صفحه ای موجود نیست</span>}
</div>
</div>
);
};
const mapStateToProps = (state) => ({
books: state.book.list,
});
const mapDispatchToProps = {};
export default connect(mapStateToProps, mapDispatchToProps)(SearchResult);

@ -1,15 +1,17 @@
import React, { useEffect, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import { connect } from "react-redux";
import {publicApi} from "../../redux/actions";
import { userProduct } from "../../redux/actions";
import _ from "lodash";
import Drawer from "../Drawer";
import Search from "../Search";
import SearchResult from "./SearchResult";
import OverLayer from "../OverLayer";
//assets
import cartIcon from "./cart-blue.svg";
// import whiteCartIcon from "./white-cart-icon.svg";
// import profileIcon from "./dark-crimson-profile-icon.svg";
// import searchIcon from "./dark-crimson-search-box.svg";
import searchIcon from "./dark-crimson-search-box.svg";
// import lightGraySearchIcon from "./light-gray-search-box.svg";
import darkCrimsonHamburgerMenu from "./dark-crimson-hamburger-menu.svg";
// import whiteHamburgerMenu from "./white-hamburger-menu-icon.svg";
@ -31,31 +33,23 @@ import dotsMenuLightIcon from "../../assets/icons/dots-menu-light.svg";
import bookmarkDeactiveLightIcon from "../../assets/icons/bookmark-deactive-light.svg";
function Navbar({
getCartProducts,
cartProductsLength,
pages,
isDark,
isMobile,
isLogin,
headerOptions,
loginBtn,
menuItems,
category,
searchBox,
topHeader,
bottomHeader,
productCategoryTextColor,
menuItemsColor,
}) {
const navigation = useNavigate();
const { logo, hamburgerMenu, qr, shown, menu, title, back, bookmark } =
headerOptions;
const [overLayer, setOverLayer] = useState(false);
const [top, setTop] = useState(false);
const [search, setSearch] = useState(null);
const [drawerOpen, setDrawerOpen] = useState(false);
const [desktopMiddleFix, setDesktopMiddleFix] = useState(false);
const [desktopEndTransform, setDesktopEndTransform] = useState(false);
useEffect(() => {
var lastScroll = window.scrollY;
if (window.scrollY === 0) {
setTop(() => true);
}
@ -68,25 +62,13 @@ function Navbar({
}
});
}
if (!isMobile) {
window.addEventListener("scroll", () => {
if (window.scrollY >= 64) {
setDesktopMiddleFix(() => true);
} else {
setDesktopMiddleFix(() => false);
}
if (window.scrollY > lastScroll && window.scrollY >= 90) {
setDesktopEndTransform(() => true);
} else {
setDesktopEndTransform(() => false);
}
lastScroll = window.scrollY;
});
}
}, []);
useEffect(() => {
if (!isMobile && isLogin) {
getCartProducts();
}
}, [isLogin]);
return isMobile ? (
<div
className={_.join(
@ -212,108 +194,78 @@ function Navbar({
{/* portrait end */}
</div>
) : (
<header className={`rounded-b-md w-full bg-transparent pb-1`}>
<div className="flex flex-row justify-between items-center px-20 border-b border-gray-200 border-solid py-4 ">
<div className="divide-x flex flex-row transform gap-4">
{/* <span className="text-sm font-normal text-blue52">
انتخاب کشور
</span> */}
<Link to="/dashboard" className="text-sm font-normal text-blue52">
پیگیری سفارش
</Link>
</div>
<div className="flex flex-row gap-5" style={{ direction: "ltr" }}>
{!isLogin && (
<Link to="/signup" className="text-sm font-semibold text-blue52">
ورود و ثبت نام
</Link>
)}
<Link to="/dashboard" className="text-sm font-normal text-blue52">
شکایات&nbsp;
</Link>
</div>
</div>
<div
className={`w-full flex flex-col z-20 ${desktopMiddleFix ? "" : ""}`}
>
<div className="w-full flex flex-row items-center h-full relative bg-white justify-between py-5 px-20 z-20 border-b border-gray-200 border-solid ">
<div className="ml-10">
<Link to="/" className="flex flex-row items-center">
<img src={logoIcon} className="w-6" />
<span
className={`text-base font-bold text-3xl text-blue52 transform translate-y-1 mr-2`}
>
دانوین
</span>
</Link>
</div>
<div
className="hidden lg:flex items-center w-3/5 justify-around flex-1 absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2"
style={{ maxWidth: "calc(100vw / 2)" }}
></div>
<div
className="flex w-full absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2"
style={{ maxWidth: "calc(100vw / 3)" }}
>
<Search />
</div>
<div className="flex justify-end items-center gap-4">
<Link to="/cart">
<img src={cartIcon} alt="" className="w-9" />
<header
className={`rounded-b-md w-full border-b border-gray-200 border-solid fixed top-0 right-0 shadow-md bg-white z-20`}
>
<div className={`w-11/12 mx-auto flex flex-col`}>
<div className="w-full flex flex-row items-center py-3 relative justify-between h-ful">
<div className="flex flex-row items-center">
<Link
to="/"
className="flex flex-row items-center text-2xl font-medium"
>
<img src={logoIcon} className="w-8 relative bottom-1 ml-1" />
دانوین
</Link>
{/* <img src={whiteCartIcon} alt="" className="w-5 h-5 ml-2" /> */}
{/* <img src={searchIcon} alt="" className="w-5 h-5 ml-2" /> */}
{/* <img src={profileIcon} alt="" className="w-5 h-5" /> */}
<ul className="flex flex-row list-none items-center relative top-0.5 mr-6">
{pages.map((page, index) => (
<li key={index}>
<Link
to={page.link}
className="text-tiny font-medium text-blue5F py-2 px-4 mx-4"
>
{page.name}
</Link>
</li>
))}
</ul>
</div>
</div>
{overLayer && (
<div
className="z-30 w-screen h-full fixed top-0 right-0 backdrop-filter blur-sm bg-opacity-60 bg-gray-600"
onClick={() => setOverLayer(false)}
>
<div className="relative w-full h-full">
<div
className="flex flex-col w-full absolute left-1/2 top-8 transform -translate-x-1/2 z-50 rounded-md"
style={{ maxWidth: "calc(100vw / 3)" }}
onClick={(e) => e.stopPropagation()}
>
<Search onChange={(val) => setSearch(val)} />
{search && <SearchResult text={search} setText={setSearch} />}
</div>
</div>
</div>
)}
<div
className={`flex items-center relative w-full py-2 px-20 border-b border-solid border-gray-200 transform bg-white ${
desktopEndTransform ? "" : ""
}`}
style={
{
// transition: "all 0.3s",
}
}
>
<div className="ml-10 flex flex-row items-center">
<div className="flex flex-row items-center">
<img
src={darkCrimsonHamburgerMenu}
src={searchIcon}
alt=""
className="w-8 transform translate-y-1 ml-2"
className="w-7 ml-3 cursor-pointer"
onClick={() => setOverLayer(true)}
/>
{/* <img src={whiteHamburgerMenu} alt="" className="w-3 h-3" /> */}
<span className={`text-sm text-blue52 ${productCategoryTextColor}`}>
دسته بندی کالاها
{isLogin && (
<div className="flex justify-end items-center gap-4">
<Link to="/cart" className="relative">
<img src={cartIcon} alt="" className="w-8" />
<span className="absolute -right-2 -top-0.5 w-4 p-2.5 h-4 flex justify-center items-center bg-green-700 bg-opacity-100 rounded-full text-white text-xs">
{cartProductsLength}
</span>
</Link>
{/* <img src={whiteCartIcon} alt="" className="w-5 h-5 ml-2" /> */}
&nbsp;&nbsp;
</span>
</div>
<div
className="flex items-center justify-around w-3/5 absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2"
style={{ maxWidth: "calc(100vw / 2)" }}
>
{/* {menuItems.map((item, index) => (
<a
href="#"
className={`text-sm text-blue52 ${menuItemsColor}`}
key={index}
>
{item}
</a>
))} */}
{pages.map((item, index) => (
{/* <img src={profileIcon} alt="" className="w-5 h-5" /> */}
</div>
)}
{!isLogin && (
<Link
to={item.link}
className={`text-sm text-blue52 ${menuItemsColor} hover:text-blueC0`}
key={"nav" + index}
to="/signup"
className="bg-blueC0 text-white rounded-md px-4 py-3 text-sm mr-7 hover:bg-opacity-90 shadow-sm"
>
{item.name}
ورود یا ثبت نام
</Link>
))}
)}
</div>
</div>
</div>
@ -326,25 +278,23 @@ const mapStateToProps = (state) => ({
isMobile: state.publicApi.isMobile,
headerOptions: state.publicApi.headerOptions,
isLogin: state.user.status,
cartProductsLength: state.userProduct.list?.filter(
(product) => product.condition < 2
)?.length,
});
const mapDispatchToProps = {
getCartProducts: userProduct.list,
};
export default connect(mapStateToProps)(Navbar);
export default connect(mapStateToProps, mapDispatchToProps)(Navbar);
Navbar.defaultProps = {
pages: [
{
link: "/",
name: "خانه",
},
{
link: "/products",
name: "محصولات",
},
{
link: "/filter",
name: "دسته بندی ها",
},
{
link: "/contact-us",
name: "تماس با ما",
@ -354,7 +304,7 @@ Navbar.defaultProps = {
name: "درباره ما",
},
{
link: "/dashboard",
link: "/orders",
name: "پیگیری",
},
{

@ -0,0 +1,28 @@
import React from "react";
import { connect } from "react-redux";
import { publicApi } from "../../redux/actions";
export const OverLayer = ({ setOverLayer, overLayer }) => {
const click = (e) => {
setOverLayer(false);
e.stopPropagation();
};
return (
overLayer && (
<div
className="z-20 w-screen h-full fixed top-0 right-0 backdrop-filter blur-sm bg-opacity-60 bg-gray-600"
onClick={(e) => click(e)}
></div>
)
);
};
const mapStateToProps = (state) => ({
overLayer: state.publicApi.overLayer,
});
const mapDispatchToProps = {
setOverLayer: publicApi.setOverLayer,
};
export default connect(mapStateToProps, mapDispatchToProps)(OverLayer);

@ -1,20 +1,23 @@
import React, { useState } from "react";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import separate from "../../utils/separate";
import StarRating from "../StarRating";
// import Tag from "../Tag";
// import ReactTooltip from "react-tooltip";
import book from "./goldon.png";
import watermelon from "./watermelon.png";
// import watermelon from "./watermelon.png";
import heart from "./vuesax-linear-heart.svg";
import discountImg from "./discount.png";
import YellowDotIcon from "./yellowDotIcon.svg";
import RedDotIcon from "./redDotIcon.svg";
import PurpleDotIcon from "./purpleDotIcon.svg";
import LightBlueDotIcon from "./lightBlueDotIcon.svg";
import StarRatingComponent from "react-star-rating-component";
// import YellowDotIcon from "./yellowDotIcon.svg";
// import RedDotIcon from "./redDotIcon.svg";
// import PurpleDotIcon from "./purpleDotIcon.svg";
// import LightBlueDotIcon from "./lightBlueDotIcon.svg";
// import StarRatingComponent from "react-star-rating-component";
const ProductDesign = ({
grades,
colors,
likeBtn,
discount,
@ -23,6 +26,7 @@ const ProductDesign = ({
productContent,
star,
productTags,
product,
priceDirection,
productTitleAlignment,
priceHolder,
@ -34,37 +38,36 @@ const ProductDesign = ({
productCatTextColor,
rangeHolder,
verticalImg,
horizontalImg,
rangeWidth,
addToCartHolder,
productName,
productPrice,
productImg,
writeGHEIMAT,
numberOfRegards,
productHolderHoverBorder,
hoverMode,
big,
starRate
starRate,
imageSize,
}) => {
const [isHovering, setIsHovering] = useState(false);
return (
<div className={`flex flex-wrap sm:flex-nowrap justify-around ${big ? 'm' : 'w-48 m-2'} `}
style={big ? {width: '300px'} : {}}
<Link
to={"/products/" + product.id}
className={`flex flex-wrap sm:flex-nowrap justify-around group`}
style={{ direction: "rtl" }}
>
<div className="w-full flex flex-wrap items-center justify-around my-5 px-4" >
<div className="w-full flex flex-wrap items-center justify-around">
<div
className={`w-full sm:w-60 md:w-72 ${big ? '' : 'mx-5'} rounded-lg transition-all p-2 my-3 ${productHolderBorder} ${hoverMode == 'blue' ? 'hover:bg-grayF4' : null} ${productHolderBorderColor} hover:${productHolderHoverBorder} hover:` }
className={`w-full sm:w-60 md:w-72 rounded-lg p-2 my-3 hover:bg-grayF4 transition-all duration-500`}
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}
>
{/* product image */}
<div className="w-full relative">
{/* icons on image */}
<div className="absolute left-0 top-10">
<div className="w-full absolute left-0 top-10">
{discountPricePercent && (
<div className="bg-discountPriceBg bg-white w-full p-2 px-3">
<div className="w-full bg-white p-2 px-3">
<p className="text-discountPriceTitle font-bold text-md text-blueC0">
23<span>%</span>
</p>
@ -82,61 +85,27 @@ const ProductDesign = ({
)}
</div>
{/* img */}
<div className={`w-full ${big ? 'h-60' : 'h-48'} flex bg-grayF4 p-0 justify-center rounded-lg`}>
{verticalImg && (
<img
src={productImg}
alt=""
className="h-full rounded-lg cursor-pointer py-5"
/>
)}
{horizontalImg && (
<img src={watermelon} alt="" className="w-full rounded-lg" />
)}
<div
className={`w-full flex bg-grayF4 p-0 justify-center rounded-lg group`}
>
<img
src={`https://dnvn.ir/api/v1/file/${product.fileIds}`}
alt=""
style={{
height: `calc(100vh / ${imageSize})`,
width: `calc(100vh / ${imageSize} * 2 / 3.5)`,
}}
className="rounded-lg cursor-pointer py-5"
/>
</div>
{/* select Color */}
{/* {colors && (
<div className="flex items-center absolute right-2 bottom-2">
<img
src={YellowDotIcon}
alt=""
data-tip="زرد"
className="w-3 h-3 ml-1 cursor-pointer"
/>
<ReactTooltip place="top" type="dark" effect="float" />
<img
src={RedDotIcon}
alt=""
data-tip="قرمز"
className="w-3 h-3 ml-1 cursor-pointer"
/>
<ReactTooltip place="top" type="dark" effect="float" />
<img
src={PurpleDotIcon}
alt=""
data-tip="بنفش"
className="w-3 h-3 ml-1 cursor-pointer"
/>
<ReactTooltip place="top" type="dark" effect="float" />
<img
src={LightBlueDotIcon}
alt=""
data-tip="آبی"
className="w-3 h-3 ml-1 cursor-pointer"
/>
<ReactTooltip place="top" type="dark" effect="float" />
</div>
)} */}
</div>
{/* product content */}
<div className="px-2">
<div className="mt-4">
<div className="w-full px-2">
<div className="w-full mt-4">
<h2
className={`leading-4 text-xl font-black py-2 ${productTitleColor} ${productTitleAlignment}`}
className={`leading-5 text-tiny font-normal py-2 text-right text-blue5F`}
>
{productName}
{product?.product[1]?.name}
</h2>
{productContent && (
<p
@ -147,31 +116,34 @@ const ProductDesign = ({
</p>
)}
{productCat && (
<span className={`text-md py-1 font-light ${productCatTextColor}`}>
{productCat}
<span className={`text-sm py-1 font-normal text-blueC0`}>
{"پایه" + " " + grades[product.gradeId]}
</span>
)}
</div>
{/* star */}
{star && (
<div className="flex items-center mt-3">
<StarRating value={starRate} size={big ? '' : 'small'}/>
<span className="text-xs text-productContent font-bold text-gray-500 mr-2">
<StarRating value={starRate || 4} />
{/* <span className="text-xs text-productContent font-bold text-gray-500 mr-2">
بر اساس {numberOfRegards} بررسی
</span>
</span> */}
</div>
)}
{/* price */}
{priceHolder && (
<div
className={`flex items-center justify-between ${priceDirection}`}
>
<div className={`flex items-center justify-between mt-2`}>
<div className="mt-2">
<div
className={`${priceDirection.indexOf("col") !== -1 ? "inline" : "flex"
}`}
className={`${
priceDirection.indexOf("col") !== -1 ? "inline" : "flex"
}`}
>
{writeGHEIMAT && <span className="text-xs text-borderColor ml-2">قیمت</span>}
{writeGHEIMAT && (
<span className="text-xs text-borderColor ml-2">
قیمت
</span>
)}
{/* price with line on it */}
{discountPrice && (
<p className="line-through text-xs text-borderColor mr-2">
@ -179,36 +151,34 @@ const ProductDesign = ({
</p>
)}
</div>
<p className="text-xl text-productPrice font-semibold inline text-blue5F">
{productPrice} <span>تومان</span>
<p className="text-lg text-productPrice font-semibold inline text-blue5F">
{separate(product?.product[1]?.price)} <span>تومان</span>
</p>
</div>
{/* add to cart */}
{addToCartHolder && (
<button
className={`rounded-2xl px-2 py-3 border text-xs text-productPrice mt-2 hover:bg-darkCrimsonBgColor hover:text-white active:bg-rangeFillBgColor transition duration-500 hover:-translate-y-2 ${priceDirection.indexOf("col") !== -1 ? "w-full" : ""
}`}
className={`rounded-2xl px-2 py-3 border text-xs text-productPrice mt-2 hover:bg-darkCrimsonBgColor hover:text-white active:bg-rangeFillBgColor transition duration-500 hover:-translate-y-2 ${
priceDirection.indexOf("col") !== -1 ? "w-full" : ""
}`}
>
اضافه کردن به سبد خرید
</button>
)}
</div>
)}
{hoverMode == 'blue' ?<div className="w-full flex justify-center mt-4">
<div
className={`bg-blueC0 text-white rounded p-4 text-xs justify-center ${isHovering ? "" : "hidden"
{hoverMode == "blue" ? (
<div className="w-full flex justify-center mt-4">
<div
className={`bg-blueC0 text-white rounded p-4 text-xs justify-center ${
isHovering ? "" : "hidden"
}`}
>
<button>افزودن به سبد خرید</button>
>
<button>افزودن به سبد خرید</button>
</div>
</div>
</div> : null}
) : null}
{/* {productTags && (
<div className="mt-2 flex flex-wrap">
@ -224,15 +194,18 @@ const ProductDesign = ({
></div>
</div>
)}
</div>
</div>
</div>
</div>
</Link>
);
};
export default ProductDesign;
const mapStateToProps = (state) => ({
grades: state.publicApi.grades,
});
export default connect(mapStateToProps)(ProductDesign);
// text colors i used for product title:
// text-darkCrimsonTextColor
@ -281,5 +254,5 @@ ProductDesign.defaultProps = {
//میتونیم تعیین کنیم که قیمت و دکمه اضاف به سبد خرید کنار یکدیگر باشند یا زیر هم
priceDirection: "flex-row",
productImg: book,
writeGHEIMAT: false
writeGHEIMAT: false,
};

@ -1,36 +1,70 @@
import React from "react";
import React, { useState, useEffect } from "react";
import "./index.scss";
import productImg from "./product-image.jpg";
const ProductImage = ({ images }) => {
console.log(images.length);
const [list, setList] = useState([]);
const [activeImage, setActiveImage] = useState(null);
// console.log(images.length);
useEffect(() => {
if (images) {
let mylist = images?.split(",");
setList(() => mylist);
setActiveImage(() => mylist[0]);
console.log(images);
}
}, [images]);
return (
<div className="flex flex-row w-1/3 gap-2">
<div className="flex flex-col items-center justify-between w-1/5" style={{height : 'calc(100vw / 5)'}}>
{images.slice(0, 4).map((image, index) => (
<div className="relative" style={{ width : "calc(100vw / 5 / 4 - 4px)", height : "calc(100vw / 5 / 4 - 4px)"}}>
<img
key={index}
src={productImg}
alt=""
className={`rounded-sm w-full h-full`}
// style={{ height: "calc(100% - 8px)" }}
// style={{ height: "calc(100% - 8px)" }}
/>
{/* این خط پایین که نوشتم برای این است که ایندکس که جنسش استرینگ است رو به نامبر تبدیل کند */}
{Number(index) === 3 && (
<div className="absolute w-full h-full bg-black bg-opacity-30 left-0 top-0 flex justify-center items-center text-white">
<strong>+ {images.length - 3}</strong>
</div>
)}
</div>
))}
</div>
<img src={productImg} alt="" style={{ height : "calc(100vw / 5)", width : "calc(100vw / 5)"}} />
<div className="flex flex-row w-1/3 gap-2">
<div
className="flex flex-col items-center justify-between w-1/5"
style={{ height: "calc(100vw / 5)" }}
>
{list?.slice(0, 4)?.map((image, index) => (
<div
className={`relative flex justify-center items-center ${ activeImage === image ? 'bg-green-200' : 'bg-gray-200'}`}
style={{
width: "calc(100vw / 5 / 4 - 4px)",
height: "calc(100vw / 5 / 4 - 4px)",
}}
onClick={() => setActiveImage(image)}
>
<img
key={index}
src={`https://dnvn.ir/api/v1/file/${image}`}
alt=""
className={`rounded-sm w-full h-full`}
style={{
width: "calc(100vw / 5 / 4 * 2 / 3 - 12px)",
height: "calc(100vw / 5 / 4 - 12px)",
}}
// style={{ height: "calc(100% - 8px)" }}
/>
{/* این خط پایین که نوشتم برای این است که ایندکس که جنسش استرینگ است رو به نامبر تبدیل کند */}
{Number(index) === 3 && (
<div className="absolute w-full h-full bg-black bg-opacity-30 left-0 top-0 flex justify-center items-center text-white">
<strong>+ {images.length - 3}</strong>
</div>
)}
</div>
))}
</div>
<div
className="rounded-md bg-gray-200 flex justify-center items-center"
style={{ height: "calc(100vw / 5)", width: "calc(100vw / 5)" }}
>
<img
src={`https://dnvn.ir/api/v1/file/${activeImage}`}
alt=""
style={{
height: "calc(100vw / 5.5)",
width: "calc(100vw / 5.5 * 2 / 3)",
}}
/>
</div>
</div>
);
};
// {[0, 1, 2, 3, 4].map((item, index) => (
@ -38,23 +72,3 @@ const ProductImage = ({ images }) => {
// ))}
export default ProductImage;
ProductImage.defaultProps = {
images: [
{
image: productImg,
},
{
image: productImg,
},
{
image: productImg,
},
{
image: productImg,
},
{
image: productImg,
},
],
};

@ -1,5 +1,8 @@
import React from "react";
import {connect} from 'react-redux';
import { connect } from "react-redux";
import { userProduct } from "../../redux/actions";
import { toast } from "react-toastify";
import separate from '../../utils/separate';
import Button from "../Button";
import arrow from "./arrow-icon.svg";
@ -10,7 +13,16 @@ import shield from "./shield-tick.svg";
import tick from "./tick-circle.svg";
import shop from "./icon-shop.svg";
const ProductStatusCard = ({ items, productPrice, discountPrice, isDark }) => {
const ProductStatusCard = ({
items,
price,
discountPrice,
isDark,
id,
userId,
isLogin,
pushToCart,
}) => {
return (
<section className="w-full">
<div className="bg-grayF9 rounded-md px-4 py-2 divide-y divide-solid divide-gray-200">
@ -41,7 +53,7 @@ const ProductStatusCard = ({ items, productPrice, discountPrice, isDark }) => {
))}
<div className="flex flex-col items-center py-3">
<p className="text-xl text-blue-600">
{productPrice}
{separate(price)}
<span className="text-sm text-gray-700 font-light">تومان</span>
</p>
<p className="text-xs font-light text-gray-600 mt-2">
@ -51,13 +63,21 @@ const ProductStatusCard = ({ items, productPrice, discountPrice, isDark }) => {
</p>
</div>
<Button
title=صافه کردن به سبد خرید"
title=ضافه کردن به سبد خرید"
backgroundColor={isDark ? "bg-blueC0" : "bg-blueC0"}
border={{ color: isDark ? "#ffffff55" : "#196EC055", width: "1px" }}
width="100%"
color={"text-white"}
selectable={true}
onClick={() => {}}
onClick={() =>
isLogin
? pushToCart({
productId: id,
userId: userId,
count: 1,
})
: toast.info("ابتدا وارد حساب کاربری خود شوید.")
}
/>
</div>
<div className="bg-grayF9 rounded px-4 py-2 mt-4 flex flex-row items-center">
@ -80,9 +100,15 @@ const ProductStatusCard = ({ items, productPrice, discountPrice, isDark }) => {
const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark,
})
isLogin: state.user.status,
userId: state.user.status.id,
});
export default connect(mapStateToProps)(ProductStatusCard);
const mapDispatchToProps = {
pushToCart: userProduct.add,
};
export default connect(mapStateToProps, mapDispatchToProps)(ProductStatusCard);
ProductStatusCard.defaultProps = {
items: [

@ -1,13 +1,20 @@
import React, { useState, useEffect } from "react";
import { product } from "../../redux/actions";
import { connect } from "react-redux";
import separate from "../../utils/separate";
import Button from "../Button";
import productImg from "./product-chair.svg";
import plus from "./plus.svg";
const ProductSuggestion = ({ suggestions, isDark, id, getSimilar, book, similarList }) => {
const ProductSuggestion = ({
suggestions,
isDark,
id,
getSimilar,
book,
similarList,
}) => {
const [selectedProduct, setSelectedProduct] = useState(null);
const [price, setPrice] = useState(0);
@ -17,14 +24,14 @@ const ProductSuggestion = ({ suggestions, isDark, id, getSimilar, book, similarL
}
}, [book]);
useEffect(() => {
if(similarList.length > 0) {
if (similarList.length > 0) {
let allPrice = 0;
for(let item of similarList) {
for (let item of similarList) {
allPrice = item.price + allPrice;
}
setPrice(() => allPrice);
}
},[similarList]);
}, [similarList]);
return (
<section className="mt-10 border-2 border-gray-300 py-10 rounded-lg bg-grayF9">
<h2 className="text-center text-lg font-bold text-productPrice">
@ -43,11 +50,15 @@ const ProductSuggestion = ({ suggestions, isDark, id, getSimilar, book, similarL
${selectedProduct === book ? "bg-white" : ""}`}
onClick={() => setSelectedProduct(book)}
>
<img src={`https://dnvn.ir/api/v1/file/${book?.book?.fileIds}`} alt="" className="w-2/3 rounded-md" />
<img
src={`https://dnvn.ir/api/v1/file/${book?.book?.fileIds}`}
alt=""
className="w-2/3 rounded-md"
/>
<h2 className="my-3 text-tiny">{book?.name}</h2>
<p className="text-base text-blueC0 font-medium">
{book?.price}
<span className="mr-1 text-xs text-black">تومان</span>
{separate(book?.price)}
<span className="mx-1 text-xs text-black">تومان</span>
</p>
{/* <div className="flex flex-col items-center mt-3">
<span className="text-xs">انتخاب شما</span>
@ -72,8 +83,7 @@ const ProductSuggestion = ({ suggestions, isDark, id, getSimilar, book, similarL
<div className="flex flex-row mb-5">
<p className="text-base text-productPrice font-bold">
&nbsp;جمع لوازم اختیاری خریداری شده&nbsp;
<span>{price}</span>
&nbsp;
<span className="mx-1">{separate(price)}</span>
تومان
</p>
<span className="text-lightBlueTextColor text-base mr-1 font-bold">
@ -84,7 +94,7 @@ const ProductSuggestion = ({ suggestions, isDark, id, getSimilar, book, similarL
در صورت تمایل می توانید موارد بالا را به سبد خرید اضافه کنید
</p>
<Button
title=صافه کردن به سبد خرید"
title=ضافه کردن به سبد خرید"
backgroundColor={isDark ? "bg-blueC0" : "bg-blueC0"}
border={{ color: isDark ? "#ffffff55" : "#196EC055", width: "1px" }}
width="calc(100% / 5)"

@ -2,7 +2,7 @@ import React, { useState } from "react";
import Table from "./table";
const ProductTab = ({ tabs }) => {
const [selectedTab, setSelectedTab] = useState(tabs[0]);
const [selectedTab, setSelectedTab] = useState(tabs[1]);
return (
<section className="mt-10 flex flex-col w-full">
@ -11,7 +11,7 @@ const ProductTab = ({ tabs }) => {
{tabs.map((tab, index) => (
<li
className={`text-sm cursor-pointer hover:text-blue-400 py-4 transition-all duration-500 ${
selectedTab === tab ? "text-blue-600 border-b-4 border-solid border-blueC0" : "border-b-4 border-solid border-transparent"
selectedTab?.title === tab?.title ? "text-blue-600 border-b-4 border-solid border-blueC0" : "border-b-4 border-solid border-transparent"
}`}
onClick={() => setSelectedTab(tab)}
key={index}

@ -1,84 +0,0 @@
import React, {useState, useEffect} from "react";
import { connect } from "react-redux";
import { book, publicApi } from "../../redux/actions";
import ScrollContainer from "react-indiana-drag-scroll";
import { Link } from "react-router-dom";
import Product from "../Product";
import './index.css';
const SalesContainer = ({
list, getList,
grades
}) =>{
const [filter, setFilter] = useState({
search: "",
grade: "",
productsType: "کتاب",
});
useEffect(() => {
getList();
}, []);
return(
<div className="w-full my-10">
<div className="w-full border-b-2 border-solid border-blue-300 mb-24" style={{height: '100px'}}>
<div className="w-1/3 p-10 bg-white flex justify-between items-center" style={{
marginBottom:'-5px',
height:'200px'
}} onClick={() => console.log(list)}>
<div className="flex items-center ">
{/* <div className="w-6 h-6 bg-blue-300 ml-4 rounded-full"></div> */}
<h1 className="text-3xl leading-normal">
<h3 className=" bg-blueC0 text-white text-center"> دوشنبه </h3>
<h3 className="mr-4 w-24 text-center" style={{background: '#EFFF00'}}> کتاااابی </h3>
</h1>
</div>
<div className="flex items-center">
<p className="text-md">بیش از ۵۰ کتاب تخفیف خورده</p>
<div className="w-6 h-6 bg-blue-300 mr-4 rounded-full">
</div>
</div>
</div>
</div>
<ScrollContainer className="flex overflow-x-scroll border-t-0 py-4 pl-10" style={{height:'550px'}} >
{
list?.map((product, index) => (
<Link to={"/products/" + product?.id}>
<Product
key={`prod_takhfif${index}`}
productsType={filter.productsType}
product={product}
index={Number(index)}
productName={`کتاب ${product?.name}`}
productCat={`پایه ${grades[product?.gradeId]}`}
productPrice={100000}
productImg={"https://dnvn.ir/api/v1/file/" + product?.fileIds}
numberOfRegards={160}
productTitleColor='text-blue5F'
productCatTextColor='text-blueC0'
productHolderBorder=''
productHolderHoverBorder='shadow-md'
big
starRate={Math.floor(Math.random() * 5) + 1}
discountPricePercent
hoverMode='blue'
/>
</Link>
))}
</ScrollContainer>
</div>
)
}
const mapStateToProps = (state) => ({
list: state.book.list,
isDark: state.publicApi.isDark,
});
export default connect(mapStateToProps, { getList: book.list })(SalesContainer);

@ -1,4 +1,6 @@
import React from "react";
import {connect} from 'react-redux';
import { publicApi } from "../../redux/actions";
import _ from "lodash";
import searchIcon from "./search.png";
@ -6,9 +8,9 @@ const langDetector = (lang = 'fa', option1, option2) => {
return lang === "fa" ? option1 : option2;
};
export default function Search(props) {
function Search(props) {
return (
<div className="flex items-center justify-center w-full my-3">
<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")], " ")}>
<button
@ -20,12 +22,25 @@ export default function Search(props) {
</span>
<input
type="search"
name="q"
className="w-full py-3 text-sm text-white border border-solid border-gray-200 rounded-md pr-5 pl-14 outline-none focus:ring-1 focus:text-gray-900 "
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...")], " ")}
autoComplete="off"
onChange={(e) => props.onChange(e.target.value)}
onFocus={() => props.setOverLayer(true)}
onBlur={() => props.setOverLayer(false)}
/>
</div>
</div>
);
}
const mapStateToProps = (state) => ({
})
const mapDispatchToProps = {
setOverLayer : publicApi.setOverLayer
}
export default connect(mapStateToProps, mapDispatchToProps)(Search);

@ -8,14 +8,14 @@ function Select({
borderColor,
backgroundColor,
onChange,
name,
name
}) {
return (
<div
className={`inline-block relative w-1/2 group ${margin} ${backgroundColor}`}
className={`inline-block w-1/2 relative group ${margin} ${backgroundColor}`}
>
<select
className={`text-gray70 text-xs 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-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}`}
onChange={(e) => onChange(name, e.target.value)}
>
{options.map((option, index) => (

@ -12,69 +12,75 @@ export default function VerticalExpandableProductFilter(props) {
const [text, setText] = useState("");
const [searchResult, setSearchResult] = useState([]);
const [checkedBox, setChecked] = useState([]);
const name = props.name||Math.random()
useEffect(() => {
let fakeSearchResult;
fakeSearchResult = props.list.filter(
(item1) => item1.name.indexOf(text) !== -1
);
setSearchResult(fakeSearchResult);
}, [text]);
const name = props.name || Math.random();
// useEffect(() => {
// let fakeSearchResult;
// fakeSearchResult = props.list.filter(
// (item1) => item1.name.indexOf(text) !== -1
// );
// setSearchResult(fakeSearchResult);
// }, [text]);
return (
<div className="flex flex-col w-full border border-solid border-gray-100 rounded-md pt-6 bg-transparent max-h-screen bg-white my-3">
<strong className="text-md text-gray-500 w-full mb-3 text-right px-3">
{props.title}
</strong>
{props.searchAble && <form className="relative w-full px-3 mb-3">
<input
type="text"
placeholder={_.join(
[langDetector(props.lang, "جستجو...", "Search...")],
" "
)}
className="border rounded-md py-1 px-2 w-full placeholder-gray-300 outline-none text-gray-500"
onChange={(e) => setText(e.target.value)}
/>
<span
className={_.join(
[
"absolute inset-y-0 flex items-center",
langDetector(props.lang, "left-4", "right-4"),
],
" "
)}
>
<button
type="submit"
className="p-1 focus:outline-none focus:shadow-outline"
{props.searchAble && (
<form className="relative w-full px-3 mb-3">
<input
type="text"
placeholder={_.join(
[langDetector(props.lang, "جستجو...", "Search...")],
" "
)}
className="border rounded-md py-1 px-2 w-full placeholder-gray-300 outline-none text-gray-500"
onChange={(e) => setText(e.target.value)}
/>
<span
className={_.join(
[
"absolute inset-y-0 flex items-center",
langDetector(props.lang, "left-4", "right-4"),
],
" "
)}
>
<img src={searchIcon} className="w-5 h-5" alt="" />
</button>
</span>
</form>}
<ul className="w-full list-none flex flex-col divide-y divide-gray-100">
<button
type="submit"
className="p-1 focus:outline-none focus:shadow-outline"
>
<img src={searchIcon} className="w-5 h-5" alt="" />
</button>
</span>
</form>
)}
<ul className="w-full list-none flex flex-col divide-y divide-gray-100 overflow-y-scroll" style={{maxHeight: 'calc(100vh / 3.5)', minHeight: 200}}>
{(searchResult.length > 0 ? searchResult : props.list)?.map(
(item1, i) => (
<li
key={i}
className="hover:bg-gray-100 px-3 flex flex-row items-center justify-between py-2"
>
{console.log(i)}
{/* {console.log(i)} */}
<div className="flex flex-row items-center">
<Checkbox name={`ch${name}_${i}`} checked={checkedBox[i]} onclick={(e) => {
checkedBox[i] = !checkedBox[i]
setChecked(checkedBox)
}} onChange={() => props.onChange(name , item1.name)} />
<Checkbox
name={`ch${name}_${i}`}
checked={false}
onclick={(e) => {
checkedBox[i] = !checkedBox[i];
setChecked(checkedBox);
}}
onChange={() => props.onChange(name, item1.name)}
/>
<strong className="text-xs font-light text-gray-500">
{props.preName ? props.preName + ' ' + item1.name : item1.name}
{props.preName
? props.preName + " " + item1.name
: item1}
</strong>
</div>
{item1.subList?.length > 0 && (
{item1?.subList?.length > 0 && (
<img
src={arrowIcon}
alt=""
@ -91,92 +97,17 @@ export default function VerticalExpandableProductFilter(props) {
)
)}
</ul>
{props.btnTitle && <div className="flex align-center justify-center">
<button className="my-4 bg-blueFFOP text-sm bg-opacity-40 transition-all w-4/5 py-3 px-6 rounded text-blueC0 hover:text-white hover:bg-blueC0" onClick={props.btnClicked}>{props.btnTitle}</button>
</div>}
{props.btnTitle && (
<div className="flex align-center justify-center">
<button
className="my-4 bg-blueFFOP text-sm bg-opacity-40 transition-all w-4/5 py-3 px-6 rounded text-blueC0 hover:text-white hover:bg-blueC0"
onClick={props.btnClicked}
>
{props.btnTitle}
</button>
</div>
)}
</div>
);
}
VerticalExpandableProductFilter.defaultProps = {
list: [
{
id: 0,
name: "وسایل آشپزخانه",
expaneded: false,
subList: [],
},
{
id: 3,
name: "ماشین و موتور سیکلت",
expaneded: false,
subList: [
{
id: 4,
name: "ماشین",
},
{
id: 5,
name: "موتور",
},
],
},
{
id: 6,
name: "اتاق خواب",
expaneded: false,
subList: [
{
id: 7,
name: "کمد",
},
{
id: 8,
name: "تخت خواب",
},
],
},
{
id: 9,
name: "دکوراسیون و چیدمان",
expaneded: false,
subList: [],
},
{
id: 10,
name: "وسایل بهداشت شخصی",
expaneded: false,
subList: [
{
id: 11,
name: "مسواک",
},
{
id: 12,
name: "حوله",
},
],
},
{
id: 13,
name: "وسایل بهداشت شخصی",
expaneded: false,
subList: [
{
id: 14,
name: "مسواک",
},
{
id: 15,
name: "حوله",
},
],
},
{
id: 16,
name: "وسایل بهداشت شخصی",
expaneded: false,
subList: [],
},
],
};

@ -1,16 +1,16 @@
import React, { useEffect, useState } from "react";
import {Link} from 'react-router-dom';
import separate from '../../utils/separate';
import StarRating from "../StarRating";
import ReactTooltip from "react-tooltip";
//assets
import videoImage1 from './videoImages/image-1.svg';
import videoImage2 from './videoImages/image-2.svg';
import videoImage3 from './videoImages/image-3.svg';
import videoImage4 from './videoImages/image-4.svg';
import videoImage5 from './videoImages/image-5.svg';
import videoImage6 from './videoImages/image-6.svg';
import videoImage1 from "./videoImages/image-1.svg";
import videoImage2 from "./videoImages/image-2.svg";
import videoImage3 from "./videoImages/image-3.svg";
import videoImage4 from "./videoImages/image-4.svg";
import videoImage5 from "./videoImages/image-5.svg";
import videoImage6 from "./videoImages/image-6.svg";
import watermelon from "./watermelon.png";
import video from "./danovin.mp4";
@ -21,36 +21,39 @@ import RedDotIcon from "./redDotIcon.svg";
import PurpleDotIcon from "./purpleDotIcon.svg";
import LightBlueDotIcon from "./lightBlueDotIcon.svg";
import whitePlayIcon from "./white-play-button-icon.svg";
import { book } from "../../redux/actions";
const videoImages = [videoImage1, videoImage2, videoImage3, videoImage4,videoImage5, videoImage6];
const videoImages = [
videoImage1,
videoImage2,
videoImage3,
videoImage4,
videoImage5,
videoImage6,
];
const VodProduct = ({
video,
index,
productColor,
colors,
likeBtn,
discount,
discountPricePercent,
discountPrice,
productContent,
star,
productTags,
priceDirection,
productTitleAlignment,
priceHolder,
productCat,
rangeHolder,
priceTitle,
addToCartHolder,
productTitleCategoryHolder,
productTitleCategoryHolderAlignment,
priceStarHolder,
priceStarAlignment,
rangeWidth,
productTitle,
poster,
price,
minHeight
height,
grades,
// minHeight,
}) => {
const [progressFlag, setProgressFlag] = useState(false);
// const [openModal, setOpenModal] = useState(false);
@ -60,12 +63,16 @@ const VodProduct = ({
}, 1000);
});
console.log(index);
// console.log(index);
return (
<>
{/* product UI Design */}
<div className="flex flex-wrap sm:flex-nowrap justify-around">
<div className="w-full flex flex-wrap items-center justify-around my-10 px-1 sm:px-4">
<Link
to={'/videos/' + video?.bookId}
className="flex flex-wrap sm:flex-nowrap justify-around"
style={{ direction: "rtl" }}
>
<div className="w-full flex flex-wrap items-center justify-around my-3 px-1 sm:px-4">
<div
className={`w-full mx-1 sm:w-60 md:w-96 rounded-lg shadow-sm p-2 my-3 border border-grayBorderColor`}
>
@ -76,12 +83,13 @@ const VodProduct = ({
backgroundImage: `url(${videoImages[Number(index)]})`,
backgroundSize: "100% 100%",
backgroundRepeat: "no-repeat",
minHeight: minHeight,
height: height,
// minHeight: minHeight,
}}
data-modal-toggle="large-modal"
>
{/* icons on image */}
<div className="absolute left-6 top-2">
<div className="absolute left-2 top-1">
{discountPricePercent && (
<div className="bg-discountPriceBg rounded-md px-2 py-2 mt-2 transition ease-in-out duration-300 transform hover:-translate-y-1 hover:scale-110 cursor-pointer bg-white bg-opacity-70">
<p className="text-discountPriceTitle font-bold text-xs">
@ -114,7 +122,7 @@ const VodProduct = ({
</div>
{/* select Color */}
{productColor && (
<div className="flex items-center absolute right-6 bottom-2">
<div className="flex items-center absolute right-2 bottom-3">
{/* {colors.map((color,index))} */}
<img
src={YellowDotIcon}
@ -130,21 +138,16 @@ const VodProduct = ({
<div className="px-2">
{/* content */}
<div className="mt-4 flex flex-col">
<div
className={`flex ${productTitleCategoryHolder} ${productTitleCategoryHolderAlignment} justify-between `}
>
<div className={`flex justify-between `}>
<h2
className={`leading-4 text-base mb-2 font-semibold text-darkCrimsonTextColor ${productTitleAlignment}`}
className={`leading-4 text-tiny mb-2 font-normal text-blue5F text-right`}
>
{productTitle}
{"دوره ویدیویی" + " " + video?.name}
</h2>
{productCat && (
<span
className={`text-xs font-light text-darkCrimsonTextColor`}
>
{productCat}
</span>
)}
{console.log(video?.gradeId)}
<span className={`text-sm font-light text-blueC0`}>
{ 'پایه' + ' ' + grades[video?.gradeId]}
</span>
</div>
{productContent && (
<p
@ -172,23 +175,22 @@ const VodProduct = ({
: "flex"
}`}
>
{priceTitle && (
<span className="text-xs text-borderColor ml-2">
قیمت
</span>
)}
{discountPrice && (
<span className="text-xs text-borderColor ml-2">
</span>
{/* {discountPrice && (
<p className="line-through text-xs text-borderColor">
<span> قیمت</span> 140<span>تومان</span>
</p>
)}
)} */}
</div>
<p
className={`text-sm font-semibold inline text-productPrice`}
{/* <p
className={`text-base font-semibold text-left`}
>
{price}
{separate(video?.price) + ' '}
<span>تومان</span>
</p>
</p> */}
</div>
{/* add to cart */}
{addToCartHolder && (
@ -202,14 +204,14 @@ const VodProduct = ({
)}
</div>
)}
{star && (
{/* {star && (
<div className="flex items-center">
<StarRating />
<span className="text-xs text-productContent font-bold mr-2">
39
</span>
</div>
)}
)} */}
</div>
{productTags && (
<div className="mt-2 flex flex-wrap">
@ -237,7 +239,7 @@ const VodProduct = ({
</div>
</div>
</div>
</div>
</Link>
{/* <div
class="hidden overflow-y-auto overflow-x-hidden fixed right-0 left-0 top-4 z-50 justify-center items-center md:inset-0 h-modal sm:h-full"
id="large-modal"

@ -6,6 +6,7 @@ export { default as blog } from "./blog";
export { default as product } from "./product";
export { default as userFactor } from "./userFactor";
export { default as userProduct } from "./userProduct";
export { default as userAddress } from "./userAddress";
export { default as content } from "./content";
export { default as faq } from "./faq";
export { default as file } from "./file";

@ -1,5 +1,7 @@
import proxy from "../proxy";
const publicApi = {
setOverLayer: (data) => async (dispatch) =>
await dispatch({ type: "public/setOverLayer", data }),
setDesktopContentTransform: (data) => async (dispatch) =>
await dispatch({ type: "public/setDesktopContentTransform", data }),
setHeaderOptions: (data) => async (dispatch) =>

@ -1,11 +1,11 @@
import proxy from "../proxy";
const user = {
otp: (data) => async (dispatch) =>
otp: (data = {}) => async (dispatch) =>
await proxy.post("public/sendOTP", data, { dispatch }),
otp_login: (data) => async (dispatch) =>
await proxy.login("user/otp/login", data, { dispatch }),
await proxy.login("user/otp/login", data, { dispatch }), //{cellphone, otp}
login: (data) => async (dispatch) =>
await proxy.login("user/login", data, { dispatch }),

@ -0,0 +1,33 @@
import proxy from "../proxy";
const userAddress = {
list:
(data = {}) =>
async (dispatch) => {
await proxy.get("userAddress/list", data, { dispatch });
},
info:
(data = {}) =>
async (dispatch) => {
await dispatch({ type: "userAddress/info", data });
},
update:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.put("userAddress/update", data);
await proxy.get("userAddress/list", data2, { dispatch });
},
add:
(data = {}, data2 = {}, data3 = {}) =>
async (dispatch) => {
await proxy.post("userAddress/add", data, { dispatch });
await proxy.get("userAddress/list", data2, { dispatch });
},
del:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.delete("userAddress/delete", data);
await proxy.get("userAddress/list", data2, { dispatch });
},
};
export default userAddress;

@ -0,0 +1,23 @@
import { toast } from "react-toastify";
const initialState = {
loading: false,
video: null,
listVOD: [],
};
export default function content(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "content/listVOD":
return {...state, loading: false, listVOD : data };
case "content/infoVOD":
return {...state, loading: false, video : data };
case "content/loading":
return { ...state, loading: true };
case "content/error":
toast.error(data.message);
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -4,6 +4,8 @@ export { default as user } from "./user";
export { default as book } from "./book";
export { default as blog } from "./blog";
export { default as product } from "./product";
export { default as content } from "./content";
export { default as userAddress } from "./userAddress";
export { default as faq } from "./faq";
export { default as file } from "./file";
export { default as userFactor } from "./userFactor";

@ -12,8 +12,8 @@ const initialState = {
arList: [],
blogList: [],
blog: null,
province: null,
city: null,
province: ["استان"],
city: ["شهر"],
departmans: [
{
id: 0,
@ -61,6 +61,9 @@ const initialState = {
title: false,
},
desktopContentTransform: false,
overLayer: false,
provinces: [],
cities : []
};
const grades = [
@ -82,6 +85,8 @@ const grades = [
export default function publicApi(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "public/setOverLayer":
return { ...state, overLayer: data };
case "public/setDesktopContentTransform":
return { ...state, desktopContentTransform: data };
case "public/setHeaderOptions":
@ -167,9 +172,21 @@ export default function publicApi(state = initialState, action) {
case "public/setSubscribe":
return { ...state, loading: false, error: null, selectedSubscribe: data };
case "public/province":
return { ...state, loading: false, error: null, province: data };
return {
...state,
loading: false,
error: null,
province: [...state.province, ...data.map((item) => item.name)],
provinces : data
};
case "public/city":
return { ...state, loading: false, error: null, city: data };
return {
...state,
loading: false,
error: null,
city: [...state.city, ...data.map((item) => item.name)],
cities : data,
};
case "public/selectMenu":
return { ...state, loading: false, error: null, selectedMenu: data };
case "public/VOD/homePage":

@ -19,7 +19,7 @@ export default function user(state = initialState, action) {
// case "user/register":
// case "user/switchRole":
case "public/sendOTP":
return { ...state, loading: false, status: data.profile, error: null };
return { ...state, loading: false, error: null };
case "user/login":
case "user/otp/login":
return {

@ -0,0 +1,35 @@
import { toast } from "react-toastify";
const initialState = {
loading: false,
error: null,
list: [],
info : null,
};
export default function userAddress(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "userAddress/list":
return {
...state,
loading: false,
list: data,
error: null,
};
case "userAddress/info":
return { ...state, loading: false, info: data, error: null };
case "userAddress/update":
return { ...state, loading: false, error: null };
case "userAddress/add":
return { ...state, loading: false, error: null, sum: data.payPrice };
case "userAddress/delete":
return { ...state, loading: false, error: null };
case "userAddress/loading":
return { ...state, loading: true };
case "userAddress/error":
toast.error(data.message);
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -27,6 +27,7 @@ import Faq from "./views/Faq";
import Contact from "./views/Contact";
import Dashboard from "./views/Dashboard";
import FooterDesign1 from "./components/Footer";
import Bugs from "./views/BugsAndProblems";
// import VideoTube from "./views/Home/VideoTube";
function Router({
@ -351,6 +352,7 @@ function Router({
/>
}
/>
<Route path="/bugs" exact element={<Bugs />} />
<Route
path="*"
exact

@ -1,3 +1,5 @@
export const connectToParent = (list) => {
let comments = [];
for (let item of list) {
@ -18,5 +20,5 @@ export const connectToParent = (list) => {
}
}
// comments = comments.filter((comment) => comment.pid === null);
console.log(comments);
// console.log(comments);
};

@ -80,16 +80,16 @@ class onInput {
englishAndNumberWithoutSpace = (txt) => {
let newText = txt;
newText = newText.replace(/`/g, "");
newText = newText.replace(/0/g, "0");
newText = newText.replace(/1/g, "1");
newText = newText.replace(/2/g, "2");
newText = newText.replace(/3/g, "3");
newText = newText.replace(/4/g, "4");
newText = newText.replace(/5/g, "5");
newText = newText.replace(/6/g, "6");
newText = newText.replace(/7/g, "7");
newText = newText.replace(/8/g, "8");
newText = newText.replace(/9/g, "9");
newText = newText.replace(/۰/g, "0");
newText = newText.replace(/۱/g, "1");
newText = newText.replace(/۲/g, "2");
newText = newText.replace(/۳/g, "3");
newText = newText.replace(/۴/g, "4");
newText = newText.replace(/۵/g, "5");
newText = newText.replace(/۶/g, "6");
newText = newText.replace(/۷/g, "7");
newText = newText.replace(/۸/g, "8");
newText = newText.replace(/۹/g, "9");
newText = newText.replace(/ا/g, "");
newText = newText.replace(/ب/g, "");
newText = newText.replace(/پ/g, "");
@ -149,6 +149,16 @@ class onInput {
newText = newText.replace(/7/g, "7");
newText = newText.replace(/8/g, "8");
newText = newText.replace(/9/g, "9");
newText = newText.replace(/۰/g, "0");
newText = newText.replace(/۱/g, "1");
newText = newText.replace(/۲/g, "2");
newText = newText.replace(/۳/g, "3");
newText = newText.replace(/۴/g, "4");
newText = newText.replace(/۵/g, "5");
newText = newText.replace(/۶/g, "6");
newText = newText.replace(/۷/g, "7");
newText = newText.replace(/۸/g, "8");
newText = newText.replace(/۹/g, "9");
newText = newText.replace(/ا/g, "");
newText = newText.replace(/ب/g, "");
newText = newText.replace(/پ/g, "");

@ -157,7 +157,7 @@ class scroll {
initializeBoxPosition = (currentScroll) => {
const height= window.innerHeight;
if(currentScroll < height){
console.log(currentScroll);
// console.log(currentScroll);
return {
translateX: -5,
translateY: -5,

@ -0,0 +1,12 @@
const separate = (number) => {
number += "";
number = number.replace(",", "");
let x = number.split(".");
let y = x[0];
let z = x.length > 1 ? "." + x[1] : "";
let rgx = /(\d+)(\d{3})/;
while (rgx.test(y)) y = y.replace(rgx, "$1" + "," + "$2");
return y + z;
};
export default separate;

@ -9,8 +9,7 @@ function NotFound({ headerOptions, setHeaderOptions }) {
}, []);
return (
<div
className="w-full flex h-full transform justify-center items-center flex-col bg-transparent px-4"
style={{ height: "calc(100vh - 160px)" }}
className="w-full flex h-screen transform justify-center items-center flex-col bg-transparent px-4"
>
<h1
className="dark:text-white text-5xl font-semibold"
@ -19,7 +18,7 @@ function NotFound({ headerOptions, setHeaderOptions }) {
404
</h1>
<img src={notFoundImage} alt="404" className="mt-10" />
<p className="text-base dark:text-white mt-12">
<p className="text-base dark:text-white mt-12 leading-7">
وای!!
<br />
صفحه ای که بدنبال آن بودهاید دیگر وجود ندارد :(

@ -12,7 +12,7 @@ function AR({ getArList, arList, headerOptions, setHeaderOptions }) {
}, []);
return (
<div className="flex flex-col flex-1 gap-4 px-4">
<div className="flex flex-col flex-1 gap-4 px-4 lg:w-1/2 lg:min-h-screen lg:py-24 lg:mx-auto">
{arList.length > 0 &&
arList.map((book, index) => <Book book={book} key={index} />)}
</div>

@ -18,8 +18,8 @@ function Activation({ headerOptions, setHeaderOptions, isMobile }) {
}, []);
return (
<div
className="w-full flex h-full flex-col bg-transparent"
style={{ height: "calc(100vh - 145px)" }}
className="w-full flex h-full flex-col bg-transparent lg:pt-36 lg:pb-24"
// style={{ height: "calc(100vh - 145px)" }}
>
<Header bg={isMobile ? qrBgImage : desktopQrBgImage} title="فعالسازی کتاب دیجیتال" />
<div className="flex-1 flex flex-col justify-between lg:justify-start px-4 lg:w-1/4 lg:mx-auto">

@ -0,0 +1,140 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { publicApi } from "../../redux/actions";
import onInput from "../../utils/onInput";
import Input from "../../components/Input";
import Select from "../../components/Select";
export const Address = ({ city, province, getCity, getProvince }) => {
const [addressFields, setAddressFields] = useState({});
useEffect(() => {
if (province.length <= 1) {
getProvince();
}
}, []);
useEffect(() => {
if (addressFields?.provinceId) {
getCity({ provinceId: addressFields?.provinceId });
}
}, [addressFields]);
const onChange = (name, value) => {};
const Header = ({ title, text }) => {
return (
<div className="flex flex-row items-center gap-2 mb-4">
<strong className="text-blue5F text-base">{title}</strong>
<p className="mt-1 inline flex-1 text-sm text-gray70">{text}</p>
</div>
);
};
return (
<div
className="flex flex-row-reverse flex-1 pb-20 gap-5 divide-x divide-solid divide-gray-200"
style={{ minHeight: "calc(100vh - 500px)" }}
>
<div className="flex flex-col w-1/2"></div>
<div className="flex flex-col w-1/2 pl-4">
<Header
title="اطلاعات هویتی"
text="( لطفا نام و نام خانوادگی خود را به طور کامل وارد نمایید )"
/>
<div className="flex flex-row items-center gap-5 w-full">
<Input
width="50%"
label={"نام"}
regex={(val) => val}
name="firstName"
onChange={(name, value) => onChange(name, value)}
value={addressFields?.firstName}
align="text-right"
direction="rtl"
/>
<Input
width="50%"
label={"نام خانوادگی"}
regex={(val) => val}
name="lastName"
onChange={(name, value) => onChange(name, value)}
value={addressFields?.lastName}
align="text-right"
direction="rtl"
/>
</div>
<br />
<br />
<Header
title="شماره تماس"
text="( شماره موبایل و شماره تلفن ثابت خود را
به همراه پیش شماره وارد کنید )"
/>
<div className="flex flex-row items-center gap-5 w-full">
<Input
width="50%"
label={"شماره موبایل"}
regex={(val) => onInput.numberOnly(val)}
name="cellphone"
onChange={(name, value) => onChange(name, value)}
value={addressFields?.cellphone}
align="text-right"
direction="ltr"
/>
<Input
width="50%"
label={"شماره تلفن"}
regex={(val) => onInput.numberOnly(val)}
name="tellphone"
onChange={(name, value) => onChange(name, value)}
value={addressFields?.lastName}
align="text-right"
direction="ltr"
/>
</div>
<br />
<br />
<Header
title="آدرس"
text="( لطفا نام استان و شهرستان و آدرس
خود را با دقت تکمیل نمایید )"
/>
<div className="flex flex-row items-center gap-5 w-full mt-3">
<Select
options={province}
name="provinceId"
onChange={(name, value) => onChange(name, value)}
/>
<Select
options={city}
name="cityId"
onChange={(name, value) => onChange(name, value)}
/>
</div>
<br />
<Input
width="50%"
label={"کد پستی"}
regex={(val) => onInput.numberOnly(val)}
name="tellphone"
onChange={(name, value) => onChange(name, value)}
value={addressFields?.lastName}
align="text-right"
direction="ltr"
/>
</div>
</div>
);
};
const mapStateToProps = (state) => ({
province: state.publicApi.province,
city: state.publicApi.city,
});
const mapDispatchToProps = {
getProvince: publicApi.getProvince,
getCity: publicApi.getCity,
};
export default connect(mapStateToProps, mapDispatchToProps)(Address);

@ -13,8 +13,8 @@ import Birthdate from "./Birthdate";
import MultipleSelector from "./MultipleSelector";
import Document from "./Document";
function Profile({
isMobile,
profile,
uploads,
getProvince,
@ -187,7 +187,7 @@ function Profile({
// if (setDone) return <Navigate path="/" />;
return (
return isMobile ? (
<div className="profile main d-flex justify-content-center">
<main>
<header className="d-flex align-items-center justify-content-between">
@ -336,7 +336,7 @@ function Profile({
/>
</div>
) : null}
{console.log(province)}
{/* {console.log(province)} */}
<div className="mb-2" style={{ minWidth: "100%" }}>
<Select
options={provinceList}
@ -419,6 +419,16 @@ function Profile({
</div>
</main>
</div>
) : (
<ul className="flex flex-col flex-1">
<li className="flex flex-row gap-5">
<div className="flex flex-col w-4/12">
<strong>اطلاعات هویتی</strong>
<p>لطفا نام و نام خانوادگی خود را به طور کامل وارد نمایید</p>
</div>
<div className="flex flex-row w-8/12"></div>
</li>
</ul>
);
}
@ -431,6 +441,7 @@ export default connect(
uploads: state.file.uploads,
provinceList: state.publicApi.province,
cityList: state.publicApi.city,
isMobile: state.publicApi.isMobile,
}),
{
getProfile: user.getProfile,

@ -130,7 +130,7 @@ function SignUp({
useEffect(() => {
if (loginFlag) {
// navigate("/");
navigate("/");
}
}, [loginFlag]);
const light = theme === "light";
@ -152,7 +152,7 @@ function SignUp({
<Input
label={"شماره موبایل"}
name="cellphone"
regex={onInput.phonenumber}
regex={onInput.numberOnly}
onChange={(name, value) => onChange(name, value)}
value={signUpFields?.cellphone}
align="text-center"
@ -241,7 +241,7 @@ function SignUp({
onChange={(e) =>
onChange(
e.target.name,
(e.target.value = onInput.numberOnly(e.target.value))
(e.target.value = onInput.englishAndNumberWithoutSpace(e.target.value))
)
}
maxlength="1"
@ -276,13 +276,17 @@ function SignUp({
);
}
const mapStateToProps = (state) => ({
loginFlag : state.user.status,
});
const mapDispatchToProps = {
sendOtp: user.otp_login,
sendPhoneNumber: user.otp,
setHeaderOptions: publicApi.setHeaderOptions,
};
export default connect(
(state) => ({
loginFlag: state.user.status,
}),
{
sendOtp: user.otp_login,
sendPhoneNumber: user.otp,
setHeaderOptions: publicApi.setHeaderOptions,
}
mapStateToProps,
mapDispatchToProps
)(SignUp);

@ -0,0 +1,124 @@
const list = [
{
title: "دسکتاپ - بنر بالای سایت",
description: "گرفتن لیست واقعی بنرها از دیتابیس",
status: 0,
developer: "",
},
{
title: "دسکتاپ - اسلایدر",
description: "اضافه کردن دکمه های اسلایدر",
status: 0,
developer: "",
},
{
title: "دسکتاپ - منوی بالای سایت",
description: "فعال سازی جستجو",
status: 0,
developer: "",
},
{
title: "دسکتاپ - منوی بالای سایت",
description: "تعداد محصولات داخل سبد خرید نمایش داده شود",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه محصولات ",
description: "فیلتر محصولات کاملا درست شود.",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه محصول",
description: "خطای اجرای منطق داریم",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه محصول",
description: "اسلایدر عکس محصول کار نمیکند و به سرور وصل نیست.",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه محصول",
description: "دکمه مشاهده نمونه کار نمیکند.",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه محصول",
description: "دکمه مشاهده دوره ویدیویی محصول کار نمیکند.",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه محصول",
description: "قسمت ثبت رضایت مشتری توسط ستاره به سرور وصل نیست",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه محصول",
description: "اصلاعات منوی سمت چپ واقعی نیست و همچنین دکمه اضافه کردن به سبد خرید کار نمیکند.",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه محصول",
description: "تب مشخصات اطلاعاتش واقعی نیست.",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه محصول",
description: "تب پرسش و پاسخ و محتوایی ندارد.",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه محصول",
description: "امکان ثبت نظر برای محصول فراهم نیست.",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه ویدئو",
description: "قسمت نمایش ویدئو به api وصل نیست.",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه ویدئو",
description: "اسلایدر کار نمیکند.",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه ویدئو",
description: "تب مشخصات و پرسش و پاسخ محتوایی ندارد.",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه ویدئو",
description: "تب سرفصل ها مرتب نیست.",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه ویدئو",
description: "اضافه کردن به سبد خرید کار نمیکند.",
status: 0,
developer: "",
},
{
title: "دسکتاپ - صفحه نمایش ویدئو",
description: "دیزاین این صفحه مرتب نیست کاملا.",
status: 0,
developer: "",
},
];
export default list;

@ -0,0 +1,66 @@
import React from "react";
import list from "./data";
const colors = ['bg-white', 'bg-blue-200', 'bg-green-200', 'bg-red-200'];
const statuses = ['کاری انجام نشده', 'در حال انجام', 'انجام شد', 'به مشکل خوردم'];
function Bugs({}) {
return (
<ul className="flex flex-col w-4/5 gap-4 mx-auto h-screen">
<div className="w-full flex justify-center mx-auto">
<div className="flex flex-col w-full">
<div className="w-full">
<div className="w-full ">
<table className="w-full">
<thead className="bg-gray-500">
<tr>
<th className="px-6 py-2 text-tiny text-white">Title</th>
<th className="px-6 py-2 text-tiny text-white">
Description
</th>
<th className="px-6 py-2 text-tiny text-white">Status</th>
<th className="px-6 py-2 text-tiny text-white">
Developer
</th>
</tr>
</thead>
<tbody
className="overflow-y-scroll"
style={{ minHeight: "100%" }}
>
{list.map((bug, index) => (
<tr
className={`whitespace-nowrap p-2 w-full border border-solid border-gray-300 ${
colors[bug.status]
}`}
key={bug.title}
>
<td className="px-6 py-4 text-center border border-solid border-gray-300">
<div className="text-sm text-gray-900">{bug.title}</div>
</td>
<td className="px-6 py-4 text-center border border-solid border-gray-300">
<div className="text-sm text-gray-900">
{bug?.description}
</div>
</td>
<td className="px-6 py-4 text-sm text-gray-900 text-center border border-solid border-gray-300">
{statuses[bug.status]}
</td>
<td className="px-6 py-4 text-center border border-solid border-gray-300">
<div className="text-sm text-gray-900">
{bug?.developer}
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
</ul>
);
}
export default Bugs;

@ -48,7 +48,7 @@ function Contact({ headerOptions, setHeaderOptions, info, isMobile, isDark }) {
return (
<div
className="w-full flex h-auto flex-col bg-transparent"
className="w-full flex h-auto flex-col bg-transparent lg:pt-36 lg:pb-24"
// style={{ height: "calc(100vh - 140px)" }}
>
<Header

@ -7,9 +7,9 @@ export const Dashboard = ({ isMobile }) => {
return isMobile ? (
<div className=""></div>
) : (
<div className="h-screen w-full bg-grayF9 py-5">
<div className="w-full bg-grayF9 py-5">
<div className="gap-5 w-11/12 h-full mx-auto flex flex-row bg-transparent">
<Sidebar />
{/* <Sidebar /> */}
<Main />
</div>
</div>

@ -0,0 +1,46 @@
import React from "react";
import { Link } from "react-router-dom";
import { Carousel } from "@trendyol-js/react-carousel";
import Product from '../../../../../../components/Product';
import arrow from "../../../../../../assets/icons/slider-arrow.svg";
function Suggestion({ products, grades, isMobile }) {
return (
<div className="flex flex-col mt-8 px-4">
<strong className="text-blueC0 dark:text-white font-bold text-sm lg:text-base">
پیشنهادات ما به شما
</strong>
{products.length > 0 && (
<div className="relative w-full" style={{ direction: "ltr" }}>
<Carousel
show={Math.round(window.innerWidth / 300)}
slide={2}
swiping={true}
useArrowKeys={true}
transition={0.5}
rightArrow={
<img
className="absolute top-1/2 transform -translate-y-1/2 cursor-pointer p-2"
src={arrow}
alt=""
/>
}
leftArrow={
<img
className="absolute top-1/2 transform -translate-y-1/2 -translate-x-5 cursor-pointer -rotate-180 p-2"
src={arrow}
alt=""
/>
}
>
{products.map((product, index) => (
<Product key={index} product={product} imageSize={4.5} />
))}
</Carousel>
</div>
)}
</div>
);
}
export default Suggestion;

@ -1,21 +1,35 @@
import React from "react";
import React, {useEffect} from "react";
import { connect } from "react-redux";
import {book} from '../../../../../redux/actions';
import MyBooks from "../../../../Home/Portrait/Private/MyBooks";
import Videos from "../../../../Home/Portrait/Private/Videos";
import ProductSuggestion from './ProductSuggestion';
export const UserItems = ({}) => {
export const UserItems = ({list, grades, getList, isMobile}) => {
useEffect(() => {
if(list.length <= 0){
getList();
}
},[]);
return (
<div className="flex-1 flex flex-col overflow-y-scroll">
<MyBooks />
<Videos />
<div className="w-full flex flex-col lg:pt-20">
<MyBooks books={list} grades={grades} />
<br/>
<Videos videos={list} grades={grades} />
<ProductSuggestion products={list} grades={grades} isMobile={isMobile} />
</div>
);
};
const mapStateToProps = (state) => ({});
const mapStateToProps = (state) => ({
list : state.book.list,
grades: state.publicApi.grades,
isMobile: state.publicApi.isMobile
});
const mapDispatchToProps = {};
const mapDispatchToProps = {
getList : book.list,
};
export default connect(mapStateToProps, mapDispatchToProps)(UserItems);

@ -1,20 +1,26 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import {publicApi} from '../../../../redux/actions';
import Orders from "../../../Orders";
import UserItems from "../Main/UserItems";
export const Main = ({}) => {
export const Main = ({setHeaderOptions}) => {
useEffect(() => {
setHeaderOptions({shown: true});
},[]);
const views = {
orders: <Orders />,
// orders: <Orders />,
userItems: <UserItems />
};
const [page, setPage] = useState("orders");
return <div className="flex-1 py-2.5 overflow-y-scroll">{views[page]}</div>;
const [page, setPage] = useState("userItems");
return <div className="w-full py-2.5">{views[page]}</div>;
};
const mapStateToProps = (state) => ({});
const mapDispatchToProps = {};
const mapDispatchToProps = {
setHeaderOptions: publicApi.setHeaderOptions,
};
export default connect(mapStateToProps, mapDispatchToProps)(Main);

@ -3,7 +3,7 @@ import { connect } from "react-redux";
import Button from "../../../components/Button";
import Radio from "../../../components/Radio";
function Address({ addresses, isDark, isMobile }) {
function Address({ addresses, isDark, isMobile, setPhase }) {
const [activeAddress, setActiveAddress] = useState(addresses[0]);
const Location = ({ address }) => {
return isMobile ? (
@ -97,7 +97,7 @@ function Address({ addresses, isDark, isMobile }) {
bgOpacity="bg-opacity-100"
width="100%"
color={isDark ? "text-white" : "text-gray70"}
onClick={() => {}}
onClick={() => setPhase("address")}
/>
</div>
</section>

@ -1,6 +1,6 @@
import React, { useEffect } from "react";
import { connect } from "react-redux";
import { publicApi, userFactor } from "../../redux/actions";
import { publicApi, userFactor, userAddress } from "../../redux/actions";
import Address from "./Address";
import TransportMethod from "./TransportMethod";
import TransportDate from "./TransportDate";
@ -10,6 +10,8 @@ import ExpressIcon from "../../assets/icons/express.svg";
import PishtazIcon from "../../assets/icons/pishtaz.svg";
export const DeliveryForm = ({
getList,
list,
setHeaderOptions,
headerOptions,
form,
@ -18,13 +20,14 @@ export const DeliveryForm = ({
userId,
isDark,
isMobile,
setPhase,
}) => {
useEffect(() => {
if (isMobile) {
setHeaderOptions(headerOptions);
}
getFactorInfo({ userId });
getList();
}, []);
const PriceStatus = ({ name, value, type }) => {
@ -82,7 +85,7 @@ export const DeliveryForm = ({
<span className="w-6 h-6 rounded-full bg-grayF4 flex justify-center items-center text-sm">
1
</span>
<Address addresses={form.addresses} />
<Address addresses={list} setPhase={setPhase} />
</div>
<div className="w-full flex flex-row gap-5 mt-8">
<span className="w-6 h-6 rounded-full bg-grayF4 flex justify-center items-center text-sm">
@ -105,11 +108,14 @@ const mapStateToProps = (state) => ({
userId: state.user.status.id,
isDark: state.publicApi.isDark,
isMobile: state.publicApi.isMobile,
list : state.userAddress.list
});
const mapDispatchToProps = {
setHeaderOptions: publicApi.setHeaderOptions,
getFactorInfo: userFactor.info,
getList: userAddress.list
};
export default connect(mapStateToProps, mapDispatchToProps)(DeliveryForm);

@ -18,8 +18,8 @@ function Faq({ headerOptions, setHeaderOptions, isMobile }) {
}, []);
return (
<div
className="w-full flex h-full flex-col bg-transparent"
style={{ height: "calc(100vh - 145px)" }}
className="w-full flex h-full flex-col bg-transparent lg:pt-36 lg:pb-24"
// style={{ height: "calc(100vh - 145px)" }}
>
<Header
bg={isMobile ? faqBgImage : desktopFaqBgImage}

@ -1,88 +1,87 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { book} from '../../../../redux/actions'
import { book } from "../../../../redux/actions";
import { Carousel } from "@trendyol-js/react-carousel";
import arrow from "../../../../assets/icons/slider-arrow.svg";
import { Link } from "react-router-dom";
import Product from '../../../../components/Product';
import Product from "../../../../components/Product";
import Button from "../../../../components/Button";
import ScrollContainer from "react-indiana-drag-scroll";
const Part2 = (
{ books,
getBooks,
grades}
) => {
console.log({books})
const [filter, setFilter] = useState({
search: "",
grade: "",
productsType: "کتاب",
});
useEffect(() => {
getBooks();
}, []);
return (
<div className="w-full my-6" style={{
height: '550px'
}}>
<div className="w-full flex justify-between items-center pr-10">
<div className="flex items-center text-4xl font-black text-blue52">
<div className="w-6 h-6 bg-blue-300 ml-4 rounded-full"></div>
<h1>
کتاب های جدید
</h1>
</div>
<div>
<Link to='/products'>
<Button
title="مشاهده لیست محصولات"
backgroundColor="bg-blue-100"
border={{
color: "#196EC055",
width: "0px",
}}
width="100%"
selectable={true}
// import ScrollContainer from "react-indiana-drag-scroll";
color= "text-blueC0"
onClick={() => null}
radius={false}
twPaddings="py-4 px-12 rounded"
/>
</Link>
</div>
</div>
<ScrollContainer className="flex overflow-x-scroll py-4 pl-10">
{
books?.slice(15,24).map((product, index) => (
<Link to={"/products/" + product?.id}>
<Product
key={`prod_New${index}`}
productsType={filter.productsType}
product={product}
index={Number(index)}
productName={`کتاب ${product?.name}`}
productCat={`پایه ${grades[product?.gradeId]}`}
productPrice={100000}
productImg={"https://dnvn.ir/api/v1/file/" + product?.fileIds}
numberOfRegards={160}
productTitleColor='text-blue5F'
productCatTextColor='text-blueC0'
productHolderBorder=''
productHolderHoverBorder='shadow-md'
hoverMode='blue'
big
starRate={Math.floor(Math.random() * 5) + 1}
const Part2 = ({ books, grades }) => {
// console.log({ books });
const [filter, setFilter] = useState({
search: "",
grade: "",
productsType: "کتاب",
});
return (
<div
className="w-full my-6"
style={
{
// height: "550px",
}
}
>
<div className="w-full flex justify-between items-center mb-4">
<div className="flex items-center text-4xl font-black text-blue52">
<div className="w-6 h-6 bg-blue-300 ml-4 rounded-full"></div>
<h1 className="text-2xl text-blue5F">کتاب های جدید</h1>
</div>
<div>
<Link to="/products">
<Button
title="مشاهده لیست محصولات"
backgroundColor="bg-blue-100"
border={{
color: "#196EC055",
width: "0px",
}}
width="100%"
selectable={true}
color="text-blueC0"
onClick={() => null}
radius={false}
twPaddings="py-4 px-12 rounded"
/>
</Link>
</div>
</div>
{books.length > 0 && (
<div className="relative w-full" style={{ direction: "ltr" }}>
<Carousel
show={Math.round(window.innerWidth / 350)}
slide={2}
swiping={true}
useArrowKeys={true}
transition={0.5}
rightArrow={
<img
className="absolute top-1/2 transform -translate-y-1/2 cursor-pointer p-2"
src={arrow}
alt=""
/>
}
leftArrow={
<img
className="absolute top-1/2 transform -translate-y-1/2 -translate-x-5 cursor-pointer -rotate-180 p-2"
src={arrow}
alt=""
/>
</Link>
}
>
{books.map((product, index) => (
<Product key={index} product={product} imageSize={3} />
))}
</ScrollContainer>
</Carousel>
</div>
)
}
)}
</div>
);
};
const mapStateToProps = (state) => ({
books: state.book.list,
isDark: state.publicApi.isDark,
isDark: state.publicApi.isDark,
});
export default connect(mapStateToProps, { getBooks: book.list })(Part2);
export default connect(mapStateToProps, {})(Part2);

@ -2,118 +2,110 @@ import React from "react";
import Button from "../../../../components/Button";
import VodProduct from "../../../../components/VodProduct";
import { Link } from "react-router-dom";
import posterImage from '../../../../assets/images/poster.svg'
const Part4 = () => {
const videosData = [
{
id: 0,
name: "ریاضی",
price: "145.000",
grade: " پایه چهارم ",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 2,
name: "علوم تجربی",
price: "145.000 ",
grade: "پایه سوم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 1,
name: "زمین شناسی",
price: "145.000 ",
grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 3,
name: "ریاضی",
price: "145.000 ",
grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 5,
name: "ریاضی",
price: "145.000 ",
grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 4,
name: "ریاضی",
price: "145.000 ",
grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
}
];
return <div className="w-full my-6" >
<div className="w-full flex justify-between items-center">
<div className="flex items-center text-4xl font-black text-blue52">
<div className="w-6 h-6 bg-blue-300 ml-4 rounded-full"></div>
<h1>
جدیدترین دوره های ویدیویی
</h1>
</div>
<div>
<Link to='/products'>
<Button
title="مشاهده لیست محصولات"
backgroundColor="bg-blue-100"
border={{
color: "#196EC055",
width: "0px",
}}
width="100%"
selectable={true}
color= "text-blueC0"
onClick={() => null}
radius={false}
twPaddings="py-4 px-12"
/>
</Link>
</div>
</div>
<ul className="py-6 my-10 border-t border-b border-solid border-gray-200 justify-center" style={{}}>
<ul className="flex flex-wrap justify-center ">
{
videosData.slice(0,6).map((video, index) => (
<li className={`flex flex-col border-solid border-gray-200 ${index != 3 && index != 4 && index != 5 ? 'border-b' : null} video ${index != 0 && index != 3 ?'border-r' : null}`}
style={{width: '33.333333%',}}>
<Link
to={"/videos/" + video.id}
import posterImage from "../../../../assets/images/poster.svg";
const Part4 = ({ books, grades }) => {
const videosData = [
{
id: 0,
name: "ریاضی",
price: "145.000",
grade: " پایه چهارم ",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 2,
name: "علوم تجربی",
price: "145.000 ",
grade: "پایه سوم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 1,
name: "زمین شناسی",
price: "145.000 ",
grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 3,
name: "ریاضی",
price: "145.000 ",
grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 5,
name: "ریاضی",
price: "145.000 ",
grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 4,
name: "ریاضی",
price: "145.000 ",
grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
];
return (
<div className="w-full my-6">
<div className="w-full flex justify-between items-center">
<div className="flex items-center text-4xl font-black text-blue52">
<div className="w-6 h-6 bg-blue-300 ml-4 rounded-full"></div>
<h1 className="text-2xl text-blue5F">جدیدترین دوره های ویدیویی</h1>
</div>
<div>
<Link to="/products">
<Button
title="مشاهده لیست محصولات"
backgroundColor="bg-blue-100"
border={{
color: "#196EC055",
width: "0px",
}}
width="100%"
selectable={true}
color="text-blueC0"
onClick={() => null}
radius={false}
twPaddings="py-4 px-12"
/>
</Link>
</div>
</div>
<ul
className="py-6 my-10 border-t border-b border-solid border-gray-200 justify-center"
style={{}}
>
<ul className="flex flex-wrap justify-center ">
{books.slice(0, 6).map((video, index) => (
<li
className={`flex flex-col border-solid border-gray-200 ${
index != 3 && index != 4 && index != 5 ? "border-b" : null
} video ${index != 0 && index != 3 ? "border-r" : null}`}
style={{ width: "33.333333%" }}
>
<VodProduct
productTitle={`دوره ی ویدیویی ${video.name}`}
productCat={video.grade}
price={video.price}
priceTitle={false}
discountPrice={false}
video={video}
key={index}
index={index}
minHeight={"calc(100vh / 3.5)"}
height={"calc(100vh / 3.8)"}
grades={grades}
/>
</Link>
</li>
))
}
</ul>
</ul>
</div>
}
</li>
))}
</ul>
</ul>
</div>
);
};
export default Part4;

@ -0,0 +1,78 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { book, publicApi } from "../../../../redux/actions";
// import ScrollContainer from "react-indiana-drag-scroll";
import { Carousel } from "@trendyol-js/react-carousel";
import arrow from "../../../../assets/icons/slider-arrow.svg";
import { Link } from "react-router-dom";
import Product from "../../../../components/Product";
import "./index.css";
const SalesContainer = ({ books }) => {
const [filter, setFilter] = useState({
search: "",
grade: "",
productsType: "کتاب",
});
return (
<div className="w-full my-10">
<div className="w-full py-10 pl-2 bg-white flex justify-between items-center gap-3">
<div className="flex flex-row items-center pl-4">
{/* <div className="w-6 h-6 bg-blue-300 ml-4 rounded-full"></div> */}
<div className="text-3xl leading-normal">
<h3 className=" bg-blueC0 text-white text-center"> دوشنبه </h3>
<h3
className="mr-4 text-center"
style={{ background: "#EFFF00" }}
>
{" "}
کتاااابی{" "}
</h3>
</div>
</div>
<div className="flex items-center">
<p className="text-md flex">بیش از ۵۰ کتاب تخفیف خورده&nbsp;</p>
<div className="w-6 h-6 bg-blue-300 mr-4 rounded-full"></div>
</div>
<span className="flex-1 h-0.5 bg-gray-200 mr-10"></span>
</div>
{books.length > 0 && (
<div className="relative w-full" style={{ direction: "ltr" }}>
<Carousel
show={Math.round(window.innerWidth / 350)}
slide={2}
swiping={true}
useArrowKeys={true}
transition={0.5}
rightArrow={
<img
className="absolute top-1/2 transform -translate-y-1/2 cursor-pointer p-2"
src={arrow}
alt=""
// onClick={(e) => e.stopPropagation()}
/>
}
leftArrow={
<img
className="absolute top-1/2 transform -translate-y-1/2 -translate-x-5 cursor-pointer -rotate-180 p-2"
src={arrow}
alt=""
// onClick={(e) => e.stopPropagation()}
/>
}
>
{books.map((product, index) => (
<Product key={index} product={product} imageSize={3} />
))}
</Carousel>
</div>
)}
</div>
);
};
const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark,
});
export default connect(mapStateToProps, { getList: book.list })(SalesContainer);

@ -1,92 +1,94 @@
import React, { useState, useEffect, useCallback } from "react";
import ScrollContainer from "react-indiana-drag-scroll";
import { connect } from 'react-redux';
import { Link } from "react-router-dom";
import filterIcon from '../../../assets/images/vuesax-linear-filter-tick.svg';
import Banners from "../../../components/Banners";
import SalesContainer from "../../../components/SalesContainer";
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import SalesContainer from "./SalesContainer";
import { book, publicApi } from "../../../redux/actions";
import { book, publicApi, product } from "../../../redux/actions";
import Part2 from "./Part2";
import HomeImg from '../../../assets/images/HomeImg.png';
import HomeImg from "../../../assets/images/HomeImg.png";
import Part4 from "./Part4";
import Design2D from "../../../components/Design2D";
const DesktopHome = (
{
books,
grades
}
const DesktopHome = ({ grades, getBooks, books }) => {
const banners = [
{
flex: 4,
items: [
{
bg: "",
flex: 1,
image:
"https://dkstatics-public.digikala.com/digikala-adservice-banners/d2a56a4a0c3ce4645bf0b405b0bbf3a29da1cbd3_1642861192.jpg",
},
],
},
{
flex: 2,
items: [
{
bg: "",
flex: 1,
image:
"https://dkstatics-public.digikala.com/digikala-adservice-banners/e13aefeda2d3b44db78a92aac9cdc82a9b1650e9_1632230372.jpg?",
},
{
bg: "",
flex: 1,
image:
"https://dkstatics-public.digikala.com/digikala-adservice-banners/fe8f275f4e4b5e6eb2f66cf65f3895398e049b40_1625578273.jpg",
},
],
},
{
flex: 2,
items: [
{
bg: "",
flex: 1,
image:
"https://dkstatics-public.digikala.com/digikala-adservice-banners/54d75e08cb0a72920ac3b2338232bf5ca70ccc74_1641638418.jpg",
},
],
},
];
) =>{
const banners = [
{
flex: 4,
items: [{ bg:'',
flex: 1,
image: 'https://dkstatics-public.digikala.com/digikala-adservice-banners/d2a56a4a0c3ce4645bf0b405b0bbf3a29da1cbd3_1642861192.jpg'
}],
},
{
flex: 2,
items: [
{ bg:'',
flex: 1,
image: 'https://dkstatics-public.digikala.com/digikala-adservice-banners/e13aefeda2d3b44db78a92aac9cdc82a9b1650e9_1632230372.jpg?'
},
{ bg:'',
flex: 1,
image: 'https://dkstatics-public.digikala.com/digikala-adservice-banners/fe8f275f4e4b5e6eb2f66cf65f3895398e049b40_1625578273.jpg'
},
],
},
{
flex: 2,
items: [{ bg:'',
flex: 1,
image: 'https://dkstatics-public.digikala.com/digikala-adservice-banners/54d75e08cb0a72920ac3b2338232bf5ca70ccc74_1641638418.jpg'
}],
},
]
useEffect(() => {
getBooks();
},[]);
return (
<div className="flex flex-col items-center w-11/12 justify-center my-10">
{/* <Banners
return (
<div className="flex flex-col items-center w-11/12 justify-center py-24">
{/* <Banners
mainBanner='https://dkstatics-public.digikala.com/digikala-adservice-banners/d2a56a4a0c3ce4645bf0b405b0bbf3a29da1cbd3_1642861192.jpg'
midBottomBanner='https://dkstatics-public.digikala.com/digikala-adservice-banners/e13aefeda2d3b44db78a92aac9cdc82a9b1650e9_1632230372.jpg?'
leftBanner=
midTopBanner='https://dkstatics-public.digikala.com/digikala-adservice-banners/fe8f275f4e4b5e6eb2f66cf65f3895398e049b40_1625578273.jpg'
/> */}
<div className="w-full">
<div className="w-full">
<Design2D array={banners} />
</div>
<SalesContainer books={books} grades={grades}/>
<Part2 grades={grades}/>
<div className="mb-16">
<img src={HomeImg} />
</div>
<Part4 />
</div>
<SalesContainer books={books} />
<Part2 grades={grades} books={books} />
<div className="mb-16">
<img src={HomeImg} />
</div>
<Part4 books={books} grades={grades} />
</div>
)
}
);
};
const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark,
isMobile: state.publicApi.isMobile,
books: state.book.list,
grades: state.publicApi.grades,
gradeFilterBooks: state.book.gradeFilterBooks,
selectedGrade: state.book.selectedGrade,
});
const mapDispatchToProps = {
getList: book.list,
gradeFilter: book.gradeFilter,
setHeaderOptions: publicApi.setHeaderOptions,
};
isDark: state.publicApi.isDark,
isMobile: state.publicApi.isMobile,
books: state.book.list,
gradeFilterBooks: state.book.gradeFilterBooks,
selectedGrade: state.book.selectedGrade,
grades: state.publicApi.grades,
});
export default connect(mapStateToProps, mapDispatchToProps)(DesktopHome);
const mapDispatchToProps = {
getBooks: book.list,
gradeFilter: book.gradeFilter,
setHeaderOptions: publicApi.setHeaderOptions,
};
export default connect(mapStateToProps, mapDispatchToProps)(DesktopHome);

@ -1,17 +1,13 @@
import React, { useEffect } from "react";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import { book } from "../../../../../redux/actions";
import Progress from '../../../../../components/Progress';
import { ScrollingCarousel } from "@trendyol-js/react-carousel";
import Progress from "../../../../../components/Progress";
function MyBooks({ list, getList, grades, isMobile }) {
useEffect(() => {
getList();
}, []);
const Book = ({ book}) => {
function MyBooks({ books, getList, grades, isMobile }) {
const Book = ({ book }) => {
return (
<li className="flex flex-col">
<li className="flex flex-col lg:ml-6 lg:p-2 lg:border lg:border-solid lg:border-gray-200 lg:shadow-md lg:rounded-md">
<Link to={"/products/" + book.id}>
<img
src={`https://dnvn.ir/api/v1/file/${book.fileIds}`}
@ -21,11 +17,15 @@ function MyBooks({ list, getList, grades, isMobile }) {
height: isMobile ? "" : "calc(100vh / 5)",
width: isMobile ? "" : "calc(100vh / 5 * 3 / 4)",
minHeight: isMobile ? "calc(100vh / 5)" : "",
minWidth: isMobile ? "calc(100vh / 5 * 3 / 4)" : ""
minWidth: isMobile ? "calc(100vh / 5 * 3 / 4)" : "",
}}
/>
<h2 className="mt-2 text-sm lg:text-tiny font-semibold text-blue5F dark:text-white lg:mt-4">{book.name}</h2>
<p className="font-medium text-blueC0 dark:text-greenBA text-xs lg:text-sm mt-1 lg:mt-2">{`پایه ${grades[book.gradeId]}`}</p>
<h2 className="mt-2 text-sm lg:text-tiny font-semibold text-blue5F dark:text-white lg:mt-4">
{book.name}
</h2>
<p className="font-medium text-blueC0 dark:text-greenBA text-xs lg:text-sm mt-1 lg:mt-2">{`پایه ${
grades[book.gradeId]
}`}</p>
<Progress percent={60} />
</Link>
</li>
@ -33,24 +33,33 @@ function MyBooks({ list, getList, grades, isMobile }) {
};
return (
<div className="w-full px-4 mb-5">
<div className="px-4 mb-5" style={{maxWidth: '100%'}}>
<div className="w-full flex flex-col rounded-md pt-4 lg:py-5 px-2 lg:px-4 bg-blueFF1 dark:bg-gray2077 overflow-hidden">
<strong className="text-blueC0 dark:text-white font-bold text-sm lg:text-base">کتابهای من</strong>
<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">
{list?.slice(0,5)?.map((book, index) => (
<Book book={book} key={index} />
))}
</ul>
<strong className="text-blueC0 dark:text-white font-bold text-sm lg:text-base">
کتابهای من
</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">
{books?.slice(0, 5)?.map((book, index) => (
<Book book={book} key={index} />
))}
</ul>
) : (
<div className="w-full scrolling-carousel mt-4 pb-2">
<ScrollingCarousel className="py-3">
{books?.map((book, index) => (
<Book book={book} key={index} />
))}
</ScrollingCarousel>
</div>
)}
</div>
</div>
);
}
const mapStateToProps = (state) => ({
list: state.book.list,
grades : state.publicApi.grades,
isMobile: state.publicApi.isMobile
isMobile: state.publicApi.isMobile,
});
export default connect(mapStateToProps, { getList: book.list })(MyBooks);
export default connect(mapStateToProps)(MyBooks);

@ -1,37 +1,33 @@
import React, { useEffect } from "react";
import { Link } from "react-router-dom";
import { ScrollingCarousel } from "@trendyol-js/react-carousel";
import { connect } from "react-redux";
import { book } from "../../../../../redux/actions";
import Progress from "../../../../../components/Progress";
import arrowBlueIcon from "../../../../../assets/icons/arrow-right-blue.svg";
import arrowWhiteIcon from "../../../../../assets/icons/arrow-left-white.svg";
function Videos({ list, getList, grades, isDark, isMobile }) {
useEffect(() => {
getList();
}, []);
const Book = ({ book }) => {
function Videos({ videos, grades, isDark, isMobile }) {
const Video = ({ video }) => {
return (
<li className="flex flex-col">
<Link to={"/products/" + book.name}>
<li className="flex flex-col lg:ml-6 lg:p-2 lg:border lg:border-solid lg:border-gray-200 lg:shadow-md lg:rounded-md">
<Link to={"/products/" + video.id}>
<img
src={`https://dnvn.ir/api/v1/file/${book.fileIds}`}
src={`https://dnvn.ir/api/v1/file/${video.posterId}`}
alt=""
className="rounded-sm"
style={{
height: isMobile ? "" : "calc(100vw / 8 * 2 / 4)",
width: isMobile ? "" : "calc(100vw / 8 )",
maxHeight: isMobile ? "calc(100vw / 2 * 2 / 3)" : "",
minWidth: isMobile ? "calc(100vw / 2)" : ""
minWidth: isMobile ? "calc(100vw / 2)" : "",
}}
/>
<h2 className="mt-2 text-sm font-semibold text-blue5F dark:text-white lg:mt-4 lg:text-tiny">
{book.name}
<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>
<p className="font-medium text-blueC0 dark:text-greenBA text-xs mt-1 lg:mt-2 lg:text-sm">{`پایه ${
grades[book.gradeId]
}`}</p>
{/* <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} />
</Link>
</li>
@ -39,7 +35,7 @@ function Videos({ list, getList, grades, isDark, isMobile }) {
};
return (
<div className="w-full px-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">
<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-blueFF1">
<header className="w-full flex flex-row justify-between items-center">
<strong className="text-blueC0 dark:text-white font-bold text-sm lg:text-base">
دورههای ویدئویی شما
@ -50,21 +46,27 @@ function Videos({ list, getList, grades, isDark, isMobile }) {
className={`transform lg:hidden ${isDark ? "w-7" : "rotate-180"}`}
/>
</header>
<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">
{list.slice(0,5)?.map((book, index) => (
<Book book={book} key={index} />
))}
</ul>
{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) => (
<Video video={video} key={index} />
))}
</ul>
) : (
<ScrollingCarousel className="mt-6 pb-3">
{videos?.map((video, index) => (
<Video video={video} key={index} />
))}
</ScrollingCarousel>
)}
</div>
</div>
);
}
const mapStateToProps = (state) => ({
list: state.book.list,
grades: state.publicApi.grades,
isDark: state.publicApi.isDark,
isMobile: state.publicApi.isMobile
isMobile: state.publicApi.isMobile,
});
export default connect(mapStateToProps, { getList: book.list })(Videos);
export default connect(mapStateToProps)(Videos);

@ -20,7 +20,7 @@ const status = {
function Order({ order, isMobile }) {
return (
<div className="w-full flex flex-col rounded-md overflow-hidden my-3 border border-solid border-blueFF1 dark:border-bluec0 dark:border-opacity-10">
<div className="w-full flex flex-col rounded-md overflow-hidden my-3 border border-solid border-blueFF1 dark:border-bluec0 dark:border-opacity-10 lg:w-3/5 mx-auto">
<div className="flex flex-row w-full justify-between items-center p-3 bg-blueFF1 dark:bg-blueC0 dark:bg-opacity-10">
<strong className="font-medium text-sm lg:text-tiny text-blue52 dark:text-white">
{_.join(["شماره سفارش:", order.number], " ")}

@ -10,7 +10,7 @@ function Orders({ orders, headerOptions, setHeaderOptions }) {
setHeaderOptions(headerOptions);
}, []);
return (
<div className="flex flex-col px-4">
<div className="flex flex-col px-4 lg:pb-20 lg:pt-24">
{orders.map((order, index) => (
<Order order={order} key={index} />
))}

@ -1,5 +1,6 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { toast } from "react-toastify";
import { book, userProduct, publicApi } from "../../../../redux/actions";
import proxy from "../../../../redux/proxy";
@ -27,24 +28,22 @@ export const ProductOverAll = ({
headerOptions,
setHeaderOptions,
}) => {
const [type, setType] = useState("physical");
const [type, setType] = useState("1");
return (
<div className="w-full">
<header className={`w-full flex flex-row justify-between gap-5`}>
<ProductImages />
<ProductImages images={book?.fileIds} />
<div className="flex flex-col w-1/2 divide-y divide-solid divide-gray-200">
<div className="w-full flex flex-col pr-2 py-2 border-0">
<h1 className="text-blue5F mb-3 font-semibold text-xl dark:text-white">
{type === "digital"
? book?.product[0]?.name
: book?.product[1]?.name}
<h1 className="text-blue5F mb-3 font-semibold text-lg dark:text-white">
{book?.product[type]?.name}
</h1>
<div className="text-blueC0 text-xs dark:text-greenBA">
<div className="text-blueC0 text-tiny dark:text-greenBA">
{"پایه" + " " + grades[book?.gradeId]}
</div>
<div className="flex justify-end">
<div className="flex justify-end items-center">
<div className="p-2">
<StarRating />
<StarRating value={book?.rate || 4} />
</div>
<div className="p-2 border-0 border-solid border-r border-gray-100 text-sm text-gray-400">
بیش از 160 نفر امتیاز داده اند
@ -68,9 +67,9 @@ export const ProductOverAll = ({
}}
width="38%"
color={isDark ? "text-white" : "text-blueC0"}
active={type === "physical"}
active={type === "1"}
selectable={true}
onClick={() => setType("physical")}
onClick={() => setType("1")}
borderType="dashed"
customStyle=""
twPaddings="py-4 px-12"
@ -85,9 +84,10 @@ export const ProductOverAll = ({
}}
width="38%"
selectable={true}
active={type === "digital"}
active={type === "0"}
color={isDark ? "text-white" : "text-blueC0"}
onClick={() => setType("digital")}
onClick={() => setType("0")}
borderType="dashed"
radius={false}
twPaddings="py-4 px-12"
/>
@ -107,27 +107,18 @@ export const ProductOverAll = ({
</div>
</div>
<div className="flex py-4">
<Button
title="مشاهده دوره ویدیویی این محصول >"
backgroundColor={isDark ? "bg-transparent" : "bg-blue-100'"}
border={{
color: isDark ? "#ffffff55" : "#196EC055",
width: "2px",
}}
color={isDark ? "text-white" : "text-blue52"}
selectable={true}
onClick={() => setType("physical")}
customStyle=" bg-blue-100"
twPaddings="py-4 px-32"
radius={false}
/>
<Link
to={"/videos/" + book?.id}
className="bg-blueFF1 text-blueC0 text-tiny rounded-sm border border-solid border-blueC0 w-2/3 py-4 text-center"
>
مشاهده دوره ویدیویی این محصول
</Link>
</div>
</div>
<div className="flex flex-col w-1/3">
<ProductStatusCard />
<ProductStatusCard price={book?.product[type]?.price} id={book?.product[type]?.id} />
</div>
</header>
</div>
);
};

@ -42,144 +42,155 @@ export const Product = ({
<>
{/* Portrait */}
{isMobile ? (
<div className="w-full flex flex-col bg-transparent px-4">
<header
className={`w-full flex ${
productType === "book" ? "flex-row" : "flex-col"
}`}
>
<img
src={`https://dnvn.ir/api/v1/file/${book?.fileIds}`}
alt=""
className="w-5/12 rounded-md"
/>
<div className="flex flex-1 flex-col pr-2 pt-2">
<h1 className="text-blue5F mb-3 font-semibold text-sm dark:text-white">
{type === "digital"
? book?.product[0]?.name
: book?.product[1]?.name}
</h1>
<div className="text-blueC0 text-xs dark:text-greenBA">
{"پایه" + " " + grades[book?.gradeId]}
<div className="w-full flex flex-col bg-transparent px-4">
<header
className={`w-full flex ${
productType === "book" ? "flex-row" : "flex-col"
}`}
>
<img
src={`https://dnvn.ir/api/v1/file/${book?.fileIds}`}
alt=""
className="w-5/12 rounded-md"
/>
<div className="flex flex-1 flex-col pr-2 pt-2">
<h1 className="text-blue5F mb-3 font-semibold text-sm dark:text-white">
{type === "digital"
? book?.product[0]?.name
: book?.product[1]?.name}
</h1>
<div className="text-blueC0 text-xs dark:text-greenBA">
{"پایه" + " " + grades[book?.gradeId]}
</div>
</div>
</header>
<ul
className="list-none flex flex-row divide-x items-center mt-4"
style={{ direction: "ltr" }}
>
<li className="border-solid border-blueFE flex-1 flex-shrink-0 text-center text-xs font-medium text-blueC0 dark:text-white">
{book?.pagesNum} <br /> صفحه
</li>
<li className="border-solid border-blueFE flex-1 flex-shrink-0 text-center text-xs font-medium text-blueC0 dark:text-white">
{"فیزیکی - دیجیتالی"} <br /> در دسترس
</li>
<li className="border-solid border-blueFE flex-1 flex-shrink-0 text-center text-xs font-medium text-blueC0 dark:text-white">
{book?.rate} <br /> امتیاز
</li>
</ul>
<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">
<Button
title="نسخه فیزیکی"
backgroundColor={isDark ? "bg-transparent" : "bg-white"}
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">
<Button
onClick={() =>
proxy.status()
? pushToCart({
productId:
type === "digital"
? book?.product[0]?.id
: book?.product[1]?.id,
userId: userId,
count: 1,
})
: toast.info("ابتدا وارد حساب کاربری خود شوید.")
}
title={
"خرید با قیمت" +
" " +
(type === "digital"
? book?.product[0]?.price
: book?.product[1]?.price) +
" " +
"تومان"
}
backgroundColor="bg-blueC0"
border={{ color: "#196EC055", width: "1px" }}
width="65%"
color="text-white"
/>
<Button
title="مشاهده نمونه"
backgroundColor={isDark ? "bg-transparent" : "bg-white"}
border={{
color: isDark ? "#ffffff55" : "#196EC055",
width: "1px",
}}
width="33%"
color={isDark ? "text-white" : "text-blueC0"}
onClick={() => {}}
/>
</div>
<div className="w-full flex flex-row justify-between items-center mt-4">
<Button
title="مشاهده دوره ویدئویی این محصول"
backgroundColor="bg-blueC0"
border={{ color: "#196EC055", width: "0px" }}
bgOpacity="bg-opacity-10"
width="100%"
color={isDark ? "text-white" : "text-blueC0"}
onClick={() => {}}
/>
</div>
<div className="w-full flex flex-col justify-between items-center mt-4">
<Header title="توضیحات" link="#" />
<p className="text-xs text-gray1 mt-2 dark:text-white">
خالد حسینی تو رمان باد بادک باز مینویسه : ﻣﺮﺩ ﺁﻫﺴﺘﻪ ﺩﺭ ﮔﻮﺵ ﻓﺮﺯﻧﺪ
ﺗﺎﺯﻩ ﺑﻪ ﺑﻠﻮﻍ ﺭﺳﯿﺪﻩ ﺍﺵ ﺑﺮﺍﯼ ﭘﻨﺪ ﭼﻨﯿﻦ ﻧﺠﻮﺍ ﮐﺮﺩ : ﭘﺴﺮﻡ ﺩﺭ ﺯﻧﺪﮔﯽ
ﻫﺮﮔﺰ ﺩﺯﺩﯼ ﻧﮑﻦ ﭘﺴﺮ ﻣﺘﻌﺠﺐ ﻣﺒﻬﻮﺕ ﺑﻪ ﭘﺪﺭ ﻧﮕﺎﻩ ﮐﺮﺩ ﺑﺪﯾﻦ ﻣﻌﻨﺎ ﮐﻪ ﺍﻭ
ﻫﺮﮔﺰ ﺩﺳﺖ ﮐﺞ ﻧﺪﺍﺷﺘﻪ ﭘﺪﺭ ﺑﻪ ﻧﮕﺎﻩ ﻣﺘﻌﺠﺐ ﻓﺮﺯﻧﺪ ﻟﺒﺨﻨﺪﯼ ﺯﺩ ﺍﺩﺍﻣﻪ ﺩﺍﺩ :
ﺩﺭ ﺯﻧﺪﮔﯽ ﺩﺭﻭﻍ ﻧﮕﻮ ﭼﺮﺍ ﮐﻪ ﺍﮔﺮ ﮔﻔﺘﯽ ﺻﺪﺍﻗﺖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ ﺍﯼ، ﺧﯿﺎﻧﺖ ﻧﮑﻦ ﮐﻪ
ﺍﮔﺮ ﮐﺮﺩﯼ ﻋﺸﻖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ ﺍﯼ، ﺧﺸﻮﻧﺖ ﻧﮑﻦ ﺍﮔﺮ ﮐﺮﺩﯼ ﻣﺤﺒﺖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ ﺍﯼ،
ﻧﺎ ﺣﻖ ﻧﮕﻮ ﺍﮔﺮ ﮔﻔﺘﯽ ﺣﻖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ ﺍﯼ، ﺑﯽ ﺣﯿﺎﯾﯽ ﻧﮑﻦ ﺍﮔﺮ ﮐﺮﺩﯼ ﺷﺮﺍﻓﺖ ﺭﺍ
ﺩﺯﺩﯾﺪﻩ ﺍی... ﭘﺲ ﺩﺭ ﺯﻧﺪﮔﯽ ﻓﻘﻂ ﺩﺯﺩﯼ نکن{" "}
</p>
</div>
<div className="w-full flex flex-col justify-between items-center mt-4">
<Header title="امتیازات و نظرات" link="#" />
<Rate />
</div>
<div
className="flex flex-row w-full pb-4 mt-6"
style={{ overflowX: "scroll" }}
>
{[0, 1, 2, 2].map((comment, index) => (
<Comment key={index} />
))}
</div>
</header>
<ul
className="list-none flex flex-row divide-x items-center mt-4"
style={{ direction: "ltr" }}
>
<li className="border-solid border-blueFE flex-1 flex-shrink-0 text-center text-xs font-medium text-blueC0 dark:text-white">
{book?.pagesNum} <br /> صفحه
</li>
<li className="border-solid border-blueFE flex-1 flex-shrink-0 text-center text-xs font-medium text-blueC0 dark:text-white">
{"فیزیکی - دیجیتالی"} <br /> در دسترس
</li>
<li className="border-solid border-blueFE flex-1 flex-shrink-0 text-center text-xs font-medium text-blueC0 dark:text-white">
{book?.rate} <br /> امتیاز
</li>
</ul>
<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">
<Button
title="نسخه فیزیکی"
backgroundColor={isDark ? "bg-transparent" : "bg-white"}
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">
<Button
onClick={() =>
proxy.status()
? pushToCart({
productId:
type === "digital"
? book?.product[0]?.id
: book?.product[1]?.id,
userId: userId,
count: 1,
})
: toast.info("ابتدا وارد حساب کاربری خود شوید.")
}
title={
"خرید با قیمت" +
" " +
(type === "digital"
? book?.product[0]?.price
: book?.product[1]?.price) +
" " +
"تومان"
}
backgroundColor="bg-blueC0"
border={{ color: "#196EC055", width: "1px" }}
width="65%"
color="text-white"
/>
<Button
title="مشاهده نمونه"
backgroundColor={isDark ? "bg-transparent" : "bg-white"}
border={{ color: isDark ? "#ffffff55" : "#196EC055", width: "1px" }}
width="33%"
color={isDark ? "text-white" : "text-blueC0"}
onClick={() => {}}
/>
</div>
<div className="w-full flex flex-row justify-between items-center mt-4">
<Button
title="مشاهده دوره ویدئویی این محصول"
backgroundColor="bg-blueC0"
border={{ color: "#196EC055", width: "0px" }}
bgOpacity="bg-opacity-10"
width="100%"
color={isDark ? "text-white" : "text-blueC0"}
onClick={() => {}}
/>
</div>
<div className="w-full flex flex-col justify-between items-center mt-4">
<Header title="توضیحات" link="#" />
<p className="text-xs text-gray1 mt-2 dark:text-white">
خالد حسینی تو رمان باد بادک باز مینویسه : ﻣﺮﺩ ﺁﻫﺴﺘﻪ ﺩﺭ ﮔﻮﺵ ﻓﺮﺯﻧﺪ
ﺗﺎﺯﻩ ﺑﻪ ﺑﻠﻮﻍ ﺭﺳﯿﺪﻩ ﺍﺵ ﺑﺮﺍﯼ ﭘﻨﺪ ﭼﻨﯿﻦ ﻧﺠﻮﺍ ﮐﺮﺩ : ﭘﺴﺮﻡ ﺩﺭ ﺯﻧﺪﮔﯽ ﻫﺮﮔﺰ
ﺩﺯﺩﯼ ﻧﮑﻦ ﭘﺴﺮ ﻣﺘﻌﺠﺐ ﻣﺒﻬﻮﺕ ﺑﻪ ﭘﺪﺭ ﻧﮕﺎﻩ ﮐﺮﺩ ﺑﺪﯾﻦ ﻣﻌﻨﺎ ﮐﻪ ﺍﻭ ﻫﺮﮔﺰ
ﺩﺳﺖ ﮐﺞ ﻧﺪﺍﺷﺘﻪ ﭘﺪﺭ ﺑﻪ ﻧﮕﺎﻩ ﻣﺘﻌﺠﺐ ﻓﺮﺯﻧﺪ ﻟﺒﺨﻨﺪﯼ ﺯﺩ ﺍﺩﺍﻣﻪ ﺩﺍﺩ : ﺩﺭ
ﺯﻧﺪﮔﯽ ﺩﺭﻭﻍ ﻧﮕﻮ ﭼﺮﺍ ﮐﻪ ﺍﮔﺮ ﮔﻔﺘﯽ ﺻﺪﺍﻗﺖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ ﺍﯼ، ﺧﯿﺎﻧﺖ ﻧﮑﻦ ﮐﻪ ﺍﮔﺮ
ﮐﺮﺩﯼ ﻋﺸﻖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ ﺍﯼ، ﺧﺸﻮﻧﺖ ﻧﮑﻦ ﺍﮔﺮ ﮐﺮﺩﯼ ﻣﺤﺒﺖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ ﺍﯼ، ﻧﺎ ﺣﻖ
ﻧﮕﻮ ﺍﮔﺮ ﮔﻔﺘﯽ ﺣﻖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ ﺍﯼ، ﺑﯽ ﺣﯿﺎﯾﯽ ﻧﮑﻦ ﺍﮔﺮ ﮐﺮﺩﯼ ﺷﺮﺍﻓﺖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ
ﺍی... ﭘﺲ ﺩﺭ ﺯﻧﺪﮔﯽ ﻓﻘﻂ ﺩﺯﺩﯼ نکن{" "}
</p>
</div>
<div className="w-full flex flex-col justify-between items-center mt-4">
<Header title="امتیازات و نظرات" link="#" />
<Rate />
</div>
<div
className="flex flex-row w-full pb-4 mt-6"
style={{ overflowX: "scroll" }}
>
{[0, 1, 2, 2].map((comment, index) => (
<Comment key={index} />
))}
) : (
<div className="flex flex-col items-center justify-center lg:py-24">
<DesktopProductLayout />
</div>
</div>) :<div className="flex flex-col items-center justify-center">
<DesktopProductLayout />
</div>
}
)}
</>
);
};
@ -189,7 +200,7 @@ const mapStateToProps = (state) => ({
grades: state.publicApi.grades,
isMobile: state.publicApi.isMobile,
isDark: state.publicApi.isDark,
userId: state.user.status.id,
userId: state.user.status?.id,
});
const mapDispatchToProps = {

@ -23,15 +23,12 @@ export const Products = ({
headerOptions,
desktopContentTransform,
}) => {
const [filter, setFilter] = useState({
search: "",
grade: "",
productsType: "کتاب",
});
const onChange = (name, value) => {
setFilter({ ...filter, [name]: value });
};
@ -45,8 +42,6 @@ export const Products = ({
gradeFilter(filter.grade);
}, [filter]);
const Product = ({ productsType, product, index }) => {
return (
<>
@ -80,7 +75,7 @@ export const Products = ({
<img
src={"https://dnvn.ir/api/v1/file/" + product?.fileIds}
className="w-full rounded-md mb-2"
style={{height : "calc(100vh / 5)"}}
style={{ height: "calc(100vh / 5)" }}
/>
<strong className="text-blue5F dark:text-white text-tiny font-bold mb-2">
{product?.name}
@ -149,7 +144,6 @@ export const Products = ({
/>
))
: books?.map((product, index) => (
<Product
key={index}
productsType={filter.productsType}
@ -161,13 +155,15 @@ export const Products = ({
</>
) : (
<div
className={`w-full flex flex-row gap-10 px-5 overflow-y-hidden mt-3 justify-center`}
// style={{ height: 1500 }}
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-4/5 flex">
<Sidebar onChange={onChange}/>
<Main filter={filter}/>
<div className="w-11/12 flex flex-row gap-5">
<Sidebar onChange={onChange} />
<Main
filter={filter}
books={books}
grades={grades}
/>
</div>
</div>
)}
@ -180,6 +176,7 @@ 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,

@ -1,18 +1,17 @@
import React, { useState, useEffect, useCallback } from "react";
import ScrollContainer from "react-indiana-drag-scroll";
import { connect } from 'react-redux';
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import filterIcon from '../../../assets/images/vuesax-linear-filter-tick.svg';
import { Carousel } from "@trendyol-js/react-carousel";
import Product from '../../../components/Product'
import filterIcon from "../../../assets/images/vuesax-linear-filter-tick.svg";
import Product from "../../../components/Product";
import VodProduct from "../../../components/VodProduct";
import { book, publicApi } from "../../../redux/actions";
import { book, publicApi, product } from "../../../redux/actions";
import posterImage from "../../../assets/images/poster.svg";
import arrow from "../../../assets/icons/slider-arrow.svg";
export const Main = ({ isMobile,
export const Main = ({
books,
getList,
grades,
gradeFilter,
selectedGrade,
@ -20,170 +19,121 @@ export const Main = ({ isMobile,
setHeaderOptions,
headerOptions,
videos,
filter }) => {
useEffect(() => {
window.scrollTo(0, 0)
}, [])
filter,
}) => {
useEffect(() => {
window.scrollTo(0, 0);
}, []);
const filteringNavItems = [
{
title: 'بیشترین بازدید'
title: "بیشترین بازدید",
},
{
title: 'پرفروش ترین'
title: "پرفروش ترین",
},
{
title: 'کمترین قیمت'
title: "کمترین قیمت",
},
{
title: 'بیشترین قیمت'
title: "بیشترین قیمت",
},
{
title: 'محبوب ترین'
title: "محبوب ترین",
},
];
const videosData = [
{
id: 0,
name: "ریاضی",
price: "145.000",
grade: " پایه چهارم ",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 2,
name: "علوم تجربی",
price: "145.000 ",
grade: "پایه سوم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 1,
name: "زمین شناسی",
price: "145.000 ",
grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 3,
name: "ریاضی",
price: "145.000 ",
grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
},
{
id: 5,
name: "ریاضی",
price: "145.000 ",
grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
}
]
return <div className="flex flex-col w-3/4 p-4">
<div className="flex w-full bg-blue rounded-lg border border-solid border-gray-200 p-2 items-center my-1.5 justify-center text-blue52">
<div className='flex text-xs items-center mx-4'>
<img src={filterIcon} />
<span>
مرتب سازی بر اساس
</span>
</div>
<ul className='flex justify-between w-3/4 px-4 py-0 '>
{
filteringNavItems.map(e => (
<li className='text-sm rounded py-2 px-6 transition-all duration-700 hover:bg-gray-300 hover:text-blueC0 cursor-pointer' onClick={() => console.log('a')}>{e.title}</li>
))
}
</ul>
</div>
<ScrollContainer className="flex">
{
videosData.map((video, index) => (
<Link
to={"/videos/" + video.id}
className="flex flex-col rounded-md ml-4 "
return (
<div className="flex flex-col w-3/4 p-4 pb-20">
<div className="flex w-full bg-blue rounded-lg border border-solid border-gray-200 p-2 items-center my-1.5 justify-center text-blue52">
<div className="flex text-xs items-center mx-4">
<img src={filterIcon} />
<span>مرتب سازی بر اساس</span>
</div>
<ul className="flex justify-between w-3/4 px-4 py-0 ">
{filteringNavItems.map((e) => (
<li
className="text-sm rounded py-2 px-6 transition-all duration-700 hover:bg-gray-300 hover:text-blueC0 cursor-pointer"
onClick={() => console.log("a")}
>
{e.title}
</li>
))}
</ul>
</div>
{books?.length > 0 && (
<div className="relative w-full" style={{ direction: "ltr" }}>
<Carousel
show={Math.round(window.innerWidth / 500)}
slide={2}
swiping={true}
useArrowKeys={true}
transition={0.5}
className="flex flex-row"
rightArrow={
<img
className="absolute top-1/2 transform -translate-y-1/2 cursor-pointer p-2"
src={arrow}
alt=""
/>
}
leftArrow={
<img
className="absolute top-1/2 transform -translate-y-1/2 -translate-x-5 cursor-pointer -rotate-180 p-2"
src={arrow}
alt=""
/>
}
>
{books?.map((video, index) => (
<VodProduct
productTitle={`دوره ی ویدیویی ${video.name}`}
productCat={video.grade}
price={video.price}
priceTitle={false}
discountPrice={false}
key={index}
index={index}
minHeight={"250px"}
video={video}
key={index}
index={index}
height={"calc(100vh / 5)"}
grades={grades}
/>
</Link>
))
}
</ScrollContainer>
))}
</Carousel>
</div>
)}
<div className="w-full flex flex-row flex-wrap mt-0 border-t-2 border-solid border-gray-100 overflow-y-hidden justify-between">
<div className="w-full flex flex-row flex-wrap mt-0 border-t-2 border-solid border-gray-100 overflow-y-hidden justify-evenly">
{selectedGrade
? gradeFilterBooks?.map((product, index) => (
<Product
key={index}
productsType={filter.productsType}
product={product}
index={Number(index)}
grades={grades}
roductName={`کتاب ${product?.name}`}
productCat={`پایه ${grades[product?.gradeId]}`}
productPrice={100000}
productImg={"https://dnvn.ir/api/v1/file/" + product?.fileIds}
numberOfRegards={160}
productTitleColor='text-blue5F'
productCatTextColor='text-blueC0'
productHolderBorder=''
productHolderHoverBorder='shadow-md'
starRate={Math.floor(Math.random() * 5) + 1}
/>
))
: books?.map((product, index) => (
<Link to={"/products/" + product?.id}>
<Product
key={index}
productsType={filter.productsType}
product={product}
index={Number(index)}
productName={`کتاب ${product?.name}`}
productCat={`پایه ${grades[product?.gradeId]}`}
productPrice={100000}
productImg={"https://dnvn.ir/api/v1/file/" + product?.fileIds}
numberOfRegards={160}
productTitleColor='text-blue5F'
productCatTextColor='text-blueC0'
productHolderBorder=''
productHolderHoverBorder='shadow-md'
starRate={Math.floor(Math.random() * 5) + 2}
grades={grades}
imageSize={4.5}
/>
</Link>
))}
))
: books?.map((product, index) => (
<Link
to={"/products/" + product?.id}
className="w-full lg:w-1/3 xl:w-1/4 2xl:w-1/5"
>
<Product
product={product}
index={Number(index)}
imageSize={4.5}
grades={grades}
/>
</Link>
))}
</div>
</div>;
</div>
);
};
Main.defaultProps ={
videos: [
]
}
Main.defaultProps = {
videos: [],
};
const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark,
isMobile: state.publicApi.isMobile,
books: state.book.list,
grades: state.publicApi.grades,
gradeFilterBooks: state.book.gradeFilterBooks,
selectedGrade: state.book.selectedGrade,
});
const mapDispatchToProps = {

@ -3,69 +3,33 @@ import { connect } from "react-redux";
import Checkbox from "../../../components/Checkbox";
import VerticalExpandableProductFilter from "../../../components/VerticalExpandableProductFilter";
export const Sidebar = ({onChange}) => {
const filteronGrade = [
{
id:0,
name: "اول",
expaneded: false,
subList: [{
id:1,
name: 'علوم اجتماعی'
}],
},
{
id:1,
name: "دوم",
expaneded: false,
subList: [{
id:1,
name: 'علوم اجتماعی'
}],
},
{
id:2,
name: "سوم",
expaneded: false,
subList: [],
},
];
export const Sidebar = ({ onChange, grades }) => {
const categories = [
{
id: 0,
expaneded: false,
name: 'کتاب فیزیکی',
subList: []
},
{
id: 1,
expaneded: false,
name: 'کتاب دیجیتال',
subList: []
},
{
id: 2,
expaneded: false,
name: 'دوره ویدیویی',
subList: []
},
{
id: 3,
expaneded: false,
name: 'بسته های آموزشی',
subList: []
},
]
return <div className="flex flex-col w-1/4 p-4">
<VerticalExpandableProductFilter onChange={onChange} name="grade" preName='پایه' btnTitle='مشاهده همه ی کالاهای آموزشی' list={filteronGrade} title="پایه تحصیلی" searchAble={true}/>
<VerticalExpandableProductFilter name="category" list={categories} title="دسته بندی" searchAble={false}/>
</div>;
"کتاب فیزیکی",
"کتاب دیجیتال",
"دوره ویدیویی",
"بسته های آموزشی",
];
return (
<div className="flex flex-col w-1/4 p-4">
<VerticalExpandableProductFilter
onChange={onChange}
name="grade"
list={Object.values(grades)}
title="پایه تحصیلی"
/>
<VerticalExpandableProductFilter
name="category"
list={categories}
title="دسته بندی"
/>
</div>
);
};
const mapStateToProps = (state) => ({});
const mapStateToProps = (state) => ({
grades: state.publicApi.grades,
});
const mapDispatchToProps = {};

@ -12,14 +12,14 @@ export const Content = ({
}) => {
useEffect(() => {
const path = window.location.pathname;
console.log(path.slice(path.lastIndexOf("/") + 1, path.length));
// console.log(path.slice(path.lastIndexOf("/") + 1, path.length));
setHeaderOptions(headerOptions);
getQrData({ tail: path.slice(path.lastIndexOf("/") + 1, path.length) });
}, []);
useEffect(() => {
if (data) {
console.log(data?.book?.name);
// console.log(data?.book?.name);
}
}, [data]);

@ -18,7 +18,7 @@ export const Scan = ({
};
const handleError = (err) => {
console.error(err);
// console.error(err);
};
useEffect(() => {

@ -139,9 +139,20 @@ function Product({ product, grades, pushToCart, isMobile }) {
&nbsp;{product?.product?.price}&nbsp;&nbsp;تومان
</strong>
<img
onClick={() =>
pushToCart(
{
productId: product?.productId,
userId: product?.userId,
count: product?.productType === 1 ? -1 : -product?.count,
},
{},
{ id: product?.factorId }
)
}
src={deleteIcon}
alt="delete"
className="border border-red-800 border-solid p-1 w-8 bg-red-100 rounded-md mr-4"
className="border border-red-800 border-solid p-1 w-8 bg-red-100 rounded-md mr-4 cursor-pointer"
/>
</div>
</div>

@ -3,10 +3,12 @@ import { userProduct, userFactor, publicApi } from "../../redux/actions";
import DeliveryForm from "../DeliveryForm";
import Product from "./Product";
import Address from "../Address";
import Code from "./Code";
import Button from "../../components/Button";
//assets
import dropdownIcon from "../../assets/icons/dropdown-blue.svg";
import alertIcon from "../../assets/icons/alert.svg";
import { connect } from "react-redux";
@ -17,7 +19,7 @@ function ShoppingCart({
list,
payPrice,
factorInfo,
userId,
user,
hasPhysical,
getList,
getInfo,
@ -31,10 +33,19 @@ function ShoppingCart({
useEffect(() => {
getList();
getFactorInfo({ userId });
getFactorInfo({ userId: user?.id });
setHeaderOptions(headerOptions);
}, []);
const next = {
products: () => setPhase("deliveryForm"),
deliveryForm: () => console.log("Go to shaparak"),
profile: () => {
console.log("Set profile");
console.log("Go to shaparak");
},
};
const Table = () => {
return (
<div className="w-full flex flex-col">
@ -50,9 +61,10 @@ function ShoppingCart({
</strong>
</header>
<ul className="w-full mt-2 list-none p-0">
{list.map((product, index) => (
<Product key={index} product={product} />
))}
{list.map(
(product, index) =>
product.condition < 2 && <Product key={index} product={product} />
)}
</ul>
</div>
);
@ -96,6 +108,12 @@ function ShoppingCart({
);
};
const layouts = {
products: <Table />,
deliveryForm: <DeliveryForm setPhase={setPhase} />,
address: <Address setPhase={setPhase} />,
};
return isMobile ? (
<div className="w-full flex flex-col px-4">
{list.map((product, index) => (
@ -147,95 +165,104 @@ function ShoppingCart({
</div>
) : (
<div
className={`w-full flex flex-row relative gap-10 px-5 mt-10 ${
className={`w-11/12 mx-auto flex flex-row relative gap-10 px-5 mt-10 pb-20 pt-24 ${
desktopContentTransform ? "top-24" : ""
}`}
>
<div className="flex flex-col w-3/4">
{phase === "products" && <Table />}
{phase === "delivery-form" && <DeliveryForm />}
</div>
<div
className="flex flex-col w-1/4 p-10 bg-grayF9 border border-solid border-grayDB rounded-md px-4 py-4"
style={{ height: "fit-content" }}
>
<div className="flex flex-col w-full border-t py-2 border-gray-300 border-b">
<PriceStatus
name="مبلغ سبد خرید"
value={factorInfo?.sumPrice}
type="normal"
/>
<PriceStatus
name="میزان تخفیف"
value={factorInfo?.offPrice}
type="error"
/>
<PriceStatus
name="مالیات بر ارزش افزوده"
value={factorInfo?.sumPrice * 0.009}
type="error"
/>
</div>
<div className="flex flex-row justify-between items-center w-full py-4 border-t border-b border-grayDB border-solid">
<strong className="font-medium text-tiny text-blue5F dark:text-white">
جمع کل سبد خرید
</strong>
<p className="font-medium text-greenBA text-xl dark:text-white">
{factorInfo?.payPrice}
<span className="font-medium text-greenBA text-sm mr-2">تومان</span>
</p>
</div>
{phase === "products" && (
<div
className="w-full rounded-md flex flex-row justify-center items-center py-2.5 px-3 mt-10 mb-4"
style={{ backgroundColor: "#196EC01a" }}
>
<img src={alertIcon} className="w-5 ml-2" />
<p className="text-xs text-blueC0 dark:text-white text-justify">
هزینه ارسال کالا پس از تعیین محل آدرس مشخص میشود
</p>
</div>
)}
{phase === "delivery-form" && (
<div className="flex flex-col mt-10">
<strong className="text-tiny text-blue52 mb-5 font-medium">
انتخاب شیوه پرداخت
</strong>
<Button
title="ادامه فرایند خرید"
backgroundColor="bg-transparent"
border={{ color: "#77777755", width: "1px" }}
width="100%"
color="text-blue52"
onClick={() =>
setPhase(phase === "products" ? "delivery-form" : "")
}
<div className="flex flex-col flex-1">{layouts[phase]}</div>
{phase !== "address" && (
<div
className="flex flex-col w-1/4 p-10 bg-grayF9 border border-solid border-grayDB rounded-md px-4 py-4"
style={{ height: "fit-content" }}
>
<div className="flex flex-col w-full border-t py-2 border-gray-300 border-b">
<PriceStatus
name="مبلغ سبد خرید"
value={factorInfo?.sumPrice}
type="normal"
/>
<br />
<Button
title="پرداخت در محل"
backgroundColor="bg-transparent"
border={{ color: "#77777755", width: "1px" }}
width="100%"
color="text-blue52"
onClick={() =>
setPhase(phase === "products" ? "delivery-form" : "")
}
<PriceStatus
name="میزان تخفیف"
value={factorInfo?.offPrice}
type="error"
/>
<PriceStatus
name="مالیات بر ارزش افزوده"
value={Math.floor(factorInfo?.sumPrice * 0.009)}
type="error"
/>
<br/>
<br/>
</div>
)}
<Button
title="ادامه فرایند خرید"
backgroundColor="bg-blueC0"
border={{ color: "#196EC055", width: "1px" }}
width="100%"
color="text-white"
onClick={() => setPhase(phase === "products" ? "delivery-form" : "")}
/>
</div>
<div className="flex flex-row justify-between items-center w-full py-4 border-t border-b border-grayDB border-solid">
<strong className="font-medium text-tiny text-blue5F dark:text-white">
جمع کل سبد خرید
</strong>
<p className="font-medium text-greenBA text-xl dark:text-white">
{factorInfo?.payPrice}
<span className="font-medium text-greenBA text-sm mr-2">
تومان
</span>
</p>
</div>
{phase === "products" && (
<div
className="w-full rounded-md flex flex-row justify-center items-center py-2.5 px-3 mt-10 mb-4"
style={{ backgroundColor: "#196EC01a" }}
>
<img src={alertIcon} className="w-5 ml-2" />
<p className="text-xs text-blueC0 dark:text-white text-justify">
هزینه ارسال کالا پس از تعیین محل آدرس مشخص میشود
</p>
</div>
)}
{phase === "deliveryForm" && (
<div className="flex flex-col mt-10">
<strong className="text-tiny text-blue52 mb-5 font-medium">
انتخاب شیوه پرداخت
</strong>
<Button
title="از طریق درگاه پرداخت"
backgroundColor="bg-transparent"
border={{ color: "#77777755", width: "1px" }}
width="100%"
color="text-blue52"
onClick={() => {}}
/>
<br />
<Button
title="پرداخت در محل"
backgroundColor="bg-transparent"
border={{ color: "#77777755", width: "1px" }}
width="100%"
color="text-blue52"
onClick={() => {}}
/>
<br />
<br />
</div>
)}
<Button
title="ادامه فرایند خرید"
backgroundColor="bg-blueC0"
border={{ color: "#196EC055", width: "1px" }}
width="100%"
color="text-white"
onClick={next[phase]}
/>
{phase === "deliveryForm" && (
<button
className="bg-transparent mt-4 text-tiny text-blueC0 py-3 flex flex-row justify-center items-center"
onClick={() => setPhase("products")}
>
بازگشت
<img
src={dropdownIcon}
alt=""
className="w-4 transform rotate-90"
/>
</button>
)}
</div>
)}
</div>
);
}
@ -246,7 +273,7 @@ const mapStateToProps = (state) => ({
list: state.userProduct.list,
payPrice: state.userProduct.sum,
factorInfo: state.userFactor.info,
userId: state.user.status.id,
user: state.user.status,
hasPhysical: state.userProduct.hasPhysical,
desktopContentTransform: state.publicApi.desktopContentTransform,
});

@ -1,31 +1,46 @@
import React from "react";
import React, {useState, useEffect} from "react";
import "../../../../components/ProductImage/index.scss";
import productImg from "../../../../components/ProductImage/product-image.jpg";
const Videos = ({ videos }) => {
const [list, setList] = useState([]);
const [activeVideo, setActiveVideo] = useState([]);
useEffect(() => {
if (videos) {
let mylist = videos?.split(",");
setList(() => mylist);
setActiveVideo(() => mylist[0]);
console.log(videos);
}
}, [videos]);
return (
<div className="flex flex-row gap-5">
<div
className="flex flex-col items-start justify-between"
// style={{ height: "calc(100vh / 2 * 9 / 16)" }}
>
{videos.slice(0, 4).map((video, index) => (
{list?.slice(0, 4).map((video, index) => (
<div
className="relative rounded-md"
className={`relative rounded-md flex justify-center items-center ${activeVideo === video ? 'bg-green-200' : 'bg-gray-200'}`}
style={{
width: "calc(100vh / 5.5 - 8px)",
height: "calc(100vh / 5.5 - 8px)",
}}
key={index}
>
<img
key={index}
src={productImg}
src={`https://dnvn.ir/api/v1/file/${video}`}
alt=""
className={`rounded-sm w-full h-full`}
// style={{ height: "calc(100% - 8px)" }}
// style={{ height: "calc(100% - 8px)" }}
style={{
width: "calc(100vh / 5.5 * 2 / 3 - 12px)",
height: "calc(100vh / 5.5 - 20px)",
}}
/>
{/* این خط پایین که نوشتم برای این است که ایندکس که جنسش استرینگ است رو به نامبر تبدیل کند */}
{Number(index) === 3 && (
@ -51,16 +66,3 @@ const Videos = ({ videos }) => {
export default Videos;
Videos.defaultProps = {
videos: [
{
image: productImg,
},
{
image: productImg,
},
{
image: productImg,
},
],
};

@ -1,8 +1,12 @@
import React, { useState } from "react";
import { connect } from "react-redux";
import location from "../../../utils/location";
import { Link } from "react-router-dom";
import { publicApi } from "../../../redux/actions";
//assets
import dropdownIcon from "../../../assets/icons/dropdown-blue.svg";
const Season = ({
toggle,
season,
@ -12,6 +16,14 @@ const Season = ({
realSeasons,
vodDuration,
}) => {
const setCategory = (seasonId, videoId) => {
localStorage.removeItem("bookId");
localStorage.setItem(
"season",
location.getId() + "," + seasonId + "," + videoId
);
};
const duration = (value) => {
const minute = value % 60;
const hour = Math.round(value / 60);
@ -24,7 +36,7 @@ const Season = ({
);
};
// const [activeSeason, setActiveSeason] = useState(null);
const Unit = ({ unit }) => {
const Unit = ({ unit, index }) => {
return isMobile ? (
<Link
to="/videos/0/display"
@ -58,9 +70,9 @@ const Season = ({
</div> */}
</Link>
) : (
<Link to="/videos/0/display" className="d-flex flex-column">
<div className="d-flex flex-column">
<li
className="lesson__files--sample justify-content-between align-items-center p-5"
className="lesson__files--sample justify-content-between align-items-center py-2 px-6"
style={{
display: season[0].categoryId === activeSeason ? "flex" : "none",
}}
@ -68,11 +80,28 @@ const Season = ({
// setSelectedLesson(selectedLesson === data.id ? null : data.id)
// }
>
<div className="d-flex align-items-center">
<div className="flex items-center justify-between w-full">
<h5>{unit.name}</h5>
<div className="flex items-center gap-4">
<Link
to={
Number(index) === 0
? window.location.pathname + "/display"
: "#"
}
className={`bg-white border border-solid ${
Number(index) === 0
? "border-blue-300 text-blueC0"
: "border-gray-300 text-gray70"
} py-2.5 w-24 text-center text-tiny rounded-sm shadow-sm`}
onClick={() => setCategory(season[0].categoryId, unit.name)}
>
{Number(index) === 0 ? "تماشا" : "قفل"}
</Link>
</div>
</div>
</li>
</Link>
</div>
);
};
return isMobile ? (
@ -99,21 +128,38 @@ const Season = ({
season.map((unit, index) => <Unit unit={unit} key={index} />)}
</div>
) : (
<li
className="w-full flex flex-col bg-grayF7 rounded-md overflow-hidden cursor-pointer"
onClick={() => toggle(season[0].categoryId)}
>
<header className="w-full flex flex-row justify-between p-4">
<strong className="text-tiny text-gray1 font-medium">
<li className="w-full flex flex-col bg-blueFF1 rounded-md overflow-hidden shadow-md">
<header
className="w-full flex flex-row justify-between items-center py-3 px-6"
onClick={() => toggle(season[0].categoryId)}
>
<strong className="text-tiny text-blueC0 font-medium">
{
realSeasons.filter((item) => item.id === season[0].categoryId)[0]
.name
}
</strong>
<img
src={dropdownIcon}
alt=""
className={`w-6 transform transition-all ${
season[0].categoryId === activeSeason ? "rotate-180" : ""
}`}
/>
</header>
<ul className="w-full flex flex-col px-4 divide-y-2 divide-solid divide-gray-200">
{season[0].categoryId === activeSeason &&
season.map((unit, index) => <Unit unit={unit} key={index} />)}
<ul
className={`w-full flex flex-col px-4 divide-y-2 divide-solid transform origin-bottom transition-all divide-blue-100 overflow-hidden`}
style={{
height: isMobile
? "auto"
: season[0].categoryId === activeSeason
? (24 + 34.5) * season.length
: 0,
}}
>
{season.map((unit, index) => (
<Unit unit={unit} key={index} index={index} />
))}
</ul>
</li>
);

@ -1,6 +1,8 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { publicApi } from "../../redux/actions";
import {toast} from 'react-toastify';
import { Link } from "react-router-dom";
import { publicApi, userProduct } from "../../redux/actions";
import location from "../../utils/location";
import Divider from "../../components/Divider";
import Season from "./components/Season";
@ -15,7 +17,9 @@ import poster from "../../assets/images/poster.svg";
import tickIcon from "../../components/ProductStatusCard/tick-circle.svg";
function Video({
isLogin,
pushToCart,
userId,
product = {
id: 0,
type: "کتاب ها",
@ -64,19 +68,9 @@ function Video({
const [type, setType] = useState(0);
useEffect(() => {
window.scrollTo(0, 0)
}, []);
useEffect(() => {
getBook({ bookId: 19 });
getBook({ bookId: location.getId() });
setHeaderOptions(headerOptions);
}, []);
useEffect(() => {
if (book) {
// console.log(book);
}
}, [book]);
return isMobile ? (
<div className="w-full flex flex-col px-4">
<div className="w-full flex flex-col">
@ -91,14 +85,14 @@ function Video({
}}
>
<img
src={product.imageUrl}
src={`https://dnvn.ir/api/v1/file/${book?.fileIds}`}
className="rounded-md absolute left-2 top-1/2 transform -translate-y-1/2"
style={{ width: 70, height: 100 }}
/>
</div>
<div className="flex flex-col flex-1 justify-between pr-2">
<div className="flex flex-col">
<strong className="mt-2 text-blue5F text-lg dark:text-white">
<strong className="mt-2 text-blue5F text-base dark:text-white font-normal">
{book?.name}
</strong>
<span className="text-blueC0 text-sm mb-1 dark:text-greenBA mt-2">
@ -115,10 +109,10 @@ function Video({
</div>
</div>
) : (
<div className="flex flex-col w-11/12 min-h-screen mx-auto pb-20">
<div className="flex flex-col w-11/12 min-h-screen mx-auto pb-20 pt-24">
<header className="w-full flex flex-row gap-12">
<div className="w-9/12">
<Videos />
<Videos videos={book?.fileIds} />
<ProductTab
tabs={[
{
@ -152,11 +146,11 @@ function Video({
{book?.name}
</h1>
<div className="text-blueC0 text-sm dark:text-greenBA">
{"پایه" + " " + (grades[book?.gradeId] || "پایه دوازدهم")}
{"پایه" + " " + grades[book?.gradeId]}
</div>
<div className="flex justify-end">
<div className="p-2">
<StarRating />
<StarRating value={book?.rate || 4} />
</div>
<div className="p-2 border-0 border-solid border-r border-gray-100 text-sm text-gray-400">
بیش از 160 نفر امتیاز داده اند
@ -164,7 +158,7 @@ function Video({
</div>
</div>
<div className="bg-grayF9 w-full flex flex-col rounded-md divide-y divide-solid divide-gray-200 mb-4">
<div className="flex flex-row justify-center items-center w-full gap-5 py-3">
<div className="flex flex-row justify-center items-center w-full gap-5 my-5">
<img src={tickIcon} alt="" className="w-9" />
<p className="text-blue52 text-sm font-light">{`توسعه خرید توسط ${
book?.recommendedPeople || 4234
@ -172,16 +166,14 @@ function Video({
</div>
<div className="flex flex-col w-full py-4 px-4">
<div className="flex flex-row items-center justify-center gap-2">
<strong className="text-blueC0 text-xl">
{book?.price || "56/894/000"}
</strong>
<strong className="text-blueC0 text-xl">{book?.price}</strong>
<span className="text-sm text-gray-500">تومان</span>
</div>
<p className="text-gray-500 text-xs text-center mt-2 mb-4">
با خرید این کالا 540.000 صرفه جویی کنید
</p>
<Button
title=صافه کردن به سبد خرید"
title=ضافه کردن به سبد خرید"
backgroundColor={isDark ? "bg-blueC0" : "bg-blueC0"}
border={{
color: isDark ? "#ffffff55" : "#196EC055",
@ -190,19 +182,24 @@ function Video({
width="100%"
color={"text-white"}
selectable={true}
onClick={() => {}}
onClick={() =>
isLogin
? pushToCart({
productId: book?.id,
userId: userId,
count: 1,
})
: toast.info("ابتدا وارد حساب کاربری خود شوید.")
}
/>
</div>
</div>
<Button
title="مشاهده دوره ویدئویی این محصول"
backgroundColor="bg-blueC0"
border={{ color: "#196EC055", width: "0px" }}
bgOpacity="bg-opacity-10"
width="100%"
color={isDark ? "text-white" : "text-blueC0"}
onClick={() => {}}
/>
<Link
to={"/products/" + book?.id}
className="bg-blueFF1 text-blueC0 text-sm rounded-md border border-solid border-blueC01 w-full py-4 text-center"
>
مشاهده کتاب این محصول
</Link>
</div>
</header>
</div>
@ -215,11 +212,14 @@ const mapStateToProps = (state) => ({
book: state.publicApi.bookInfo,
seasons: state.publicApi.categories,
grades: state.publicApi.grades,
isLogin: state.user.status,
userId: state.user.status.id,
});
const mapDispatchToProps = {
setHeaderOptions: publicApi.setHeaderOptions,
getBook: publicApi.bookInfo,
pushToCart: userProduct.add,
};
export default connect(mapStateToProps, mapDispatchToProps)(Video);

@ -1,38 +0,0 @@
import React from "react";
import CourseChapter from "../../../components/CourseChapter";
import VideoPlayer from "../../../components/VideoPlayer";
const DesktopVideoDisplay = () =>{
return(
<div className="w-full flex flex-col px-4 items-center">
<div className="w-4/5 flex flex-col mb-6 justify-center items-center">
<div className="w-full flex flex-row flex-1 justify-center overflow-hidden relative">
<div className="flex flex-col w-4/5">
<VideoPlayer playerWidth='100%' />
<h1 className="mx-4 my-2 text-4xl text-blue52 py-6 border-b-2 border-solid border-gray-300">ساز های باستانی ایران عزیز</h1>
<p className="m-4 text-gray-600">
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با استفاده از طراحان گرافیک است، چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است، و برای شرایط فعلی تکنولوژی مورد نیاز، و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد، کتابهای زیادی در شصت و سه درصد گذشته حال و آینده، شناخت فراوان جامعه و متخصصان را می طلبد، تا با نرم افزارها شناخت بیشتری را برای طراحان رایانه ای علی الخصوص طراحان خلاقی، و فرهنگ پیشرو در زبان فارسی ایجاد کرد، در این صورت می توان امید داشت که تمام و دشواری موجود در ارائه راهکارها، و شرایط سخت تایپ به پایان رسد و زمان مورد نیاز شامل حروفچینی دستاوردهای اصلی، و جوابگوی سوالات پیوسته اهل دنیای موجود طراحی اساسا مورد استفاده قرار گیرد.
</p>
</div>
<CourseChapter />
</div>
{/* <div className="flex flex-col flex-1 justify-between pr-2">
<div className="flex flex-col">
<strong className="mt-1 text-blue5F text-base dark:text-white">
{product.name}
</strong>
<span className="text-blueC0 text-xs mb-1 dark:text-greenBA">{product.grade}</span>
</div>
<Divider type={"vertical"} />
</div> */}
<div>
</div>
</div>
</div>
);
};
export default DesktopVideoDisplay;

@ -1,10 +1,13 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { publicApi } from "../../redux/actions";
import PlayList from "../../components/CourseChapter";
import VideoPlayer from "../../components/VideoPlayer";
import JolPlayer from "../../components/JolPlayer";
import poster from "../../assets/images/poster.svg";
import Divider from "../../components/Divider";
import Season from "./components/Season";
import DesktopVideoDisplay from "./Desktop";
function VideoDisplay({
isMobile,
@ -48,17 +51,24 @@ function VideoDisplay({
seasons,
grades,
getBook,
getSeason,
selectedVideo,
}) {
useEffect(() => {
const id = window.location.pathname.slice(
8,
window.location.pathname.lastIndexOf("/")
);
getBook({bookId : id});
setHeaderOptions(headerOptions);
// getBook({ bookId: id });
const cat = localStorage.getItem("season")?.split(",");
getSeason({ bookId: cat[0], categoryId: cat[1] });
}, []);
useEffect(() => {
},[])
const enamad =
'<a referrerpolicy="origin" target="_blank" href="https://trustseal.enamad.ir/?id=224965&amp;Code=x8oNSO7tTnqAniyPpPyN"><img referrerpolicy="origin" src="https://Trustseal.eNamad.ir/logo.aspx?id=224965&amp;Code=x8oNSO7tTnqAniyPpPyN" alt="" style="cursor:pointer" id="x8oNSO7tTnqAniyPpPyN"></a>';
return isMobile ? (
@ -92,21 +102,58 @@ function VideoDisplay({
</div>
</div>
) : (
<DesktopVideoDisplay />
<div className="w-11/12 flex flex-col mb-6 justify-center items-center mx-auto pt-24 pb-20">
<div className="w-full flex flex-row justify-between overflow-hidden relative gap-2 mt-4">
<div className="flex flex-col w-8/12">
<JolPlayer
fileIds={selectedVideo?.fileIds}
posterId={selectedVideo?.posterId}
/>
<h1 className="mx-4 my-2 text-4xl text-blue52 pb-4 border-b-2 border-solid border-gray-200">
{selectedVideo?.name}
</h1>
<p className="m-4 text-gray70 leading-7 font-normal text-tiny">
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با
استفاده از طراحان گرافیک است، چاپگرها و متون بلکه روزنامه و مجله در
ستون و سطرآنچنان که لازم است، و برای شرایط فعلی تکنولوژی مورد نیاز،
و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد، کتابهای
زیادی در شصت و سه درصد گذشته حال و آینده، شناخت فراوان جامعه و
متخصصان را می طلبد، تا با نرم افزارها شناخت بیشتری را برای طراحان
رایانه ای علی الخصوص طراحان خلاقی، و فرهنگ پیشرو در زبان فارسی ایجاد
کرد، در این صورت می توان امید داشت که تمام و دشواری موجود در ارائه
راهکارها، و شرایط سخت تایپ به پایان رسد و زمان مورد نیاز شامل
حروفچینی دستاوردهای اصلی، و جوابگوی سوالات پیوسته اهل دنیای موجود
طراحی اساسا مورد استفاده قرار گیرد.
</p>
</div>
<PlayList playList={book?.vods} />
</div>
{/* <div className="flex flex-col flex-1 justify-between pr-2">
<div className="flex flex-col">
<strong className="mt-1 text-blue5F text-base dark:text-white">
{product.name}
</strong>
<span className="text-blueC0 text-xs mb-1 dark:text-greenBA">{product.grade}</span>
</div>
<Divider type={"vertical"} />
</div> */}
<div></div>
</div>
);
}
const mapStateToProps = (state) => ({
isMobile: state.publicApi.isMobile,
book: state.publicApi.bookInfo,
grades: state.publicApi.categories,
book: state.publicApi.bookSection,
seasons: state.publicApi.categories,
grades: state.publicApi.grades,
selectedVideo: state.publicApi.selectedVideo,
});
const mapDispatchToProps = {
setHeaderOptions: publicApi.setHeaderOptions,
getBook: publicApi.getBook,
getBook: publicApi.bookInfo,
getSeason: publicApi.bookSection
};
export default connect(mapStateToProps, mapDispatchToProps)(VideoDisplay);

@ -3,7 +3,7 @@ import { Link } from "react-router-dom";
import Header from "../../../components/Header";
import posterImage from "../../../assets/images/poster.svg";
function MostViewedVideo({}) {
function MostViewedVideo({videos, grades}) {
const Video = ({ video }) => {
return (
<Link
@ -13,7 +13,7 @@ function MostViewedVideo({}) {
<div
className="w-full flex flex-row flex-1 justify-between items-center relative overflow-hidden"
style={{
backgroundImage: `url(${video.poster})`,
backgroundImage: `url(${posterImage})`,
backgroundSize: "100% 100%",
repeat: "no-repeat",
minWidth: "calc(100vw / 1.4)",
@ -21,7 +21,7 @@ function MostViewedVideo({}) {
}}
>
<img
src={video.imageUrl}
src={`https://dnvn.ir/api/v1/file/${video.fileIds}`}
className="rounded-md h-full absolute left-2 top-1/2 transform -translate-y-1/2"
style={{
width: "calc(100vw / 7)",
@ -29,7 +29,7 @@ function MostViewedVideo({}) {
}}
/>
</div>
<strong className="text-lg mt-1 text-blue5F dark:text-white">
<strong className="text-tiny mt-1 text-blue5F dark:text-white font-normal">
{video.name}
</strong>
<div className="w-full flex flex-row justify-between items-center mt-3">
@ -37,7 +37,7 @@ function MostViewedVideo({}) {
{video.price}
</strong>
<span className="text-blueC0 text-sm dark:text-white">
{"پایه" + " " + video.grade}
{"پایه" + " " + grades[video.gradeId]}
</span>
</div>
</Link>
@ -47,17 +47,10 @@ function MostViewedVideo({}) {
<div className="w-full flex flex-col">
<Header title="پربازدیدترین" link="/videos/video" />
<div className="w-full flex flex-row overflow-x-scroll pb-4">
{[0, 1, 2].map((video, index) => (
{videos.map((video, index) => (
<Video
key={index}
video={{
id: 0,
name: "ریاضی",
price: "145.000 تومان",
grade: "4",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
}}
video={video}
/>
))}
</div>

@ -1,27 +1,32 @@
import React from "react";
import {Link} from 'react-router-dom';
import { Link } from "react-router-dom";
import Header from "../../../components/Header";
import posterImage from "../../../assets/images/poster.svg";
const NewestVideo = () => {
const NewestVideo = ({ videos, grades }) => {
const Video = ({ video }) => {
return (
<Link
to={'/videos/' + video.id}
className="flex flex-col items-start mb-4 shadow-md p-1.5 rounded-md"
style={{width: 'calc(100vw / 2.2)'}}
to={"/videos/" + video.id}
className="flex flex-col items-start mb-4 shadow-md p-2 rounded-md overflow-hidden"
style={{ width: "calc(100vw / 2.2)" }}
>
<img
src={video.poster}
className="w-full rounded-md"
/>
<strong
className="text-base mt-2 text-blue5F dark:text-white"
>
<div className="w-full bg-gray-200 py-2 rounded-t-md">
<img
src={`https://dnvn.ir/api/v1/file/${video.fileIds}`}
className="rounded-md mx-auto"
style={{
height: "calc(100vh / 7)",
width: "calc(100vh / 7 * 2 / 3)",
}}
/>
</div>
<strong className="text-base mt-2 text-blue5F dark:text-white font-normal">
{video.name}
</strong>
<span className="text-blueC0 text-sm mt-2 dark:text-greenBA">
{"پایه" + " " + video.grade}
{"پایه" + " " + grades[video.gradeId]}
</span>
</Link>
);
@ -30,19 +35,8 @@ const NewestVideo = () => {
<div className="w-full flex flex-col">
<Header title="جدیدترین دورهها" link="/videos/video" />
<div className="w-full flex flex-row flex-wrap justify-between overflow-x-scroll mt-3">
{[0, 1, 2, 3].map((video, index) => (
<Video
key={index}
video={{
id : 0,
name: "ریاضی",
price: "145.000 تومان",
grade: "4",
imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage,
}}
key={index}
/>
{videos.map((video, index) => (
<Video key={index} video={video} />
))}
</div>
</div>

@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { publicApi } from "../../redux/actions";
import { publicApi, book } from "../../redux/actions";
import Search from "../../components/Search";
import VerticalGradeFilter from "./components/VerticalGradeFilter";
import Divider from "../../components/Divider";
@ -9,10 +9,11 @@ import NewestVideo from "./components/NewestVideo";
//assets
import searchLight from "../../assets/icons/search-light.svg";
function Videos({ headerOptions, setHeaderOptions }) {
function Videos({ headerOptions, setHeaderOptions, getList, videos, grades }) {
const [search, setSearch] = useState("");
useEffect(() => {
setHeaderOptions(headerOptions);
getList();
}, []);
return (
<div className="flex flex-col">
@ -31,20 +32,24 @@ function Videos({ headerOptions, setHeaderOptions }) {
<Divider type={"vertical"} />
</div>
<div className="pr-4">
<MostViewedVideo />
<MostViewedVideo videos={videos} grades={grades} />
</div>
<div className="px-4 flex flex-col">
<Divider type={"vertical"} />
<NewestVideo />
<NewestVideo videos={videos} grades={grades} />
</div>
</div>
);
}
const mapStateToProps = (state) => ({});
const mapStateToProps = (state) => ({
videos : state.book.list,
grades: state.publicApi.grades,
});
const mapDispatchToProps = {
setHeaderOptions: publicApi.setHeaderOptions,
getList : book.list
};
export default connect(mapStateToProps, mapDispatchToProps)(Videos);

Loading…
Cancel
Save