| 
		 Before Width: | Height: | Size: 966 B After Width: | Height: | Size: 996 B  | 
| 
		 Before Width: | Height: | Size: 516 B After Width: | Height: | Size: 525 B  | 
| 
		 Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB  | 
| 
		 Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB  | 
| 
		 Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.3 KiB  | 
| 
		 Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.4 KiB  | 
| 
		 Before Width: | Height: | Size: 829 B After Width: | Height: | Size: 856 B  | 
| 
		 Before Width: | Height: | Size: 864 B After Width: | Height: | Size: 882 B  | 
@ -1,6 +0,0 @@ | 
				
			|||||||
.specifications-li:hover div{ | 
					 | 
				
			||||||
    background-color: rgba(25,110,192,0.15); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
.specifications-li div{ | 
					 | 
				
			||||||
    transition: all 0.2s; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,11 +1,11 @@ | 
				
			|||||||
import React from "react"; | 
					import React from "react"; | 
				
			||||||
import "./index.scss"; | 
					import "./index.scss"; | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function index() { | 
					export default function Switch({checked}) { | 
				
			||||||
  return ( | 
					  return ( | 
				
			||||||
    <div className="switch"> | 
					    <div className="switchbox transition-all"> | 
				
			||||||
      <input type="checkbox" id="toggle" /> | 
					      <input className="transition-all" type="checkbox" id="toggle" checked={checked} /> | 
				
			||||||
      <label for="toggle"></label> | 
					      <label className="transition-all" for="toggle"></label> | 
				
			||||||
    </div> | 
					    </div> | 
				
			||||||
  ); | 
					  ); | 
				
			||||||
} | 
					} | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,17 @@ | 
				
			|||||||
 | 
					import proxy from "../proxy"; | 
				
			||||||
 | 
					const transport = { | 
				
			||||||
 | 
					  list: | 
				
			||||||
 | 
					    (data = {}) => | 
				
			||||||
 | 
					    async (dispatch) => { | 
				
			||||||
 | 
					      await proxy.get("transport/list", data, { dispatch }); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					  set: | 
				
			||||||
 | 
					    (data = {}, data2 = {}, data3 = {}) => | 
				
			||||||
 | 
					    async (dispatch) => { | 
				
			||||||
 | 
					      await proxy.post("transport/setTransport", data, { dispatch }); | 
				
			||||||
 | 
					      await proxy.get("userFactor/info", data2, { dispatch }); | 
				
			||||||
 | 
					      await proxy.get("transport/list", data3, { dispatch }); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default transport; | 
				
			||||||
@ -0,0 +1,28 @@ | 
				
			|||||||
 | 
					import { toast } from "react-toastify"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const initialState = { | 
				
			||||||
 | 
					  loading: false, | 
				
			||||||
 | 
					  error: null, | 
				
			||||||
 | 
					  list: [], | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					export default function transport(state = initialState, action) { | 
				
			||||||
 | 
					  let { type, data } = action; | 
				
			||||||
 | 
					  switch (type) { | 
				
			||||||
 | 
					    case "transport/list": | 
				
			||||||
 | 
					      return { | 
				
			||||||
 | 
					        ...state, | 
				
			||||||
 | 
					        loading: false, | 
				
			||||||
 | 
					        list: data, | 
				
			||||||
 | 
					        error: null, | 
				
			||||||
 | 
					      }; | 
				
			||||||
 | 
					    case "transport/info": | 
				
			||||||
 | 
					      return { ...state, loading: false, error: null}; | 
				
			||||||
 | 
					    case "transport/loading": | 
				
			||||||
 | 
					      return { ...state, loading: true }; | 
				
			||||||
 | 
					    case "transport/error": | 
				
			||||||
 | 
					      toast.error(data.message); | 
				
			||||||
 | 
					      return { ...state, loading: false, error: data.message }; | 
				
			||||||
 | 
					    default: | 
				
			||||||
 | 
					      return state; | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,61 @@ | 
				
			|||||||
 | 
					const grades = [ | 
				
			||||||
 | 
					  "پیش دبستان", | 
				
			||||||
 | 
					  "اول", | 
				
			||||||
 | 
					  "دوم", | 
				
			||||||
 | 
					  "سوم", | 
				
			||||||
 | 
					  "چهارم", | 
				
			||||||
 | 
					  "پنجم", | 
				
			||||||
 | 
					  "ششم", | 
				
			||||||
 | 
					  "هفتم", | 
				
			||||||
 | 
					  "هشتم", | 
				
			||||||
 | 
					  "نهم", | 
				
			||||||
 | 
					  "دهم", | 
				
			||||||
 | 
					  "یازدهم", | 
				
			||||||
 | 
					  "دوازدهم", | 
				
			||||||
 | 
					]; | 
				
			||||||
 | 
					class filter { | 
				
			||||||
 | 
					  productsPage = (products, options) => { | 
				
			||||||
 | 
					    const { grade, subject, sort } = options; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (grade.length > 0 || subject.length > 0 || sort) { | 
				
			||||||
 | 
					      localStorage.setItem("filter", "ON"); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					    let finalSort; | 
				
			||||||
 | 
					    let byGradeFilter = []; | 
				
			||||||
 | 
					    if (grade.length > 0) { | 
				
			||||||
 | 
					      grade.map((item1) => { | 
				
			||||||
 | 
					        for (let i = 0; i < products.length; i++) { | 
				
			||||||
 | 
					          if (grades[products[i].gradeId] === item1) { | 
				
			||||||
 | 
					            byGradeFilter.push(products[i]); | 
				
			||||||
 | 
					          } | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					      }); | 
				
			||||||
 | 
					    } else { | 
				
			||||||
 | 
					      byGradeFilter = products; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					    let bySubjectFilter = []; | 
				
			||||||
 | 
					    if (subject.length > 0) { | 
				
			||||||
 | 
					      subject.map((item1) => { | 
				
			||||||
 | 
					        for (let i = 0; i < byGradeFilter.length; i++) { | 
				
			||||||
 | 
					          if (byGradeFilter[i].name === item1) { | 
				
			||||||
 | 
					            bySubjectFilter.push(byGradeFilter[i]); | 
				
			||||||
 | 
					          } | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					      }); | 
				
			||||||
 | 
					    } else { | 
				
			||||||
 | 
					      bySubjectFilter = byGradeFilter; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (sort === "گران ترین") { | 
				
			||||||
 | 
					      finalSort = bySubjectFilter.sort((item1, item2) => { | 
				
			||||||
 | 
					        return item1.product[0].price - item2.product[0].price; | 
				
			||||||
 | 
					      }); | 
				
			||||||
 | 
					    } else { | 
				
			||||||
 | 
					      finalSort = bySubjectFilter; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const _filter = new filter(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default _filter; | 
				
			||||||
@ -1,36 +1,131 @@ | 
				
			|||||||
import React from "react"; | 
					import React, { useState, useMemo } from "react"; | 
				
			||||||
import { connect } from "react-redux"; | 
					import { connect } from "react-redux"; | 
				
			||||||
 | 
					import { book } from "../../../redux/actions"; | 
				
			||||||
import Checkbox from "../../../components/Checkbox"; | 
					import Checkbox from "../../../components/Checkbox"; | 
				
			||||||
import VerticalExpandableProductFilter from "../../../components/VerticalExpandableProductFilter"; | 
					import Switch from "../../../components/Switch"; | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Sidebar = ({ onChange, grades }) => { | 
					//assets
 | 
				
			||||||
  const categories = [ | 
					import dropdownIcon from "../../../assets/icons/dropdown-blue.svg"; | 
				
			||||||
    "کتاب فیزیکی", | 
					
 | 
				
			||||||
    "کتاب دیجیتال", | 
					export const Sidebar = ({ | 
				
			||||||
    "دوره ویدیویی", | 
					  onChange, | 
				
			||||||
    "بسته های آموزشی", | 
					  levels, | 
				
			||||||
  ]; | 
					  subjects, | 
				
			||||||
 | 
					  productTypes, | 
				
			||||||
 | 
					  setFilterOptions, | 
				
			||||||
 | 
					  filterOptions, | 
				
			||||||
 | 
					}) => { | 
				
			||||||
 | 
					  const [toggleList, setToggleList] = useState({ | 
				
			||||||
 | 
					    subject: false, | 
				
			||||||
 | 
					    grade: false, | 
				
			||||||
 | 
					    productType: false, | 
				
			||||||
 | 
					  }); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Dropdown = ({ list, title, name, active }) => { | 
				
			||||||
    return ( | 
					    return ( | 
				
			||||||
    <div className="flex flex-col w-1/4 p-4"> | 
					      <div className="flex flex-col"> | 
				
			||||||
      <VerticalExpandableProductFilter | 
					        <div | 
				
			||||||
        onChange={onChange} | 
					          className="flex flex-row justify-between items-center py-5 cursor-pointer" | 
				
			||||||
 | 
					          onClick={() => | 
				
			||||||
 | 
					            setToggleList({ ...toggleList, [name]: !toggleList[name] }) | 
				
			||||||
 | 
					          } | 
				
			||||||
 | 
					        > | 
				
			||||||
 | 
					          <strong className="font-semibold text-tiny text-green4F"> | 
				
			||||||
 | 
					            {title} | 
				
			||||||
 | 
					          </strong> | 
				
			||||||
 | 
					          <img | 
				
			||||||
 | 
					            src={dropdownIcon} | 
				
			||||||
 | 
					            alt="" | 
				
			||||||
 | 
					            className={`w-4 transform transition-all ${ | 
				
			||||||
 | 
					              toggleList[name] ? "rotate-180" : "" | 
				
			||||||
 | 
					            }`}
 | 
				
			||||||
 | 
					          /> | 
				
			||||||
 | 
					        </div> | 
				
			||||||
 | 
					        <ul | 
				
			||||||
 | 
					          className={`list-none p-0 mt-2 mb-0 mx-0 flex overflow-x-hidden flex-col transition-all`} | 
				
			||||||
 | 
					          style={{ | 
				
			||||||
 | 
					            maxHeight: !toggleList[name] ? 0 : "calc(100vh / 2.2)", | 
				
			||||||
 | 
					            overflowY: !toggleList[name] ? "hidden" : "scroll", | 
				
			||||||
 | 
					          }} | 
				
			||||||
 | 
					        > | 
				
			||||||
 | 
					          {list.map((item, index) => ( | 
				
			||||||
 | 
					            <li | 
				
			||||||
 | 
					              key={index} | 
				
			||||||
 | 
					              className="flex flex-row items-center mb-3" | 
				
			||||||
 | 
					              onClick={() => | 
				
			||||||
 | 
					                active !== item | 
				
			||||||
 | 
					                  ? setFilterOptions({ ...filterOptions, [name]: item }) | 
				
			||||||
 | 
					                  : setFilterOptions({ ...filterOptions, [name]: null }) | 
				
			||||||
 | 
					              } | 
				
			||||||
 | 
					            > | 
				
			||||||
 | 
					              <Checkbox checked={active === item} /> | 
				
			||||||
 | 
					              <span className="text-tiny font-medium">{item}</span> | 
				
			||||||
 | 
					            </li> | 
				
			||||||
 | 
					          ))} | 
				
			||||||
 | 
					        </ul> | 
				
			||||||
 | 
					      </div> | 
				
			||||||
 | 
					    ); | 
				
			||||||
 | 
					  }; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const CkeckItem = ({ title, name }) => { | 
				
			||||||
 | 
					    return ( | 
				
			||||||
 | 
					      <div | 
				
			||||||
 | 
					        className="flex flex-row justify-between items-center py-4" | 
				
			||||||
 | 
					        onClick={() => | 
				
			||||||
 | 
					          setFilterOptions({ | 
				
			||||||
 | 
					            ...filterOptions, | 
				
			||||||
 | 
					            [name]: !filterOptions.available, | 
				
			||||||
 | 
					          }) | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					      > | 
				
			||||||
 | 
					        <span className="font-semibold text-tiny text-green4F">{title}</span> | 
				
			||||||
 | 
					        <Switch checked={filterOptions.available} /> | 
				
			||||||
 | 
					      </div> | 
				
			||||||
 | 
					    ); | 
				
			||||||
 | 
					  }; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return ( | 
				
			||||||
 | 
					    <div | 
				
			||||||
 | 
					      className="flex flex-col w-1/4 px-4 pt-5 pb-2 bg-gray-50 transform translate-y-5 border border-solid border-gray-200 rounded-md" | 
				
			||||||
 | 
					      style={{ | 
				
			||||||
 | 
					        height: "fit-content", | 
				
			||||||
 | 
					      }} | 
				
			||||||
 | 
					    > | 
				
			||||||
 | 
					      <strong className="text-lg text-green4F mb-10">فیلترها</strong> | 
				
			||||||
 | 
					      <div className="flex flex-col divide-y divide-solid divide-gray-200"> | 
				
			||||||
 | 
					        <Dropdown | 
				
			||||||
 | 
					          list={productTypes} | 
				
			||||||
 | 
					          title="نوع محصول" | 
				
			||||||
 | 
					          name="productType" | 
				
			||||||
 | 
					          active={filterOptions.productType} | 
				
			||||||
 | 
					        /> | 
				
			||||||
 | 
					        <Dropdown | 
				
			||||||
 | 
					          list={Object.values(levels)} | 
				
			||||||
 | 
					          title={"پایه تحصیلی"} | 
				
			||||||
          name="grade" | 
					          name="grade" | 
				
			||||||
        list={Object.values(grades)} | 
					          active={filterOptions.grade} | 
				
			||||||
        title="پایه تحصیلی" | 
					 | 
				
			||||||
        /> | 
					        /> | 
				
			||||||
      <VerticalExpandableProductFilter | 
					        <Dropdown | 
				
			||||||
        name="category" | 
					          list={subjects} | 
				
			||||||
        list={categories} | 
					          title={"عنوان کتاب"} | 
				
			||||||
        title="دسته بندی" | 
					          name="subject" | 
				
			||||||
 | 
					          active={filterOptions.subject} | 
				
			||||||
        /> | 
					        /> | 
				
			||||||
 | 
					        <CkeckItem title="فقط کالاهای موجود" name={"available"} /> | 
				
			||||||
 | 
					      </div> | 
				
			||||||
    </div> | 
					    </div> | 
				
			||||||
  ); | 
					  ); | 
				
			||||||
}; | 
					}; | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapStateToProps = (state) => ({ | 
					const mapStateToProps = (state) => ({ | 
				
			||||||
  grades: state.publicApi.grades, | 
					  levels: state.book.levels, | 
				
			||||||
 | 
					  subjects: state.book.subjects, | 
				
			||||||
 | 
					  productTypes: state.book.productTypes, | 
				
			||||||
 | 
					  filterOptions: state.book.filterOptions, | 
				
			||||||
}); | 
					}); | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapDispatchToProps = {}; | 
					const mapDispatchToProps = { | 
				
			||||||
 | 
					  setFilterOptions: book.setFilterOptions, | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					
 | 
				
			||||||
export default connect(mapStateToProps, mapDispatchToProps)(Sidebar); | 
					export default connect(mapStateToProps, mapDispatchToProps)(Sidebar); | 
				
			||||||
 | 
				
			|||||||