import React, { useState, useEffect } from "react";
import {
Container,
Image,
Button,
Row,
Col,
ProgressBar,
Nav,
Tab,
Tooltip,
OverlayTrigger,
} from "react-bootstrap";
import { Link, useParams, useNavigate } from "react-router-dom";
import "./Product.css";
import ImageGallery from "react-image-gallery";
import NumericInput from "react-numeric-input";
import TopSellingProductIndex from "./TopSellingProductIndex";
import { withTranslation, useTranslation } from "react-multi-lang";
import CustomerReviewIndex from "../landingPage/CustomerReviewIndex";
import WriteReviewModal from "./WriteReviewModal";
import { connect } from "react-redux";
import {
fetchMoreProductReviewListStart,
fetchProductListStart,
fetchProductReviewListStart,
fetchSingleProductStart,
saveWishlistsStart,
} from "../store/actions/ProductAction";
import SomethingWrong from "../Helper/SomethingWrong";
import NoDataFound from "../Helper/NoDataFound";
import CommonCenterLoader from "../Helper/CommonCenterLoader";
import {
saveCartDetailsStart,
guestCartList,
} from "../store/actions/CartsAction";
import ReactStars from "react-rating-stars-component";
import Skeleton from "react-loading-skeleton";
import "react-loading-skeleton/dist/skeleton.css";
import NoReviewsFound from "../Helper/NoReviewsFound";
import ThcProgress from "./ThcProgress";
import CbdProgress from "./CbdProgress";
import Breadcrumb from 'react-bootstrap/Breadcrumb';
const SingleProductIndex = (props) => {
const navigate = useNavigate();
const t = useTranslation();
const params = useParams();
const { singleProduct, productReviews } = props;
const [isCarted, setIsCarted] = useState(false);
const [isWishlisted, setIsWishlisted] = useState(false);
const [skipRender, setSkipRender] = useState(true);
const [clamped, setClamped] = useState(true);
const [showButton, setShowButton] = useState(true);
const handleClick = () => setClamped(!clamped);
useEffect(() => {
window.scrollTo(0, 0);
props.dispatch(
fetchSingleProductStart({ product_unique_id: params.productUniqueId })
);
props.dispatch(
fetchProductReviewListStart({
product_unique_id: params.productUniqueId,
skip: 0,
take: 12,
})
);
props.dispatch(
fetchProductListStart({
order_by: "newest",
skip: 0,
take: 9,
})
);
}, [params.productUniqueId]);
useEffect(() => {
if (
!skipRender &&
!singleProduct.loading &&
Object.keys(singleProduct.data).length > 0
) {
setIsWishlisted(singleProduct.data.product.is_wishlisted ? true : false);
if (
props.guestCartList.filter(
(product) =>
product.product_id === singleProduct.data.product.product_id
).length > 0
)
setIsCarted(true);
}
setSkipRender(false);
}, [singleProduct]);
const [writeReview, setWriteReview] = useState(false);
const closeWriteReviewModal = () => {
setWriteReview(false);
};
const onCartClick = (e) => {
e.preventDefault();
//User Add to cart
if (singleProduct.data.product.is_carted === 0) {
props.dispatch(
saveCartDetailsStart({
product_id: singleProduct.data.product.product_id,
quantity: 1,
})
);
} else {
navigate("/cart");
}
};
const onGuestCartClick = (e) => {
e.preventDefault();
if (!isCarted) {
const cartProduct = {
product_id: singleProduct.data.product.product_id,
quantity: 1,
};
let cartItems = [...props.guestCartList, cartProduct];
localStorage.setItem("carts", JSON.stringify(cartItems));
props.dispatch(guestCartList(cartItems));
setIsCarted(true);
} else {
navigate("/cart");
}
};
const wishListToggle = () => {
if (Object.keys(props.profile.data).length > 0) {
props.dispatch(
saveWishlistsStart({
product_unique_id: singleProduct.data.product.product_unique_id,
})
);
} else {
localStorage.setItem("product", params.productUniqueId);
navigate("/login");
}
};
const loadMoreReview = () => {
props.dispatch(
fetchMoreProductReviewListStart({
product_unique_id: params.productUniqueId,
skip: productReviews.data.reviews.length,
take: 12,
})
);
};
return (
<>
{singleProduct.loading ? (
<div className="single-product-sec">
<Container>
<Row>
<Col md={6}>
<Skeleton className="product-image-loader" />
</Col>
<Col md={6}>
<Skeleton height={100} />
<Skeleton count={2} width={300} />
<Skeleton count={4} />
<Skeleton height={200} />
</Col>
</Row>
</Container>
</div>
) : Object.keys(singleProduct.data).length > 0 &&
singleProduct.data.product &&
Object.keys(singleProduct.data.product).length > 0 ? (
<>
<div className="single-product-sec">
<Container>
<Row>
<Breadcrumb>
<Link to="/" className="breadcrumb-item">Home</Link>
<Link to="/shop" className="breadcrumb-item">Shop</Link>
{/* <Link to={`/shop?category_id=${category.category_id}`} className="breadcrumb-item">
{singleProduct.data.product.category_name}
</Link> */}
<Link to="/" className="breadcrumb-item active">
{props.singleProduct.data.product.name}
</Link>
</Breadcrumb>
<Col md={6}>
<div className="single-product-full-img-sec">
<ImageGallery
items={singleProduct.data.product.product_files}
/>
</div>
</Col>
<Col md={6}>
<div className="single-product-info-sec">
<div className="">
<h4>{props.singleProduct.data.product.name}</h4>
</div>
<div className="single-product-review-card">
<ReactStars
count={5}
value={props.singleProduct.data.product.review_stars}
size={24}
isHalf={true}
edit={false}
emptyIcon={<i className="far fa-star"></i>}
halfIcon={<i className="fa fa-star-half-alt"></i>}
fullIcon={<i className="fa fa-star"></i>}
activeColor="#ffd700"
/>
<Link
to={localStorage.getItem("userId") ? "#" : "/login"}
className="write-review-link"
onClick={() => setWriteReview(true)}
>
<span>{t("write_review")}</span>
<Image
className="single-product-review-edit-icon"
src={
window.location.origin +
"/images/icons/edit-icon.svg"
}
type="image/png"
/>
</Link>
</div>
<div className="single-product-thc-sec">
<div className="thc-left-sec">
<h3>
{singleProduct.data.product.selling_price_formatted}{" "}
{singleProduct.data.product.discount_tag ? (
<sub>
<del>
{
singleProduct.data.product
.original_price_formatted
}
</del>
</sub>
) : null}
</h3>
<p>
{t("category")}{" "}
<span>
{singleProduct.data.product.category_name}
</span>
</p>
<span
className="add-wishlist-sec point"
onClick={wishListToggle}
>
{isWishlisted ? (
<>
<Image
src={
window.location.origin +
"/images/like-fill.svg"
}
/>
{t("remove_from_wishlist")}
</>
) : (
<>
<Image
src={
window.location.origin + "/images/like-1.svg"
}
/>
{t("add_to_wishlist")}
</>
)}
</span>
</div>
{singleProduct.data.product.thc_drug_content || singleProduct.data.product.cbd_drug_content ?
<div className="thc-details-right-sec">
<div className="product-percentage-sec">
{singleProduct.data.product.thc_drug_content ?
<div className="pack-icon-sec">
<ThcProgress percentage={singleProduct.data.product.thc_avg} />
<div className="pack-value">
<h4>{singleProduct.data.product.thc_formatted ? singleProduct.data.product.thc_formatted : '0.00'}</h4>
<h4>{singleProduct.data.product.thc_per_formatted ? singleProduct.data.product.thc_per_formatted : '0.00'}</h4>
</div>
<div className="pack-info">
<OverlayTrigger
placement="top"
overlay={
<Tooltip id="button-tooltip-2">
THC is an active component in TodayKat
responsible for psychoactive, or
intoxicating, effects such as changes in
perception and mobility.
</Tooltip>
}
>
{({ ref, ...triggerHandler }) => (
<Button {...triggerHandler}>
<Image
ref={ref}
src={
window.location.origin +
"/images/additional-info.svg"
}
type="image/png"
/>
</Button>
)}
</OverlayTrigger>
</div>
</div>
: null
}
{singleProduct.data.product.cbd_drug_content ?
<div className="pack-icon-sec">
<CbdProgress percentage={singleProduct.data.product.cbd_avg} />
<div className="pack-value">
<h4>{singleProduct.data.product.cbd_formatted ? singleProduct.data.product.cbd_formatted : '0.00'}</h4>
<h4>{singleProduct.data.product.cbd_per_formatted ? singleProduct.data.product.cbd_per_formatted : '0.00'}</h4>
</div>
<div className="pack-info">
<OverlayTrigger
placement="top"
overlay={
<Tooltip id="button-tooltip-2">
CBD is an active, but non-intoxicating
component in TodayKat.
</Tooltip>
}
>
{({ ref, ...triggerHandler }) => (
<Button {...triggerHandler}>
<Image
ref={ref}
src={
window.location.origin +
"/images/additional-info.svg"
}
type="image/png"
/>
</Button>
)}
</OverlayTrigger>
</div>
</div>
: null
}
</div>
</div>
: null}
</div>
<div className={`progress-bar-sec`}>
<h5
className={
singleProduct.data.product.stock_status === 0
? "text-danger"
: ""
}
>
{singleProduct.data.product.stock_availablity_formatted}
</h5>
<ProgressBar
now={
(singleProduct.data.product.product_inventory
.remaining /
singleProduct.data.product.product_inventory
.total) *
100
}
/>
</div>
{/* <div className="single-product-quantity-sec">
<p>
QTY
<span>
<NumericInput mobile className="form-control" />
</span>
</p>
</div> */}
{singleProduct.data.product.stock_status === 1 ? (
<div className="single-product-action-btn-sec default-btn-sec mt-0">
{localStorage.getItem("userId") &&
Object.keys(props.profile.data).length > 0 ? (
<Button
className="add-to-cart-btn"
onClick={onCartClick}
>
{singleProduct.data.product.is_carted === 0
? t("add_to_cart")
: t("go_to_cart")}
</Button>
) : (
<Button
className="add-to-cart-btn"
onClick={onGuestCartClick}
>
{!isCarted ? t("add_to_cart") : t("go_to_cart")}
</Button>
)}
{/* <Button className="default-btn">Buy It Now</Button> */}
</div>
) : null}
{/* <div className="single-product-support-sec">
<div className="single-product-support-box">
<div className="single-product-support-card">
<Image
className="single-product-support-icon"
src={
window.location.origin +
"/images/product/24-hours-support.png"
}
type="image/png"
/>
<span>{t("24x7_support")}</span>
</div>
<div className="single-product-support-card">
<Image
className="single-product-support-icon"
src={
window.location.origin +
"/images/product/shield.png"
}
type="image/png"
/>
<span>100% {t("safe_products")}</span>
</div>
</div>
<div className="single-product-trusted-sec">
<Image
className="single-product-trusted-icon"
src={
window.location.origin +
"/images/product/trusted-img.png"
}
type="image/png"
/>
</div>
</div> */}
<div className="single-about-product vis-hidden">
<div className="about-product-details">
<div className="single-product-detail-about">
<h4>Brand</h4>
<p>Canaca</p>
</div>
<div className="single-product-detail-about">
<h4>Potency</h4>
<p>Very Strong</p>
</div>
<div className="single-product-detail-about">
<h4>Plant Type</h4>
<p>{singleProduct.data.product.plant_type}</p>
</div>
<div className="single-product-detail-about">
<h4>Terpenes</h4>
<p>Terpenes May Vary</p>
</div>
<div className="single-product-detail-about">
<h4>Growing Province</h4>
<p>Ontario</p>
</div>
</div>
</div>
</div>
</Col>
</Row>
{/* <div className="single-about-product margin-top-lg">
<h4>About This product</h4>
<div className="about-product-details">
<div className="single-product-detail-about">
<h4>Brand</h4>
<p>Canaca</p>
</div>
<div className="single-product-detail-about mt-4">
<h4>Potency</h4>
<p>Very Strong</p>
</div>
<div className="single-product-detail-about mt-4">
<h4>Plant Type</h4>
<p>Indica dominant</p>
</div>
<div className="single-product-detail-about mt-4">
<h4>Terpenes</h4>
<p>Terpenes May Vary</p>
</div>
<div className="single-product-detail-about mt-4">
<h4>Growing Province</h4>
<p>Ontario</p>
</div>
</div>
</div> */}
<Row className="margin-top-lg">
<Col md={12}>
<div className="single-product-description-review-sec">
<Tab.Container
id="left-tabs-example"
defaultActiveKey="description"
>
<Row>
<Col sm={12}>
<Nav variant="pills">
<Nav.Item>
<Nav.Link eventKey="description">
{t("description")}
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="reviews">
{t("reviews")}
</Nav.Link>
</Nav.Item>
</Nav>
</Col>
<Col sm={12}>
<Tab.Content>
<Tab.Pane eventKey="description">
<div
className={`single-product-overflow-text ${clamped
? "single-product-description-sec"
: ""
}`}
>
{singleProduct.data.product
.description_formatted ? (
singleProduct.data.product
.description_formatted
) : (
<NoDataFound />
)}
</div>
{/* {showButton && (
<Button
className="read-more-btn"
onClick={handleClick}
>
{t("read")} {clamped ? t("more") : t("less")}
</Button>
)} */}
</Tab.Pane>
<Tab.Pane eventKey="reviews">
<div className="single-product-review-sec">
{productReviews.loading ? (
<CommonCenterLoader />
) : productReviews.data.reviews.length > 0 ? (
<>
<div className="single-product-review-box">
{productReviews.data.reviews.map(
(review, i) => (
<div
className="single-product-review-item"
key={i}
>
<div className="single-product-review-left">
<div className="single-product-review-user-img-sec">
<Image
className="single-product-review-user-img"
src={
review.user
? review.user.picture
: window.location.origin +
"/images/profile.png"
}
type="image/png"
/>
</div>
<div className="single-product-review-info">
<h4>
{review.user
? review.user.name
: t("na")}
</h4>
<p>{review.review}</p>
<ReactStars
count={5}
value={review.star}
size={24}
isHalf={true}
edit={false}
emptyIcon={
<i className="far fa-star"></i>
}
halfIcon={
<i className="fa fa-star-half-alt"></i>
}
fullIcon={
<i className="fa fa-star"></i>
}
activeColor="#ffd700"
/>
</div>
</div>
</div>
)
)}
</div>
<div className="text-center">
{productReviews.data.reviews.length <
productReviews.data.total_reviews ? (
productReviews.loadMore ? (
<CommonCenterLoader />
) : (
<div className="default-btn-sec">
{console.log(productReviews)}
{console.log(
productReviews.loadMore
)}
<Button
className="default-btn"
onClick={() => loadMoreReview()}
>
Load More
</Button>
</div>
)
) : null}
</div>
</>
) : (
<NoReviewsFound />
)}
</div>
</Tab.Pane>
</Tab.Content>
</Col>
</Row>
</Tab.Container>
</div>
</Col>
</Row>
</Container>
{props.productList.loading ? (
"Loading"
) : props.productList.data.products &&
props.productList.data.products.length > 0 ? (
<div className="top-selling-product-page">
<Container>
<Row>
<Col md={12}>
<div className="section-title-sec">
<h3>{t("top_selling_products")}</h3>
<h2>
<span>{t("fabulous_products")}</span>
</h2>
</div>
</Col>
</Row>
<Row>
<Col md="12">
<TopSellingProductIndex
products={
props.productList.data.products
.filter(product => product.product_unique_id !== props.singleProduct.data.product.product_unique_id)
.slice(0, 8)
}
/>
</Col>
</Row>
</Container>
</div>
) : null}
<CustomerReviewIndex />
</div>
{writeReview && singleProduct.data.product && (
<WriteReviewModal
writeReview={writeReview}
closeWriteReviewModal={closeWriteReviewModal}
setWriteReview={setWriteReview}
singleProduct={singleProduct.data.product}
/>
)}
</>
) : (
<SomethingWrong />
)}
</>
);
};
const mapStateToPros = (state) => ({
singleProduct: state.product.singleProduct,
productReviews: state.product.productReviews,
profile: state.users.profile,
guestCartList: state.carts.guestCartList,
productList: state.product.productList,
wishlistSave: state.product.wishlistSave,
});
function mapDispatchToProps(dispatch) {
return { dispatch };
}
export default connect(
mapStateToPros,
mapDispatchToProps
)(withTranslation(SingleProductIndex));
Back to Directory