Viewing File: /home/ubuntu/todaykat-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