parent
669c4732b2
commit
fc6d4c4132
18 changed files with 326 additions and 74 deletions
After Width: | Height: | Size: 731 B |
@ -0,0 +1,49 @@ |
|||||||
|
import React from "react"; |
||||||
|
import _ from "lodash"; |
||||||
|
|
||||||
|
const langDetector = (lang = "fa", option1, option2) => { |
||||||
|
return lang === "fa" ? option1 : option2; |
||||||
|
}; |
||||||
|
|
||||||
|
export default function Search({ |
||||||
|
lang, |
||||||
|
backgroundColor, |
||||||
|
borderColor, |
||||||
|
textColor, |
||||||
|
icon, |
||||||
|
}) { |
||||||
|
return ( |
||||||
|
<div |
||||||
|
className={`flex items-center justify-center border-solid w-full border rounded-md overflow-hidden my-2 ${backgroundColor} ${borderColor}`} |
||||||
|
> |
||||||
|
<div className="relative text-gray-600 w-full bg-transparent"> |
||||||
|
<span |
||||||
|
className={_.join( |
||||||
|
[ |
||||||
|
"absolute inset-y-0 flex items-center pl-2", |
||||||
|
langDetector(lang, "left-0", "right-0"), |
||||||
|
], |
||||||
|
" " |
||||||
|
)} |
||||||
|
> |
||||||
|
<button |
||||||
|
type="submit" |
||||||
|
className="p-1 focus:outline-none focus:shadow-outline" |
||||||
|
> |
||||||
|
{icon && <img src={icon} className="w-6 h-6" alt="" />} |
||||||
|
</button> |
||||||
|
</span> |
||||||
|
<input |
||||||
|
type="search" |
||||||
|
name="q" |
||||||
|
className={`w-full py-3 text-sm rounded-md pr-3 outline-none bg-transparent ${textColor}`} |
||||||
|
placeholder={_.join( |
||||||
|
[langDetector(lang, "جستجو...", "Search...")], |
||||||
|
" " |
||||||
|
)} |
||||||
|
autoComplete="off" |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
import React from "react"; |
||||||
|
|
||||||
|
function Select({ |
||||||
|
options, |
||||||
|
icon, |
||||||
|
fill, |
||||||
|
hoverFill, |
||||||
|
margin, |
||||||
|
borderColor, |
||||||
|
backgroundColor, |
||||||
|
onChane, |
||||||
|
name, |
||||||
|
}) { |
||||||
|
return ( |
||||||
|
<div |
||||||
|
className={`inline-block relative w-1/2 group ${margin} ${backgroundColor}`} |
||||||
|
> |
||||||
|
<select |
||||||
|
className={`text-gray70 text-xs block appearance-none bg-transparent w-full border border-solid px-4 py-3 pr-3 rounded-md leading-tight focus:outline-none focus:border-blueC0 focus:text-blueC0 ${borderColor}`} |
||||||
|
onChane={(e) => onChane(name, e.target.value)} |
||||||
|
> |
||||||
|
{options.map((option, index) => ( |
||||||
|
<option key={index} className=""> |
||||||
|
{option} |
||||||
|
</option> |
||||||
|
))} |
||||||
|
</select> |
||||||
|
<div className="pointer-events-none absolute inset-y-0 left-0 flex items-center px-2"> |
||||||
|
<svg |
||||||
|
className={`${fill} h-5 w-5 group-focus:${hoverFill}`} |
||||||
|
xmlns="http://www.w3.org/2000/svg" |
||||||
|
viewBox="0 0 20 20" |
||||||
|
> |
||||||
|
<path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z" /> |
||||||
|
</svg> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
export default Select; |
||||||
|
|
||||||
|
Select.defaultProps = { |
||||||
|
options: ["Really", "Option 2", "Option 3"], |
||||||
|
}; |
@ -0,0 +1,112 @@ |
|||||||
|
import React, { useState, useEffect, useCallback } from "react"; |
||||||
|
import { Link } from "react-router-dom"; |
||||||
|
import { connect } from "react-redux"; |
||||||
|
import Search from "../../components/Search"; |
||||||
|
import Select from "../../components/Select"; |
||||||
|
import { book } from "../../redux/actions"; |
||||||
|
|
||||||
|
//assets
|
||||||
|
import searchLight from "../../assets/icons/search-light.svg"; |
||||||
|
|
||||||
|
const Product = ({ productsType, product, index, grades }) => { |
||||||
|
return ( |
||||||
|
<> |
||||||
|
{productsType === "book" && ( |
||||||
|
<Link |
||||||
|
to={"/products" + product?.name} |
||||||
|
className={`w-1/2 flex flex-col border-t border-grayDB dark:border-gray45 p-3 border-solid ${ |
||||||
|
index % 2 === 0 ? "border-l" : "" |
||||||
|
}`}
|
||||||
|
> |
||||||
|
<img |
||||||
|
src={"https://dnvn.ir/api/v1/file/" + product?.fileIds} |
||||||
|
className="w-full rounded-md mb-2" |
||||||
|
/> |
||||||
|
<strong className="text-blue5F dark:text-white text-md font-bold mb-1"> |
||||||
|
{product?.name} |
||||||
|
</strong> |
||||||
|
<span className="text-xs text-blueC0 dark:text-white font-light mb-4"> |
||||||
|
{"پایه" + " " + grades[product?.gradeId]} |
||||||
|
</span> |
||||||
|
<div className="w-full flex flex-row justify-center font-semibold text-md text-blue5F dark:text-white"> |
||||||
|
{1399 + " " + "تومان"} |
||||||
|
</div> |
||||||
|
</Link> |
||||||
|
)} |
||||||
|
</> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export const Products = ({ isDark, books, getList, grades }) => { |
||||||
|
const [filter, setFilter] = useState({ |
||||||
|
search: "", |
||||||
|
grade: "", |
||||||
|
productsType: "book", |
||||||
|
}); |
||||||
|
|
||||||
|
const onChange = (name, value) => { |
||||||
|
setFilter({ ...filter, [name]: value }); |
||||||
|
}; |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
getList(); |
||||||
|
}, []); |
||||||
|
return ( |
||||||
|
<> |
||||||
|
{/* Portrait */} |
||||||
|
<div className="w-full flex flex-col bg-transparent pt-20"> |
||||||
|
<header className="w-full px-4"> |
||||||
|
<Search |
||||||
|
backgroundColor="bg-grayF9 dark:bg-gray36" |
||||||
|
borderColor="border-grayDB dark:border-gray45" |
||||||
|
textColor="text-blueC0 dark:text-white" |
||||||
|
icon={searchLight} |
||||||
|
/> |
||||||
|
<div className="w-full flex flex-row justify-between mt-3"> |
||||||
|
<Select |
||||||
|
margin="ml-1" |
||||||
|
fill="fill-blueC0 dark:fill-white" |
||||||
|
borderColor="border-grayDB dark:border-gray45" |
||||||
|
backgroundColor="bg-grayF9 dark:bg-gray36" |
||||||
|
onChange={onChange} |
||||||
|
name="productsType" |
||||||
|
options={["کتاب", "ویديو", "اشتراک"]} |
||||||
|
// hoverFill="fill-greenBA"
|
||||||
|
/> |
||||||
|
<Select |
||||||
|
margin="mr-1" |
||||||
|
fill="fill-blueC0 dark:fill-white" |
||||||
|
borderColor="border-grayDB dark:border-gray45" |
||||||
|
backgroundColor="bg-grayF9 dark:bg-gray36" |
||||||
|
onChange={onChange} |
||||||
|
name="grade" |
||||||
|
options={Object.values(grades)} |
||||||
|
// hoverFill="fill-grayBA"
|
||||||
|
/> |
||||||
|
</div> |
||||||
|
</header> |
||||||
|
<div className="w-full flex flex-row flex-wrap mt-3"> |
||||||
|
{books?.map((product, index) => ( |
||||||
|
<Product |
||||||
|
key={index} |
||||||
|
productsType={filter.productsType} |
||||||
|
product={product} |
||||||
|
index={Number(index)} |
||||||
|
grades={grades} |
||||||
|
/> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
const mapStateToProps = (state) => ({ |
||||||
|
isDark: state.publicApi.isDark, |
||||||
|
books: state.book.list, |
||||||
|
grades: state.publicApi.grades, |
||||||
|
}); |
||||||
|
|
||||||
|
const mapDispatchToProps = { getList: book.list }; |
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(Products); |
Loading…
Reference in new issue