|
|
@ -1,7 +1,7 @@ |
|
|
|
import React, { useState, useEffect } from "react"; |
|
|
|
import React, { useState, useEffect } from "react"; |
|
|
|
import { connect } from "react-redux"; |
|
|
|
import { connect } from "react-redux"; |
|
|
|
import { toast } from "react-toastify"; |
|
|
|
import { toast } from "react-toastify"; |
|
|
|
import { book, userProduct, publicApi } from "../../redux/actions"; |
|
|
|
import { book, userProduct, publicApi, dialog } from "../../redux/actions"; |
|
|
|
import { Link, useNavigate } from "react-router-dom"; |
|
|
|
import { Link, useNavigate } from "react-router-dom"; |
|
|
|
import proxy from "../../redux/proxy"; |
|
|
|
import proxy from "../../redux/proxy"; |
|
|
|
import location from "../../utils/location"; |
|
|
|
import location from "../../utils/location"; |
|
|
@ -22,6 +22,7 @@ import arrow from "../../assets/icons/dropdown-blue.svg"; |
|
|
|
export const Product = ({ |
|
|
|
export const Product = ({ |
|
|
|
isMobile, |
|
|
|
isMobile, |
|
|
|
productType, |
|
|
|
productType, |
|
|
|
|
|
|
|
userProducts, |
|
|
|
getInfo, |
|
|
|
getInfo, |
|
|
|
book, |
|
|
|
book, |
|
|
|
grades, |
|
|
|
grades, |
|
|
@ -29,13 +30,60 @@ export const Product = ({ |
|
|
|
userId, |
|
|
|
userId, |
|
|
|
pushToCart, |
|
|
|
pushToCart, |
|
|
|
headerOptions, |
|
|
|
headerOptions, |
|
|
|
bookmarkLoading, |
|
|
|
userProductLoading, |
|
|
|
setHeaderOptions, |
|
|
|
setHeaderOptions, |
|
|
|
|
|
|
|
availableForSell, |
|
|
|
|
|
|
|
setDialog, |
|
|
|
}) => { |
|
|
|
}) => { |
|
|
|
const [type, setType] = useState("physical"); |
|
|
|
const [whichTypeAdded, setWhichTypeAdded] = React.useState(null); |
|
|
|
const [desktopContentTransform, setDesktopContentTransform] = useState(false); |
|
|
|
const [desktopContentTransform, setDesktopContentTransform] = useState(false); |
|
|
|
const navigation = useNavigate(); |
|
|
|
const navigation = useNavigate(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const physicalAvailableForSell = React.useMemo(() => { |
|
|
|
|
|
|
|
return availableForSell?.find((product) => product === 2); |
|
|
|
|
|
|
|
}, [availableForSell]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const digitalAvailableForSell = React.useMemo(() => { |
|
|
|
|
|
|
|
return availableForSell?.find((product) => product === 1); |
|
|
|
|
|
|
|
}, [availableForSell]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const videoAvailableForSell = React.useMemo(() => { |
|
|
|
|
|
|
|
return availableForSell?.find((product) => product === 4); |
|
|
|
|
|
|
|
}, [availableForSell]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const physicalProduct = React.useMemo(() => { |
|
|
|
|
|
|
|
return book?.product?.find((product) => product?.productType === 2); |
|
|
|
|
|
|
|
}, [book]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const digitalProduct = React.useMemo(() => { |
|
|
|
|
|
|
|
return book?.product?.find((product) => product?.productType === 1); |
|
|
|
|
|
|
|
}, [book]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const videoProduct = React.useMemo(() => { |
|
|
|
|
|
|
|
return book?.product?.find((product) => product?.productType === 4); |
|
|
|
|
|
|
|
}, [book]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const physicalAvailabileInCart = React.useMemo(() => { |
|
|
|
|
|
|
|
return userProducts?.find( |
|
|
|
|
|
|
|
(product) => |
|
|
|
|
|
|
|
product?.productId === physicalProduct?.id && product?.condition < 2 |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
}, [userProducts, book]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const digitalAvailabileInCart = React.useMemo(() => { |
|
|
|
|
|
|
|
return userProducts?.find( |
|
|
|
|
|
|
|
(product) => |
|
|
|
|
|
|
|
product?.productId === digitalProduct?.id && product?.condition < 2 |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
}, [userProducts, book]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const videoAvailabileInCart = React.useMemo(() => { |
|
|
|
|
|
|
|
return userProducts?.find( |
|
|
|
|
|
|
|
(product) => |
|
|
|
|
|
|
|
product?.productId === videoProduct?.id && product?.condition < 2 |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
}, [userProducts, book]); |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
|
getInfo({ id: location.getId(), vod: true }); |
|
|
|
getInfo({ id: location.getId(), vod: true }); |
|
|
|
if (!isMobile) { |
|
|
|
if (!isMobile) { |
|
|
@ -49,6 +97,12 @@ export const Product = ({ |
|
|
|
} |
|
|
|
} |
|
|
|
}, []); |
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
if (!userProductLoading) { |
|
|
|
|
|
|
|
setWhichTypeAdded(null); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, [userProductLoading]); |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
|
if (book) { |
|
|
|
if (book) { |
|
|
|
setHeaderOptions({ ...headerOptions, productId: book?.id }); |
|
|
|
setHeaderOptions({ ...headerOptions, productId: book?.id }); |
|
|
@ -92,7 +146,11 @@ export const Product = ({ |
|
|
|
{book?.pagesNum} <br /> صفحه |
|
|
|
{book?.pagesNum} <br /> صفحه |
|
|
|
</li> |
|
|
|
</li> |
|
|
|
<li className="border-solid border-blueFE flex-1 flex-shrink-0 text-center text-tiny leading-5 font-medium text-green7B dark:text-white"> |
|
|
|
<li className="border-solid border-blueFE flex-1 flex-shrink-0 text-center text-tiny leading-5 font-medium text-green7B dark:text-white"> |
|
|
|
{"فیزیکی - دیجیتالی"} <br /> در دسترس |
|
|
|
<span>{videoAvailableForSell ? "ویدئویی - " : ""}</span> |
|
|
|
|
|
|
|
<span>{digitalAvailableForSell ? "دیجیتال - " : ""}</span> |
|
|
|
|
|
|
|
<span>{physicalAvailableForSell ? "فیزیکی" : ""}</span> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<br /> در دسترس |
|
|
|
</li> |
|
|
|
</li> |
|
|
|
{book?.rate ? ( |
|
|
|
{book?.rate ? ( |
|
|
|
<li className="border-solid border-blueFE flex-1 flex-shrink-0 text-center text-tiny leading-5 font-medium text-green7B dark:text-white"> |
|
|
|
<li className="border-solid border-blueFE flex-1 flex-shrink-0 text-center text-tiny leading-5 font-medium text-green7B dark:text-white"> |
|
|
@ -103,36 +161,91 @@ export const Product = ({ |
|
|
|
<h2 className="text-green7B text-base font-semibold mt-10 dark:text-greenBA"> |
|
|
|
<h2 className="text-green7B text-base font-semibold mt-10 dark:text-greenBA"> |
|
|
|
نسخه محصول را انتخاب کنید |
|
|
|
نسخه محصول را انتخاب کنید |
|
|
|
</h2> |
|
|
|
</h2> |
|
|
|
<div className="w-full flex justify-between items-center mt-5"> |
|
|
|
{physicalProduct && physicalAvailableForSell ? ( |
|
|
|
|
|
|
|
<div className="w-full flex justify-between items-center mt-5 gap-2"> |
|
|
|
<ButtonBetween |
|
|
|
<ButtonBetween |
|
|
|
width="100%" |
|
|
|
width="72%" |
|
|
|
item={"خرید نسخه فیزیکی کتاب"} |
|
|
|
item={"خرید نسخه فیزیکی کتاب"} |
|
|
|
status={separate(book?.product[1]?.price) + " " + "تومان"} |
|
|
|
status={separate(physicalProduct?.price) + " " + "تومان"} |
|
|
|
onClick={() => |
|
|
|
onClick={() => { |
|
|
|
userId |
|
|
|
if (userId) { |
|
|
|
? pushToCart({ |
|
|
|
if (physicalAvailabileInCart) { |
|
|
|
productId: book?.product[1]?.id, |
|
|
|
setDialog({ |
|
|
|
userId, |
|
|
|
text: window.t( |
|
|
|
|
|
|
|
"این محصول قبلا به سبد خرید شما اضافه شده است." |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
type: "confirm", |
|
|
|
|
|
|
|
accept: () => navigation("/cart"), |
|
|
|
|
|
|
|
open: true, |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
setWhichTypeAdded("physical"); |
|
|
|
|
|
|
|
pushToCart({ |
|
|
|
|
|
|
|
productId: physicalProduct?.id, |
|
|
|
|
|
|
|
userId: userId, |
|
|
|
count: 1, |
|
|
|
count: 1, |
|
|
|
}) |
|
|
|
}); |
|
|
|
: toast.info("ابتدا وارد حساب کاربری خود شوید.") |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
setDialog({ |
|
|
|
|
|
|
|
text: window.t( |
|
|
|
|
|
|
|
"ابتدا میبایست وارد حساب کاربری خود شوید." |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
type: "confirm", |
|
|
|
|
|
|
|
accept: () => navigation("/login"), |
|
|
|
|
|
|
|
open: true, |
|
|
|
|
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
loading={userProductLoading && whichTypeAdded === "physical"} |
|
|
|
/> |
|
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<a |
|
|
|
|
|
|
|
href={`https://dnvn.ir/xpdf/${book?.sampleFileId}`} |
|
|
|
|
|
|
|
className="flex-1 border-2 border-solid text-sm border-green-500 bg-green-50 bg-opacity-70 rounded-sm font-bold text-green-700 text-center" |
|
|
|
|
|
|
|
style={{ padding: "18px 0px" }} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
مشاهده نمونه |
|
|
|
|
|
|
|
</a> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
) : null} |
|
|
|
|
|
|
|
{digitalProduct && digitalAvailableForSell ? ( |
|
|
|
<div className="w-full flex justify-between items-center mt-4 gap-2"> |
|
|
|
<div className="w-full flex justify-between items-center mt-4 gap-2"> |
|
|
|
<ButtonBetween |
|
|
|
<ButtonBetween |
|
|
|
width="72%" |
|
|
|
width="72%" |
|
|
|
item={"خرید نسخه دیجیتال کتاب"} |
|
|
|
item={"خرید نسخه دیجیتال کتاب"} |
|
|
|
status={separate(book?.product[0]?.price) + " " + "تومان"} |
|
|
|
status={separate(digitalProduct?.price) + " " + "تومان"} |
|
|
|
onClick={() => |
|
|
|
onClick={() => { |
|
|
|
userId |
|
|
|
if (userId) { |
|
|
|
? pushToCart({ |
|
|
|
if (digitalAvailabileInCart) { |
|
|
|
productId: book?.product[0]?.id, |
|
|
|
setDialog({ |
|
|
|
userId, |
|
|
|
text: window.t( |
|
|
|
|
|
|
|
"این محصول قبلا به سبد خرید شما اضافه شده است." |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
type: "confirm", |
|
|
|
|
|
|
|
accept: () => navigation("/cart"), |
|
|
|
|
|
|
|
open: true, |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
setWhichTypeAdded("digital"); |
|
|
|
|
|
|
|
pushToCart({ |
|
|
|
|
|
|
|
productId: digitalProduct?.id, |
|
|
|
|
|
|
|
userId: userId, |
|
|
|
count: 1, |
|
|
|
count: 1, |
|
|
|
}) |
|
|
|
}); |
|
|
|
: toast.info("ابتدا وارد حساب کاربری خود شوید.") |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
setDialog({ |
|
|
|
|
|
|
|
text: window.t( |
|
|
|
|
|
|
|
"ابتدا میبایست وارد حساب کاربری خود شوید." |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
type: "confirm", |
|
|
|
|
|
|
|
accept: () => navigation("/login"), |
|
|
|
|
|
|
|
open: true, |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
loading={userProductLoading && whichTypeAdded === "digital"} |
|
|
|
/> |
|
|
|
/> |
|
|
|
<a |
|
|
|
<a |
|
|
|
href={`https://dnvn.ir/xpdf/${book?.sampleFileId}`} |
|
|
|
href={`https://dnvn.ir/xpdf/${book?.sampleFileId}`} |
|
|
@ -142,20 +255,44 @@ export const Product = ({ |
|
|
|
مشاهده نمونه |
|
|
|
مشاهده نمونه |
|
|
|
</a> |
|
|
|
</a> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
) : null} |
|
|
|
|
|
|
|
{videoProduct && videoAvailableForSell ? ( |
|
|
|
<div className="w-full flex justify-between items-center mt-4"> |
|
|
|
<div className="w-full flex justify-between items-center mt-4"> |
|
|
|
<ButtonBetween |
|
|
|
<ButtonBetween |
|
|
|
width="72%" |
|
|
|
width="72%" |
|
|
|
item={"خرید نسخه ویدئویی کتاب"} |
|
|
|
item={"خرید نسخه ویدئویی کتاب"} |
|
|
|
status={separate(book?.product[2]?.price) + " " + "تومان"} |
|
|
|
status={separate(videoProduct?.price) + " " + "تومان"} |
|
|
|
onClick={() => |
|
|
|
onClick={() => { |
|
|
|
userId |
|
|
|
if (userId) { |
|
|
|
? pushToCart({ |
|
|
|
if (videoAvailabileInCart) { |
|
|
|
productId: book?.product[2]?.id, |
|
|
|
setDialog({ |
|
|
|
userId, |
|
|
|
text: window.t( |
|
|
|
|
|
|
|
"این محصول قبلا به سبد خرید شما اضافه شده است." |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
type: "confirm", |
|
|
|
|
|
|
|
accept: () => navigation("/cart"), |
|
|
|
|
|
|
|
open: true, |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
setWhichTypeAdded("video"); |
|
|
|
|
|
|
|
pushToCart({ |
|
|
|
|
|
|
|
productId: videoProduct?.id, |
|
|
|
|
|
|
|
userId: userId, |
|
|
|
count: 1, |
|
|
|
count: 1, |
|
|
|
}) |
|
|
|
}); |
|
|
|
: toast.info("ابتدا وارد حساب کاربری خود شوید.") |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
setDialog({ |
|
|
|
|
|
|
|
text: window.t( |
|
|
|
|
|
|
|
"ابتدا میبایست وارد حساب کاربری خود شوید." |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
type: "confirm", |
|
|
|
|
|
|
|
accept: () => navigation("/login"), |
|
|
|
|
|
|
|
open: true, |
|
|
|
|
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
loading={userProductLoading && whichTypeAdded === "video"} |
|
|
|
/> |
|
|
|
/> |
|
|
|
<ButtonBetween |
|
|
|
<ButtonBetween |
|
|
|
width="25%" |
|
|
|
width="25%" |
|
|
@ -163,6 +300,8 @@ export const Product = ({ |
|
|
|
onClick={() => navigation("/videos/" + book?.id)} |
|
|
|
onClick={() => navigation("/videos/" + book?.id)} |
|
|
|
/> |
|
|
|
/> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
) : null} |
|
|
|
|
|
|
|
|
|
|
|
<div className="w-full flex flex-col justify-between items-center mt-8"> |
|
|
|
<div className="w-full flex flex-col justify-between items-center mt-8"> |
|
|
|
<Header title="توضیحات" link="#" /> |
|
|
|
<Header title="توضیحات" link="#" /> |
|
|
|
<p className="text-sm text-gray70 mt-2 dark:text-white leading-6"> |
|
|
|
<p className="text-sm text-gray70 mt-2 dark:text-white leading-6"> |
|
|
@ -205,12 +344,16 @@ const mapStateToProps = (state) => ({ |
|
|
|
isDark: state.publicApi.isDark, |
|
|
|
isDark: state.publicApi.isDark, |
|
|
|
userId: state.user.status?.id, |
|
|
|
userId: state.user.status?.id, |
|
|
|
bookmarkLoading: state.userFavorite.loading, |
|
|
|
bookmarkLoading: state.userFavorite.loading, |
|
|
|
|
|
|
|
availableForSell: state.config.availableForSell, |
|
|
|
|
|
|
|
userProduct: state.userProduct.list, |
|
|
|
|
|
|
|
userProductLoading: state.userProduct.loading, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const mapDispatchToProps = { |
|
|
|
const mapDispatchToProps = { |
|
|
|
getInfo: book.info, |
|
|
|
getInfo: book.info, |
|
|
|
pushToCart: userProduct.add, |
|
|
|
pushToCart: userProduct.add, |
|
|
|
setHeaderOptions: publicApi.setHeaderOptions, |
|
|
|
setHeaderOptions: publicApi.setHeaderOptions, |
|
|
|
|
|
|
|
setDialog: dialog.set, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(Product); |
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(Product); |
|
|
|