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"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <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="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" 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 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/ 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. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. 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. 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`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React App</title> <title>دانوین</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <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; direction: rtl;
} }
.scrolling-carousel button{
display: none;
}
@font-face { @font-face {
font-family: Black; font-family: Black;
src: url("./assets/font/IranSansX/Farsi/Black.ttf"); 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'; import './index.css';
export default function Checkbox(props) { export default function Checkbox(props) {
console.log(props) // console.log(props)
return ( return (
<div> <div>
<svg className="checkbox-symbol"> <svg className="checkbox-symbol">

@ -1,112 +1,160 @@
import React, { useState } from "react"; import React, { useState } from "react";
import './index.css'; import { connect } from "react-redux";
import { publicApi } from "../../redux/actions";
const CourseChapter = ({ chapters }) => { import { toast } from "react-toastify";
const [selectedLesson, setSelectedLesson] = useState(null); 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 ( return (
<section style={{ width: "40%" }} className="bg-white mx-auto my-20 p-4"> <section
<div className="bg-blueFF1 py-5 pr-5 overflow-hidden flex flex-col"
className="rounded py-5 px-4 relative" style={{
style={{ backgroundColor: "#196EC033", height: '530px'}} width: "calc(100% / 12 * 3.5)",
> height: "calc(100vh - 300px)",
{/* top */} }}
<div className="flex flex-row items-center justify-between"> >
<div> <div className="flex flex-row w-full items-center justify-between">
<h2 className="text-blue-800 text-base">سرفصل دوره</h2> <div>
</div> <h2 className="text-blue-800 text-base font-semibold">سرفصل دوره</h2>
<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>
</div> </div>
{/* divider */} <div className="flex flex-row-reverse items-center divide-x divide-solid transform translate-x-2">
<div className="border-b border-blue-300 border-solid bg-opacity-10 my-5"></div> <span className="text-blue-800 text-sm px-2">{book?.name}</span>
{/* course title */} <span className="text-blue-800 text-sm px-2">
<div className="overflow-y-scroll w-full hasScrollbar" style={{ {"پایه" + " " + grades[book?.gradeId]}
height: '430px' </span>
}}> </div>
{chapters.map((chapter, index) => ( </div>
<div className="flex flex-col" key={index}> <span className="w-full h-px bg-blue-200 my-4"></span>
<div className="bg-blue-600 rounded-sm p-4 flex flex-row items-center justify-between"> <div className="overflow-y-scroll w-full hasScrollbar flex-1 flex flex-col">
<p className="text-sm text-white">{chapter.title}</p> <div className="bg-blue-600 rounded-sm p-4 flex flex-row items-center justify-between mb-2">
<span className="text-sm text-white">{chapter.duration}</span> {/* <p className="text-sm text-white">
</div> {(seasons.length > 0 && playList.length > 0) &&
{/* course lessons */} seasons?.filter((item) => item?.id === playList[0]?.categoryId)[0]
{chapter.lessons.map((lesson, i) => ( ?.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 <div
className="flex flex-row items-center justify-around" className="flex items-center justify-center relative flex-col h-full"
key={i} 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 <div
className="flex items-center relative flex-col " className={`w-full bg-white flex flex-col transition duration-400 hover:scale-95 shadow-md transform rounded-md
style={{ width: "10%", transform: "translateY(30px)" }} ${
> selectedVideo?.id === video?.id
<div ? "bg-blue-600 text-white-700"
className={`flex justify-center items-center w-4 h-4 rounded-full : "text-blue-500"
${selectedLesson === lesson ? "bg-red-600" : "bg-blue-600"}, }
${lesson.passed ? "bg-blue-600" : "bg-gray-400"}
`} `}
></div> onClick={() =>
<span video?.isFreeVod || +userId === 140
className="w-1" ? setVideoActive(video)
style={{ : toast.error("ابتدا محصول رو خریداری کن!")
borderRight: "2px dashed #86A0B9", }
transform: "translateX(-1px)", disabled={true}
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)}
> >
{/* top */} {/* 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 <p
className={`text-sm group-hover:text-white className={`text-tiny
${selectedLesson === lesson ? "text-white" : ""}`} ${selectedVideo?.id === video?.id ? "text-white" : ""}`}
> >
{lesson.title} {video?.name}
</p> </p>
<span <span
className={`text-xs group-hover:text-white border-r border-solid border-blue-200 pr-1 className={`text-sm border-r border-solid border-blue-200 pr-1
${selectedLesson === lesson ? "text-white" : "text-blue-500"}`} ${
selectedVideo?.id === video?.id
? "text-white"
: "text-blue-500"
}`}
> >
{lesson.duration} {duration(video?.duration)}
</span> </span>
</div> </div>
{/* divider */} {/* divider */}
<div <div
className={`border-t border-blue-600 group-hover:border-white ${ className={`border-t border-blue-600 ${
selectedLesson === lesson ? "border-red-600" : "" selectedVideo?.id === video?.id ? "border-red-600" : ""
}`} }`}
></div> ></div>
{/* bottom */} {/* bottom */}
<span <span
className={`text-xs text-center group-hover:text-white p-2 className={`text-tiny text-center p-3
${selectedLesson === lesson ? "text-white" : "text-blue-500"}`} ${
selectedVideo?.id === video?.id
? "text-white"
: "text-blue-500"
}`}
> >
{lesson.play} پخش
</span> </span>
</div> </div>
</div> </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> </div>
</section> </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 = { CourseChapter.defaultProps = {
chapters: [ 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 React from "react";
import { Link } from "react-router-dom";
import _ from "lodash"; import _ from "lodash";
// import enamadlogo from './enamad-pic.svg'; // import enamadlogo from './enamad-pic.svg';
import callIcon from '../../assets/icons/vuesax-linear-call-calling.svg'; import callIcon from "../../assets/icons/vuesax-linear-call-calling.svg";
import samandehi from './samandehi-pic.svg'; import samandehi from "./samandehi-pic.svg";
import iosIcon from "./IOS.svg";
import bazarIcon from "./Bazar.svg";
import lightBlueLine from "./light-blue-line.svg"; import lightBlueLine from "./light-blue-line.svg";
const FooterDesign1 = ({ color, bg, items, hasHeader }) => {
const FooterDesign1 = ({ color, bg, links, hasHeader }) => {
const enamad = 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>'; '<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 ( return (
<> <>
{hasHeader ? {hasHeader ? (
<div className=" bg-gray-100 flex items-center justify-center py-6 text-blue52"> <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 "> <div className="mr-8 text-lg font-black transform translate-y-0.5">
<img src={callIcon} className="p-2" /> <h1 className="text-left mb-5">654412 021</h1>
<div> <h1>Info[at]danovin.ir</h1>
<h1 className="text-2xl text-bold mb-2 font-black"> </div>
<span className=" text-blueC0">7</span> روز هفته <span className="font-black text-blueC0">24</span> ساعته </div>
</h1> <div className="flex items-center">
<p className="text-lg font-light text-blue-700">منتظر شنیدن صدای گرمتان هستیم</p> <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> </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> </div>
: null} ) : null}
<footer <footer
className={`flex flex-col bg-gray-200 py-16 md:flex-row justify-around items-start md:items-start relative shadow-md ${bg}`} 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="w-11/12 flex justify-between">
<div className="flex items-start"> <div className="flex flex-row gap-10">
<> {items.map((item, index) => (
{ <div className="flex flex-col" key={index}>
links.map((section, index) => <ul className={index != 0 ? 'mr-16' : ''} key={index}> <strong className="text-xl text-gray70">{item.name}</strong>
{ <ul className="flex flex-col mt-0">
section.map((link, index) => <li {item.links.map((link, index) => (
className={`font-light text-md leading-7 hover:font-bold ${color}`} <li className="mt-6">
key={index} <Link className="text-gray70 text-base" to={link.link} key={index}>
> {link.name}
<a href="" className={`${index == 0 ? ' text-lg font-bold' : ''}`}>{link}</a> </Link>
</li>) </li>
} ))}
</ul>) </ul>
} </div>
</> ))}
</div> </div>
<div className="flex items-center justify-between mt-10 md:mt-0"> <div className="flex items-center justify-between mt-10 md:mt-0">
<div <div
@ -61,10 +72,12 @@ const FooterDesign1 = ({ color, bg, links, hasHeader }) => {
__html: enamad, __html: enamad,
}} }}
className="w-28 p-2 rounded-md bg-gray-300 mx-6" className="w-28 p-2 rounded-md bg-gray-300 mx-6"
> ></div>
<img
</div> src={samandehi}
<img src={samandehi} alt="" className="w-28 p-2 rounded-md bg-gray-300 mr-6" /> alt=""
className="w-28 p-2 rounded-md bg-gray-300 mr-6"
/>
</div> </div>
</div> </div>
{/* line {/* line
@ -73,7 +86,6 @@ const FooterDesign1 = ({ color, bg, links, hasHeader }) => {
alt="" alt=""
className="hidden sm:block absolute bottom-5 left-20" className="hidden sm:block absolute bottom-5 left-20"
/> */} /> */}
</footer> </footer>
</> </>
); );
@ -82,26 +94,71 @@ const FooterDesign1 = ({ color, bg, links, hasHeader }) => {
export default FooterDesign1; export default FooterDesign1;
FooterDesign1.defaultProps = { 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", bg: "bg-white",
color: "text-gray-600", color: "text-gray-600",

@ -49,9 +49,10 @@ export default function Input(props) {
return ( return (
<div <div
className={_.join( 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 {/* <label
className={_.join( className={_.join(
@ -92,7 +93,7 @@ export default function Input(props) {
], ],
" " " "
)} )}
style={{ direction: direction, width , }} style={{ direction: direction }}
onChange={(e) => onChange={(e) =>
onChange(name, (e.target.value = regex(e.target.value))) onChange(name, (e.target.value = regex(e.target.value)))
} }

@ -4,7 +4,6 @@ import JoLPlayer from "jol-player";
function Video({ fileIds, posterId, autoPlay }) { function Video({ fileIds, posterId, autoPlay }) {
const videoRef = useRef(null); const videoRef = useRef(null);
return ( return (
<div <div
style={{ style={{
@ -20,7 +19,10 @@ function Video({ fileIds, posterId, autoPlay }) {
option={{ option={{
videoSrc: `https://dnvn.ir/api/v1/file/${fileIds}`, videoSrc: `https://dnvn.ir/api/v1/file/${fileIds}`,
width: "100%", 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", theme: "#4dd35b",
language: "en", language: "en",
isShowMultiple: window.innerWidth > 700, 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 React, { useEffect, useState } from "react";
import { Link, useNavigate } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import { connect } from "react-redux"; import { connect } from "react-redux";
import {publicApi} from "../../redux/actions"; import { userProduct } from "../../redux/actions";
import _ from "lodash"; import _ from "lodash";
import Drawer from "../Drawer"; import Drawer from "../Drawer";
import Search from "../Search"; import Search from "../Search";
import SearchResult from "./SearchResult";
import OverLayer from "../OverLayer";
//assets //assets
import cartIcon from "./cart-blue.svg"; import cartIcon from "./cart-blue.svg";
// import whiteCartIcon from "./white-cart-icon.svg"; // import whiteCartIcon from "./white-cart-icon.svg";
// import profileIcon from "./dark-crimson-profile-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 lightGraySearchIcon from "./light-gray-search-box.svg";
import darkCrimsonHamburgerMenu from "./dark-crimson-hamburger-menu.svg"; import darkCrimsonHamburgerMenu from "./dark-crimson-hamburger-menu.svg";
// import whiteHamburgerMenu from "./white-hamburger-menu-icon.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"; import bookmarkDeactiveLightIcon from "../../assets/icons/bookmark-deactive-light.svg";
function Navbar({ function Navbar({
getCartProducts,
cartProductsLength,
pages, pages,
isDark, isDark,
isMobile, isMobile,
isLogin, isLogin,
headerOptions, headerOptions,
loginBtn,
menuItems,
category,
searchBox,
topHeader,
bottomHeader,
productCategoryTextColor,
menuItemsColor,
}) { }) {
const navigation = useNavigate(); const navigation = useNavigate();
const { logo, hamburgerMenu, qr, shown, menu, title, back, bookmark } = const { logo, hamburgerMenu, qr, shown, menu, title, back, bookmark } =
headerOptions; headerOptions;
const [overLayer, setOverLayer] = useState(false);
const [top, setTop] = useState(false); const [top, setTop] = useState(false);
const [search, setSearch] = useState(null);
const [drawerOpen, setDrawerOpen] = useState(false); const [drawerOpen, setDrawerOpen] = useState(false);
const [desktopMiddleFix, setDesktopMiddleFix] = useState(false);
const [desktopEndTransform, setDesktopEndTransform] = useState(false);
useEffect(() => { useEffect(() => {
var lastScroll = window.scrollY;
if (window.scrollY === 0) { if (window.scrollY === 0) {
setTop(() => true); 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 ? ( return isMobile ? (
<div <div
className={_.join( className={_.join(
@ -212,108 +194,78 @@ function Navbar({
{/* portrait end */} {/* portrait end */}
</div> </div>
) : ( ) : (
<header className={`rounded-b-md w-full bg-transparent pb-1`}> <header
<div className="flex flex-row justify-between items-center px-20 border-b border-gray-200 border-solid py-4 "> 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="divide-x flex flex-row transform gap-4"> >
{/* <span className="text-sm font-normal text-blue52"> <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">
</span> */} <div className="flex flex-row items-center">
<Link to="/dashboard" className="text-sm font-normal text-blue52"> <Link
پیگیری سفارش to="/"
</Link> className="flex flex-row items-center text-2xl font-medium"
</div> >
<div className="flex flex-row gap-5" style={{ direction: "ltr" }}> <img src={logoIcon} className="w-8 relative bottom-1 ml-1" />
{!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" />
</Link> </Link>
{/* <img src={whiteCartIcon} alt="" className="w-5 h-5 ml-2" /> */} <ul className="flex flex-row list-none items-center relative top-0.5 mr-6">
{/* <img src={searchIcon} alt="" className="w-5 h-5 ml-2" /> */} {pages.map((page, index) => (
{/* <img src={profileIcon} alt="" className="w-5 h-5" /> */} <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>
</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 <div className="flex flex-row items-center">
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">
<img <img
src={darkCrimsonHamburgerMenu} src={searchIcon}
alt="" 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" /> */} {isLogin && (
<span className={`text-sm text-blue52 ${productCategoryTextColor}`}> <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; {/* <img src={profileIcon} alt="" className="w-5 h-5" /> */}
</span> </div>
</div> )}
<div {!isLogin && (
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) => (
<Link <Link
to={item.link} to="/signup"
className={`text-sm text-blue52 ${menuItemsColor} hover:text-blueC0`} className="bg-blueC0 text-white rounded-md px-4 py-3 text-sm mr-7 hover:bg-opacity-90 shadow-sm"
key={"nav" + index}
> >
{item.name} ورود یا ثبت نام
</Link> </Link>
))} )}
</div> </div>
</div> </div>
</div> </div>
@ -326,25 +278,23 @@ const mapStateToProps = (state) => ({
isMobile: state.publicApi.isMobile, isMobile: state.publicApi.isMobile,
headerOptions: state.publicApi.headerOptions, headerOptions: state.publicApi.headerOptions,
isLogin: state.user.status, 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 = { Navbar.defaultProps = {
pages: [ pages: [
{
link: "/",
name: "خانه",
},
{ {
link: "/products", link: "/products",
name: "محصولات", name: "محصولات",
}, },
{
link: "/filter",
name: "دسته بندی ها",
},
{ {
link: "/contact-us", link: "/contact-us",
name: "تماس با ما", name: "تماس با ما",
@ -354,7 +304,7 @@ Navbar.defaultProps = {
name: "درباره ما", name: "درباره ما",
}, },
{ {
link: "/dashboard", link: "/orders",
name: "پیگیری", 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 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 StarRating from "../StarRating";
// import Tag from "../Tag"; // import Tag from "../Tag";
// import ReactTooltip from "react-tooltip"; // import ReactTooltip from "react-tooltip";
import book from "./goldon.png"; import book from "./goldon.png";
import watermelon from "./watermelon.png"; // import watermelon from "./watermelon.png";
import heart from "./vuesax-linear-heart.svg"; import heart from "./vuesax-linear-heart.svg";
import discountImg from "./discount.png"; import discountImg from "./discount.png";
import YellowDotIcon from "./yellowDotIcon.svg"; // import YellowDotIcon from "./yellowDotIcon.svg";
import RedDotIcon from "./redDotIcon.svg"; // import RedDotIcon from "./redDotIcon.svg";
import PurpleDotIcon from "./purpleDotIcon.svg"; // import PurpleDotIcon from "./purpleDotIcon.svg";
import LightBlueDotIcon from "./lightBlueDotIcon.svg"; // import LightBlueDotIcon from "./lightBlueDotIcon.svg";
import StarRatingComponent from "react-star-rating-component"; // import StarRatingComponent from "react-star-rating-component";
const ProductDesign = ({ const ProductDesign = ({
grades,
colors, colors,
likeBtn, likeBtn,
discount, discount,
@ -23,6 +26,7 @@ const ProductDesign = ({
productContent, productContent,
star, star,
productTags, productTags,
product,
priceDirection, priceDirection,
productTitleAlignment, productTitleAlignment,
priceHolder, priceHolder,
@ -34,37 +38,36 @@ const ProductDesign = ({
productCatTextColor, productCatTextColor,
rangeHolder, rangeHolder,
verticalImg, verticalImg,
horizontalImg,
rangeWidth, rangeWidth,
addToCartHolder, addToCartHolder,
productName, productName,
productPrice, productPrice,
productImg,
writeGHEIMAT, writeGHEIMAT,
numberOfRegards, numberOfRegards,
productHolderHoverBorder, productHolderHoverBorder,
hoverMode, hoverMode,
big, starRate,
starRate imageSize,
}) => { }) => {
const [isHovering, setIsHovering] = useState(false); const [isHovering, setIsHovering] = useState(false);
return ( return (
<div className={`flex flex-wrap sm:flex-nowrap justify-around ${big ? 'm' : 'w-48 m-2'} `} <Link
style={big ? {width: '300px'} : {}} 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 <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)} onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)} onMouseLeave={() => setIsHovering(false)}
> >
{/* product image */} {/* product image */}
<div className="w-full relative"> <div className="w-full relative">
{/* icons on image */} {/* icons on image */}
<div className="absolute left-0 top-10"> <div className="w-full absolute left-0 top-10">
{discountPricePercent && ( {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"> <p className="text-discountPriceTitle font-bold text-md text-blueC0">
23<span>%</span> 23<span>%</span>
</p> </p>
@ -82,61 +85,27 @@ const ProductDesign = ({
)} )}
</div> </div>
{/* img */} {/* img */}
<div className={`w-full ${big ? 'h-60' : 'h-48'} flex bg-grayF4 p-0 justify-center rounded-lg`}> <div
{verticalImg && ( className={`w-full flex bg-grayF4 p-0 justify-center rounded-lg group`}
<img >
src={productImg} <img
alt="" src={`https://dnvn.ir/api/v1/file/${product.fileIds}`}
className="h-full rounded-lg cursor-pointer py-5" alt=""
style={{
/> height: `calc(100vh / ${imageSize})`,
)} width: `calc(100vh / ${imageSize} * 2 / 3.5)`,
{horizontalImg && ( }}
<img src={watermelon} alt="" className="w-full rounded-lg" /> className="rounded-lg cursor-pointer py-5"
)} />
</div> </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> </div>
{/* product content */} {/* product content */}
<div className="px-2"> <div className="w-full px-2">
<div className="mt-4"> <div className="w-full mt-4">
<h2 <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> </h2>
{productContent && ( {productContent && (
<p <p
@ -147,31 +116,34 @@ const ProductDesign = ({
</p> </p>
)} )}
{productCat && ( {productCat && (
<span className={`text-md py-1 font-light ${productCatTextColor}`}> <span className={`text-sm py-1 font-normal text-blueC0`}>
{productCat} {"پایه" + " " + grades[product.gradeId]}
</span> </span>
)} )}
</div> </div>
{/* star */} {/* star */}
{star && ( {star && (
<div className="flex items-center mt-3"> <div className="flex items-center mt-3">
<StarRating value={starRate} size={big ? '' : 'small'}/> <StarRating value={starRate || 4} />
<span className="text-xs text-productContent font-bold text-gray-500 mr-2"> {/* <span className="text-xs text-productContent font-bold text-gray-500 mr-2">
بر اساس {numberOfRegards} بررسی بر اساس {numberOfRegards} بررسی
</span> </span> */}
</div> </div>
)} )}
{/* price */} {/* price */}
{priceHolder && ( {priceHolder && (
<div <div className={`flex items-center justify-between mt-2`}>
className={`flex items-center justify-between ${priceDirection}`}
>
<div className="mt-2"> <div className="mt-2">
<div <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 */} {/* price with line on it */}
{discountPrice && ( {discountPrice && (
<p className="line-through text-xs text-borderColor mr-2"> <p className="line-through text-xs text-borderColor mr-2">
@ -179,36 +151,34 @@ const ProductDesign = ({
</p> </p>
)} )}
</div> </div>
<p className="text-xl text-productPrice font-semibold inline text-blue5F"> <p className="text-lg text-productPrice font-semibold inline text-blue5F">
{productPrice} <span>تومان</span> {separate(product?.product[1]?.price)} <span>تومان</span>
</p> </p>
</div> </div>
{/* add to cart */} {/* add to cart */}
{addToCartHolder && ( {addToCartHolder && (
<button <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> </button>
)} )}
</div> </div>
)} )}
{hoverMode == "blue" ? (
<div className="w-full flex justify-center mt-4">
{hoverMode == 'blue' ?<div className="w-full flex justify-center mt-4"> <div
<div className={`bg-blueC0 text-white rounded p-4 text-xs justify-center ${
className={`bg-blueC0 text-white rounded p-4 text-xs justify-center ${isHovering ? "" : "hidden" isHovering ? "" : "hidden"
}`} }`}
> >
<button>افزودن به سبد خرید</button> <button>افزودن به سبد خرید</button>
</div>
</div> </div>
</div> : null} ) : null}
{/* {productTags && ( {/* {productTags && (
<div className="mt-2 flex flex-wrap"> <div className="mt-2 flex flex-wrap">
@ -224,15 +194,18 @@ const ProductDesign = ({
></div> ></div>
</div> </div>
)} )}
</div> </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 colors i used for product title:
// text-darkCrimsonTextColor // text-darkCrimsonTextColor
@ -281,5 +254,5 @@ ProductDesign.defaultProps = {
//میتونیم تعیین کنیم که قیمت و دکمه اضاف به سبد خرید کنار یکدیگر باشند یا زیر هم //میتونیم تعیین کنیم که قیمت و دکمه اضاف به سبد خرید کنار یکدیگر باشند یا زیر هم
priceDirection: "flex-row", priceDirection: "flex-row",
productImg: book, productImg: book,
writeGHEIMAT: false writeGHEIMAT: false,
}; };

@ -1,36 +1,70 @@
import React from "react"; import React, { useState, useEffect } from "react";
import "./index.scss"; import "./index.scss";
import productImg from "./product-image.jpg"; import productImg from "./product-image.jpg";
const ProductImage = ({ images }) => { 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 ( return (
<div className="flex flex-row w-1/3 gap-2"> <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)'}}> <div
{images.slice(0, 4).map((image, index) => ( className="flex flex-col items-center justify-between w-1/5"
<div className="relative" style={{ width : "calc(100vw / 5 / 4 - 4px)", height : "calc(100vw / 5 / 4 - 4px)"}}> style={{ height: "calc(100vw / 5)" }}
<img >
key={index} {list?.slice(0, 4)?.map((image, index) => (
src={productImg} <div
alt="" className={`relative flex justify-center items-center ${ activeImage === image ? 'bg-green-200' : 'bg-gray-200'}`}
className={`rounded-sm w-full h-full`} style={{
// style={{ height: "calc(100% - 8px)" }} width: "calc(100vw / 5 / 4 - 4px)",
// style={{ height: "calc(100% - 8px)" }} height: "calc(100vw / 5 / 4 - 4px)",
/> }}
{/* این خط پایین که نوشتم برای این است که ایندکس که جنسش استرینگ است رو به نامبر تبدیل کند */} onClick={() => setActiveImage(image)}
{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"> <img
<strong>+ {images.length - 3}</strong> key={index}
</div> src={`https://dnvn.ir/api/v1/file/${image}`}
)} alt=""
</div> className={`rounded-sm w-full h-full`}
))} style={{
</div> width: "calc(100vw / 5 / 4 * 2 / 3 - 12px)",
<img src={productImg} alt="" style={{ height : "calc(100vw / 5)", width : "calc(100vw / 5)"}} /> 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>
</div>
); );
}; };
// {[0, 1, 2, 3, 4].map((item, index) => ( // {[0, 1, 2, 3, 4].map((item, index) => (
@ -38,23 +72,3 @@ const ProductImage = ({ images }) => {
// ))} // ))}
export default ProductImage; 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 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 Button from "../Button";
import arrow from "./arrow-icon.svg"; import arrow from "./arrow-icon.svg";
@ -10,7 +13,16 @@ import shield from "./shield-tick.svg";
import tick from "./tick-circle.svg"; import tick from "./tick-circle.svg";
import shop from "./icon-shop.svg"; import shop from "./icon-shop.svg";
const ProductStatusCard = ({ items, productPrice, discountPrice, isDark }) => { const ProductStatusCard = ({
items,
price,
discountPrice,
isDark,
id,
userId,
isLogin,
pushToCart,
}) => {
return ( return (
<section className="w-full"> <section className="w-full">
<div className="bg-grayF9 rounded-md px-4 py-2 divide-y divide-solid divide-gray-200"> <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"> <div className="flex flex-col items-center py-3">
<p className="text-xl text-blue-600"> <p className="text-xl text-blue-600">
{productPrice} {separate(price)}
<span className="text-sm text-gray-700 font-light">تومان</span> <span className="text-sm text-gray-700 font-light">تومان</span>
</p> </p>
<p className="text-xs font-light text-gray-600 mt-2"> <p className="text-xs font-light text-gray-600 mt-2">
@ -51,13 +63,21 @@ const ProductStatusCard = ({ items, productPrice, discountPrice, isDark }) => {
</p> </p>
</div> </div>
<Button <Button
title=صافه کردن به سبد خرید" title=ضافه کردن به سبد خرید"
backgroundColor={isDark ? "bg-blueC0" : "bg-blueC0"} backgroundColor={isDark ? "bg-blueC0" : "bg-blueC0"}
border={{ color: isDark ? "#ffffff55" : "#196EC055", width: "1px" }} border={{ color: isDark ? "#ffffff55" : "#196EC055", width: "1px" }}
width="100%" width="100%"
color={"text-white"} color={"text-white"}
selectable={true} selectable={true}
onClick={() => {}} onClick={() =>
isLogin
? pushToCart({
productId: id,
userId: userId,
count: 1,
})
: toast.info("ابتدا وارد حساب کاربری خود شوید.")
}
/> />
</div> </div>
<div className="bg-grayF9 rounded px-4 py-2 mt-4 flex flex-row items-center"> <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) => ({ const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark, 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 = { ProductStatusCard.defaultProps = {
items: [ items: [

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

@ -2,7 +2,7 @@ import React, { useState } from "react";
import Table from "./table"; import Table from "./table";
const ProductTab = ({ tabs }) => { const ProductTab = ({ tabs }) => {
const [selectedTab, setSelectedTab] = useState(tabs[0]); const [selectedTab, setSelectedTab] = useState(tabs[1]);
return ( return (
<section className="mt-10 flex flex-col w-full"> <section className="mt-10 flex flex-col w-full">
@ -11,7 +11,7 @@ const ProductTab = ({ tabs }) => {
{tabs.map((tab, index) => ( {tabs.map((tab, index) => (
<li <li
className={`text-sm cursor-pointer hover:text-blue-400 py-4 transition-all duration-500 ${ 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)} onClick={() => setSelectedTab(tab)}
key={index} 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 React from "react";
import {connect} from 'react-redux';
import { publicApi } from "../../redux/actions";
import _ from "lodash"; import _ from "lodash";
import searchIcon from "./search.png"; import searchIcon from "./search.png";
@ -6,9 +8,9 @@ const langDetector = (lang = 'fa', option1, option2) => {
return lang === "fa" ? option1 : option2; return lang === "fa" ? option1 : option2;
}; };
export default function Search(props) { function Search(props) {
return ( 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"> <div className="relative text-gray-600 focus-within:text-gray-400 w-full">
<span className={_.join(["absolute inset-y-0 flex items-center pl-2", langDetector(props.lang, "left-0", "right-0")], " ")}> <span className={_.join(["absolute inset-y-0 flex items-center pl-2", langDetector(props.lang, "left-0", "right-0")], " ")}>
<button <button
@ -20,12 +22,25 @@ export default function Search(props) {
</span> </span>
<input <input
type="search" type="search"
name="q" name={props.name}
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 " 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...")], " ")} placeholder={_.join([langDetector(props.lang , "جستجو...", "Search...")], " ")}
autoComplete="off" autoComplete="off"
onChange={(e) => props.onChange(e.target.value)}
onFocus={() => props.setOverLayer(true)}
onBlur={() => props.setOverLayer(false)}
/> />
</div> </div>
</div> </div>
); );
} }
const mapStateToProps = (state) => ({
})
const mapDispatchToProps = {
setOverLayer : publicApi.setOverLayer
}
export default connect(mapStateToProps, mapDispatchToProps)(Search);

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

@ -12,69 +12,75 @@ export default function VerticalExpandableProductFilter(props) {
const [text, setText] = useState(""); const [text, setText] = useState("");
const [searchResult, setSearchResult] = useState([]); const [searchResult, setSearchResult] = useState([]);
const [checkedBox, setChecked] = useState([]); const [checkedBox, setChecked] = useState([]);
const name = props.name||Math.random() const name = props.name || Math.random();
useEffect(() => { // useEffect(() => {
let fakeSearchResult; // let fakeSearchResult;
fakeSearchResult = props.list.filter( // fakeSearchResult = props.list.filter(
(item1) => item1.name.indexOf(text) !== -1 // (item1) => item1.name.indexOf(text) !== -1
); // );
setSearchResult(fakeSearchResult); // setSearchResult(fakeSearchResult);
}, [text]); // }, [text]);
return ( 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"> <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"> <strong className="text-md text-gray-500 w-full mb-3 text-right px-3">
{props.title} {props.title}
</strong> </strong>
{props.searchAble && <form className="relative w-full px-3 mb-3"> {props.searchAble && (
<input <form className="relative w-full px-3 mb-3">
type="text" <input
placeholder={_.join( type="text"
[langDetector(props.lang, "جستجو...", "Search...")], 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)} 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( <span
[ className={_.join(
"absolute inset-y-0 flex items-center", [
langDetector(props.lang, "left-4", "right-4"), "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"
> >
<img src={searchIcon} className="w-5 h-5" alt="" /> <button
</button> type="submit"
</span> className="p-1 focus:outline-none focus:shadow-outline"
</form>} >
<ul className="w-full list-none flex flex-col divide-y divide-gray-100"> <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( {(searchResult.length > 0 ? searchResult : props.list)?.map(
(item1, i) => ( (item1, i) => (
<li <li
key={i} key={i}
className="hover:bg-gray-100 px-3 flex flex-row items-center justify-between py-2" 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"> <div className="flex flex-row items-center">
<Checkbox name={`ch${name}_${i}`} checked={checkedBox[i]} onclick={(e) => { <Checkbox
checkedBox[i] = !checkedBox[i] name={`ch${name}_${i}`}
setChecked(checkedBox) checked={false}
onclick={(e) => {
checkedBox[i] = !checkedBox[i];
}} onChange={() => props.onChange(name , item1.name)} /> setChecked(checkedBox);
}}
onChange={() => props.onChange(name, item1.name)}
/>
<strong className="text-xs font-light text-gray-500"> <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> </strong>
</div> </div>
{item1.subList?.length > 0 && ( {item1?.subList?.length > 0 && (
<img <img
src={arrowIcon} src={arrowIcon}
alt="" alt=""
@ -91,92 +97,17 @@ export default function VerticalExpandableProductFilter(props) {
) )
)} )}
</ul> </ul>
{props.btnTitle && <div className="flex align-center justify-center"> {props.btnTitle && (
<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 className="flex align-center justify-center">
</div>} <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> </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 React, { useEffect, useState } from "react";
import {Link} from 'react-router-dom';
import separate from '../../utils/separate';
import StarRating from "../StarRating"; import StarRating from "../StarRating";
import ReactTooltip from "react-tooltip"; import ReactTooltip from "react-tooltip";
//assets //assets
import videoImage1 from './videoImages/image-1.svg'; import videoImage1 from "./videoImages/image-1.svg";
import videoImage2 from './videoImages/image-2.svg'; import videoImage2 from "./videoImages/image-2.svg";
import videoImage3 from './videoImages/image-3.svg'; import videoImage3 from "./videoImages/image-3.svg";
import videoImage4 from './videoImages/image-4.svg'; import videoImage4 from "./videoImages/image-4.svg";
import videoImage5 from './videoImages/image-5.svg'; import videoImage5 from "./videoImages/image-5.svg";
import videoImage6 from './videoImages/image-6.svg'; import videoImage6 from "./videoImages/image-6.svg";
import watermelon from "./watermelon.png"; import watermelon from "./watermelon.png";
import video from "./danovin.mp4"; import video from "./danovin.mp4";
@ -21,36 +21,39 @@ import RedDotIcon from "./redDotIcon.svg";
import PurpleDotIcon from "./purpleDotIcon.svg"; import PurpleDotIcon from "./purpleDotIcon.svg";
import LightBlueDotIcon from "./lightBlueDotIcon.svg"; import LightBlueDotIcon from "./lightBlueDotIcon.svg";
import whitePlayIcon from "./white-play-button-icon.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 = ({ const VodProduct = ({
video,
index, index,
productColor, productColor,
colors,
likeBtn, likeBtn,
discount,
discountPricePercent, discountPricePercent,
discountPrice, discountPrice,
productContent, productContent,
star, star,
productTags, productTags,
priceDirection, priceDirection,
productTitleAlignment,
priceHolder, priceHolder,
productCat,
rangeHolder, rangeHolder,
priceTitle, priceTitle,
addToCartHolder, addToCartHolder,
productTitleCategoryHolder,
productTitleCategoryHolderAlignment,
priceStarHolder, priceStarHolder,
priceStarAlignment, priceStarAlignment,
rangeWidth, rangeWidth,
productTitle,
poster,
price, price,
minHeight height,
grades,
// minHeight,
}) => { }) => {
const [progressFlag, setProgressFlag] = useState(false); const [progressFlag, setProgressFlag] = useState(false);
// const [openModal, setOpenModal] = useState(false); // const [openModal, setOpenModal] = useState(false);
@ -60,12 +63,16 @@ const VodProduct = ({
}, 1000); }, 1000);
}); });
console.log(index); // console.log(index);
return ( return (
<> <>
{/* product UI Design */} {/* product UI Design */}
<div className="flex flex-wrap sm:flex-nowrap justify-around"> <Link
<div className="w-full flex flex-wrap items-center justify-around my-10 px-1 sm:px-4"> 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 <div
className={`w-full mx-1 sm:w-60 md:w-96 rounded-lg shadow-sm p-2 my-3 border border-grayBorderColor`} 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)]})`, backgroundImage: `url(${videoImages[Number(index)]})`,
backgroundSize: "100% 100%", backgroundSize: "100% 100%",
backgroundRepeat: "no-repeat", backgroundRepeat: "no-repeat",
minHeight: minHeight, height: height,
// minHeight: minHeight,
}} }}
data-modal-toggle="large-modal" data-modal-toggle="large-modal"
> >
{/* icons on image */} {/* icons on image */}
<div className="absolute left-6 top-2"> <div className="absolute left-2 top-1">
{discountPricePercent && ( {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"> <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"> <p className="text-discountPriceTitle font-bold text-xs">
@ -114,7 +122,7 @@ const VodProduct = ({
</div> </div>
{/* select Color */} {/* select Color */}
{productColor && ( {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))} */} {/* {colors.map((color,index))} */}
<img <img
src={YellowDotIcon} src={YellowDotIcon}
@ -130,21 +138,16 @@ const VodProduct = ({
<div className="px-2"> <div className="px-2">
{/* content */} {/* content */}
<div className="mt-4 flex flex-col"> <div className="mt-4 flex flex-col">
<div <div className={`flex justify-between `}>
className={`flex ${productTitleCategoryHolder} ${productTitleCategoryHolderAlignment} justify-between `}
>
<h2 <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> </h2>
{productCat && ( {console.log(video?.gradeId)}
<span <span className={`text-sm font-light text-blueC0`}>
className={`text-xs font-light text-darkCrimsonTextColor`} { 'پایه' + ' ' + grades[video?.gradeId]}
> </span>
{productCat}
</span>
)}
</div> </div>
{productContent && ( {productContent && (
<p <p
@ -172,23 +175,22 @@ const VodProduct = ({
: "flex" : "flex"
}`} }`}
> >
{priceTitle && ( <span className="text-xs text-borderColor ml-2">
<span className="text-xs text-borderColor ml-2">
قیمت </span>
</span>
)} {/* {discountPrice && (
{discountPrice && (
<p className="line-through text-xs text-borderColor"> <p className="line-through text-xs text-borderColor">
<span> قیمت</span> 140<span>تومان</span> <span> قیمت</span> 140<span>تومان</span>
</p> </p>
)} )} */}
</div> </div>
<p {/* <p
className={`text-sm font-semibold inline text-productPrice`} className={`text-base font-semibold text-left`}
> >
{price} {separate(video?.price) + ' '}
<span>تومان</span> <span>تومان</span>
</p> </p> */}
</div> </div>
{/* add to cart */} {/* add to cart */}
{addToCartHolder && ( {addToCartHolder && (
@ -202,14 +204,14 @@ const VodProduct = ({
)} )}
</div> </div>
)} )}
{star && ( {/* {star && (
<div className="flex items-center"> <div className="flex items-center">
<StarRating /> <StarRating />
<span className="text-xs text-productContent font-bold mr-2"> <span className="text-xs text-productContent font-bold mr-2">
39 39
</span> </span>
</div> </div>
)} )} */}
</div> </div>
{productTags && ( {productTags && (
<div className="mt-2 flex flex-wrap"> <div className="mt-2 flex flex-wrap">
@ -237,7 +239,7 @@ const VodProduct = ({
</div> </div>
</div> </div>
</div> </div>
</div> </Link>
{/* <div {/* <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" 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" id="large-modal"

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

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

@ -1,11 +1,11 @@
import proxy from "../proxy"; import proxy from "../proxy";
const user = { const user = {
otp: (data) => async (dispatch) => otp: (data = {}) => async (dispatch) =>
await proxy.post("public/sendOTP", data, { dispatch }), await proxy.post("public/sendOTP", data, { dispatch }),
otp_login: (data) => async (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) => login: (data) => async (dispatch) =>
await proxy.login("user/login", data, { 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 book } from "./book";
export { default as blog } from "./blog"; export { default as blog } from "./blog";
export { default as product } from "./product"; 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 faq } from "./faq";
export { default as file } from "./file"; export { default as file } from "./file";
export { default as userFactor } from "./userFactor"; export { default as userFactor } from "./userFactor";

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

@ -19,7 +19,7 @@ export default function user(state = initialState, action) {
// case "user/register": // case "user/register":
// case "user/switchRole": // case "user/switchRole":
case "public/sendOTP": case "public/sendOTP":
return { ...state, loading: false, status: data.profile, error: null }; return { ...state, loading: false, error: null };
case "user/login": case "user/login":
case "user/otp/login": case "user/otp/login":
return { 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 Contact from "./views/Contact";
import Dashboard from "./views/Dashboard"; import Dashboard from "./views/Dashboard";
import FooterDesign1 from "./components/Footer"; import FooterDesign1 from "./components/Footer";
import Bugs from "./views/BugsAndProblems";
// import VideoTube from "./views/Home/VideoTube"; // import VideoTube from "./views/Home/VideoTube";
function Router({ function Router({
@ -351,6 +352,7 @@ function Router({
/> />
} }
/> />
<Route path="/bugs" exact element={<Bugs />} />
<Route <Route
path="*" path="*"
exact exact

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

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

@ -157,7 +157,7 @@ class scroll {
initializeBoxPosition = (currentScroll) => { initializeBoxPosition = (currentScroll) => {
const height= window.innerHeight; const height= window.innerHeight;
if(currentScroll < height){ if(currentScroll < height){
console.log(currentScroll); // console.log(currentScroll);
return { return {
translateX: -5, translateX: -5,
translateY: -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 ( return (
<div <div
className="w-full flex h-full transform justify-center items-center flex-col bg-transparent px-4" className="w-full flex h-screen transform justify-center items-center flex-col bg-transparent px-4"
style={{ height: "calc(100vh - 160px)" }}
> >
<h1 <h1
className="dark:text-white text-5xl font-semibold" className="dark:text-white text-5xl font-semibold"
@ -19,7 +18,7 @@ function NotFound({ headerOptions, setHeaderOptions }) {
404 404
</h1> </h1>
<img src={notFoundImage} alt="404" className="mt-10" /> <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 /> <br />
صفحه ای که بدنبال آن بودهاید دیگر وجود ندارد :( صفحه ای که بدنبال آن بودهاید دیگر وجود ندارد :(

@ -12,7 +12,7 @@ function AR({ getArList, arList, headerOptions, setHeaderOptions }) {
}, []); }, []);
return ( 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.length > 0 &&
arList.map((book, index) => <Book book={book} key={index} />)} arList.map((book, index) => <Book book={book} key={index} />)}
</div> </div>

@ -18,8 +18,8 @@ function Activation({ headerOptions, setHeaderOptions, isMobile }) {
}, []); }, []);
return ( return (
<div <div
className="w-full flex h-full flex-col bg-transparent" className="w-full flex h-full flex-col bg-transparent lg:pt-36 lg:pb-24"
style={{ height: "calc(100vh - 145px)" }} // style={{ height: "calc(100vh - 145px)" }}
> >
<Header bg={isMobile ? qrBgImage : desktopQrBgImage} title="فعالسازی کتاب دیجیتال" /> <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"> <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 MultipleSelector from "./MultipleSelector";
import Document from "./Document"; import Document from "./Document";
function Profile({ function Profile({
isMobile,
profile, profile,
uploads, uploads,
getProvince, getProvince,
@ -187,7 +187,7 @@ function Profile({
// if (setDone) return <Navigate path="/" />; // if (setDone) return <Navigate path="/" />;
return ( return isMobile ? (
<div className="profile main d-flex justify-content-center"> <div className="profile main d-flex justify-content-center">
<main> <main>
<header className="d-flex align-items-center justify-content-between"> <header className="d-flex align-items-center justify-content-between">
@ -336,7 +336,7 @@ function Profile({
/> />
</div> </div>
) : null} ) : null}
{console.log(province)} {/* {console.log(province)} */}
<div className="mb-2" style={{ minWidth: "100%" }}> <div className="mb-2" style={{ minWidth: "100%" }}>
<Select <Select
options={provinceList} options={provinceList}
@ -419,6 +419,16 @@ function Profile({
</div> </div>
</main> </main>
</div> </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, uploads: state.file.uploads,
provinceList: state.publicApi.province, provinceList: state.publicApi.province,
cityList: state.publicApi.city, cityList: state.publicApi.city,
isMobile: state.publicApi.isMobile,
}), }),
{ {
getProfile: user.getProfile, getProfile: user.getProfile,

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

@ -7,9 +7,9 @@ export const Dashboard = ({ isMobile }) => {
return isMobile ? ( return isMobile ? (
<div className=""></div> <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"> <div className="gap-5 w-11/12 h-full mx-auto flex flex-row bg-transparent">
<Sidebar /> {/* <Sidebar /> */}
<Main /> <Main />
</div> </div>
</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 { connect } from "react-redux";
import {book} from '../../../../../redux/actions';
import MyBooks from "../../../../Home/Portrait/Private/MyBooks"; import MyBooks from "../../../../Home/Portrait/Private/MyBooks";
import Videos from "../../../../Home/Portrait/Private/Videos"; import Videos from "../../../../Home/Portrait/Private/Videos";
import ProductSuggestion from './ProductSuggestion';
export const UserItems = ({list, grades, getList, isMobile}) => {
export const UserItems = ({}) => { useEffect(() => {
if(list.length <= 0){
getList();
}
},[]);
return ( return (
<div className="flex-1 flex flex-col overflow-y-scroll"> <div className="w-full flex flex-col lg:pt-20">
<MyBooks /> <MyBooks books={list} grades={grades} />
<Videos /> <br/>
<Videos videos={list} grades={grades} />
<ProductSuggestion products={list} grades={grades} isMobile={isMobile} />
</div> </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); 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 { connect } from "react-redux";
import {publicApi} from '../../../../redux/actions';
import Orders from "../../../Orders"; import Orders from "../../../Orders";
import UserItems from "../Main/UserItems"; import UserItems from "../Main/UserItems";
export const Main = ({}) => { export const Main = ({setHeaderOptions}) => {
useEffect(() => {
setHeaderOptions({shown: true});
},[]);
const views = { const views = {
orders: <Orders />, // orders: <Orders />,
userItems: <UserItems /> userItems: <UserItems />
}; };
const [page, setPage] = useState("orders"); const [page, setPage] = useState("userItems");
return <div className="flex-1 py-2.5 overflow-y-scroll">{views[page]}</div>; return <div className="w-full py-2.5">{views[page]}</div>;
}; };
const mapStateToProps = (state) => ({}); const mapStateToProps = (state) => ({});
const mapDispatchToProps = {}; const mapDispatchToProps = {
setHeaderOptions: publicApi.setHeaderOptions,
};
export default connect(mapStateToProps, mapDispatchToProps)(Main); export default connect(mapStateToProps, mapDispatchToProps)(Main);

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

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

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

@ -1,88 +1,87 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { connect } from "react-redux"; 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 { Link } from "react-router-dom";
import Product from '../../../../components/Product'; import Product from "../../../../components/Product";
import Button from "../../../../components/Button"; import Button from "../../../../components/Button";
import ScrollContainer from "react-indiana-drag-scroll"; // 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}
color= "text-blueC0" const Part2 = ({ books, grades }) => {
onClick={() => null} // console.log({ books });
radius={false} const [filter, setFilter] = useState({
twPaddings="py-4 px-12 rounded" search: "",
/> grade: "",
</Link> productsType: "کتاب",
</div> });
</div> return (
<ScrollContainer className="flex overflow-x-scroll py-4 pl-10"> <div
{ className="w-full my-6"
books?.slice(15,24).map((product, index) => ( style={
<Link to={"/products/" + product?.id}> {
<Product // height: "550px",
key={`prod_New${index}`} }
productsType={filter.productsType} }
product={product} >
index={Number(index)} <div className="w-full flex justify-between items-center mb-4">
productName={`کتاب ${product?.name}`} <div className="flex items-center text-4xl font-black text-blue52">
productCat={`پایه ${grades[product?.gradeId]}`} <div className="w-6 h-6 bg-blue-300 ml-4 rounded-full"></div>
productPrice={100000} <h1 className="text-2xl text-blue5F">کتاب های جدید</h1>
productImg={"https://dnvn.ir/api/v1/file/" + product?.fileIds} </div>
numberOfRegards={160} <div>
productTitleColor='text-blue5F' <Link to="/products">
productCatTextColor='text-blueC0' <Button
productHolderBorder='' title="مشاهده لیست محصولات"
productHolderHoverBorder='shadow-md' backgroundColor="bg-blue-100"
hoverMode='blue' border={{
big color: "#196EC055",
starRate={Math.floor(Math.random() * 5) + 1} 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>
) )}
} </div>
);
};
const mapStateToProps = (state) => ({ 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 Button from "../../../../components/Button";
import VodProduct from "../../../../components/VodProduct"; import VodProduct from "../../../../components/VodProduct";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import posterImage from '../../../../assets/images/poster.svg' import posterImage from "../../../../assets/images/poster.svg";
const Part4 = () => { const Part4 = ({ books, grades }) => {
const videosData = [ const videosData = [
{ {
id: 0, id: 0,
name: "ریاضی", name: "ریاضی",
price: "145.000", price: "145.000",
grade: " پایه چهارم ", grade: " پایه چهارم ",
imageUrl: "https://dnvn.ir/api/v1/file/2105", imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage, poster: posterImage,
}, },
{ {
id: 2, id: 2,
name: "علوم تجربی", name: "علوم تجربی",
price: "145.000 ", price: "145.000 ",
grade: "پایه سوم", grade: "پایه سوم",
imageUrl: "https://dnvn.ir/api/v1/file/2105", imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage, poster: posterImage,
}, },
{ {
id: 1, id: 1,
name: "زمین شناسی", name: "زمین شناسی",
price: "145.000 ", price: "145.000 ",
grade: "پایه چهارم", grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105", imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage, poster: posterImage,
}, },
{ {
id: 3, id: 3,
name: "ریاضی", name: "ریاضی",
price: "145.000 ", price: "145.000 ",
grade: "پایه چهارم", grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105", imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage, poster: posterImage,
}, },
{ {
id: 5, id: 5,
name: "ریاضی", name: "ریاضی",
price: "145.000 ", price: "145.000 ",
grade: "پایه چهارم", grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105", imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage, poster: posterImage,
}, },
{ {
id: 4, id: 4,
name: "ریاضی", name: "ریاضی",
price: "145.000 ", price: "145.000 ",
grade: "پایه چهارم", grade: "پایه چهارم",
imageUrl: "https://dnvn.ir/api/v1/file/2105", imageUrl: "https://dnvn.ir/api/v1/file/2105",
poster: posterImage, 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}
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 <VodProduct
productTitle={`دوره ی ویدیویی ${video.name}`} video={video}
productCat={video.grade}
price={video.price}
priceTitle={false}
discountPrice={false}
key={index} key={index}
index={index} index={index}
minHeight={"calc(100vh / 3.5)"} height={"calc(100vh / 3.8)"}
grades={grades}
/> />
</Link> </li>
</li> ))}
)) </ul>
} </ul>
</ul> </div>
);
};
</ul>
</div>
}
export default Part4; 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 React, { useState, useEffect } from "react";
import ScrollContainer from "react-indiana-drag-scroll"; import { connect } from "react-redux";
import { connect } from 'react-redux'; import SalesContainer from "./SalesContainer";
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 { book, publicApi } from "../../../redux/actions"; import { book, publicApi, product } from "../../../redux/actions";
import Part2 from "./Part2"; import Part2 from "./Part2";
import HomeImg from '../../../assets/images/HomeImg.png'; import HomeImg from "../../../assets/images/HomeImg.png";
import Part4 from "./Part4"; import Part4 from "./Part4";
import Design2D from "../../../components/Design2D"; import Design2D from "../../../components/Design2D";
const DesktopHome = ( const DesktopHome = ({ grades, getBooks, books }) => {
{ const banners = [
books, {
grades 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(() => {
const banners = [ getBooks();
{ },[]);
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'
}],
},
]
return ( return (
<div className="flex flex-col items-center w-11/12 justify-center py-24">
<div className="flex flex-col items-center w-11/12 justify-center my-10"> {/* <Banners
{/* <Banners
mainBanner='https://dkstatics-public.digikala.com/digikala-adservice-banners/d2a56a4a0c3ce4645bf0b405b0bbf3a29da1cbd3_1642861192.jpg' mainBanner='https://dkstatics-public.digikala.com/digikala-adservice-banners/d2a56a4a0c3ce4645bf0b405b0bbf3a29da1cbd3_1642861192.jpg'
midBottomBanner='https://dkstatics-public.digikala.com/digikala-adservice-banners/e13aefeda2d3b44db78a92aac9cdc82a9b1650e9_1632230372.jpg?' midBottomBanner='https://dkstatics-public.digikala.com/digikala-adservice-banners/e13aefeda2d3b44db78a92aac9cdc82a9b1650e9_1632230372.jpg?'
leftBanner= leftBanner=
midTopBanner='https://dkstatics-public.digikala.com/digikala-adservice-banners/fe8f275f4e4b5e6eb2f66cf65f3895398e049b40_1625578273.jpg' midTopBanner='https://dkstatics-public.digikala.com/digikala-adservice-banners/fe8f275f4e4b5e6eb2f66cf65f3895398e049b40_1625578273.jpg'
/> */} /> */}
<div className="w-full"> <div className="w-full">
<Design2D array={banners} /> <Design2D array={banners} />
</div> </div>
<SalesContainer books={books} grades={grades}/> <SalesContainer books={books} />
<Part2 grades={grades}/> <Part2 grades={grades} books={books} />
<div className="mb-16"> <div className="mb-16">
<img src={HomeImg} /> <img src={HomeImg} />
</div> </div>
<Part4 /> <Part4 books={books} grades={grades} />
</div> </div>
);
) };
}
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark, isDark: state.publicApi.isDark,
isMobile: state.publicApi.isMobile, isMobile: state.publicApi.isMobile,
books: state.book.list, books: state.book.list,
grades: state.publicApi.grades, gradeFilterBooks: state.book.gradeFilterBooks,
gradeFilterBooks: state.book.gradeFilterBooks, selectedGrade: state.book.selectedGrade,
selectedGrade: state.book.selectedGrade, grades: state.publicApi.grades,
}); });
const mapDispatchToProps = {
getList: book.list,
gradeFilter: book.gradeFilter,
setHeaderOptions: publicApi.setHeaderOptions,
};
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 React, { useEffect } from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { book } from "../../../../../redux/actions"; import { ScrollingCarousel } from "@trendyol-js/react-carousel";
import Progress from '../../../../../components/Progress'; import Progress from "../../../../../components/Progress";
function MyBooks({ list, getList, grades, isMobile }) { function MyBooks({ books, getList, grades, isMobile }) {
useEffect(() => { const Book = ({ book }) => {
getList();
}, []);
const Book = ({ book}) => {
return ( 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}> <Link to={"/products/" + book.id}>
<img <img
src={`https://dnvn.ir/api/v1/file/${book.fileIds}`} src={`https://dnvn.ir/api/v1/file/${book.fileIds}`}
@ -21,11 +17,15 @@ function MyBooks({ list, getList, grades, isMobile }) {
height: isMobile ? "" : "calc(100vh / 5)", height: isMobile ? "" : "calc(100vh / 5)",
width: isMobile ? "" : "calc(100vh / 5 * 3 / 4)", width: isMobile ? "" : "calc(100vh / 5 * 3 / 4)",
minHeight: isMobile ? "calc(100vh / 5)" : "", 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> <h2 className="mt-2 text-sm lg:text-tiny font-semibold text-blue5F dark:text-white lg:mt-4">
<p className="font-medium text-blueC0 dark:text-greenBA text-xs lg:text-sm mt-1 lg:mt-2">{`پایه ${grades[book.gradeId]}`}</p> {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} /> <Progress percent={60} />
</Link> </Link>
</li> </li>
@ -33,24 +33,33 @@ function MyBooks({ list, getList, grades, isMobile }) {
}; };
return ( 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"> <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> <strong className="text-blueC0 dark:text-white font-bold text-sm lg:text-base">
<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) => ( </strong>
<Book book={book} key={index} /> {isMobile ? (
))} <ul className="list-none w-full overflow-x-scroll pt-2 flex flex-row lg:pt-5 lg:flex-wrap lg:overflow-y-scroll gap-3 lg:gap-10">
</ul> {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>
</div> </div>
); );
} }
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
list: state.book.list, isMobile: state.publicApi.isMobile,
grades : state.publicApi.grades,
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 React, { useEffect } from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { ScrollingCarousel } from "@trendyol-js/react-carousel";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { book } from "../../../../../redux/actions";
import Progress from "../../../../../components/Progress"; import Progress from "../../../../../components/Progress";
import arrowBlueIcon from "../../../../../assets/icons/arrow-right-blue.svg"; import arrowBlueIcon from "../../../../../assets/icons/arrow-right-blue.svg";
import arrowWhiteIcon from "../../../../../assets/icons/arrow-left-white.svg"; import arrowWhiteIcon from "../../../../../assets/icons/arrow-left-white.svg";
function Videos({ list, getList, grades, isDark, isMobile }) { function Videos({ videos, grades, isDark, isMobile }) {
useEffect(() => { const Video = ({ video }) => {
getList();
}, []);
const Book = ({ book }) => {
return ( 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.name}> <Link to={"/products/" + video.id}>
<img <img
src={`https://dnvn.ir/api/v1/file/${book.fileIds}`} src={`https://dnvn.ir/api/v1/file/${video.posterId}`}
alt="" alt=""
className="rounded-sm" className="rounded-sm"
style={{ style={{
height: isMobile ? "" : "calc(100vw / 8 * 2 / 4)", height: isMobile ? "" : "calc(100vw / 8 * 2 / 4)",
width: isMobile ? "" : "calc(100vw / 8 )", width: isMobile ? "" : "calc(100vw / 8 )",
maxHeight: isMobile ? "calc(100vw / 2 * 2 / 3)" : "", 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"> <h2 className="mt-2 text-sm font-normal text-blue5F dark:text-white lg:mt-4 lg:text-tiny lg:mb-5">
{book.name} {'دوره ویدئویی' + ' ' + video.name}
</h2> </h2>
<p className="font-medium text-blueC0 dark:text-greenBA text-xs mt-1 lg:mt-2 lg:text-sm">{`پایه ${ {/* <p className="font-medium text-blueC0 dark:text-greenBA text-xs mt-1 lg:mt-2 lg:text-sm">{`پایه ${
grades[book.gradeId] grades[video.gradeId]
}`}</p> }`}</p> */}
<Progress percent={60} /> <Progress percent={60} />
</Link> </Link>
</li> </li>
@ -39,7 +35,7 @@ function Videos({ list, getList, grades, isDark, isMobile }) {
}; };
return ( return (
<div className="w-full px-4"> <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"> <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"> <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"}`} className={`transform lg:hidden ${isDark ? "w-7" : "rotate-180"}`}
/> />
</header> </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"> {isMobile ? (
{list.slice(0,5)?.map((book, index) => ( <ul className="list-none w-full overflow-x-scroll pt-3 gap-3 lg:gap-5 flex flex-row lg:pt-5 lg:flex-wrap lg:overflow-y-scroll">
<Book book={book} key={index} /> {videos.slice(0, 5)?.map((video, index) => (
))} <Video video={video} key={index} />
</ul> ))}
</ul>
) : (
<ScrollingCarousel className="mt-6 pb-3">
{videos?.map((video, index) => (
<Video video={video} key={index} />
))}
</ScrollingCarousel>
)}
</div> </div>
</div> </div>
); );
} }
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
list: state.book.list,
grades: state.publicApi.grades,
isDark: state.publicApi.isDark, 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 }) { function Order({ order, isMobile }) {
return ( 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"> <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"> <strong className="font-medium text-sm lg:text-tiny text-blue52 dark:text-white">
{_.join(["شماره سفارش:", order.number], " ")} {_.join(["شماره سفارش:", order.number], " ")}

@ -10,7 +10,7 @@ function Orders({ orders, headerOptions, setHeaderOptions }) {
setHeaderOptions(headerOptions); setHeaderOptions(headerOptions);
}, []); }, []);
return ( 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) => ( {orders.map((order, index) => (
<Order order={order} key={index} /> <Order order={order} key={index} />
))} ))}

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

@ -42,144 +42,155 @@ export const Product = ({
<> <>
{/* Portrait */} {/* Portrait */}
{isMobile ? ( {isMobile ? (
<div className="w-full flex flex-col bg-transparent px-4"> <div className="w-full flex flex-col bg-transparent px-4">
<header <header
className={`w-full flex ${ className={`w-full flex ${
productType === "book" ? "flex-row" : "flex-col" productType === "book" ? "flex-row" : "flex-col"
}`} }`}
> >
<img <img
src={`https://dnvn.ir/api/v1/file/${book?.fileIds}`} src={`https://dnvn.ir/api/v1/file/${book?.fileIds}`}
alt="" alt=""
className="w-5/12 rounded-md" className="w-5/12 rounded-md"
/> />
<div className="flex flex-1 flex-col pr-2 pt-2"> <div className="flex flex-1 flex-col pr-2 pt-2">
<h1 className="text-blue5F mb-3 font-semibold text-sm dark:text-white"> <h1 className="text-blue5F mb-3 font-semibold text-sm dark:text-white">
{type === "digital" {type === "digital"
? book?.product[0]?.name ? book?.product[0]?.name
: book?.product[1]?.name} : book?.product[1]?.name}
</h1> </h1>
<div className="text-blueC0 text-xs dark:text-greenBA"> <div className="text-blueC0 text-xs dark:text-greenBA">
{"پایه" + " " + grades[book?.gradeId]} {"پایه" + " " + grades[book?.gradeId]}
</div>
</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> </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>
<div ) : (
className="flex flex-row w-full pb-4 mt-6" <div className="flex flex-col items-center justify-center lg:py-24">
style={{ overflowX: "scroll" }} <DesktopProductLayout />
>
{[0, 1, 2, 2].map((comment, index) => (
<Comment key={index} />
))}
</div> </div>
</div>) :<div className="flex flex-col items-center justify-center"> )}
<DesktopProductLayout />
</div>
}
</> </>
); );
}; };
@ -189,7 +200,7 @@ const mapStateToProps = (state) => ({
grades: state.publicApi.grades, grades: state.publicApi.grades,
isMobile: state.publicApi.isMobile, isMobile: state.publicApi.isMobile,
isDark: state.publicApi.isDark, isDark: state.publicApi.isDark,
userId: state.user.status.id, userId: state.user.status?.id,
}); });
const mapDispatchToProps = { const mapDispatchToProps = {

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

@ -1,18 +1,17 @@
import React, { useState, useEffect, useCallback } from "react"; 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 { 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 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 posterImage from "../../../assets/images/poster.svg";
import arrow from "../../../assets/icons/slider-arrow.svg";
export const Main = ({
export const Main = ({ isMobile,
books, books,
getList,
grades, grades,
gradeFilter, gradeFilter,
selectedGrade, selectedGrade,
@ -20,170 +19,121 @@ export const Main = ({ isMobile,
setHeaderOptions, setHeaderOptions,
headerOptions, headerOptions,
videos, videos,
filter }) => { filter,
useEffect(() => { }) => {
window.scrollTo(0, 0) useEffect(() => {
}, []) window.scrollTo(0, 0);
}, []);
const filteringNavItems = [ 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 <VodProduct
productTitle={`دوره ی ویدیویی ${video.name}`} video={video}
productCat={video.grade} key={index}
price={video.price} index={index}
priceTitle={false} height={"calc(100vh / 5)"}
discountPrice={false} grades={grades}
key={index}
index={index}
minHeight={"250px"}
/> />
</Link> ))}
)) </Carousel>
} </div>
)}
</ScrollContainer>
<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 {selectedGrade
? gradeFilterBooks?.map((product, index) => ( ? 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 <Product
key={index} key={index}
productsType={filter.productsType}
product={product} product={product}
index={Number(index)} index={Number(index)}
productName={`کتاب ${product?.name}`} grades={grades}
productCat={`پایه ${grades[product?.gradeId]}`} imageSize={4.5}
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}
/> />
</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>
</div>; );
}; };
Main.defaultProps ={ Main.defaultProps = {
videos: [ videos: [],
};
]
}
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark, isDark: state.publicApi.isDark,
isMobile: state.publicApi.isMobile, isMobile: state.publicApi.isMobile,
books: state.book.list,
grades: state.publicApi.grades,
gradeFilterBooks: state.book.gradeFilterBooks,
selectedGrade: state.book.selectedGrade,
}); });
const mapDispatchToProps = { const mapDispatchToProps = {

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

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

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

@ -139,9 +139,20 @@ function Product({ product, grades, pushToCart, isMobile }) {
&nbsp;{product?.product?.price}&nbsp;&nbsp;تومان &nbsp;{product?.product?.price}&nbsp;&nbsp;تومان
</strong> </strong>
<img <img
onClick={() =>
pushToCart(
{
productId: product?.productId,
userId: product?.userId,
count: product?.productType === 1 ? -1 : -product?.count,
},
{},
{ id: product?.factorId }
)
}
src={deleteIcon} src={deleteIcon}
alt="delete" 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>
</div> </div>

@ -3,10 +3,12 @@ import { userProduct, userFactor, publicApi } from "../../redux/actions";
import DeliveryForm from "../DeliveryForm"; import DeliveryForm from "../DeliveryForm";
import Product from "./Product"; import Product from "./Product";
import Address from "../Address";
import Code from "./Code"; import Code from "./Code";
import Button from "../../components/Button"; import Button from "../../components/Button";
//assets //assets
import dropdownIcon from "../../assets/icons/dropdown-blue.svg";
import alertIcon from "../../assets/icons/alert.svg"; import alertIcon from "../../assets/icons/alert.svg";
import { connect } from "react-redux"; import { connect } from "react-redux";
@ -17,7 +19,7 @@ function ShoppingCart({
list, list,
payPrice, payPrice,
factorInfo, factorInfo,
userId, user,
hasPhysical, hasPhysical,
getList, getList,
getInfo, getInfo,
@ -31,10 +33,19 @@ function ShoppingCart({
useEffect(() => { useEffect(() => {
getList(); getList();
getFactorInfo({ userId }); getFactorInfo({ userId: user?.id });
setHeaderOptions(headerOptions); 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 = () => { const Table = () => {
return ( return (
<div className="w-full flex flex-col"> <div className="w-full flex flex-col">
@ -50,9 +61,10 @@ function ShoppingCart({
</strong> </strong>
</header> </header>
<ul className="w-full mt-2 list-none p-0"> <ul className="w-full mt-2 list-none p-0">
{list.map((product, index) => ( {list.map(
<Product key={index} product={product} /> (product, index) =>
))} product.condition < 2 && <Product key={index} product={product} />
)}
</ul> </ul>
</div> </div>
); );
@ -96,6 +108,12 @@ function ShoppingCart({
); );
}; };
const layouts = {
products: <Table />,
deliveryForm: <DeliveryForm setPhase={setPhase} />,
address: <Address setPhase={setPhase} />,
};
return isMobile ? ( return isMobile ? (
<div className="w-full flex flex-col px-4"> <div className="w-full flex flex-col px-4">
{list.map((product, index) => ( {list.map((product, index) => (
@ -147,95 +165,104 @@ function ShoppingCart({
</div> </div>
) : ( ) : (
<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" : "" desktopContentTransform ? "top-24" : ""
}`} }`}
> >
<div className="flex flex-col w-3/4"> <div className="flex flex-col flex-1">{layouts[phase]}</div>
{phase === "products" && <Table />} {phase !== "address" && (
{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"
<div style={{ height: "fit-content" }}
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
<div className="flex flex-col w-full border-t py-2 border-gray-300 border-b"> name="مبلغ سبد خرید"
<PriceStatus value={factorInfo?.sumPrice}
name="مبلغ سبد خرید" type="normal"
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" : "")
}
/> />
<br /> <PriceStatus
<Button name="میزان تخفیف"
title="پرداخت در محل" value={factorInfo?.offPrice}
backgroundColor="bg-transparent" type="error"
border={{ color: "#77777755", width: "1px" }} />
width="100%" <PriceStatus
color="text-blue52" name="مالیات بر ارزش افزوده"
onClick={() => value={Math.floor(factorInfo?.sumPrice * 0.009)}
setPhase(phase === "products" ? "delivery-form" : "") type="error"
}
/> />
<br/>
<br/>
</div> </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">
<Button جمع کل سبد خرید
title="ادامه فرایند خرید" </strong>
backgroundColor="bg-blueC0" <p className="font-medium text-greenBA text-xl dark:text-white">
border={{ color: "#196EC055", width: "1px" }} {factorInfo?.payPrice}
width="100%" <span className="font-medium text-greenBA text-sm mr-2">
color="text-white" تومان
onClick={() => setPhase(phase === "products" ? "delivery-form" : "")} </span>
/> </p>
</div> </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> </div>
); );
} }
@ -246,7 +273,7 @@ const mapStateToProps = (state) => ({
list: state.userProduct.list, list: state.userProduct.list,
payPrice: state.userProduct.sum, payPrice: state.userProduct.sum,
factorInfo: state.userFactor.info, factorInfo: state.userFactor.info,
userId: state.user.status.id, user: state.user.status,
hasPhysical: state.userProduct.hasPhysical, hasPhysical: state.userProduct.hasPhysical,
desktopContentTransform: state.publicApi.desktopContentTransform, desktopContentTransform: state.publicApi.desktopContentTransform,
}); });

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

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

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

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

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

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

Loading…
Cancel
Save