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 React from "react"; |
||||||
import { Link } from "react-router-dom"; |
import { Link } from "react-router-dom"; |
||||||
import {connect} from 'react-redux'; |
import { connect } from "react-redux"; |
||||||
import arrowBlueIcon from "../../assets/icons/arrow-right-blue.svg"; |
import arrowGreenIcon from "../../assets/icons/dropdown-blue.svg"; |
||||||
import arrowWhiteIcon from "../../assets/icons/arrow-left-white.svg"; |
import arrowWhiteIcon from "../../assets/icons/arrow-left-white.svg"; |
||||||
|
|
||||||
function Header({ title, link, isDark }) { |
function Header({ title, link, isDark }) { |
||||||
return ( |
return ( |
||||||
<header className="w-full flex flex-row justify-between items-center pl-0"> |
<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} |
{title} |
||||||
</strong> |
</strong> |
||||||
<Link to={link} className="ml-2"> |
<Link to={link} className="ml-2"> |
||||||
<img |
{isDark ? ( |
||||||
src={isDark ? arrowWhiteIcon : arrowBlueIcon} |
<img |
||||||
alt="" |
src={arrowWhiteIcon} |
||||||
className={`transform ${isDark ? "w-6" : "w-6 rotate-180"}`} |
alt="" |
||||||
/> |
className={`transform ${"w-6"}`} |
||||||
|
/> |
||||||
|
) : ( |
||||||
|
<img |
||||||
|
src={arrowGreenIcon} |
||||||
|
alt="" |
||||||
|
className={`transform rotate-90 w-2}`} |
||||||
|
/> |
||||||
|
)} |
||||||
</Link> |
</Link> |
||||||
</header> |
</header> |
||||||
); |
); |
||||||
} |
} |
||||||
|
|
||||||
const mapStateToProps = (state) => ({ |
const mapStateToProps = (state) => ({ |
||||||
isDark: state.publicApi.isDark |
isDark: state.publicApi.isDark, |
||||||
}) |
}); |
||||||
|
|
||||||
const mapDispatchToProps = { |
const mapDispatchToProps = {}; |
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(Header); |
export default connect(mapStateToProps, mapDispatchToProps)(Header); |
||||||
|
@ -1,18 +1,40 @@ |
|||||||
import React from 'react'; |
import React, { useEffect } from "react"; |
||||||
import MyBooks from './MyBooks'; |
import { connect } from "react-redux"; |
||||||
import Shop from './Shop'; |
import { book, blog } from "../../../../redux/actions"; |
||||||
import Videos from './Videos'; |
import MyBooks from "./MyBooks"; |
||||||
import Blogs from './Blogs'; |
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 ( |
return ( |
||||||
<div className="w-full flex-1 pb-6"> |
<div className="w-full flex-1 pb-6"> |
||||||
<MyBooks /> |
<MyBooks books={products} grades={grades} /> |
||||||
<Shop /> |
<Shop list={products} grades={grades} /> |
||||||
<Videos /> |
<Videos videos={products} grades={grades} /> |
||||||
<Blogs /> |
<Blogs list={blogs} /> |
||||||
</div> |
</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 React, { useState, useMemo } from "react"; |
||||||
import { connect } from "react-redux"; |
import { connect } from "react-redux"; |
||||||
import { book } from "../../../redux/actions"; |
import { book } from "../../../../redux/actions"; |
||||||
import Checkbox from "../../../components/Checkbox"; |
import Checkbox from "../../../../components/Checkbox"; |
||||||
import Switch from "../../../components/Switch"; |
import Switch from "../../../../components/Switch"; |
||||||
|
|
||||||
//assets
|
//assets
|
||||||
import dropdownIcon from "../../../assets/icons/dropdown-blue.svg"; |
import dropdownIcon from "../../../../assets/icons/dropdown-blue.svg"; |
||||||
|
|
||||||
export const Sidebar = ({ |
export const Sidebar = ({ |
||||||
onChange, |
|
||||||
levels, |
levels, |
||||||
subjects, |
subjects, |
||||||
productTypes, |
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