Viewing File: /home/ubuntu/vedadeals-frontend-base/src/components/Product/ProductSearchIndex.jsx
import React, { Fragment, useState, useEffect } from "react";
import {
Navbar,
Container,
Image,
Nav,
Row,
Col,
Button,
Collapse,
Form,
InputGroup,
} from "react-bootstrap";
import { Link, useParams, useNavigate, useSearchParams } from "react-router-dom";
import "./Product.css";
import { connect } from "react-redux";
import { withTranslation, useTranslation } from "react-multi-lang";
import { fetchCategoriesListStart } from "../store/actions/HomePageAction";
import {
fetchProductListStart,
fetchMoreProductListStart,
} from "../store/actions/ProductAction";
import InfiniteScroll from "react-infinite-scroll-component";
import NoDataFound from "../Helper/NoDataFound";
import SomethingWrong from "../Helper/SomethingWrong";
import ProductCard from "./ProductCard";
import Skeleton from "react-loading-skeleton";
import "react-loading-skeleton/dist/skeleton.css";
import NoProductsFound from "../Helper/NoProductsFound";
const initialCondition = {
category_id: "",
sub_category_id: [],
stock_status: "",
order_by: "newest",
from: "",
to: "",
};
const ProductSearchIndex = (props) => {
const params = useParams();
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const [showProducts, setShowProducts] = useState(true);
const [skipRender, setSkipRender] = useState(true);
const [open, setOpen] = useState(false);
const [search, setSearch] = useState("");
const t = useTranslation();
const [conditions, setConditions] = useState(initialCondition);
const [price, setPrice] = useState({
from: "",
to: "",
});
useEffect(() => {
props.dispatch(fetchCategoriesListStart());
}, []);
useEffect(() => {
if (
!skipRender &&
((!props.productList.loading && props.productList.error !== false) ||
(!props.categoriesList.loading && props.categoriesList.error !== false))
) {
setShowProducts(false);
}
}, [props.productList, props.categoriesList]);
useEffect(() => {
if (!skipRender && !props.categoriesList.loading && Object.keys(props.categoriesList.data).length > 0) {
if (searchParams.get('category')) {
const selectedCategory = props.categoriesList.data.categories.filter(cat => cat.category_unique_id == searchParams.get('category'));
if (selectedCategory.length > 0) {
setOpen(`c-${selectedCategory[0].category_id}`)
const subCategories = selectedCategory[0].sub_category.map(subCategory => subCategory.sub_category_id);
setConditions({
...conditions,
sub_category_id: subCategories,
})
} else {
fetchProducts("");
}
}
}
}, [props.categoriesList]);
useEffect(() => {
if (!skipRender) {
if (params.search) {
fetchProducts(params.search);
setSearch(params.search);
} else {
fetchProducts("");
setSearch("");
}
}
}, [params.search]);
useEffect(() => {
if (params.search) {
fetchProducts(params.search);
setSearch(params.search);
} else {
if (skipRender && searchParams.get('category')) {
// fetchProducts(search, searchParams.get('category_id'))
} else {
fetchProducts();
}
}
setSkipRender(false);
}, [conditions]);
const continueShopping = () => {
resetFilter();
props.dispatch(fetchCategoriesListStart());
setTimeout(() => {
setShowProducts(true);
}, 10);
}
const fetchProducts = (searchKey = search) => {
let data = {
...conditions,
sub_category_id: "",
search_key: searchKey,
skip: 0,
take: 12,
};
if (conditions.sub_category_id.length > 0) {
data = {
...data,
sub_category_id: JSON.stringify(conditions.sub_category_id),
};
}
props.dispatch(fetchProductListStart(data));
};
const fetchMoreProducts = () => {
let data = {
...conditions,
sub_category_id: "",
search_key: search,
skip: props.productList.data.products.length,
take: 12,
};
if (conditions.sub_category_id.length > 0) {
data = {
...data,
sub_category_id: JSON.stringify(conditions.sub_category_id),
};
}
props.dispatch(fetchMoreProductListStart(data));
};
const setFromPrice = (e) => {
e.preventDefault();
const val = e.target.value;
if (val > 0) {
setPrice({ ...price, from: parseInt(val) });
} else if (val === "") {
setPrice({ ...price, from: val });
}
};
const setToPrice = (e) => {
e.preventDefault();
const val = e.target.value;
if (val > 0) {
setPrice({ ...price, to: parseInt(val) });
} else if (val === "") {
setPrice({ ...price, to: val });
}
};
const setPriceFilter = (e) => {
setConditions({
...conditions,
from: price.from,
to: price.to,
});
};
const resetFilter = (e) => {
setPrice({
from: "",
to: "",
});
setSearch("");
setConditions(initialCondition);
};
return (
<>
<div className="product-search-sec">
{showProducts ? (
<Container>
<Row>
<Col md={12}>
<div className="product-search-box">
<div className="product-search-left">
{props.categoriesList.loading ? (
<>
<Skeleton height={350} className="mb-4" />
</>
) : props.categoriesList.data.categories &&
props.categoriesList.data.categories.length > 0 ? (
<div className="product-search-left-card-1">
<div className="product-search-header-card">
{t("shop_by_categories")}
{JSON.stringify(conditions) !==
JSON.stringify(initialCondition) ? (
<Link to="" onClick={resetFilter}>
{t("clear")}
</Link>
) : null}
</div>
{props.categoriesList.data.categories.map(
(category, i) => (
<Fragment key={i}>
<Button
onClick={() =>
setOpen(open === `c-${category.category_id}` ? false : `c-${category.category_id}`)
}
className="btn-categories"
aria-controls="example-collapse-text"
aria-expanded={open}
>
{category.name}
<span>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"
>
<path d="M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z" />
</svg>
</span>
</Button>
<Collapse in={open == `c-${category.category_id}`}>
<div id="example-collapse-text">
<div className="catgories-availablity-sec">
{category.sub_category.map(
(subCategory, j) => (
<div
className="custom-checkbox"
key={j}
>
<input
type="checkbox"
id={`category-${i}${j}`}
checked={conditions.sub_category_id.includes(
subCategory.sub_category_id
)}
onClick={() =>
setConditions({
...conditions,
sub_category_id:
conditions.sub_category_id.includes(
subCategory.sub_category_id
)
? conditions.sub_category_id.filter(
(id) =>
id !==
subCategory.sub_category_id
)
: [
...conditions.sub_category_id,
subCategory.sub_category_id,
],
})
}
/>
<label htmlFor={`category-${i}${j}`}>
<span>{subCategory.name}</span>
</label>
</div>
)
)}
</div>
</div>
</Collapse>
</Fragment>
)
)}
</div>
) : null}
<div className="product-search-left-card-1">
<div className="product-search-header-card">
{t("filter_by")}
{JSON.stringify(conditions) !==
JSON.stringify(initialCondition) ? (
<Link to="" onClick={resetFilter}>
{t("clear")}
</Link>
) : null}
</div>
<Button
onClick={() => setOpen(open === 3 ? false : 3)}
className="btn-categories"
aria-controls="example-collapse-text"
aria-expanded={open}
>
{t("availability")}
<span>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"
>
<path d="M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z" />
</svg>
</span>
</Button>
<Collapse in={open == 3}>
<div id="example-collapse-text">
<div className="catgories-availablity-sec">
<div className="custom-checkbox">
<input
type="checkbox"
id="sold_out"
checked={conditions.stock_status === 1}
onClick={() =>
setConditions({
...conditions,
stock_status:
conditions.stock_status === 1 ? "" : 1,
})
}
/>
<label htmlFor="sold_out">
<span>
{t("in_stock")} (
{props.productList.data
.total_in_stock_products
? props.productList.data
.total_in_stock_products
: 0}
)
</span>
</label>
</div>
<div className="custom-checkbox">
<input
type="checkbox"
id="available"
checked={conditions.stock_status === 0}
onClick={() =>
setConditions({
...conditions,
stock_status:
conditions.stock_status === 0 ? "" : 0,
})
}
/>
<label htmlFor="available">
<span>
{t("out_of_stock")} (
{props.productList.data
.total_out_of_stock_products
? props.productList.data
.total_out_of_stock_products
: 0}
)
</span>
</label>
</div>
</div>
</div>
</Collapse>
<Button
onClick={() => setOpen(open === 4 ? false : 4)}
className="btn-categories"
aria-controls="example-collapse-text"
aria-expanded={open}
>
{t("price")}
<span>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"
>
<path d="M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z" />
</svg>
</span>
</Button>
<Collapse in={open == 4}>
<div id="example-collapse-text">
<div className="catgories-list-sec">
<div className="categories-search-price-card">
<InputGroup className="mb-0">
<Form.Control
type="number"
placeholder={t("from")}
value={price.from}
onChange={setFromPrice}
/>
</InputGroup>
<InputGroup className="mb-0">
<Form.Control
type="number"
placeholder={t("to")}
value={price.to}
onChange={setToPrice}
/>
</InputGroup>
<Button
className="subscribe-btn"
onClick={setPriceFilter}
disabled={price.from >= price.to}
>
{t("filter")}
</Button>
</div>
</div>
</div>
</Collapse>
</div>
</div>
<div className="product-search-right">
{/* <div className="product-search-right-header-sec">
<h4>Search Your Product Here</h4>
<div className="product-search-input">
<Form.Group
className="mb-0"
controlId="exampleForm.ControlInput1"
>
<Form.Control
type="text"
placeholder="CBD Creams"
value={search}
onChange={e => setSearch(e.target.value)}
/>
</Form.Group>
<Button className="search-btn" onClick={() => fetchProducts()}>SUBMIT</Button>
</div>
</div> */}
{props.productList.loading || skipRender ? (
<>
<div className="product-search-sortby-sec">
<Skeleton />
</div>
<div className="product-search-result-grid-box">
{[...Array(6)].map((i) => (
<Skeleton count={1} height={350} />
))}
</div>
</>
) : props.productList.data.products.length > 0 ? (
<>
<div className="product-search-sortby-sec">
<h4>
{t("products")} (
{props.productList.data.total_products})
</h4>
<div className="product-search-sortby-card">
<h4>{t("sort_by")}</h4>
<Form.Select
aria-label="Default select example"
value={conditions.order_by}
onChange={(e) =>
setConditions({
...conditions,
order_by: e.target.value,
})
}
>
<option value="price_lh">
{t("price_low_to_high")}
</option>
<option value="price_hl">
{t("price_high_to_low")}
</option>
<option value="newest">{t("newest")}</option>
<option value="oldest">{t("oldest")}</option>
</Form.Select>
</div>
</div>
<div className="product-search-right-body-sec">
<InfiniteScroll
dataLength={props.productList.data.products.length}
next={fetchMoreProducts}
hasMore={
props.productList.data.products.length <
props.productList.data.total_products
}
loader={
<div className="product-search-result-grid-box">
{[...Array(6)].map((i) => (
<Skeleton count={1} height={400} />
))}
</div>
}
>
<div className="product-search-result-grid-box">
{props.productList.data.products.map(
(product, i) => (
<ProductCard product={product} key={i} />
)
)}
</div>
</InfiniteScroll>
</div>
</>
) : (
<NoProductsFound />
)}
</div>
</div>
</Col>
</Row>
</Container>
) : (
<div className="text-center">
<SomethingWrong />
<div className="default-btn-sec">
<Button
className="default-btn"
onClick={continueShopping}
>
Continue Shopping
</Button>
</div>
</div>
)}
</div>
</>
);
};
const mapStateToPros = (state) => ({
categoriesList: state.homepage.categoriesList,
productList: state.product.productList,
});
function mapDispatchToProps(dispatch) {
return { dispatch };
}
export default connect(
mapStateToPros,
mapDispatchToProps
)(withTranslation(ProductSearchIndex));
Back to Directory
File Manager