@ -0,0 +1,41 @@ |
||||
import React from 'react'; |
||||
import { connect } from 'react-redux'; |
||||
import { createStructuredSelector } from "reselect"; |
||||
import { withRouter } from 'react-router-dom'; |
||||
|
||||
|
||||
|
||||
import { selectCartItems } from "../../redux/cart/cart.selectors"; |
||||
import { toggleCartHidden } from '../../redux/cart/cart.actions'; |
||||
|
||||
|
||||
import './cart-dropdown.styles.scss'; |
||||
|
||||
const CartDropdown = ({ cartItems, history, dispatch }) => ( |
||||
<div className='cart-dropdown'> |
||||
<div className='cart-items'> |
||||
{ |
||||
cartItems.length ? ( |
||||
cartItems.map(cartItem => ( |
||||
<CartItem key={cartItem.id} item={cartItem}/>
|
||||
)) |
||||
):( |
||||
<span className='empty-message'>سبد خرید شما خالیست.</span> |
||||
)} |
||||
</div> |
||||
<center><button |
||||
onClick={() => { |
||||
history.push('/checkout'); |
||||
dispatch(toggleCartHidden()) |
||||
}}>
|
||||
تسویه حساب |
||||
</button> |
||||
</center> |
||||
</div> |
||||
) |
||||
|
||||
const mapStateToProps = createStructuredSelector({ |
||||
cartItems: selectCartItems |
||||
}) |
||||
|
||||
export default withRouter(connect(mapStateToProps)(CartDropdown)); |
After Width: | Height: | Size: 868 B |
After Width: | Height: | Size: 86 KiB |
@ -0,0 +1,276 @@ |
||||
import React, { useState } from "react"; |
||||
|
||||
// import Tag from "../Tag";
|
||||
// import ReactTooltip from "react-tooltip";
|
||||
|
||||
import book from "./goldon.png"; |
||||
import watermelon from "./watermelon.png"; |
||||
import heart from "./vuesax-linear-heart.svg"; |
||||
import discountImg from "./discount.png"; |
||||
import YellowDotIcon from "./yellowDotIcon.svg"; |
||||
import RedDotIcon from "./redDotIcon.svg"; |
||||
import PurpleDotIcon from "./purpleDotIcon.svg"; |
||||
import LightBlueDotIcon from "./lightBlueDotIcon.svg"; |
||||
|
||||
|
||||
const ProductDesign = ({ |
||||
colors, |
||||
likeBtn, |
||||
discount, |
||||
discountPricePercent, |
||||
discountPrice, |
||||
productContent, |
||||
star, |
||||
productTags, |
||||
priceDirection, |
||||
productTitleAlignment, |
||||
priceHolder, |
||||
productHolderBorder, |
||||
productHolderBorderColor, |
||||
productTitleColor, |
||||
productExcerptTextColor, |
||||
productCat, |
||||
productCatTextColor, |
||||
rangeHolder, |
||||
verticalImg, |
||||
horizontalImg, |
||||
rangeWidth, |
||||
addToCartHolder, |
||||
productName, |
||||
productPrice, |
||||
productImg, |
||||
writeGHEIMAT, |
||||
numberOfRegards, |
||||
productHolderHoverBorder, |
||||
hoverMode, |
||||
big, |
||||
starRate |
||||
}) => { |
||||
const [isHovering, setIsHovering] = useState(false); |
||||
return ( |
||||
<div className={`flex flex-wrap sm:flex-nowrap justify-around ${big ? 'm' : 'w-48 m-2'} `} |
||||
style={big ? {width: '300px'} : {}} |
||||
|
||||
> |
||||
<div className="w-full flex flex-wrap items-center justify-around my-5 px-4" > |
||||
<div |
||||
className={`w-full sm:w-60 md:w-72 ${big ? '' : 'mx-5'} rounded-lg transition-all p-2 my-3 ${productHolderBorder} ${hoverMode == 'blue' ? 'hover:bg-grayF4' : null} ${productHolderBorderColor} hover:${productHolderHoverBorder} hover:` } |
||||
onMouseEnter={() => setIsHovering(true)} |
||||
onMouseLeave={() => setIsHovering(false)} |
||||
> |
||||
{/* product image */} |
||||
<div className="w-full relative"> |
||||
{/* icons on image */} |
||||
<div className="absolute left-0 top-10"> |
||||
{discountPricePercent && ( |
||||
<div className="bg-discountPriceBg bg-white w-full p-2 px-3"> |
||||
<p className="text-discountPriceTitle font-bold text-md text-blueC0"> |
||||
23<span>%</span> |
||||
</p> |
||||
</div> |
||||
)} |
||||
{likeBtn && ( |
||||
<div className="bg-likeBtnBg rounded-md flex justify-center my-2"> |
||||
<img src={heart} alt="" className="w-5" /> |
||||
</div> |
||||
)} |
||||
{discount && ( |
||||
<div className="rounded-md"> |
||||
<img src={discountImg} alt="" className="w-full" /> |
||||
</div> |
||||
)} |
||||
</div> |
||||
{/* img */} |
||||
<div className={`w-full ${big ? 'h-60' : 'h-48'} flex bg-grayF4 p-0 justify-center rounded-lg`}> |
||||
{verticalImg && ( |
||||
<img |
||||
src={productImg} |
||||
alt="" |
||||
className="h-full rounded-lg cursor-pointer py-5" |
||||
|
||||
/> |
||||
)} |
||||
{horizontalImg && ( |
||||
<img src={watermelon} alt="" className="w-full rounded-lg" /> |
||||
)} |
||||
</div> |
||||
{/* select Color */} |
||||
{/* {colors && ( |
||||
<div className="flex items-center absolute right-2 bottom-2"> |
||||
<img |
||||
src={YellowDotIcon} |
||||
alt="" |
||||
data-tip="زرد" |
||||
className="w-3 h-3 ml-1 cursor-pointer" |
||||
/> |
||||
<ReactTooltip place="top" type="dark" effect="float" /> |
||||
<img |
||||
src={RedDotIcon} |
||||
alt="" |
||||
data-tip="قرمز" |
||||
className="w-3 h-3 ml-1 cursor-pointer" |
||||
/> |
||||
<ReactTooltip place="top" type="dark" effect="float" /> |
||||
<img |
||||
src={PurpleDotIcon} |
||||
alt="" |
||||
data-tip="بنفش" |
||||
className="w-3 h-3 ml-1 cursor-pointer" |
||||
/> |
||||
<ReactTooltip place="top" type="dark" effect="float" /> |
||||
<img |
||||
src={LightBlueDotIcon} |
||||
alt="" |
||||
data-tip="آبی" |
||||
className="w-3 h-3 ml-1 cursor-pointer" |
||||
/> |
||||
<ReactTooltip place="top" type="dark" effect="float" /> |
||||
</div> |
||||
)} */} |
||||
|
||||
</div> |
||||
{/* product content */} |
||||
<div className="px-2"> |
||||
<div className="mt-4"> |
||||
<h2 |
||||
className={`leading-4 text-xl font-black py-2 ${productTitleColor} ${productTitleAlignment}`} |
||||
> |
||||
{productName} |
||||
</h2> |
||||
{productContent && ( |
||||
<p |
||||
className={`text-justify mt-2 text-xs leading-6 ${productExcerptTextColor}`} |
||||
> |
||||
این کتاب شامل گلدان و گیاه و خاک می باشد و همچنین آپشن های خوب |
||||
دیگری نیز دارد. |
||||
</p> |
||||
)} |
||||
{productCat && ( |
||||
<span className={`text-md py-1 font-light ${productCatTextColor}`}> |
||||
{productCat} |
||||
</span> |
||||
)} |
||||
</div> |
||||
{/* star */} |
||||
{/* price */} |
||||
{priceHolder && ( |
||||
<div |
||||
className={`flex items-center justify-between ${priceDirection}`} |
||||
> |
||||
<div className="mt-2"> |
||||
<div |
||||
className={`${priceDirection.indexOf("col") !== -1 ? "inline" : "flex" |
||||
}`}
|
||||
> |
||||
{writeGHEIMAT && <span className="text-xs text-borderColor ml-2">قیمت</span>} |
||||
{/* price with line on it */} |
||||
{discountPrice && ( |
||||
<p className="line-through text-xs text-borderColor mr-2"> |
||||
145<span>تومان</span> |
||||
</p> |
||||
)} |
||||
</div> |
||||
<p className="text-xl text-productPrice font-semibold inline text-blue5F"> |
||||
{productPrice} <span>تومان</span> |
||||
</p> |
||||
</div> |
||||
{/* add to cart */} |
||||
{addToCartHolder && ( |
||||
<button |
||||
className={`rounded-2xl px-2 py-3 border text-xs text-productPrice mt-2 hover:bg-darkCrimsonBgColor hover:text-white active:bg-rangeFillBgColor transition duration-500 hover:-translate-y-2 ${priceDirection.indexOf("col") !== -1 ? "w-full" : "" |
||||
}`}
|
||||
> |
||||
اضافه کردن به سبد خرید |
||||
</button> |
||||
|
||||
)} |
||||
|
||||
|
||||
</div> |
||||
|
||||
)} |
||||
|
||||
|
||||
|
||||
{hoverMode == 'blue' ?<div className="w-full flex justify-center mt-4"> |
||||
<div |
||||
className={`bg-blueC0 text-white rounded p-4 text-xs justify-center ${isHovering ? "" : "hidden" |
||||
}`}
|
||||
> |
||||
<button>افزودن به سبد خرید</button> |
||||
</div> |
||||
</div> : null} |
||||
|
||||
{/* {productTags && ( |
||||
<div className="mt-2 flex flex-wrap"> |
||||
{ |
||||
productTags.map((item, index) => <Tag title={item} key={index} />) |
||||
} |
||||
</div> |
||||
)} */} |
||||
{rangeHolder && ( |
||||
<div className="bg-rangeBgColor h-3 w-full rounded mt-2"> |
||||
<div |
||||
className={`bg-rangeFillBgColor h-3 rounded ${rangeWidth}`} |
||||
></div> |
||||
</div> |
||||
)} |
||||
|
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
export default ProductDesign; |
||||
|
||||
// text colors i used for product title:
|
||||
// text-darkCrimsonTextColor
|
||||
// text-productTitle
|
||||
|
||||
// text color i used for product excerpt:
|
||||
// text-productContent
|
||||
|
||||
// text color i used for product cat:
|
||||
// text-darkCrimsonTextColor
|
||||
|
||||
ProductDesign.defaultProps = { |
||||
// icons on product image
|
||||
colors: false, |
||||
likeBtn: false, |
||||
discount: false, |
||||
discountPricePercent: false, |
||||
// product price
|
||||
discountPrice: false, |
||||
priceHolder: true, |
||||
|
||||
productContent: false, |
||||
star: true, |
||||
productTags: [], |
||||
productCat: true, |
||||
rangeHolder: true, |
||||
|
||||
// دو مدل عکس طراحی کردم که یکی عرض بیشتری دارد یکی ارتفاع
|
||||
verticalImg: true, |
||||
horizontalImg: false, |
||||
|
||||
addToCartHolder: false, |
||||
|
||||
productTitleColor: "text-productTitle", |
||||
|
||||
productExcerptTextColor: "text-productContent", |
||||
|
||||
productCatTextColor: "text-darkCrimsonTextColor", |
||||
// برای درصد دادن به عرض رنج
|
||||
rangeWidth: "w-44", |
||||
//دی ای وی که محصول داخلش است میتونیم بهش بوردر بدیم
|
||||
productHolderBorder: "border", |
||||
productHolderBorderColor: "border-grayBorderColor", |
||||
|
||||
productTitleAlignment: "text-justify", |
||||
//میتونیم تعیین کنیم که قیمت و دکمه اضاف به سبد خرید کنار یکدیگر باشند یا زیر هم
|
||||
priceDirection: "flex-row", |
||||
productImg: book, |
||||
writeGHEIMAT: false |
||||
}; |
After Width: | Height: | Size: 177 B |
After Width: | Height: | Size: 177 B |
After Width: | Height: | Size: 177 B |
After Width: | Height: | Size: 675 B |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 177 B |
@ -1,18 +1,28 @@ |
||||
import React from "react"; |
||||
const Class = ({ |
||||
title, |
||||
description, |
||||
teacher, |
||||
group, |
||||
price, |
||||
}) => { |
||||
return( |
||||
<div> |
||||
<h1>{title}</h1> |
||||
<p>{description}</p> |
||||
{teacher} {group} {price} |
||||
import React from 'react'; |
||||
import { connect } from 'react-redux'; |
||||
|
||||
import { addItem }from '../../../redux/cart/cart.actions.js'; |
||||
|
||||
|
||||
|
||||
const Class = ({item, addItem}) => { |
||||
const {name, price, imageUrl} = item; |
||||
return ( |
||||
<div className="collection-item"> |
||||
|
||||
<img src={imageUrl} className='image'/> |
||||
<div className="collection-footer"> |
||||
<span className="name"> {name} </span> |
||||
<span className="price"> {price} </span> |
||||
</div> |
||||
) |
||||
}; |
||||
|
||||
export default Class |
||||
<button onClick={ () => addItem(item)} inverted>افزودن به سبد خرید</button> |
||||
</div> |
||||
); |
||||
} |
||||
|
||||
const mapDispatchToProps = dispatch => ({ |
||||
addItem: item => dispatch(addItem(item)) |
||||
}) |
||||
|
||||
export default connect(null, mapDispatchToProps) (Class); |
@ -0,0 +1,36 @@ |
||||
// gray |
||||
$gray : #aaa; |
||||
$gray1 : #383838; |
||||
$gray2 : #6c6c6c; |
||||
$gray3 : rgb(143, 142, 142); |
||||
$gray4 : #666666; |
||||
$gray5 : #555; |
||||
$gray6 : #ddd; |
||||
$gray7 : #797979; |
||||
$gray8 : #272727; |
||||
$gray9 : #b3b3b3; |
||||
$gray10 : #cccccc; |
||||
$gray11 : #969696; |
||||
$gray12 : #e9e9e9; |
||||
$gray13 : #f6f6f6; |
||||
// green |
||||
$green : #4dd35b; |
||||
$green1 : #81C342; |
||||
$green2 : #6cbe44; |
||||
$green3 : #00cc69; |
||||
$green4 : #84de56; |
||||
$green5 : #9cdf52; |
||||
$green6 : #08793d; |
||||
// blue |
||||
$blue : #a2b4cb; |
||||
$blue1 : #505a82; |
||||
$blue2 : #00FFF8; |
||||
// red |
||||
$red : red; |
||||
$red1 : rgb(255, 115, 115); |
||||
|
||||
//yellow |
||||
$yellow : #FFD70F; |
||||
|
||||
//orange |
||||
$orange : orange; |
@ -0,0 +1,9 @@ |
||||
export const ApiConfig = { |
||||
apiKey: 'AIzaSyBBksq-Asxq2M4Ot-75X19IyrEYJqNBPcg', |
||||
authDomain: 'dnvn.ir', |
||||
baseUrl: 'https://dnvn.ir/api/v1', |
||||
//baseUrl: 'http://localhost:3030/api/v1',
|
||||
loginURL: 'user/login', |
||||
otploginURL: 'user/otp/login', |
||||
logoutURL: 'user/logout', |
||||
}; |
@ -0,0 +1,8 @@ |
||||
$xs : 320px; |
||||
$sm : 640px; |
||||
$md : 768px; |
||||
$lg : 1024px; |
||||
$xl : 1280px; |
||||
$xxl : 1536px; |
||||
|
||||
$maxWidth : calc(100% - 120px); |
@ -0,0 +1,27 @@ |
||||
import proxy from "../proxy"; |
||||
const blog = { |
||||
list: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("public/blogList", data, { dispatch }), |
||||
// update:
|
||||
// (data = {}, data2 = {}) =>
|
||||
// async (dispatch : Dispatch) => {
|
||||
// await proxy.put("blog/update", data);
|
||||
// await proxy.get("blog/list", data2, { dispatch });
|
||||
// },
|
||||
// add:
|
||||
// (data = {}, data2 = {}) =>
|
||||
// async (dispatch : Dispatch) => {
|
||||
// await proxy.post("blog/add", data);
|
||||
// await proxy.get("blog/list", data2, { dispatch });
|
||||
// },
|
||||
// del:
|
||||
// (data = {}, data2 = {}) =>
|
||||
// async (dispatch : Dispatch) => {
|
||||
// await proxy.delete("blog/delete", data);
|
||||
// await proxy.get("blog/list", data2, { dispatch });
|
||||
// },
|
||||
}; |
||||
|
||||
export default blog; |
@ -0,0 +1,44 @@ |
||||
import proxy from "../proxy"; |
||||
const book = { |
||||
list: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("book/list", data, { dispatch }), |
||||
info: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("book/info", data, { dispatch }), |
||||
setLessonActive: (data) => async (dispatch) => |
||||
await dispatch({ type: "book/lesson/active", data: data }), |
||||
gradeFilter: (data) => async (dispatch) => |
||||
await dispatch({ type: "book/gradeFilter", data: data }), |
||||
sortFilter: (data) => async (dispatch) => |
||||
await dispatch({ type: "book/sortFilter", data: data }), |
||||
|
||||
// update:
|
||||
// (data = {}, data2 = {}) =>
|
||||
// async (dispatch : Dispatch) => {
|
||||
// await proxy.put("book/update", data);
|
||||
// await proxy.get("book/list", data2, { dispatch });
|
||||
// },
|
||||
// add:
|
||||
// (data = {}, data2 = {}) =>
|
||||
// async (dispatch) => {
|
||||
// await proxy.post("book/add", data);
|
||||
// await proxy.get("book/list", data2, { dispatch });
|
||||
// },
|
||||
// del:
|
||||
// (data = {}, data2 = {}) =>
|
||||
// async (dispatch) => {
|
||||
// await proxy.delete("book/delete", data);
|
||||
// await proxy.get("book/list", data2, { dispatch });
|
||||
// },
|
||||
// searchBook: (data) => async (dispatch) => {
|
||||
// dispatch({ type: "book/search", data: data });
|
||||
// },
|
||||
// filterBook: (data) => async (dispatch) => {
|
||||
// dispatch({ type: "book/filter", data: data });
|
||||
// },
|
||||
}; |
||||
|
||||
export default book; |
@ -0,0 +1,14 @@ |
||||
import proxy from "../proxy"; |
||||
import { Dispatch } from "redux"; |
||||
const content = { |
||||
listVOD: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("content/listVOD", data, { dispatch }), |
||||
infoVOD: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("content/infoVOD", data, { dispatch }), |
||||
}; |
||||
|
||||
export default content; |
@ -0,0 +1,20 @@ |
||||
import proxy from "../proxy"; |
||||
import { Dispatch } from "redux"; |
||||
const faq = { |
||||
list: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("faq/list", data, { dispatch }), |
||||
add: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.post("faq/add", data, { dispatch }), |
||||
selectFaq: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await dispatch({ type: "faq/selectFaq", data: data }), |
||||
searchFaq: (data) => async (dispatch) => |
||||
await dispatch({ type: "faq/search", data: data }), |
||||
}; |
||||
|
||||
export default faq; |
@ -0,0 +1,22 @@ |
||||
import proxy from "../proxy"; |
||||
const file = { |
||||
upload: |
||||
(data = {}) => |
||||
async (dispatch) => { |
||||
var formData = new FormData(); |
||||
for (let key in data) formData.append(key, data[key]); |
||||
return await proxy.post( |
||||
"file/upload", |
||||
formData, |
||||
{ |
||||
dispatch, |
||||
headers: { |
||||
"Content-Type": "multipart/form-data", |
||||
}, |
||||
}, |
||||
data |
||||
); |
||||
}, |
||||
}; |
||||
|
||||
export default file; |
@ -0,0 +1,18 @@ |
||||
// @create-index
|
||||
export { default as publicApi } from "./public"; |
||||
export { default as user } from "./user"; |
||||
export { default as book } from "./book"; |
||||
export { default as blog } from "./blog"; |
||||
export { default as product } from "./product"; |
||||
export { default as userFactor } from "./userFactor"; |
||||
export { default as userProduct } from "./userProduct"; |
||||
export { default as content } from "./content"; |
||||
export { default as faq } from "./faq"; |
||||
export { default as file } from "./file"; |
||||
export {default as scrollAction} from "./scroll"; |
||||
export {default as qr} from "./qr"; |
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,30 @@ |
||||
import proxy from "../proxy"; |
||||
const product = { |
||||
getSimilar: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("product/similar", data, { dispatch }), |
||||
listVOD: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("product/listVOD", data, { dispatch }), |
||||
addVOD: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.post("product/addVOD", data); |
||||
await proxy.get("product/listVOD", data2, { dispatch }); |
||||
}, |
||||
deleteVOD: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.delete("product/deleteVOD", data); |
||||
await proxy.get("product/listVOD", data2, { dispatch }); |
||||
}, |
||||
selectVOD: |
||||
(data = {}) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "product/selectVOD", data }); |
||||
}, |
||||
}; |
||||
|
||||
export default product; |
@ -0,0 +1,56 @@ |
||||
import proxy from "../proxy"; |
||||
const publicApi = { |
||||
setDesktopContentTransform: (data) => async (dispatch) => |
||||
await dispatch({ type: "public/setDesktopContentTransform", data }), |
||||
setHeaderOptions: (data) => async (dispatch) => |
||||
await dispatch({ type: "public/setHeaderOptions", data }), |
||||
setIsDark: (data) => async (dispatch) => |
||||
await dispatch({ type: "public/setIsDark", data }), |
||||
getHomeData: (data) => async (dispatch) => |
||||
await proxy.get("public/homePage", data, { dispatch }), |
||||
|
||||
setFaqActive: (data) => async (dispatch) => |
||||
await dispatch({ type: "public/faq/activate", data }), |
||||
bookInfo: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("public/vod/bookCourse", data, { dispatch }), |
||||
bookSection: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("public/vod/bookSection", data, { dispatch }), |
||||
getContactData: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("public/contact", data, { dispatch }), |
||||
|
||||
getBlogList: (data) => async (dispatch) => |
||||
await proxy.get("public/blogList", data, { dispatch }), |
||||
|
||||
getBlogInfo: (data) => async (dispatch) => |
||||
await proxy.get("public/blogInfo", data, { dispatch }), |
||||
setSubscribe: (data) => async (dispatch) => |
||||
await dispatch({ type: "public/setSubscribe", data }), |
||||
getProvince: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("public/province", data, { dispatch }), |
||||
getCity: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("public/city", data, { dispatch }), |
||||
selectMenu: (data) => async (dispatch) => |
||||
await dispatch({ type: "public/selectMenu", data }), |
||||
getHeader: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("public/VOD/homePage", data, { dispatch }), |
||||
activeCategory: (data) => async (dispatch) => |
||||
await dispatch({ type: "active/category", data }), |
||||
setVideoActive: (data) => async (dispatch) => |
||||
await dispatch({ type: "active/video", data }), |
||||
getArList: (data, history) => async (dispatch) => |
||||
await proxy.get("public/ar", data, { history, dispatch }), |
||||
}; |
||||
|
||||
export default publicApi; |
@ -0,0 +1,32 @@ |
||||
import proxy from "../proxy"; |
||||
const qr = { |
||||
list: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("qr/list", data, { dispatch }), |
||||
info: |
||||
(data = {}) => |
||||
async (dispatch) => { |
||||
await proxy.get("qr/info", data, { dispatch }); |
||||
}, |
||||
add: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.post("qr/add", data); |
||||
await proxy.get("qr/list", data2, { dispatch }); |
||||
}, |
||||
del: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.delete("ar/delete", data); |
||||
await proxy.get("ar/list", data2, { dispatch }); |
||||
}, |
||||
update: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.put("ar/update", data); |
||||
await proxy.get("ar/list", data2, { dispatch }); |
||||
}, |
||||
}; |
||||
|
||||
export default qr; |
@ -0,0 +1,74 @@ |
||||
const scrollAction = { |
||||
floatMouseToggle: |
||||
(data = null) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/page1/floatMouse", data }); |
||||
}, |
||||
handlePage1TopPosition: |
||||
(data = null) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/page1/top", data }); |
||||
}, |
||||
handlePage2TopPosition: |
||||
(data = null) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/page2/top", data }); |
||||
}, |
||||
handlePage2RotateX: |
||||
(data = window.scrollY) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/page2/rotateX", data }); |
||||
}, |
||||
handlePage2BoxPosition: |
||||
(data = window.scrollY) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/page2/boxPosition", data }); |
||||
}, |
||||
handlePage2MobilePosition: |
||||
(data = window.scrollY) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/page2/mobilePosition", data }); |
||||
}, |
||||
handlePage2VideoPosition: |
||||
(data = window.scrollY) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/page2/videoPosition", data }); |
||||
}, |
||||
handlePage2VideoTopPosition: |
||||
(data = window.scrollY) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/page2/videoTopPosition", data }); |
||||
}, |
||||
handlePage2MobileUnit: |
||||
(data = window.scrollY) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/page2/mobileUnit", data }); |
||||
}, |
||||
handleVideoTubeTopPosition: |
||||
(data = window.scrollY) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/videoTube/top", data }); |
||||
}, |
||||
handleTestTranslateY: |
||||
(data = window.scrollY) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/test/translateY", data }); |
||||
}, |
||||
handlePage3TopPosition: |
||||
(data = window.scrollY) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/page3/top", data }); |
||||
}, |
||||
handlePage3TestTranslateY: |
||||
(data = window.scrollY) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/page3/testTranslateY", data }); |
||||
}, |
||||
handlePage4TopPosition: |
||||
(data = window.scrollY) => |
||||
async (dispatch) => { |
||||
await dispatch({ type: "scroll/page4/top", data }); |
||||
}, |
||||
}; |
||||
|
||||
export default scrollAction; |
@ -0,0 +1,63 @@ |
||||
import proxy from "../proxy"; |
||||
|
||||
const user = { |
||||
otp: (data) => async (dispatch) => |
||||
await proxy.post("public/sendOTP", data, { dispatch }), |
||||
|
||||
otp_login: (data) => async (dispatch) => |
||||
await proxy.login("user/otp/login", data, { dispatch }), |
||||
|
||||
login: (data) => async (dispatch) => |
||||
await proxy.login("user/login", data, { dispatch }), |
||||
|
||||
// register: (data : undefined) => async (dispatch : Dispatch) =>
|
||||
// await proxy.login("user/register", data, { dispatch }),
|
||||
|
||||
// switchRole: (data : String) => async (dispatch : Dispatch) =>
|
||||
// await proxy.login("user/switchRole", data, { dispatch }),
|
||||
|
||||
logout: (data) => async (dispatch) => |
||||
await proxy.logout("user/logout", data, { dispatch }), |
||||
|
||||
getUserRole: (data) => async (dispatch) => |
||||
await proxy.get("user/getUserRole", data, { dispatch }), |
||||
|
||||
// list:
|
||||
// (data = {}) =>
|
||||
// async (dispatch : Dispatch) =>
|
||||
// await proxy.get("user/list", data, { dispatch }),
|
||||
// domains:
|
||||
// (data = {}) =>
|
||||
// async (dispatch : Dispatch) =>
|
||||
// await proxy.get("user/domains", data, { dispatch }),
|
||||
// getmothers:
|
||||
// (data = {}) =>
|
||||
// async (dispatch : Dispatch) =>
|
||||
// await proxy.get("mothers/list", data, {
|
||||
// dispatch,
|
||||
// }),
|
||||
getProfile: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("user/getProfile", data, { dispatch }), |
||||
setProfile: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.put("user/setProfile", data, { dispatch }); |
||||
await proxy.get("user/getProfile", data2, { dispatch }); |
||||
}, |
||||
add: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.post("user/add", data); |
||||
await proxy.get("user/list", data2, { dispatch }); |
||||
}, |
||||
del: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.delete("user/delete", data); |
||||
await proxy.get("user/list", data2, { dispatch }); |
||||
}, |
||||
}; |
||||
|
||||
export default user; |
@ -0,0 +1,55 @@ |
||||
import proxy from "../proxy"; |
||||
const userFactor = { |
||||
//dnvn
|
||||
list: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("userFactor/list", data, { dispatch }), |
||||
payment: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.post("userFactor/payment", data, { dispatch }); |
||||
}, |
||||
add: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.post("userFactor/add", data, { dispatch }); |
||||
await proxy.get("userFactor/list", data2, { dispatch }); |
||||
}, |
||||
del: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.delete("userFactor/delete", data); |
||||
await proxy.get("userFactor/list", data2, { dispatch }); |
||||
}, |
||||
|
||||
//vod
|
||||
payment: |
||||
(data1 = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.post("userProduct/addVOD", data1, { dispatch }); |
||||
await proxy.post("userFactor/paymentVOD", data2, { dispatch }); |
||||
}, |
||||
verify: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.post("userFactor/verifyVOD", data, { dispatch }), |
||||
info: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("userFactor/info", data, { dispatch }), |
||||
update: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.put("userFactor/update", data, { dispatch }); |
||||
await proxy.get("userFactor/info", data2, { dispatch }); |
||||
}, |
||||
deleteUserOffCode: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.delete("userFactor/deleteUserOffCode", data, { dispatch }); |
||||
await proxy.get("userFactor/info", data2, { dispatch }); |
||||
}, |
||||
}; |
||||
|
||||
export default userFactor; |
@ -0,0 +1,33 @@ |
||||
import proxy from "../proxy"; |
||||
const userProduct = { |
||||
list: |
||||
(data = {}) => |
||||
async (dispatch) => { |
||||
await proxy.get("userProduct/list", data, { dispatch }); |
||||
}, |
||||
info: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("userProduct/info", data, { dispatch }), |
||||
update: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.put("userProduct/update", data); |
||||
await proxy.get("userProduct/list", data2, { dispatch }); |
||||
}, |
||||
add: |
||||
(data = {}, data2 = {}, data3 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.post("userProduct/add", data, { dispatch }); |
||||
await proxy.get("userProduct/list", data2, { dispatch }); |
||||
await proxy.get("userFactor/info", data3, { dispatch }); |
||||
}, |
||||
del: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.delete("userProduct/delete", data); |
||||
await proxy.get("userProduct/list", data2, { dispatch }); |
||||
}, |
||||
}; |
||||
|
||||
export default userProduct; |
@ -0,0 +1,8 @@ |
||||
const CartActionTypes = { |
||||
TOGGLE_CART_HIDDEN: "TOGGLE_CART_HIDDEN", |
||||
ADD_ITEM: "ADD_ITEM", |
||||
REMOVE_ITEM: "REMOVE_ITEM", |
||||
CLEAR_ITEM_FROM_CART: "CLEAR_ITEM_FROM_CART" |
||||
}; |
||||
|
||||
export default CartActionTypes; |
@ -0,0 +1,20 @@ |
||||
import CartActionTypes from './card.types' |
||||
|
||||
export const toggleCartHidden = () => ({ |
||||
type: CartActionTypes.TOGGLE_CART_HIDDEN |
||||
}) |
||||
|
||||
export const addItem = item =>({ |
||||
type: CartActionTypes.ADD_ITEM, |
||||
payload: item
|
||||
}) |
||||
|
||||
export const removeItem = item =>({ |
||||
type: CartActionTypes.REMOVE_ITEM, |
||||
payload: item |
||||
}) |
||||
|
||||
export const clearItemFromCart = item => ({ |
||||
type: CartActionTypes.CLEAR_ITEM_FROM_CART, |
||||
payload: item |
||||
}) |
@ -0,0 +1,43 @@ |
||||
import CartActionTypes from './card.types.js'; |
||||
import {addItemsToCart, removeItemFromCart} from './cart.utils.js'; |
||||
|
||||
const INITIAL_STATE = { |
||||
hidden: true, |
||||
cartItems: [] |
||||
} |
||||
|
||||
const cartReducer = (state = INITIAL_STATE, action) => { |
||||
switch (action.type){ |
||||
|
||||
case CartActionTypes.TOGGLE_CART_HIDDEN: |
||||
return { |
||||
...state, |
||||
hidden: !state.hidden |
||||
} |
||||
|
||||
case CartActionTypes.ADD_ITEM: |
||||
return{ |
||||
...state, |
||||
cartItems: addItemsToCart(state.cartItems, action.payload ) |
||||
} |
||||
|
||||
case CartActionTypes.REMOVE_ITEM: |
||||
return{ |
||||
...state, |
||||
cartItems: removeItemFromCart(state.cartItems, action.payload) |
||||
} |
||||
|
||||
case CartActionTypes.CLEAR_ITEM_FROM_CART: |
||||
return{ |
||||
...state, |
||||
cartItems: state.cartItems.filter( |
||||
cartItem => cartItem.id !== action.payload.id |
||||
) |
||||
} |
||||
|
||||
default: |
||||
return state; |
||||
} |
||||
} |
||||
|
||||
export default cartReducer; |
@ -0,0 +1,34 @@ |
||||
import { createSelector } from 'reselect'; |
||||
|
||||
const selectCart = state => state.cart; |
||||
|
||||
export const selectCartItems = createSelector( |
||||
[selectCart], |
||||
cart => cart.cartItems |
||||
) |
||||
|
||||
export const selectCartHidden = createSelector( |
||||
[selectCart], |
||||
cart => cart.hidden |
||||
) |
||||
|
||||
export const selectCartItemsCount = createSelector( |
||||
[selectCartItems], |
||||
cartItems => |
||||
cartItems.reduce( |
||||
(accumulatedQuantity, cartItem) => |
||||
accumulatedQuantity + cartItem.quantity, |
||||
0 |
||||
) |
||||
) |
||||
|
||||
export const selectCartTotal = createSelector( |
||||
[selectCartItems], |
||||
cartItems => |
||||
cartItems.reduce( |
||||
(accumulatedQuantity, cartItem) => |
||||
accumulatedQuantity + cartItem.quantity * cartItem.price, |
||||
0 |
||||
) |
||||
|
||||
) |
@ -0,0 +1,31 @@ |
||||
export const addItemsToCart = (cartItems, cartItemToAdd) => { |
||||
const existingCartItem = cartItems.find( |
||||
cartItem => cartItem.id === cartItemToAdd.id
|
||||
) |
||||
|
||||
if(existingCartItem){ |
||||
return cartItems.map(cartItem => |
||||
cartItem.id === cartItemToAdd.id |
||||
? { ...cartItem, quantity: cartItem.quantity + 1 } |
||||
: cartItem |
||||
) |
||||
} |
||||
|
||||
return [...cartItems, { ...cartItemToAdd, quantity: 1 }] |
||||
} |
||||
|
||||
export const removeItemFromCart = (cartItems, cartItemToRemove) => { |
||||
const existingCartItem = cartItems.find( |
||||
cartItem => cartItem.id === cartItemToRemove.id |
||||
) |
||||
|
||||
if(existingCartItem.quantity === 1){ |
||||
return cartItems.filter(cartItem => cartItem.id !== cartItemToRemove.id) |
||||
} |
||||
|
||||
return cartItems.map(cartItem => |
||||
cartItem.id === cartItemToRemove.id |
||||
? {...cartItem, quantity: cartItem.quantity -1 } |
||||
:cartItem |
||||
) |
||||
} |
@ -0,0 +1,44 @@ |
||||
const INITIAL_STATE = { |
||||
sections: [ |
||||
{ |
||||
title: "موس (موشواره)", |
||||
imageUrl: "https://www.pngkey.com/png/full/957-9575055_redragon-m908-impact-mmo-gaming-mouse-up-to.png", |
||||
id: 1, |
||||
linkUrl: "shop/hats" |
||||
}, |
||||
{ |
||||
title: "کیبورد", |
||||
imageUrl: "https://www.pngplay.com/wp-content/uploads/13/Gaming-Keyboard-Transparent-Free-PNG.png", |
||||
id: 2, |
||||
linkUrl: "shop/jackets" |
||||
}, |
||||
{ |
||||
title: "وبکم", |
||||
imageUrl: "https://www.pngkey.com/png/full/246-2465497_webcam-transparent-images-trust-exis-webcam-17003.png", |
||||
id: 3, |
||||
linkUrl: "shop/sneakers" |
||||
}, |
||||
{ |
||||
title: "اسپیکر", |
||||
imageUrl: "https://www.pngarts.com/files/12/Portable-Bluetooth-Speaker-Transparent-Images.png", |
||||
size: "large", |
||||
id: 4, |
||||
linkUrl: "shop/womens" |
||||
}, |
||||
{ |
||||
title: "مانیتور", |
||||
imageUrl: "https://static.acer.com/up/Resource/Acer/Monitors/BE0/Image/20160503/BE240Y_sku_preview.png", |
||||
size: "large", |
||||
id: 5, |
||||
linkUrl: "shop/mens" |
||||
} |
||||
] |
||||
} |
||||
const directoryReducer = (state = INITIAL_STATE, action) => { |
||||
switch(action.type){ |
||||
default: |
||||
return state |
||||
} |
||||
} |
||||
|
||||
export default directoryReducer |
@ -0,0 +1,8 @@ |
||||
import { createSelector } from 'reselect' |
||||
|
||||
const selectDirectory = state => state.directory |
||||
|
||||
export const selectDirectorySections = createSelector( |
||||
[selectDirectory], |
||||
directory => directory.sections |
||||
) |
@ -0,0 +1,7 @@ |
||||
// @create-index
|
||||
|
||||
export { default as actions } from './actions'; |
||||
export { default as proxy } from './proxy.js'; |
||||
export { default as reducers } from './reducers'; |
||||
export { default as store } from './store.js'; |
||||
|
@ -0,0 +1,120 @@ |
||||
import { ApiConfig } from "../constants/defaultValues"; |
||||
import axios from "axios"; |
||||
|
||||
let { baseUrl } = ApiConfig; |
||||
let access = window.localStorage.getItem("access"); |
||||
baseUrl = baseUrl + "/"; |
||||
|
||||
const Axios = axios.create({ |
||||
withCredentials: true, |
||||
validateStatus: null, |
||||
baseURL: baseUrl, |
||||
//headers: access ? { Authorization: `Bearer ${access}` } : {},
|
||||
}); |
||||
class Proxy { |
||||
get = async (url, params, opt, data) => |
||||
await this.check( |
||||
url, |
||||
opt, |
||||
async () => await Axios.get(url, { params, ...opt }), |
||||
data || params |
||||
); |
||||
post = async (url, params, opt, data ) => |
||||
await this.check( |
||||
url, |
||||
opt, |
||||
async () => await Axios.post(url, params, opt), |
||||
data || params |
||||
); |
||||
put = async (url , params , opt , data ) => |
||||
await this.check( |
||||
url, |
||||
opt, |
||||
async () => await Axios.put(url, params, opt), |
||||
data || params |
||||
); |
||||
delete = async (url , params , opt , data ) => { |
||||
await this.check( |
||||
url, |
||||
opt, |
||||
async () => await Axios.delete(url, { ...opt, data: params }), |
||||
data || params |
||||
); |
||||
}; |
||||
|
||||
check = async (url , { dispatch } , fetch , params ) => { |
||||
dispatch = dispatch || (() => {}); |
||||
dispatch({ type: url.split("/")[0] + "/" + "loading" }); |
||||
let response = await fetch(); |
||||
switch (response.status) { |
||||
case 200: |
||||
dispatch({ type: url, data: response.data.data, params }); |
||||
return response.data.data; |
||||
case 401: |
||||
if (await this.refresh()) { |
||||
let response = await fetch(); |
||||
dispatch({ type: url, data: response.data.data, params }); |
||||
return response.data.data; |
||||
} |
||||
break; |
||||
default: |
||||
dispatch({ |
||||
type: url.split("/")[0] + "/" + "error", |
||||
data: response.data, |
||||
params, |
||||
}); |
||||
} |
||||
return false; |
||||
}; |
||||
|
||||
refresh = async () => { |
||||
let refresh = localStorage.getItem("refresh"); |
||||
if (!refresh) window.location.href = "/"; |
||||
let login = await this.login( |
||||
"user/login", |
||||
{}, |
||||
{ headers: { Authorization: `Bearer ${refresh}` } } |
||||
); |
||||
return login ? true : false; |
||||
}; |
||||
login = async (url , params , { dispatch } ) => |
||||
this.post(url, params, { |
||||
dispatch: (obj ) => { |
||||
let login = obj.data; |
||||
if (!login || !login.refreshToken) return false; |
||||
localStorage.setItem("refresh", login.refreshToken); |
||||
localStorage.setItem("access", login.accessToken); |
||||
delete login.refreshToken; |
||||
delete login.accessToken; |
||||
localStorage.setItem("userData", JSON.stringify(login.profile)); |
||||
dispatch(obj); |
||||
}, |
||||
}); |
||||
|
||||
logout = async (url , params , { dispatch } ) => { |
||||
this.post(url, params, { |
||||
dispatch: (obj ) => { |
||||
localStorage.removeItem("refresh"); |
||||
localStorage.removeItem("access"); |
||||
localStorage.removeItem("userData"); |
||||
dispatch(obj); |
||||
}, |
||||
}); |
||||
}; |
||||
status = () => { |
||||
let refresh = localStorage.getItem("refresh"); |
||||
let userData = localStorage.getItem("userData"); |
||||
if (!refresh) return false; |
||||
if (refresh == "undefined") { |
||||
localStorage.removeItem("refresh"); |
||||
localStorage.removeItem("access"); |
||||
localStorage.removeItem("userData"); |
||||
return false; |
||||
} |
||||
|
||||
return JSON.parse(userData || ''); |
||||
}; |
||||
} |
||||
const _proxy = new Proxy(); |
||||
|
||||
export default _proxy; |
@ -0,0 +1,28 @@ |
||||
import { toast } from "react-toastify"; |
||||
|
||||
const initialState = { |
||||
loading: false, |
||||
error: null, |
||||
list: [], |
||||
}; |
||||
export default function blog(state = initialState, action) { |
||||
let { type, data } = action; |
||||
switch (type) { |
||||
case "public/blogList": |
||||
return { ...state, loading: false, list: data, error: null }; |
||||
// case "blog/update":
|
||||
// return { ...state, loading: false, error: null };
|
||||
// case "blog/add":
|
||||
// return { ...state, loading: false, error: null };
|
||||
// case "blog/delete":
|
||||
// return { ...state, loading: false, error: null };
|
||||
/////////////
|
||||
case "blog/loading": |
||||
return { ...state, loading: true }; |
||||
case "blog/error": |
||||
toast.error(data.message); |
||||
return { ...state, loading: false, error: data.message }; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
@ -0,0 +1,57 @@ |
||||
import { toast } from "react-toastify"; |
||||
|
||||
const initialState = { |
||||
loading: false, |
||||
error: null, |
||||
list: [], |
||||
searchResult: [], |
||||
search: null, |
||||
}; |
||||
export default function faq(state = initialState, action) { |
||||
let { type, data } = action; |
||||
switch (type) { |
||||
case "faq/list": |
||||
return { ...state, loading: false, list: data, error: null }; |
||||
case "faq/add": |
||||
return { ...state, loading: false, error: null }; |
||||
case "faq/selectFaq": |
||||
return { |
||||
...state, |
||||
loading: false, |
||||
error: null, |
||||
list: !state.search |
||||
? state.list.map((item) => |
||||
item.id === data |
||||
? { ...item, active: !item.active } |
||||
: { ...item, active: false } |
||||
) |
||||
: state.list, |
||||
searchResult: state.search |
||||
? state.searchResult.map((item) => |
||||
item.id === data |
||||
? { ...item, active: !item.active } |
||||
: { ...item, active: false } |
||||
) |
||||
: state.searchResult, |
||||
}; |
||||
case "faq/search": |
||||
return { |
||||
...state, |
||||
loading: false, |
||||
error: null, |
||||
search: data, |
||||
searchResult: state.list.filter( |
||||
(item) => |
||||
item.title.indexOf(data) !== -1 || |
||||
item.description.indexOf(data) !== -1 |
||||
), |
||||
}; |
||||
case "faq/loading": |
||||
return { ...state, loading: true }; |
||||
case "faq/error": |
||||
toast.error(data.message); |
||||
return { ...state, loading: false, error: data.message }; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
@ -0,0 +1,26 @@ |
||||
const initialState = { |
||||
loading: false, |
||||
error: null, |
||||
uploads: {}, |
||||
lastUpload: null, |
||||
}; |
||||
|
||||
export default function file(state = initialState, action) { |
||||
let { type, data, params } = action; |
||||
switch (type) { |
||||
case "file/upload": |
||||
return { |
||||
...state, |
||||
loading: false, |
||||
error: null, |
||||
uploads: { ...state.uploads, [params?.target || "last"]: data.id }, |
||||
lastUpload: data.id, |
||||
}; |
||||
case "file/loading": |
||||
return { ...state, loading: true }; |
||||
case "file/error": |
||||
return { ...state, loading: false, error: data.message }; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
@ -0,0 +1,12 @@ |
||||
// @create-index
|
||||
export { default as publicApi } from "./public"; |
||||
export { default as user } from "./user"; |
||||
export { default as book } from "./book"; |
||||
export { default as blog } from "./blog"; |
||||
export { default as product } from "./product"; |
||||
export { default as faq } from "./faq"; |
||||
export { default as file } from "./file"; |
||||
export { default as userFactor } from "./userFactor"; |
||||
export { default as userProduct } from "./userProduct"; |
||||
export {default as scrollAction} from "./scroll"; |
||||
export {default as qr} from "./qr"; |
@ -0,0 +1,31 @@ |
||||
import { toast } from "react-toastify"; |
||||
|
||||
const initialState = { |
||||
loading: false, |
||||
error: null, |
||||
listVOD: [], |
||||
selectedVOD: null, |
||||
similarList : [], |
||||
}; |
||||
export default function product(state = initialState, action) { |
||||
let { type, data } = action; |
||||
switch (type) { |
||||
case "product/listVOD": |
||||
return { ...state, loading: false, listVOD: data, error: null }; |
||||
case "product/similar": |
||||
return { ...state, loading: false, similarList: data, error: null }; |
||||
case "product/addVOD": |
||||
return { ...state, loading: false, error: null }; |
||||
case "product/deleteVOD": |
||||
return { ...state, loading: false, error: null }; |
||||
case "product/selectVOD": |
||||
return { ...state, selectedVOD: data }; |
||||
case "product/loading": |
||||
return { ...state, loading: true }; |
||||
case "product/error": |
||||
toast.error(data.message); |
||||
return { ...state, loading: false, error: data.message }; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
@ -0,0 +1,32 @@ |
||||
const initialState = { |
||||
loading: false, |
||||
error: null, |
||||
list: null, |
||||
}; |
||||
export default function qr(state = initialState, action) { |
||||
let { type, data } = action; |
||||
switch (type) { |
||||
case "qr/list": |
||||
return { ...state, loading: false, error: null }; |
||||
case "qr/update": |
||||
return { ...state, loading: false, error: null }; |
||||
case "qr/add": |
||||
return { ...state, loading: false, error: null }; |
||||
case "qr/delete": |
||||
return { ...state, loading: false, error: null }; |
||||
case "qr/info": |
||||
return { |
||||
...state, |
||||
loading: false, |
||||
list: data, |
||||
error: null, |
||||
}; |
||||
/////////////
|
||||
case "loading": |
||||
return { ...state, loading: true }; |
||||
case "error": |
||||
return { ...state, loading: false, error: data.message }; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
@ -0,0 +1,185 @@ |
||||
import scroll from "../../utils/scroll"; |
||||
const height = window.innerHeight; |
||||
const width = window.innerWidth; |
||||
const prevScroll = localStorage.getItem("prevScroll"); |
||||
|
||||
const initialState = { |
||||
page1TopPosition: scroll.homeScrollHandler(1), |
||||
page2TopPosition: scroll.homeScrollHandler(2), |
||||
page2RotateX: scroll.linearFormula( |
||||
scroll.linearFormula( |
||||
prevScroll > height ? height : prevScroll, |
||||
45, |
||||
0, |
||||
0, |
||||
height |
||||
) |
||||
), |
||||
page2BoxPosition: scroll.initializeBoxPosition(prevScroll), |
||||
page2MobilePosition: scroll.linearFormula( |
||||
prevScroll > 2.5 * height ? 2.5 * height : prevScroll, |
||||
-(((height * 10) / 20 / width) * 100), |
||||
6, |
||||
2 * height, |
||||
2.5 * height |
||||
), |
||||
page2VideoPosition: |
||||
window.scrollY > 4 * height |
||||
? scroll.videoLinearFormula(4 * height) |
||||
: window.scrollY > height |
||||
? scroll.videoLinearFormula(window.scrollY) |
||||
: null, |
||||
page2VideoTopPosition: |
||||
prevScroll > 3 * height |
||||
? scroll.linearFormula(3 * height, 70, 50, 2.8 * height, 3 * height) |
||||
: scroll.linearFormula(prevScroll, 70, 50, 2.8 * height, 3 * height), |
||||
page2MobileUnit: scroll.initializeMobileUnit(prevScroll), |
||||
videoTubeTopPosition: scroll.homeScrollHandler(3), |
||||
testTranslateY: scroll.linearFormula( |
||||
prevScroll > 5 * window.innerHeight ? 5 * window.innerHeight : prevScroll, |
||||
0, |
||||
-101, |
||||
4.5 * height, |
||||
5 * height |
||||
), |
||||
page3TopPosition: scroll.homeScrollHandler(4), |
||||
page3TestTranslateY: |
||||
prevScroll < 6.3 * height |
||||
? 0 |
||||
: scroll.linearFormula( |
||||
prevScroll > 7 * height ? 7 * height : prevScroll, |
||||
0, |
||||
100, |
||||
6.3 * height, |
||||
7 * height |
||||
), |
||||
page4TopPosition: scroll.homeScrollHandler(5), |
||||
}; |
||||
|
||||
export default function scrollAction(state = initialState, action) { |
||||
let { type, data } = action; |
||||
switch (type) { |
||||
case "scroll/page1/floatMouse": |
||||
return { ...state, floatMouseToggle: data }; |
||||
case "scroll/page1/top": |
||||
return { ...state, page1TopPosition: scroll.homeScrollHandler(1) }; |
||||
case "scroll/page2/top": |
||||
return { ...state, page2TopPosition: scroll.homeScrollHandler(2) }; |
||||
case "scroll/page2/rotateX": |
||||
return { |
||||
...state, |
||||
page2RotateX: scroll.linearFormula(window.scrollY, 45, 0, 0, height), |
||||
}; |
||||
case "scroll/page2/boxPosition": |
||||
return { |
||||
...state, |
||||
page2BoxPosition: { |
||||
translateY: scroll.linearFormula( |
||||
data.scrollY, |
||||
data.translateY.pos1, |
||||
data.translateY.pos2, |
||||
data.start, |
||||
data.end |
||||
), |
||||
translateX: scroll.linearFormula( |
||||
data.scrollY, |
||||
data.translateX.pos1, |
||||
data.translateX.pos2, |
||||
data.start, |
||||
data.end |
||||
), |
||||
rotate: scroll.linearFormula( |
||||
data.scrollY, |
||||
data.rotate.pos1, |
||||
data.rotate.pos2, |
||||
data.start, |
||||
data.end |
||||
), |
||||
}, |
||||
page2TopPosition: 0, |
||||
page2RotateX: 0, |
||||
}; |
||||
case "scroll/page2/mobilePosition": |
||||
return { |
||||
...state, |
||||
page2MobilePosition: scroll.linearFormula( |
||||
window.scrollY, |
||||
-(((height * 10) / 20 / width) * 100), |
||||
6, |
||||
2 * height, |
||||
2.5 * height |
||||
), |
||||
page2BoxPosition: { translateX: 32, translateY: 10, rotate: 0 }, |
||||
}; |
||||
case "scroll/page2/videoPosition": |
||||
return { |
||||
...state, |
||||
page2VideoPosition: scroll.videoLinearFormula(window.scrollY), |
||||
page2VideoTopPosition: 50, |
||||
}; |
||||
case "scroll/page2/videoTopPosition": |
||||
return { |
||||
...state, |
||||
page2VideoTopPosition: scroll.linearFormula( |
||||
window.scrollY, |
||||
70, |
||||
50, |
||||
2.8 * height, |
||||
3 * height |
||||
), |
||||
page2MobilePosition: 6, |
||||
}; |
||||
case "scroll/page2/mobileUnit": |
||||
return { |
||||
...state, |
||||
page2MobileUnit: scroll.initializeMobileUnit(window.scrollY), |
||||
}; |
||||
case "scroll/videoTube/top": |
||||
return { ...state, videoTubeTopPosition: scroll.homeScrollHandler(3) }; |
||||
case "scroll/test/translateY": |
||||
const joiRect = JSON.parse(localStorage.getItem("joiRect")); |
||||
return { |
||||
...state, |
||||
testTranslateY: scroll.linearFormula( |
||||
window.scrollY, |
||||
0, |
||||
-101, |
||||
4.5 * height, |
||||
5 * height |
||||
), |
||||
videoTubeTopPosition: 0, |
||||
page2VideoPosition: { |
||||
width: joiRect.width, |
||||
height: joiRect.height, |
||||
top: joiRect.top, |
||||
left: joiRect.left, |
||||
}, |
||||
}; |
||||
case "scroll/page3/top": |
||||
return { |
||||
...state, |
||||
page3TopPosition: scroll.homeScrollHandler(4), |
||||
testTranslateY: -101, |
||||
}; |
||||
case "scroll/page3/testTranslateY": |
||||
return { |
||||
...state, |
||||
page3TestTranslateY: scroll.linearFormula( |
||||
window.scrollY, |
||||
0, |
||||
100, |
||||
6.3 * height, |
||||
7 * height |
||||
), |
||||
page3TopPosition: 0, |
||||
}; |
||||
case "scroll/page4/top": |
||||
return { |
||||
...state, |
||||
page4TopPosition: scroll.homeScrollHandler(5), |
||||
page3TestTranslateY: 100, |
||||
}; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
@ -0,0 +1,49 @@ |
||||
import proxy from "../proxy"; |
||||
import { toast } from "react-toastify"; |
||||
|
||||
const initialState = { |
||||
status: proxy.status(), |
||||
loading: false, |
||||
error: null, |
||||
list: null, |
||||
domains: [], |
||||
mothers: [], |
||||
profileStatus: false, |
||||
setDone: false, |
||||
setLogin : false,
|
||||
}; |
||||
export default function user(state = initialState, action) { |
||||
let { type, data } = action; |
||||
switch (type) { |
||||
// case "user/login":
|
||||
// case "user/register":
|
||||
// case "user/switchRole":
|
||||
case "public/sendOTP": |
||||
return { ...state, loading: false, status: data.profile, error: null }; |
||||
case "user/login": |
||||
case "user/otp/login": |
||||
return { |
||||
...state, |
||||
loading: false, |
||||
status: data.profile, |
||||
error: null, |
||||
setLogin: !state.setLogin, |
||||
}; |
||||
case "user/getProfile": |
||||
localStorage.setItem("userData", JSON.stringify(data)); |
||||
return { ...state, loading: false, status: data, error: null, setDone : false, }; |
||||
case "user/logout": |
||||
return { ...state, loading: false, status: proxy.status(), error: null }; |
||||
case "user/getUserRole": |
||||
return { ...state, loading: false, userRoles: data, error: null }; |
||||
case "user/setProfile": |
||||
toast.success("تغییرات اعمال شد."); |
||||
return { ...state, loading: false, error: null, setDone : true }; |
||||
case "loading": |
||||
return { ...state, loading: true }; |
||||
case "error": |
||||
return { ...state, loading: false, error: data.message }; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
@ -0,0 +1,57 @@ |
||||
import { toast } from "react-toastify"; |
||||
const initialState = { |
||||
loading: false, |
||||
error: null, |
||||
list: null, |
||||
info: null, |
||||
sum: null, |
||||
checkEmpty: false, |
||||
isVerified: null, |
||||
}; |
||||
export default function userFactor(state = initialState, action) { |
||||
let { type, data } = action; |
||||
switch (type) { |
||||
//dnvn
|
||||
case "userFactor/list": |
||||
const checkEmpty = data.filter( |
||||
(item) => item.condition === 2 && item.product.productType === (1 || 3) |
||||
); |
||||
return { |
||||
...state, |
||||
loading: false, |
||||
list: data, |
||||
checkEmpty: checkEmpty.length > 0 ? false : true, |
||||
error: null, |
||||
}; |
||||
case "userFactor/info": |
||||
return { ...state, loading: false, info: data, error: null }; |
||||
case "userFactor/add": |
||||
toast.success("درخواست شما با موفقیت انجام شد."); |
||||
return { ...state, loading: false, error: null, sum: data.payPrice }; |
||||
case "userFactor/delete": |
||||
return { ...state, loading: false, error: null }; |
||||
case "userFactor/payment": |
||||
window.location.replace(data); |
||||
return { ...state, loading: false, error: null }; |
||||
//vod
|
||||
case "userFactor/myList": |
||||
return { ...state, loading: false, list: data, error: null }; |
||||
case "userFactor/update": |
||||
toast.success("درخواست شما با موفقیت انجام شد."); |
||||
return { ...state, loading: false, error: null }; |
||||
case "userFactor/deleteUserOffCode": |
||||
return { ...state, loading: false, error: null }; |
||||
case "userFactor/paymentVOD": |
||||
window.location.replace(data); |
||||
return { ...state, loading: false, error: null, isVerified: false }; |
||||
case "userFactor/verifyVOD": |
||||
return { ...state, loading: false, error: null, isVerified: true }; |
||||
case "userFactor/loading": |
||||
return { ...state, loading: true }; |
||||
case "userFactor/error": |
||||
toast.error(data.message); |
||||
return { ...state, loading: false, error: data.message }; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
@ -0,0 +1,50 @@ |
||||
import { toast } from "react-toastify"; |
||||
|
||||
const initialState = { |
||||
loading: false, |
||||
error: null, |
||||
list: [], |
||||
info: null, |
||||
sum: null, |
||||
checkEmpty: false, |
||||
hasPhysical: false, |
||||
}; |
||||
export default function userFactor(state = initialState, action) { |
||||
let { type, data } = action; |
||||
switch (type) { |
||||
case "userProduct/list": |
||||
const checkEmpty = data.filter( |
||||
(item) => item.condition === 2 && item.product.productType === (1 || 3) |
||||
); |
||||
const hasPhysical = |
||||
data.filter((item) => item.product.productType === 2).length > 0 |
||||
? true |
||||
: false; |
||||
return { |
||||
...state, |
||||
loading: false, |
||||
list: data, |
||||
checkEmpty: checkEmpty.length > 0 ? false : true, |
||||
error: null, |
||||
hasPhysical: hasPhysical, |
||||
}; |
||||
case "userProduct/info": |
||||
return { ...state, loading: false, info: data, error: null }; |
||||
case "userProduct/update": |
||||
return { ...state, loading: false, error: null }; |
||||
case "userProduct/add": |
||||
if (window.location.pathname.indexOf("products") !== -1) { |
||||
toast.success("درخواست شما با موفقیت انجام شد."); |
||||
} |
||||
return { ...state, loading: false, error: null, sum: data.payPrice }; |
||||
case "userProduct/delete": |
||||
return { ...state, loading: false, error: null }; |
||||
case "userProduct/loading": |
||||
return { ...state, loading: true }; |
||||
case "userProduct/error": |
||||
toast.error(data.message); |
||||
return { ...state, loading: false, error: data.message }; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
@ -0,0 +1,24 @@ |
||||
import { combineReducers } from 'redux' |
||||
import { persistReducer } from 'redux-persist' |
||||
import storage from 'redux-persist/lib/storage' |
||||
|
||||
import userReducer from './user/user.reducer.js' |
||||
import cartReducer from './cart/cart.reducer.js' |
||||
import directoryReducer from './directory/directory.reducer' |
||||
import shopReducer from './shop/shop.reducer' |
||||
|
||||
|
||||
const persistConfig = { |
||||
key: 'root', |
||||
storage, |
||||
whitelist: ['cart'] |
||||
} |
||||
|
||||
const rootReducer = combineReducers({ |
||||
user: userReducer, |
||||
cart: cartReducer, |
||||
directory: directoryReducer, |
||||
shop: shopReducer, |
||||
}) |
||||
|
||||
export default persistReducer(persistConfig, rootReducer) |
@ -0,0 +1,254 @@ |
||||
const SHOP_DATA = [ |
||||
{ |
||||
id: 1, |
||||
title: "mouse", |
||||
routeName: "mouse", |
||||
items: [ |
||||
{ |
||||
id: 1, |
||||
name: "ماوس ریزر مدل DEATHADDER ESSENTIAL RZ01", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/114510799.jpg", |
||||
price: 73000, |
||||
adress: '/products/razor-mouse-deathadder-rz01', |
||||
description: { |
||||
content: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با استفاده از طراحان گرافیک است، چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است، و برای شرایط فعلی تکنولوژی مورد نیاز، و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد، کتابهای زیادی در شصت و سه درصد گذشته حال و آینده، شناخت فراوان جامعه و متخصصان را می طلبد، تا با نرم افزارها شناخت بیشتری را برای طراحان رایانه ای علی الخصوص طراحان خلاقی، و فرهنگ پیشرو در زبان فارسی ایجاد کرد، در این صورت می توان امید داشت که تمام و دشواری موجود در ارائه راهکارها، و شرایط سخت تایپ به پایان رسد و زمان مورد نیاز شامل حروفچینی دستاوردهای اصلی، و جوابگوی سوالات پیوسته اهل دنیای موجود طراحی اساسا مورد استفاده قرار گیرد.', |
||||
} |
||||
}, |
||||
{ |
||||
id: 2, |
||||
name: "ماوس مخصوص بازی مدل V8", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/eddb26c7043d4092e17ba4e05a19f5b49f20f0dc_1633724598.jpg", |
||||
price: 290000 |
||||
}, |
||||
{ |
||||
id: 3, |
||||
name: "ماوس مخصوص بازی زویا مدل MMR1", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/2c9f4388ced87e860a9c9d0fccc595f3b64a55a2_1610015683.jpg", |
||||
price: 210000 |
||||
}, |
||||
{ |
||||
id: 4, |
||||
name: "ماوس مخصوص بازی تسکو مدل TSCO TM 764 GA", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/d0cc25319e2fce02acb42f679ff282b59182ed54_1597813753.jpg", |
||||
price: 186000 |
||||
}, |
||||
{ |
||||
id: 5, |
||||
name: "ماوس مخصوص بازی مدل GM02", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/33b0985d01fe4b1ec2542bd03f3b7998e68981ed_1636141537.jpg", |
||||
price: 297270 |
||||
}, |
||||
{ |
||||
id: 6, |
||||
name: "ماوس بی سیم ریزر مدل Basilisk Ultimate", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/81ad2dd69067d43c967ed76faf928837629ece45_1630752955.jpg", |
||||
price: 5250000 |
||||
}, |
||||
{ |
||||
id: 7, |
||||
name: "ماوس مخصوص بازی ریزر مدل Viper Mini", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/878005cff2b58c0d0d0ac4e9ca7eaa21d3987c2c_1600681192.jpg", |
||||
price: 1460000 |
||||
}, |
||||
{ |
||||
id: 8, |
||||
name: "ماوس تسکو مدل TM 291", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/27e2b2852f53615b577fc9130b97675cb77067ba_1628667044.jpg", |
||||
price: 83800 |
||||
}, |
||||
{ |
||||
id: 9, |
||||
name: "ماوس آرمو مدل M25", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/4b757355ca6dcae804f34d4c6af66305903b379c_1596460030.jpg", |
||||
price: 160000 |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
id: 2, |
||||
title: "وبکم", |
||||
routeName: "webcam", |
||||
items: [ |
||||
{ |
||||
id: 10, |
||||
name: "وب کم ایکس اچ سی مدل 48O", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/6f167d1f3b0aa40e19760d5f5240912e00e31dc9_1632987698.jpg", |
||||
price: '340,000' |
||||
}, |
||||
{ |
||||
id: 11, |
||||
name: "وب کم مدل PGR-008", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/3fa4c49aed640c53560fd32a117c7685923123db_1615139913.jpg", |
||||
price: '2,070,000' |
||||
}, |
||||
{ |
||||
id: 12, |
||||
name: "وب کم مایکروسافت مدل لایف کم سینما", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/32558.jpg", |
||||
price: 110 |
||||
}, |
||||
{ |
||||
id: 13, |
||||
name: "وب کم ای فورتک مدل PK-635G", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/2190153c71b9fd3ba9f191f23fa767d8b2cd9200_1601221909.jpg", |
||||
price: '630,000' |
||||
}, |
||||
{ |
||||
id: 14, |
||||
name: "وب کم HD مایکروسافت مدل لایف کم HD-3000", |
||||
imageUrl: "https://dkstatics-public.digikala.com/digikala-products/15382.jpg", |
||||
price: '1,300,000' |
||||
}, |
||||
// {
|
||||
// id: 15,
|
||||
// name: "Nike Brown High Tops",
|
||||
// imageUrl: "https://i.ibb.co/fMTV342/nike-brown.png",
|
||||
// price: 160
|
||||
// },
|
||||
// {
|
||||
// id: 16,
|
||||
// name: "Air Jordan Limited",
|
||||
// imageUrl: "https://i.ibb.co/w4k6Ws9/nike-funky.png",
|
||||
// price: 190
|
||||
// },
|
||||
// {
|
||||
// id: 17,
|
||||
// name: "Timberlands",
|
||||
// imageUrl: "https://i.ibb.co/Mhh6wBg/timberlands.png",
|
||||
// price: 200
|
||||
// }
|
||||
] |
||||
}, |
||||
{ |
||||
id: 3, |
||||
title: "Jackets", |
||||
routeName: "jackets", |
||||
items: [ |
||||
{ |
||||
id: 18, |
||||
name: "Black Jean Shearling", |
||||
imageUrl: "https://i.ibb.co/XzcwL5s/black-shearling.png", |
||||
price: 125 |
||||
}, |
||||
{ |
||||
id: 19, |
||||
name: "Blue Jean Jacket", |
||||
imageUrl: "https://i.ibb.co/mJS6vz0/blue-jean-jacket.png", |
||||
price: 90 |
||||
}, |
||||
{ |
||||
id: 20, |
||||
name: "Grey Jean Jacket", |
||||
imageUrl: "https://i.ibb.co/N71k1ML/grey-jean-jacket.png", |
||||
price: 90 |
||||
}, |
||||
{ |
||||
id: 21, |
||||
name: "Brown Shearling", |
||||
imageUrl: "https://i.ibb.co/s96FpdP/brown-shearling.png", |
||||
price: 165 |
||||
}, |
||||
{ |
||||
id: 22, |
||||
name: "Tan Trench", |
||||
imageUrl: "https://i.ibb.co/M6hHc3F/brown-trench.png", |
||||
price: 185 |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
id: 4, |
||||
title: "Womens", |
||||
routeName: "womens", |
||||
items: [ |
||||
{ |
||||
id: 23, |
||||
name: "Blue Tanktop", |
||||
imageUrl: "https://i.ibb.co/7CQVJNm/blue-tank.png", |
||||
price: 25 |
||||
}, |
||||
{ |
||||
id: 24, |
||||
name: "Floral Blouse", |
||||
imageUrl: "https://i.ibb.co/4W2DGKm/floral-blouse.png", |
||||
price: 20 |
||||
}, |
||||
{ |
||||
id: 25, |
||||
name: "Floral Dress", |
||||
imageUrl: "https://i.ibb.co/KV18Ysr/floral-skirt.png", |
||||
price: 80 |
||||
}, |
||||
{ |
||||
id: 26, |
||||
name: "Red Dots Dress", |
||||
imageUrl: "https://i.ibb.co/N3BN1bh/red-polka-dot-dress.png", |
||||
price: 80 |
||||
}, |
||||
{ |
||||
id: 27, |
||||
name: "Striped Sweater", |
||||
imageUrl: "https://i.ibb.co/KmSkMbH/striped-sweater.png", |
||||
price: 45 |
||||
}, |
||||
{ |
||||
id: 28, |
||||
name: "Yellow Track Suit", |
||||
imageUrl: "https://i.ibb.co/v1cvwNf/yellow-track-suit.png", |
||||
price: 135 |
||||
}, |
||||
{ |
||||
id: 29, |
||||
name: "White Blouse", |
||||
imageUrl: "https://i.ibb.co/qBcrsJg/white-vest.png", |
||||
price: 20 |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
id: 5, |
||||
title: "Mens", |
||||
routeName: "mens", |
||||
items: [ |
||||
{ |
||||
id: 30, |
||||
name: "Camo Down Vest", |
||||
imageUrl: "https://i.ibb.co/xJS0T3Y/camo-vest.png", |
||||
price: 325 |
||||
}, |
||||
{ |
||||
id: 31, |
||||
name: "Floral T-shirt", |
||||
imageUrl: "https://i.ibb.co/qMQ75QZ/floral-shirt.png", |
||||
price: 20 |
||||
}, |
||||
{ |
||||
id: 32, |
||||
name: "Black & White Longsleeve", |
||||
imageUrl: "https://i.ibb.co/55z32tw/long-sleeve.png", |
||||
price: 25 |
||||
}, |
||||
{ |
||||
id: 33, |
||||
name: "Pink T-shirt", |
||||
imageUrl: "https://i.ibb.co/RvwnBL8/pink-shirt.png", |
||||
price: 25 |
||||
}, |
||||
{ |
||||
id: 34, |
||||
name: "Jean Long Sleeve", |
||||
imageUrl: "https://i.ibb.co/VpW4x5t/roll-up-jean-shirt.png", |
||||
price: 40 |
||||
}, |
||||
{ |
||||
id: 35, |
||||
name: "Burgundy T-shirt", |
||||
imageUrl: "https://i.ibb.co/mh3VM1f/polka-dot-shirt.png", |
||||
price: 25 |
||||
} |
||||
] |
||||
} |
||||
]; |
||||
|
||||
export default SHOP_DATA; |
||||
|
@ -0,0 +1,14 @@ |
||||
import SHOP_DATA from './shop.data'; |
||||
|
||||
const INITIAL_STATE = { |
||||
collections: SHOP_DATA |
||||
}; |
||||
|
||||
const shopReducer = (state = INITIAL_STATE, action) => { |
||||
switch (action.type) { |
||||
default: |
||||
return state; |
||||
} |
||||
}; |
||||
|
||||
export default shopReducer; |
@ -0,0 +1,8 @@ |
||||
import { createSelector } from 'reselect' |
||||
|
||||
const selectShop = state => state.shop |
||||
|
||||
export const selectCollections = createSelector( |
||||
[selectShop], |
||||
shop => shop.collections |
||||
); |
@ -0,0 +1,14 @@ |
||||
import { createStore, applyMiddleware } from 'redux'; |
||||
import { composeWithDevTools } from 'redux-devtools-extension'; |
||||
import { combineReducers } from 'redux'; |
||||
import * as reducers from './reducers'; |
||||
import thunk from 'redux-thunk'; |
||||
const initialState = {}; |
||||
const middleware = [thunk]; |
||||
const store = createStore( |
||||
combineReducers(reducers), |
||||
initialState, |
||||
composeWithDevTools(applyMiddleware(...middleware)) |
||||
); |
||||
export default store; |
||||
|
@ -0,0 +1,6 @@ |
||||
import { UserActionTypes } from './user.types.js' |
||||
|
||||
export const setCurrentUser = user => ({ |
||||
type: UserActionTypes.SET_CURRENT_USER, |
||||
payload: user |
||||
}) |
@ -0,0 +1,19 @@ |
||||
import { UserActionTypes } from './user.types.js' |
||||
|
||||
const INITIAL_STATE = { |
||||
currentUser: null |
||||
} |
||||
|
||||
const userReducer = (state = INITIAL_STATE, action ) => { |
||||
switch(action.type){ |
||||
case UserActionTypes.SET_CURRENT_USER: |
||||
return{ |
||||
...state, |
||||
currentUser: action.payload |
||||
} |
||||
default: |
||||
return state; |
||||
} |
||||
} |
||||
|
||||
export default userReducer; |
@ -0,0 +1,9 @@ |
||||
import { createSelector } from 'reselect'; |
||||
|
||||
const selectUser = state => state.user; |
||||
|
||||
export const selectCurrentUser = createSelector( |
||||
[selectUser], |
||||
user => user.currentUser |
||||
) |
||||
|
@ -0,0 +1,3 @@ |
||||
export const UserActionTypes = { |
||||
SET_CURRENT_USER: "SET_CURRENT_USER" |
||||
}; |
@ -0,0 +1,22 @@ |
||||
export const connectToParent = (list) => { |
||||
let comments = []; |
||||
for (let item of list) { |
||||
comments.push({ ...item, child: [] }); |
||||
} |
||||
|
||||
for (let comment1 of comments) { |
||||
if (comment1.pid !== null) { |
||||
const index = comments.indexOf( |
||||
comments.filter((comment2) => comment2.id === comment1.pid)[0] |
||||
); |
||||
comments[index] = { |
||||
...comments[index], |
||||
child: [...comments[index].child, comment1], |
||||
}; |
||||
} else { |
||||
|
||||
} |
||||
} |
||||
// comments = comments.filter((comment) => comment.pid === null);
|
||||
console.log(comments); |
||||
}; |
@ -0,0 +1,11 @@ |
||||
|
||||
class location { |
||||
getId = () => { |
||||
const pathname = window.location.pathname; |
||||
return pathname.slice(pathname.lastIndexOf('/') + 1, pathname.length); |
||||
} |
||||
} |
||||
|
||||
const _location = new location(); |
||||
|
||||
export default _location; |
@ -0,0 +1,213 @@ |
||||
class scroll { |
||||
goToTop = () => { |
||||
window.scrollTo(0, 0); |
||||
}; |
||||
|
||||
homeScrollHandler = (index) => { |
||||
const prevScroll = Number(localStorage.getItem('prevScroll')); |
||||
const height = Number(window.innerHeight); |
||||
const scrollY = Number(window.scrollY); |
||||
if (index === 1) { |
||||
if (scrollY === 0) { |
||||
return 0; |
||||
}else |
||||
if (scrollY > 0 && scrollY <= height) { |
||||
return -scrollY; |
||||
} |
||||
if (scrollY > height) { |
||||
return -height; |
||||
} |
||||
} else if (index === 2) { |
||||
if (scrollY === 0) { |
||||
return height; |
||||
} |
||||
if (scrollY > 0 && scrollY <= height) { |
||||
return height - scrollY; |
||||
} |
||||
if (scrollY > 10 * height) { |
||||
return -1 * height; |
||||
} |
||||
} else if (index === 3) { |
||||
if (scrollY <= 3.5 * height) { |
||||
return height; |
||||
} |
||||
if (scrollY > 3.5 * height && scrollY <= 4 * height) { |
||||
return 4 * height - scrollY; |
||||
} |
||||
if (scrollY > 10 * height) { |
||||
return -height; |
||||
} |
||||
} else if (index === 4) { |
||||
if (scrollY <= 5 * height) { |
||||
return height; |
||||
} else if (scrollY > 5 * height && scrollY < 6 * height) { |
||||
return 6 * height - scrollY; |
||||
} |
||||
if (scrollY === 10 * height) { |
||||
return -height; |
||||
} |
||||
} else if (index === 5) { |
||||
if (scrollY <= 7.3 * height) { |
||||
return height; |
||||
} else if (scrollY > 7.3 * height && scrollY < 8.3 * height) { |
||||
return 8.3 * height - scrollY; |
||||
} |
||||
if (scrollY === 10 * height) { |
||||
return -height; |
||||
} |
||||
} |
||||
}; |
||||
|
||||
linearFormula = (currentScroll, position1, position2, scroll1, scroll2) => { |
||||
const alpha = (currentScroll - scroll1) / (scroll2 - scroll1); |
||||
const deltaPosition = position2 - position1; |
||||
const currentPosition = position1 + deltaPosition * alpha; |
||||
return currentPosition; |
||||
}; |
||||
|
||||
videoLinearFormula = (currentScroll) => { |
||||
if (!localStorage.getItem("htmlRect")) { |
||||
localStorage.setItem( |
||||
"htmlRect", |
||||
JSON.stringify(document.getElementById("video").getBoundingClientRect()) |
||||
); |
||||
} |
||||
const htmlRect = |
||||
JSON.parse(localStorage.getItem("htmlRect")) || |
||||
document.getElementById("video").getBoundingClientRect(); |
||||
const joiRect = JSON.parse(localStorage.getItem("joiRect")); |
||||
|
||||
const currentWidth = this.linearFormula( |
||||
currentScroll, |
||||
htmlRect.width, |
||||
joiRect.width, |
||||
3.5 * window.innerHeight, |
||||
4 * window.innerHeight |
||||
); |
||||
const currentHeight = this.linearFormula( |
||||
currentScroll, |
||||
htmlRect.height, |
||||
joiRect.height, |
||||
3.5 * window.innerHeight, |
||||
4 * window.innerHeight |
||||
); |
||||
const currentLeft = this.linearFormula( |
||||
currentScroll, |
||||
htmlRect.left, |
||||
joiRect.left, |
||||
3.5 * window.innerHeight, |
||||
4 * window.innerHeight |
||||
); |
||||
|
||||
const currentTop = this.linearFormula( |
||||
currentScroll, |
||||
htmlRect.top, |
||||
joiRect.top - window.innerHeight, |
||||
3.5 * window.innerHeight, |
||||
4 * window.innerHeight |
||||
); |
||||
return { |
||||
width: currentWidth, |
||||
height: currentHeight, |
||||
top: currentTop, |
||||
left: currentLeft, |
||||
}; |
||||
}; |
||||
|
||||
testLinearFolmula = (currentScroll) => { |
||||
const testRect = JSON.parse(localStorage.getItem("testRect")); |
||||
const currentWidth = this.linearFormula( |
||||
currentScroll, |
||||
testRect.width, |
||||
window.innerWidth, |
||||
4.5 * window.innerHeight, |
||||
5 * window.innerHeight |
||||
); |
||||
const currentHeight = this.linearFormula( |
||||
currentScroll, |
||||
testRect.height, |
||||
window.innerHeight, |
||||
4.5 * window.innerHeight, |
||||
5 * window.innerHeight |
||||
); |
||||
const currentLeft = this.linearFormula( |
||||
currentScroll, |
||||
testRect.left, |
||||
0, |
||||
4.5 * window.innerHeight, |
||||
5 * window.innerHeight |
||||
); |
||||
|
||||
const currentTop = this.linearFormula( |
||||
currentScroll, |
||||
testRect.top, |
||||
0, |
||||
4.5 * window.innerHeight, |
||||
5 * window.innerHeight |
||||
); |
||||
|
||||
return { |
||||
width: currentWidth, |
||||
height: currentHeight, |
||||
top: currentTop, |
||||
left: currentLeft, |
||||
}; |
||||
}; |
||||
|
||||
initializeBoxPosition = (currentScroll) => { |
||||
const height= window.innerHeight; |
||||
if(currentScroll < height){ |
||||
console.log(currentScroll); |
||||
return { |
||||
translateX: -5,
|
||||
translateY: -5, |
||||
rotate: 5 |
||||
} |
||||
} |
||||
if(currentScroll > height && currentScroll < 2 * height){ |
||||
return { |
||||
translateX: this.linearFormula(currentScroll, -5, 32, height, 2 * height),
|
||||
translateY: this.linearFormula(currentScroll, -5, 10, height, 2 * height), |
||||
rotate: this.linearFormula(currentScroll, 5, 0, height, 2 * height) |
||||
} |
||||
} |
||||
if(currentScroll > 2 * height && currentScroll <= 2.5 * height){ |
||||
return { |
||||
translateX: 32, |
||||
translateY: 10, |
||||
rotate: 0 |
||||
} |
||||
} |
||||
if(currentScroll > 2.5 * height && currentScroll <= 3 * height){ |
||||
return { |
||||
translateX: this.linearFormula(currentScroll, 32, 32, 2.5 * height, 3 * height),
|
||||
translateY: this.linearFormula(currentScroll, 10, -30, 2.5 * height, 3 * height), |
||||
rotate: this.linearFormula(currentScroll, 0, 0, 2.5 * height, 3 * height) |
||||
} |
||||
} |
||||
if(currentScroll > 3 * height){ |
||||
return { |
||||
translateX: 32, |
||||
translateY: -30, |
||||
rotate: 0 |
||||
} |
||||
} |
||||
}; |
||||
|
||||
initializeMobileUnit = (currentScroll) => { |
||||
const height = window.innerHeight; |
||||
if (currentScroll > 2 * height && currentScroll <= 2.3 * height) { |
||||
return 1; |
||||
} else if (currentScroll > 2.3 * height && currentScroll <= 2.7 * height) { |
||||
return 2; |
||||
} else if (currentScroll > 2.7 * height && currentScroll <= 2.8 * height) { |
||||
return 3; |
||||
} else if (currentScroll > 2.8 * height && currentScroll < 3.5 * height) { |
||||
return 4; |
||||
} |
||||
} |
||||
} |
||||
|
||||
const _scroll = new scroll(); |
||||
|
||||
export default _scroll; |
@ -1,18 +1,83 @@ |
||||
import React from "react"; |
||||
import React, {useEffect, useState} from "react"; |
||||
import Class from "../../components/products/classes"; |
||||
import PLATFORM_DATA from "../../store"; |
||||
const Services = () => { |
||||
import { book, publicApi } from "../../redux/actions"; |
||||
import { connect } from 'react-redux'; |
||||
import { Link } from "react-router-dom"; |
||||
import Product from '../../components/Product'; |
||||
const Services = ({ isMobile, |
||||
books, |
||||
getList, |
||||
grades, |
||||
gradeFilter, |
||||
selectedGrade, |
||||
gradeFilterBooks, |
||||
setHeaderOptions, |
||||
headerOptions, |
||||
videos, |
||||
}) => { |
||||
|
||||
const [filter, setFilter] = useState({ |
||||
search: "", |
||||
grade: "", |
||||
productsType: "کتاب", |
||||
}); |
||||
|
||||
|
||||
const onChange = (name, value) => { |
||||
setFilter({ ...filter, [name]: value }); |
||||
}; |
||||
|
||||
useEffect(() => { |
||||
getList(); |
||||
setHeaderOptions(headerOptions); |
||||
}, []); |
||||
|
||||
useEffect(() => { |
||||
gradeFilter(filter.grade); |
||||
}, [filter]); |
||||
|
||||
|
||||
return( |
||||
<div className="flex" style={{width: '93.5%', marginRight: '6.5%', marginTop: '8.5%'}}> |
||||
<button onClick={() => console.log(book)}>asdasd</button> |
||||
{ books?.map((product, index) => ( |
||||
<Link to={"/products/" + product?.id}> |
||||
<Product |
||||
key={index} |
||||
productsType={filter.productsType} |
||||
product={product} |
||||
index={Number(index)} |
||||
productName={`کتاب ${product?.name}`} |
||||
productCat={`پایه ${grades[product?.gradeId]}`} |
||||
productPrice={100000} |
||||
productImg={"https://dnvn.ir/api/v1/file/" + product?.fileIds} |
||||
numberOfRegards={160} |
||||
|
||||
productHolderBorder='' |
||||
productHolderHoverBorder='shadow-md' |
||||
|
||||
{ |
||||
PLATFORM_DATA.classes.map((item, idx) => ( |
||||
<Class title={item.title} description={item.description} price={item.price} group={item.group} teacher={item.teacher} /> |
||||
)) |
||||
} |
||||
/> |
||||
</Link> |
||||
))} |
||||
|
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
export default Services; |
||||
const mapStateToProps = (state) => ({ |
||||
isDark: state.publicApi.isDark, |
||||
isMobile: state.publicApi.isMobile, |
||||
books: state.book.list, |
||||
grades: state.publicApi.grades, |
||||
gradeFilterBooks: state.book.gradeFilterBooks, |
||||
selectedGrade: state.book.selectedGrade, |
||||
}); |
||||
|
||||
const mapDispatchToProps = { |
||||
getList: book.list, |
||||
gradeFilter: book.gradeFilter, |
||||
setHeaderOptions: publicApi.setHeaderOptions, |
||||
}; |
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Services); |
||||
|