parent
503bf41a3d
commit
8d372deb20
24 changed files with 442 additions and 214 deletions
Before Width: | Height: | Size: 964 B After Width: | Height: | Size: 1009 B |
Before Width: | Height: | Size: 940 B After Width: | Height: | Size: 976 B |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.2 KiB |
@ -1,32 +1,38 @@ |
||||
import React from "react"; |
||||
import { Link } from "react-router-dom"; |
||||
import {connect} from 'react-redux'; |
||||
import arrowBlueIcon from "../../assets/icons/arrow-right-blue.svg"; |
||||
import { connect } from "react-redux"; |
||||
import arrowGreenIcon from "../../assets/icons/dropdown-blue.svg"; |
||||
import arrowWhiteIcon from "../../assets/icons/arrow-left-white.svg"; |
||||
|
||||
function Header({ title, link, isDark }) { |
||||
return ( |
||||
<header className="w-full flex flex-row justify-between items-center pl-0"> |
||||
<strong className="text-blueC0 dark:text-white font-semibold text-sm"> |
||||
<strong className="text-green7B dark:text-white font-semibold text-base lg:text-sm"> |
||||
{title} |
||||
</strong> |
||||
<Link to={link} className="ml-2"> |
||||
<img |
||||
src={isDark ? arrowWhiteIcon : arrowBlueIcon} |
||||
alt="" |
||||
className={`transform ${isDark ? "w-6" : "w-6 rotate-180"}`} |
||||
/> |
||||
{isDark ? ( |
||||
<img |
||||
src={arrowWhiteIcon} |
||||
alt="" |
||||
className={`transform ${"w-6"}`} |
||||
/> |
||||
) : ( |
||||
<img |
||||
src={arrowGreenIcon} |
||||
alt="" |
||||
className={`transform rotate-90 w-2}`} |
||||
/> |
||||
)} |
||||
</Link> |
||||
</header> |
||||
); |
||||
} |
||||
|
||||
const mapStateToProps = (state) => ({ |
||||
isDark: state.publicApi.isDark |
||||
}) |
||||
isDark: state.publicApi.isDark, |
||||
}); |
||||
|
||||
const mapDispatchToProps = { |
||||
|
||||
} |
||||
const mapDispatchToProps = {}; |
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Header); |
||||
|
@ -1,18 +1,40 @@ |
||||
import React from 'react'; |
||||
import MyBooks from './MyBooks'; |
||||
import Shop from './Shop'; |
||||
import Videos from './Videos'; |
||||
import Blogs from './Blogs'; |
||||
import React, { useEffect } from "react"; |
||||
import { connect } from "react-redux"; |
||||
import { book, blog } from "../../../../redux/actions"; |
||||
import MyBooks from "./MyBooks"; |
||||
import Shop from "./Shop"; |
||||
import Videos from "./Videos"; |
||||
import Blogs from "./Blogs"; |
||||
|
||||
function Private() { |
||||
function Private({ getList, products, blogs, getBlogList, grades }) { |
||||
useEffect(() => { |
||||
if (products.length === 0) { |
||||
getList({ vod: true }); |
||||
} |
||||
if(blogs.length === 0){ |
||||
getBlogList(); |
||||
} |
||||
// console.log(getBlogList());
|
||||
}, []); |
||||
return ( |
||||
<div className="w-full flex-1 pb-6"> |
||||
<MyBooks /> |
||||
<Shop /> |
||||
<Videos /> |
||||
<Blogs /> |
||||
<MyBooks books={products} grades={grades} /> |
||||
<Shop list={products} grades={grades} /> |
||||
<Videos videos={products} grades={grades} /> |
||||
<Blogs list={blogs} /> |
||||
</div> |
||||
) |
||||
); |
||||
} |
||||
|
||||
export default Private; |
||||
const mapStateToProps = (state) => ({ |
||||
products: state.book.list, |
||||
blogs: state.blog.list, |
||||
grades: state.publicApi.grades |
||||
}); |
||||
|
||||
const mapDispatchToProps = { |
||||
getList: book.list, |
||||
getBlogList: blog.list |
||||
}; |
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Private); |
||||
|
@ -1,14 +1,13 @@ |
||||
import React, { useState, useMemo } from "react"; |
||||
import { connect } from "react-redux"; |
||||
import { book } from "../../../redux/actions"; |
||||
import Checkbox from "../../../components/Checkbox"; |
||||
import Switch from "../../../components/Switch"; |
||||
import { book } from "../../../../redux/actions"; |
||||
import Checkbox from "../../../../components/Checkbox"; |
||||
import Switch from "../../../../components/Switch"; |
||||
|
||||
//assets
|
||||
import dropdownIcon from "../../../assets/icons/dropdown-blue.svg"; |
||||
import dropdownIcon from "../../../../assets/icons/dropdown-blue.svg"; |
||||
|
||||
export const Sidebar = ({ |
||||
onChange, |
||||
levels, |
||||
subjects, |
||||
productTypes, |
@ -0,0 +1,69 @@ |
||||
import React from "react"; |
||||
import { connect } from "react-redux"; |
||||
import { book } from "../../../../redux/actions"; |
||||
import _ from "lodash"; |
||||
|
||||
import Search from "../../../../components/Search"; |
||||
import Select from "../../../../components/Select"; |
||||
|
||||
import searchLight from "../../../../assets/icons/search-light.svg"; |
||||
|
||||
export const Header = ({ |
||||
setFilterOptions, |
||||
filterOptions, |
||||
levels, |
||||
productTypes, |
||||
isDark |
||||
}) => { |
||||
return ( |
||||
<header className="w-full px-4 fixed top-0 left-0 pb-5 z-10" style={{backgroundColor: isDark ? '#061B30' : 'white'}}> |
||||
<Search |
||||
backgroundColor="bg-gray-100 dark:bg-blueC0 dark:bg-opacity-70" |
||||
borderColor="border-grayDB dark:border-gray45" |
||||
textColor="text-black dark:text-white" |
||||
icon={searchLight} |
||||
onChange={_.debounce( |
||||
(val) => setFilterOptions({ ...filterOptions, search: val }), |
||||
700 |
||||
)} |
||||
/> |
||||
<div className="w-full flex flex-row justify-between mt-3"> |
||||
<Select |
||||
margin="ml-1" |
||||
fill="fill-green-700 dark:fill-white" |
||||
borderColor="border-grayDB dark:border-gray45" |
||||
backgroundColor="bg-gray-100" |
||||
onChange={(name, value) => |
||||
setFilterOptions({ ...filterOptions, [name]: value }) |
||||
} |
||||
name="productType" |
||||
options={productTypes} |
||||
/> |
||||
<Select |
||||
margin="mr-1" |
||||
fill="fill-green-700 dark:fill-white" |
||||
borderColor="border-grayDB dark:border-gray45" |
||||
backgroundColor="bg-gray-100" |
||||
onChange={(name, value) => |
||||
setFilterOptions({ ...filterOptions, [name]: value }) |
||||
} |
||||
name="grade" |
||||
options={Object.values(levels)} |
||||
/> |
||||
</div> |
||||
</header> |
||||
); |
||||
}; |
||||
|
||||
const mapStateToProps = (state) => ({ |
||||
levels: state.publicApi.grades, |
||||
productTypes: state.book.productTypes, |
||||
filterOptions: state.book.filterOptions, |
||||
isDark: state.publicApi.isDark |
||||
}); |
||||
|
||||
const mapDispatchToProps = { |
||||
setFilterOptions: book.setFilterOptions, |
||||
}; |
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Header); |
@ -0,0 +1,164 @@ |
||||
import React, { useEffect, useState } from "react"; |
||||
import { connect } from "react-redux"; |
||||
import { Link } from "react-router-dom"; |
||||
|
||||
import Loading from "../../../../components/Loading"; |
||||
|
||||
//assets
|
||||
import whitePlayIcon from "../../../../components/VodProduct/white-play-button-icon.svg"; |
||||
|
||||
export const Main = ({ books, filterOptions, grades }) => { |
||||
const [filterLoading, setFilterLoading] = useState(false); |
||||
|
||||
useEffect(() => { |
||||
setFilterLoading(() => true); |
||||
setTimeout(() => { |
||||
setFilterLoading(() => false); |
||||
}, 500); |
||||
}, [filterOptions]); |
||||
|
||||
const Items = (type) => { |
||||
const { grade, subject, available, sort, productType, search } = |
||||
filterOptions; |
||||
let byGradeFilter; |
||||
let bySubjectFilter; |
||||
let byAvailableFilter; |
||||
let bySearchFilter; |
||||
if (grade) { |
||||
byGradeFilter = books?.filter((book) => grades[book?.gradeId] === grade); |
||||
} else { |
||||
byGradeFilter = books; |
||||
} |
||||
if (subject) { |
||||
bySubjectFilter = byGradeFilter?.filter( |
||||
(book) => |
||||
book?.product[type]?.name?.indexOf(subject) !== -1 || |
||||
book?.name.indexOf(subject) !== -1 |
||||
); |
||||
} else { |
||||
bySubjectFilter = byGradeFilter; |
||||
} |
||||
if (available) { |
||||
byAvailableFilter = bySubjectFilter?.filter( |
||||
(book) => book.product[type].price |
||||
); |
||||
} else { |
||||
byAvailableFilter = bySubjectFilter; |
||||
} |
||||
if (search) { |
||||
bySearchFilter = byAvailableFilter?.filter( |
||||
(book) => |
||||
book?.product[type]?.name?.indexOf(search) !== -1 || |
||||
book?.name.indexOf(search) !== -1 |
||||
); |
||||
} else { |
||||
bySearchFilter = byAvailableFilter; |
||||
} |
||||
|
||||
return filterOptions.productType === "دوره ویدئویی" |
||||
? bySearchFilter?.map((product, index) => ( |
||||
<Link |
||||
to={"/products" + product?.id} |
||||
className={`w-full flex flex-col border-grayDB dark:border-gray45 p-3 border-solid mb-5 shadow-md mx-4`} |
||||
key={index} |
||||
> |
||||
<div |
||||
className="relative w-full mb-2" |
||||
style={{ height: "calc(100vh / 5)" }} |
||||
> |
||||
<img |
||||
src={"https://dnvn.ir/api/v1/file/" + product?.fileIds} |
||||
className="w-full rounded-md h-full" |
||||
/> |
||||
<div |
||||
className={`absolute left-1/2 top-1/2 rounded-full p-4 group-hover:scale-125 transform -translate-x-1/2 -translate-y-1/2 duration-300 bg-playButtonIcon bg-black bg-opacity-20 backdrop-filter backdrop-blur-md`} |
||||
> |
||||
<img src={whitePlayIcon} alt="" className="w-5 h-5" /> |
||||
</div> |
||||
</div> |
||||
|
||||
<strong className="text-blue5F dark:text-white text-lg lg:text-tiny font-bold mb-2"> |
||||
{product?.name} |
||||
</strong> |
||||
<span className="text-tiny lg:text-sm text-green7B dark:text-white font-light mb-4"> |
||||
{"پایه" + " " + grades[product?.gradeId]} |
||||
</span> |
||||
<div className="w-full flex flex-row justify-center font-bold lg:font-medium text-lg lg:text-tiny text-blue5F dark:text-white"> |
||||
{product?.product[2]?.price + " " + "تومان"} |
||||
</div> |
||||
</Link> |
||||
)) |
||||
: bySearchFilter?.map((product, index) => ( |
||||
<> |
||||
{(productType ? productType === "کتاب دیجیتال" : true) && ( |
||||
<Link |
||||
key={index} |
||||
to={"/products/" + product?.id} |
||||
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-base lg:text-sm font-medium mb-2"> |
||||
{"کتاب دیجیتال" + " " + product?.name} |
||||
</strong> |
||||
<span className="text-tiny lg:text-xs text-green7B dark:text-white font-light mb-4"> |
||||
{"پایه" + " " + grades[product?.gradeId]} |
||||
</span> |
||||
<div className="w-full flex flex-row justify-center font-bold lg:font-medium text-lg lg:text-sm text-blue5F dark:text-white"> |
||||
{product?.product[0]?.price + " " + "تومان"} |
||||
</div> |
||||
</Link> |
||||
)} |
||||
{(productType ? productType === "کتاب فیزیکی" : true) && ( |
||||
<Link |
||||
key={index} |
||||
to={"/products/" + product?.id} |
||||
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-lg lg:text-sm font-medium mb-2"> |
||||
{"کتاب فیزیکی" + " " + product?.name} |
||||
</strong> |
||||
<span className="text-tiny lg:text-xs text-green7B dark:text-white font-light mb-4"> |
||||
{"پایه" + " " + grades[product?.gradeId]} |
||||
</span> |
||||
<div className="w-full flex flex-row justify-center font-bold lg:font-medium text-lg lg:text-sm text-blue5F dark:text-white"> |
||||
{product?.product[1]?.price + " " + "تومان"} |
||||
</div> |
||||
</Link> |
||||
)} |
||||
</> |
||||
)); |
||||
}; |
||||
|
||||
return ( |
||||
<div className="h-full overflow-y-scroll w-full flex flex-wrap py-32"> |
||||
{filterOptions?.productType === "دوره ویدئویی" && Items(2)} |
||||
{filterOptions?.productType === "کتاب دیجیتال" && Items(0)} |
||||
{filterOptions?.productType === "کتاب فیزیکی" && Items(1)} |
||||
{!filterOptions?.productType && Items(0)} |
||||
{filterLoading && ( |
||||
<div className="w-full h-screen flex justify-center items-center bg-white bg-opacity-20 backdrop-filter backdrop-blur-xl fixed left-0 top-0"> |
||||
<Loading size={4} color="bg-green-400" /> |
||||
</div> |
||||
)} |
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
const mapStateToProps = (state) => ({ |
||||
filterOptions: state.book.filterOptions, |
||||
}); |
||||
|
||||
const mapDispatchToProps = {}; |
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Main); |
Loading…
Reference in new issue