Redux is Set From Danovin

main
Pedram Keshavarzi 3 years ago
parent c931b1ad80
commit 5ff6ac0a9b
  1. 94
      package-lock.json
  2. 4
      package.json
  3. 6
      src/App.js
  4. 41
      src/components/Cart/index.js
  5. BIN
      src/components/Product/discount.png
  6. BIN
      src/components/Product/goldon.png
  7. 276
      src/components/Product/index.js
  8. 3
      src/components/Product/lightBlueDotIcon.svg
  9. 3
      src/components/Product/purpleDotIcon.svg
  10. 3
      src/components/Product/redDotIcon.svg
  11. 8
      src/components/Product/vuesax-linear-heart.svg
  12. BIN
      src/components/Product/watermelon.png
  13. 3
      src/components/Product/yellowDotIcon.svg
  14. 42
      src/components/products/classes/index.js
  15. 36
      src/constants/colors.scss
  16. 9
      src/constants/defaultValues.js
  17. 8
      src/constants/size.scss
  18. 27
      src/redux/actions/blog.js
  19. 44
      src/redux/actions/book.js
  20. 14
      src/redux/actions/content.js
  21. 20
      src/redux/actions/faq.js
  22. 22
      src/redux/actions/file.js
  23. 18
      src/redux/actions/index.js
  24. 30
      src/redux/actions/product.js
  25. 56
      src/redux/actions/public.js
  26. 32
      src/redux/actions/qr.js
  27. 74
      src/redux/actions/scroll.js
  28. 63
      src/redux/actions/user.js
  29. 55
      src/redux/actions/userFactor.js
  30. 33
      src/redux/actions/userProduct.js
  31. 8
      src/redux/cart/card.types.js
  32. 20
      src/redux/cart/cart.actions.js
  33. 43
      src/redux/cart/cart.reducer.js
  34. 34
      src/redux/cart/cart.selectors.js
  35. 31
      src/redux/cart/cart.utils.js
  36. 44
      src/redux/directory/directory.reducer.jsx
  37. 8
      src/redux/directory/directory.selector.jsx
  38. 7
      src/redux/index.js
  39. 120
      src/redux/proxy.js
  40. 28
      src/redux/reducers/blog.js
  41. 168
      src/redux/reducers/book.js
  42. 57
      src/redux/reducers/faq.js
  43. 26
      src/redux/reducers/file.js
  44. 12
      src/redux/reducers/index.js
  45. 31
      src/redux/reducers/product.js
  46. 184
      src/redux/reducers/public.js
  47. 32
      src/redux/reducers/qr.js
  48. 185
      src/redux/reducers/scroll.js
  49. 49
      src/redux/reducers/user.js
  50. 57
      src/redux/reducers/userFactor.js
  51. 50
      src/redux/reducers/userProduct.js
  52. 24
      src/redux/root-reducer.js
  53. 254
      src/redux/shop/shop.data.js
  54. 14
      src/redux/shop/shop.reducer.js
  55. 8
      src/redux/shop/shop.selectors.js
  56. 14
      src/redux/store.js
  57. 6
      src/redux/user/user.actions.js
  58. 19
      src/redux/user/user.reducer.js
  59. 9
      src/redux/user/user.selector.js
  60. 3
      src/redux/user/user.types.js
  61. 22
      src/utils/comments.js
  62. 11
      src/utils/location.js
  63. 282
      src/utils/onInput.js
  64. 213
      src/utils/scroll.js
  65. 85
      src/view/services/index.js
  66. 43
      yarn.lock

94
package-lock.json generated

@ -11,6 +11,7 @@
"@testing-library/jest-dom": "^5.16.1", "@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2", "@testing-library/react": "^12.1.2",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"axios": "^0.25.0",
"jalali-moment": "^3.3.10", "jalali-moment": "^3.3.10",
"lord-icon-element": "^3.3.3", "lord-icon-element": "^3.3.3",
"lottie-web": "^5.8.1", "lottie-web": "^5.8.1",
@ -22,7 +23,10 @@
"react-router-dom": "^6.2.1", "react-router-dom": "^6.2.1",
"react-scripts": "5.0.0", "react-scripts": "5.0.0",
"react-slideshow-image": "^3.7.0", "react-slideshow-image": "^3.7.0",
"react-toastify": "^8.1.1",
"redux": "^4.1.2", "redux": "^4.1.2",
"redux-devtools-extension": "^2.13.9",
"redux-thunk": "^2.4.1",
"sass": "^1.45.1", "sass": "^1.45.1",
"web-vitals": "^2.1.2" "web-vitals": "^2.1.2"
}, },
@ -4330,6 +4334,14 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/axios": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
"integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
"dependencies": {
"follow-redirects": "^1.14.7"
}
},
"node_modules/axobject-query": { "node_modules/axobject-query": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@ -5129,6 +5141,14 @@
"node": ">=0.8" "node": ">=0.8"
} }
}, },
"node_modules/clsx": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
"integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==",
"engines": {
"node": ">=6"
}
},
"node_modules/co": { "node_modules/co": {
"version": "4.6.0", "version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@ -7579,9 +7599,9 @@
"integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==" "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw=="
}, },
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.14.6", "version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==", "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@ -13951,6 +13971,18 @@
"react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0" "react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0"
} }
}, },
"node_modules/react-toastify": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-8.1.1.tgz",
"integrity": "sha512-KQa+j+JHjy69xpPYheaWUq3SjVw1sV2D7/QsXW6Tpo2x9HhUCvASezAMYDmLhfAYoSnaXUVnTNFAgZQA75SExQ==",
"dependencies": {
"clsx": "^1.1.1"
},
"peerDependencies": {
"react": ">=16",
"react-dom": ">=16"
}
},
"node_modules/readable-stream": { "node_modules/readable-stream": {
"version": "3.6.0", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
@ -14006,6 +14038,23 @@
"@babel/runtime": "^7.9.2" "@babel/runtime": "^7.9.2"
} }
}, },
"node_modules/redux-devtools-extension": {
"version": "2.13.9",
"resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.9.tgz",
"integrity": "sha512-cNJ8Q/EtjhQaZ71c8I9+BPySIBVEKssbPpskBfsXqb8HJ002A3KRVHfeRzwRo6mGPqsm7XuHTqNSNeS1Khig0A==",
"deprecated": "Package moved to @redux-devtools/extension.",
"peerDependencies": {
"redux": "^3.1.0 || ^4.0.0"
}
},
"node_modules/redux-thunk": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz",
"integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==",
"peerDependencies": {
"redux": "^4"
}
},
"node_modules/regenerate": { "node_modules/regenerate": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@ -19863,6 +19912,14 @@
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz",
"integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==" "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA=="
}, },
"axios": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
"integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
"requires": {
"follow-redirects": "^1.14.7"
}
},
"axobject-query": { "axobject-query": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@ -20463,6 +20520,11 @@
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4="
}, },
"clsx": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
"integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA=="
},
"co": { "co": {
"version": "4.6.0", "version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@ -22269,9 +22331,9 @@
"integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==" "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw=="
}, },
"follow-redirects": { "follow-redirects": {
"version": "1.14.6", "version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==" "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
}, },
"fork-ts-checker-webpack-plugin": { "fork-ts-checker-webpack-plugin": {
"version": "6.5.0", "version": "6.5.0",
@ -26694,6 +26756,14 @@
"resize-observer-polyfill": "^1.5.1" "resize-observer-polyfill": "^1.5.1"
} }
}, },
"react-toastify": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-8.1.1.tgz",
"integrity": "sha512-KQa+j+JHjy69xpPYheaWUq3SjVw1sV2D7/QsXW6Tpo2x9HhUCvASezAMYDmLhfAYoSnaXUVnTNFAgZQA75SExQ==",
"requires": {
"clsx": "^1.1.1"
}
},
"readable-stream": { "readable-stream": {
"version": "3.6.0", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
@ -26737,6 +26807,18 @@
"@babel/runtime": "^7.9.2" "@babel/runtime": "^7.9.2"
} }
}, },
"redux-devtools-extension": {
"version": "2.13.9",
"resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.9.tgz",
"integrity": "sha512-cNJ8Q/EtjhQaZ71c8I9+BPySIBVEKssbPpskBfsXqb8HJ002A3KRVHfeRzwRo6mGPqsm7XuHTqNSNeS1Khig0A==",
"requires": {}
},
"redux-thunk": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz",
"integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==",
"requires": {}
},
"regenerate": { "regenerate": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",

@ -6,6 +6,7 @@
"@testing-library/jest-dom": "^5.16.1", "@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2", "@testing-library/react": "^12.1.2",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"axios": "^0.25.0",
"jalali-moment": "^3.3.10", "jalali-moment": "^3.3.10",
"lord-icon-element": "^3.3.3", "lord-icon-element": "^3.3.3",
"lottie-web": "^5.8.1", "lottie-web": "^5.8.1",
@ -17,7 +18,10 @@
"react-router-dom": "^6.2.1", "react-router-dom": "^6.2.1",
"react-scripts": "5.0.0", "react-scripts": "5.0.0",
"react-slideshow-image": "^3.7.0", "react-slideshow-image": "^3.7.0",
"react-toastify": "^8.1.1",
"redux": "^4.1.2", "redux": "^4.1.2",
"redux-devtools-extension": "^2.13.9",
"redux-thunk": "^2.4.1",
"sass": "^1.45.1", "sass": "^1.45.1",
"web-vitals": "^2.1.2" "web-vitals": "^2.1.2"
}, },

@ -22,6 +22,9 @@ import LoginSignUp from './view/LoginSignUp';
import Register from './view/register' import Register from './view/register'
import Services from './view/services'; import Services from './view/services';
import {Provider, provider} from 'react-redux';
import store from './redux/store';
let data = [ let data = [
{ {
@ -641,6 +644,8 @@ function App() {
}; };
return ( return (
<Provider store={store}>
<BrowserRouter> <BrowserRouter>
<div className="App"> <div className="App">
{LOGIN && <Header />} {LOGIN && <Header />}
@ -677,6 +682,7 @@ function App() {
</Routes> </Routes>
</div> </div>
</BrowserRouter> </BrowserRouter>
</Provider>
); );
} }

@ -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));

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 B

Binary file not shown.

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
};

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<circle id="Ellipse_18" data-name="Ellipse 18" cx="8" cy="8" r="8" fill="#89ecff"/>
</svg>

After

Width:  |  Height:  |  Size: 177 B

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<circle id="Ellipse_17" data-name="Ellipse 17" cx="8" cy="8" r="8" fill="#924eeb"/>
</svg>

After

Width:  |  Height:  |  Size: 177 B

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<circle id="Ellipse_19" data-name="Ellipse 19" cx="8" cy="8" r="8" fill="#fc5353"/>
</svg>

After

Width:  |  Height:  |  Size: 177 B

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="vuesax_linear_heart" data-name="vuesax/linear/heart" transform="translate(-236 -188)">
<g id="heart">
<path id="Vector" d="M10.62,17.71a2.181,2.181,0,0,1-1.24,0C6.48,16.72,0,12.59,0,5.59A5.574,5.574,0,0,1,5.56,0,5.515,5.515,0,0,1,10,2.24,5.547,5.547,0,0,1,20,5.59C20,12.59,13.52,16.72,10.62,17.71Z" transform="translate(238 191.1)" fill="none" stroke="#e11010" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-2" data-name="Vector" d="M0,0H24V24H0Z" transform="translate(236 188)" fill="none" opacity="0"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<circle id="Ellipse_20" data-name="Ellipse 20" cx="8" cy="8" r="8" fill="#fcf653"/>
</svg>

After

Width:  |  Height:  |  Size: 177 B

@ -1,18 +1,28 @@
import React from "react"; import React from 'react';
const Class = ({ import { connect } from 'react-redux';
title,
description, import { addItem }from '../../../redux/cart/cart.actions.js';
teacher,
group,
price,
}) => { const Class = ({item, addItem}) => {
return( const {name, price, imageUrl} = item;
<div> return (
<h1>{title}</h1> <div className="collection-item">
<p>{description}</p>
{teacher} {group} {price} <img src={imageUrl} className='image'/>
<div className="collection-footer">
<span className="name"> {name} </span>
<span className="price"> {price} </span>
</div> </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,168 @@
import { toast } from "react-toastify";
const initialState = {
loading: false,
error: null,
list: [],
info: null,
searchResult: [],
filterResult: [],
subjects: [],
levels: [],
sortFilters: ["مرتب سازی", "محبوب ترین", "جدیدترین"],
selectedVideo: null,
gradeFilterBooks: null,
sortFilterCourse: null,
selectedGrade: null,
selectedSort: "پربازدید ترین ها",
};
const grades = [
"پیش دبستان",
"اول",
"دوم",
"سوم",
"چهارم",
"پنجم",
"ششم",
"هفتم",
"هشتم",
"نهم",
"دهم",
"یازدهم",
"دوازدهم",
];
export default function book(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "book/list":
let itemsSubject = (Array.isArray(data) ? data : []).map(
(item, index) => item.name
);
if (window.innerWidth < 1000) {
itemsSubject.unshift("نام کتاب");
}
let itemsLevel = (Array.isArray(data) ? data : [])
.map((item) => item.gradeId * 1)
.sort((a, b) => a - b)
.map((e) => grades[e]);
if (window.innerWidth < 1000) {
itemsLevel.unshift("پایه تحصیلی");
}
return {
...state,
loading: false,
list: data,
subjects: Array.from(new Set(itemsSubject)),
levels: Array.from(new Set(itemsLevel)),
filterResult: data,
error: null,
};
case "book/info":
return { ...state, loading: false, info: data, error: null };
case "book/lesson/active":
return {
...state,
loading: false,
error: null,
};
case "book/gradeFilter":
if (data === state.selectedGrade) {
return { ...state, gradeFilterBooks: null, selectedGrade: null };
} else {
return {
...state,
gradeFilterBooks: state.list.filter(
(item, i) => grades[item.gradeId] === data
),
selectedGrade: data,
};
}
case "book/sortFilter":
const search = state.list.filter(
(item) => item.name.indexOf(data.search) !== -1
);
if (data.sort === "تمامی دورهها") {
return { ...state, sortFilterCourse: search, selectedSort: data.sort };
} else if (data.sort === "جدیدترینها") {
return {
...state,
sortFilterCourse: search.sort((item1, item2) => {
return item1.publishYear - item2.publishYear;
}),
selectedSort: data.sort,
};
}
return { ...state, sortFilterCourse: search, selectedSort: data.sort };
// case "book/update":
// return { ...state, loading: false, error: null };
// case "book/add":
// return { ...state, loading: false, error: null };
// case "book/delete":
// return { ...state, loading: false, error: null };
// case "book/search":
// return { ...state };
// case "book/filter":
// const realList = state.list;
// const level = data.level;
// const subject = data.subject;
// const sort = data.sort;
// const search = data.search;
// if (level.length > 0 || subject.length > 0 || sort || search) {
// localStorage.setItem("filter", "ON");
// }
// let finalSort;
// let byLevelFilter = [];
// if (level.length > 0) {
// level.map((item1) => {
// for (let i = 0; i < realList.length; i++) {
// if (grades[realList[i].gradeId] === item1) {
// byLevelFilter.push(realList[i]);
// }
// }
// });
// } else {
// byLevelFilter = realList;
// }
// let bySubjectFilter = [];
// if (subject.length > 0) {
// subject.map((item1) => {
// for (let i = 0; i < byLevelFilter.length; i++) {
// if (byLevelFilter[i].name === item1) {
// bySubjectFilter.push(byLevelFilter[i]);
// }
// }
// });
// } else {
// bySubjectFilter = byLevelFilter;
// }
// const bySearchFilter = search
// ? bySubjectFilter.filter((item1) => item1.name.indexOf(search) !== -1)
// : bySubjectFilter;
// if (sort === "گران ترین") {
// finalSort = bySearchFilter.sort((item1, item2) => {
// return item1.product[0].price - item2.product[0].price;
// });
// } else {
// finalSort = bySearchFilter;
// }
// return {
// ...state,
// loading: false,
// error: null,
// filterResult: finalSort,
// };
case "book/loading":
return { ...state, loading: true };
case "book/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,184 @@
import location from "../../utils/location";
const initialState = {
isDark: false,
isMobile: window.innerWidth < 1024,
homeData: [],
newProducts: [],
levels: [],
loading: false,
error: null,
searchResult: [],
arList: [],
blogList: [],
blog: null,
province: null,
city: null,
departmans: [
{
id: 0,
name: "محتوا",
},
{
id: 0,
name: "دیزاین",
},
{
id: 0,
name: "برنامه نویسی",
},
],
header: [],
selectedMenu: null,
contactData: null,
selectedVideo: null,
bookInfo: null,
activeCategory: null,
categories: null,
bookSection: null,
grades: {
0: "پیش دبستان",
1: "اول",
2: "دوم",
3: "سوم",
4: "چهارم",
5: "پنجم",
6: "ششم",
7: "هفتم",
8: "هشتم",
9: "نهم",
10: "دهم",
11: "یازدهم",
12: "دوازدهم",
},
headerOptions: {
shown: false,
logo: false,
hamburgerMenu: false,
qr: false,
menu: false,
back: false,
title: false,
},
desktopContentTransform: false,
};
const grades = [
"پیش دبستان",
"اول",
"دوم",
"سوم",
"چهارم",
"پنجم",
"ششم",
"هفتم",
"هشتم",
"نهم",
"دهم",
"یازدهم",
"دوازدهم",
];
export default function publicApi(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "public/setDesktopContentTransform":
return { ...state, desktopContentTransform: data };
case "public/setHeaderOptions":
return { ...state, headerOptions: data };
case "public/setIsDark":
localStorage.setItem("isDark", data);
return { ...state, location: false, error: null, isDark: data };
case "active/video":
return {
...state,
loading: false,
error: null,
selectedVideo: data,
};
case "active/category":
return {
...state,
loading: false,
activeCategory: state.activeCategory === data ? null : data,
error: null,
};
case "public/vod/bookSection":
const videoId = location.getId();
return {
...state,
loading: false,
bookSection: data,
error: null,
selectedVideo: data.vods?.filter((item) => item.id !== videoId)[0],
};
case "public/vod/bookCourse":
let allCats;
allCats = Array.from(
new Set(data.vods.map((item) => item.categoryId && item.categoryId))
);
return {
...state,
loading: false,
bookInfo: {
...data,
vods: data.vods.map((item) => {
return { ...item, active: false };
}),
},
error: null,
categories: allCats.map((item) =>
data.vods.filter((item1) => item1.categoryId === item)
),
selectedVideo: data.vods.filter(
(item) => item.id !== location.getId()
)[0],
};
case "public/homePage":
let itemsLevel;
if (window.innerWidth > 1000) {
const jadidTarin = data.filter(
(item) => item.title === "جدیدترین کتابهای دانوین"
);
itemsLevel = jadidTarin[0].data
.map((item) => item.book.gradeId * 1)
.sort((a, b) => a - b)
.map((e) => grades[e]);
itemsLevel.unshift("همه");
}
return {
...state,
loading: false,
levels: window.innerWidth > 1000 ? Array.from(new Set(itemsLevel)) : [],
error: null,
homeData: data,
};
case "public/ar":
return { ...state, loading: false, error: null, arList: data };
case "public/contact":
return { ...state, loading: false, error: null, contactData: data };
case "public/blogList":
return { ...state, loading: false, error: null, blogList: data };
case "public/blogInfo":
return { ...state, loading: false, error: null, blog: data };
case "public/setSubscribe":
return { ...state, loading: false, error: null, selectedSubscribe: data };
case "public/province":
return { ...state, loading: false, error: null, province: data };
case "public/city":
return { ...state, loading: false, error: null, city: data };
case "public/selectMenu":
return { ...state, loading: false, error: null, selectedMenu: data };
case "public/VOD/homePage":
return { ...state, loading: false, error: null, header: data };
case "loading":
return { ...state, loading: true };
case "error":
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,282 @@
import { toast } from "react-toastify";
class onInput {
persianOnly = (txt) => {
let newText = txt;
newText = newText.replace(/`/g, "");
newText = newText.replace(/0/g, "");
newText = newText.replace(/1/g, "");
newText = newText.replace(/2/g, "");
newText = newText.replace(/3/g, "");
newText = newText.replace(/4/g, "");
newText = newText.replace(/5/g, "");
newText = newText.replace(/6/g, "");
newText = newText.replace(/7/g, "");
newText = newText.replace(/8/g, "");
newText = newText.replace(/9/g, "");
newText = newText.replace(/0/g, "");
newText = newText.replace(/q/g, "");
newText = newText.replace(/w/g, "");
newText = newText.replace(/e/g, "");
newText = newText.replace(/r/g, "");
newText = newText.replace(/t/g, "");
newText = newText.replace(/y/g, "");
newText = newText.replace(/u/g, "");
newText = newText.replace(/i/g, "");
newText = newText.replace(/o/g, "");
newText = newText.replace(/p/g, "");
newText = newText.replace(/\[/g, "");
newText = newText.replace(/\]/g, "");
newText = newText.replace(/a/g, "");
newText = newText.replace(/s/g, "");
newText = newText.replace(/d/g, "");
newText = newText.replace(/f/g, "");
newText = newText.replace(/g/g, "");
newText = newText.replace(/h/g, "");
newText = newText.replace(/j/g, "");
newText = newText.replace(/k/g, "");
newText = newText.replace(/l/g, "");
newText = newText.replace(/;/g, "");
newText = newText.replace(/'/g, "");
newText = newText.replace(/z/g, "");
newText = newText.replace(/x/g, "");
newText = newText.replace(/c/g, "");
newText = newText.replace(/v/g, "");
newText = newText.replace(/b/g, "");
newText = newText.replace(/n/g, "");
newText = newText.replace(/m/g, "");
newText = newText.replace(/,/g, "");
newText = newText.replace(/./g, "");
newText = newText.replace(/\//g, "");
newText = newText.replace(/~/g, " ");
newText = newText.replace(/Q/g, "");
newText = newText.replace(/W/g, "");
newText = newText.replace(/E/g, "");
newText = newText.replace(/R/g, "");
newText = newText.replace(/T/g, "");
newText = newText.replace(/Y/g, "");
newText = newText.replace(/U/g, "");
newText = newText.replace(/I/g, "");
newText = newText.replace(/O/g, "");
newText = newText.replace(/P/g, "");
newText = newText.replace(/A/g, "");
newText = newText.replace(/S/g, "");
newText = newText.replace(/G/g, "");
newText = newText.replace(/H/g, "");
newText = newText.replace(/J/g, "");
newText = newText.replace(/K/g, "");
newText = newText.replace(/L/g, "");
newText = newText.replace(/Z/g, "");
newText = newText.replace(/X/g, "");
newText = newText.replace(/B/g, "");
newText = newText.replace(/N/g, "");
newText = newText.replace(/M/g, "");
newText = newText.replace(/\?/g, "");
if (!newText && newText.length !== 0) {
toast.info("از کاراکتر فارسی استفاده کنید");
}
return newText;
};
englishAndNumberWithoutSpace = (txt) => {
let newText = txt;
newText = newText.replace(/`/g, "");
newText = newText.replace(/0/g, "0");
newText = newText.replace(/1/g, "1");
newText = newText.replace(/2/g, "2");
newText = newText.replace(/3/g, "3");
newText = newText.replace(/4/g, "4");
newText = newText.replace(/5/g, "5");
newText = newText.replace(/6/g, "6");
newText = newText.replace(/7/g, "7");
newText = newText.replace(/8/g, "8");
newText = newText.replace(/9/g, "9");
newText = newText.replace(/ا/g, "");
newText = newText.replace(/ب/g, "");
newText = newText.replace(/پ/g, "");
newText = newText.replace(/ت/g, "");
newText = newText.replace(/ث/g, "");
newText = newText.replace(/ج/g, "");
newText = newText.replace(/چ/g, "");
newText = newText.replace(/ح/g, "");
newText = newText.replace(/خ/g, "");
newText = newText.replace(/د/g, "");
newText = newText.replace(/\[/g, "");
newText = newText.replace(/\]/g, "");
newText = newText.replace(/ذ/g, "");
newText = newText.replace(/ر/g, "");
newText = newText.replace(/ز/g, "");
newText = newText.replace(/ژ/g, "");
newText = newText.replace(/ط/g, "");
newText = newText.replace(/ظ/g, "");
newText = newText.replace(/ع/g, "");
newText = newText.replace(/غ/g, "");
newText = newText.replace(/ف/g, "");
newText = newText.replace(/;/g, "");
newText = newText.replace(/'/g, "");
newText = newText.replace(/ق/g, "");
newText = newText.replace(/س/g, "");
newText = newText.replace(/ش/g, "");
newText = newText.replace(/ص/g, "");
newText = newText.replace(/ض/g, "");
newText = newText.replace(/ک/g, "");
newText = newText.replace(/گ/g, "");
newText = newText.replace(/,/g, "");
newText = newText.replace(/\./g, "");
newText = newText.replace(/\//g, "");
newText = newText.replace(/~/g, " ");
newText = newText.replace(/ل/g, "");
newText = newText.replace(/م/g, "");
newText = newText.replace(/ن/g, "");
newText = newText.replace(/و/g, "");
newText = newText.replace(/ه/g, "");
newText = newText.replace(/ی/g, "");
newText = newText.replace(/\?/g, "");
if (!newText && newText.length !== 0) {
toast.info("از کاراکتر انگلیسی واعداداستفاده کنید");
}
return newText;
};
numberOnly = (txt) => {
let newText = txt;
newText = newText.replace(/`/g, "");
newText = newText.replace(/0/g, "0");
newText = newText.replace(/1/g, "1");
newText = newText.replace(/2/g, "2");
newText = newText.replace(/3/g, "3");
newText = newText.replace(/4/g, "4");
newText = newText.replace(/5/g, "5");
newText = newText.replace(/6/g, "6");
newText = newText.replace(/7/g, "7");
newText = newText.replace(/8/g, "8");
newText = newText.replace(/9/g, "9");
newText = newText.replace(/ا/g, "");
newText = newText.replace(/ب/g, "");
newText = newText.replace(/پ/g, "");
newText = newText.replace(/ت/g, "");
newText = newText.replace(/ث/g, "");
newText = newText.replace(/ج/g, "");
newText = newText.replace(/چ/g, "");
newText = newText.replace(/ح/g, "");
newText = newText.replace(/خ/g, "");
newText = newText.replace(/د/g, "");
newText = newText.replace(/\[/g, "");
newText = newText.replace(/\]/g, "");
newText = newText.replace(/ذ/g, "");
newText = newText.replace(/ر/g, "");
newText = newText.replace(/ز/g, "");
newText = newText.replace(/ژ/g, "");
newText = newText.replace(/ط/g, "");
newText = newText.replace(/ظ/g, "");
newText = newText.replace(/ع/g, "");
newText = newText.replace(/غ/g, "");
newText = newText.replace(/ف/g, "");
newText = newText.replace(/;/g, "");
newText = newText.replace(/'/g, "");
newText = newText.replace(/ق/g, "");
newText = newText.replace(/س/g, "");
newText = newText.replace(/ش/g, "");
newText = newText.replace(/ص/g, "");
newText = newText.replace(/ض/g, "");
newText = newText.replace(/ک/g, "");
newText = newText.replace(/گ/g, "");
newText = newText.replace(/\,/g, "");
newText = newText.replace(/\./g, "");
newText = newText.replace(/\//g, "");
newText = newText.replace(/~/g, " ");
newText = newText.replace(/ل/g, "");
newText = newText.replace(/م/g, "");
newText = newText.replace(/ن/g, "");
newText = newText.replace(/و/g, "");
newText = newText.replace(/ه/g, "");
newText = newText.replace(/ی/g, "");
newText = newText.replace(/\?/g, "");
newText = newText.replace(/q/g, "");
newText = newText.replace(/w/g, "");
newText = newText.replace(/e/g, "");
newText = newText.replace(/r/g, "");
newText = newText.replace(/t/g, "");
newText = newText.replace(/y/g, "");
newText = newText.replace(/u/g, "");
newText = newText.replace(/i/g, "");
newText = newText.replace(/o/g, "");
newText = newText.replace(/p/g, "");
newText = newText.replace(/a/g, "");
newText = newText.replace(/s/g, "");
newText = newText.replace(/d/g, "");
newText = newText.replace(/f/g, "");
newText = newText.replace(/g/g, "");
newText = newText.replace(/h/g, "");
newText = newText.replace(/j/g, "");
newText = newText.replace(/k/g, "");
newText = newText.replace(/l/g, "");
newText = newText.replace(/z/g, "");
newText = newText.replace(/x/g, "");
newText = newText.replace(/c/g, "");
newText = newText.replace(/v/g, "");
newText = newText.replace(/b/g, "");
newText = newText.replace(/n/g, "");
newText = newText.replace(/m/g, "");
newText = newText.replace(/Q/g, "");
newText = newText.replace(/W/g, "");
newText = newText.replace(/E/g, "");
newText = newText.replace(/R/g, "");
newText = newText.replace(/T/g, "");
newText = newText.replace(/Y/g, "");
newText = newText.replace(/U/g, "");
newText = newText.replace(/I/g, "");
newText = newText.replace(/O/g, "");
newText = newText.replace(/P/g, "");
newText = newText.replace(/A/g, "");
newText = newText.replace(/S/g, "");
newText = newText.replace(/G/g, "");
newText = newText.replace(/H/g, "");
newText = newText.replace(/J/g, "");
newText = newText.replace(/K/g, "");
newText = newText.replace(/L/g, "");
newText = newText.replace(/Z/g, "");
newText = newText.replace(/X/g, "");
newText = newText.replace(/B/g, "");
newText = newText.replace(/N/g, "");
newText = newText.replace(/M/g, "");
if (!newText && newText.length !== 0) {
toast.info("از اعداداستفاده کنید");
}
return newText;
};
dayHandler = (num) => {
let newNum = this.numberOnly(num);
if (newNum > 31) {
toast.error("روز نباید بزرگتر از 31 باشد.");
return Math.floor(newNum / 10);
}
return newNum;
};
monthHandler = (num) => {
let newNum = this.numberOnly(num);
if (newNum > 12 || newNum < 0) {
toast.error("ماه باید بین 1 تا 12 باشد.");
return Math.floor(newNum / 10);
}
return newNum;
};
yearHandler = (num) => {
let newNum = this.numberOnly(num);
if (newNum > 1395) {
toast.error("سال باید کوچکتر از 1395 باشد.");
return Math.floor(newNum / 10);
}
return newNum;
};
phonenumber = (value) => {
let formattedValue = value
.replace(/[\u0660-\u0669\u06f0-\u06f9]/g, function (c) {
return c.charCodeAt(0) & 0xf;
})
.replace(/[^\d]/, "");
return formattedValue;
};
}
const _onInput = new onInput();
export default _onInput;

@ -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 Class from "../../components/products/classes";
import PLATFORM_DATA from "../../store"; import { book, publicApi } from "../../redux/actions";
const Services = () => { 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( return(
<div className="flex" style={{width: '93.5%', marginRight: '6.5%', marginTop: '8.5%'}}> <div className="flex" style={{width: '93.5%', marginRight: '6.5%', marginTop: '8.5%'}}>
<button onClick={() => console.log(book)}>asdasd</button>
{ { books?.map((product, index) => (
PLATFORM_DATA.classes.map((item, idx) => ( <Link to={"/products/" + product?.id}>
<Class title={item.title} description={item.description} price={item.price} group={item.group} teacher={item.teacher} /> <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'
/>
</Link>
))}
</div> </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);

@ -2400,6 +2400,13 @@
"resolved" "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz" "resolved" "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz"
"version" "4.3.5" "version" "4.3.5"
"axios@^0.25.0":
"integrity" "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g=="
"resolved" "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz"
"version" "0.25.0"
dependencies:
"follow-redirects" "^1.14.7"
"axobject-query@^2.2.0": "axobject-query@^2.2.0":
"integrity" "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==" "integrity" "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA=="
"resolved" "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz" "resolved" "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz"
@ -2899,6 +2906,11 @@
"resolved" "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz" "resolved" "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz"
"version" "1.0.4" "version" "1.0.4"
"clsx@^1.1.1":
"integrity" "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA=="
"resolved" "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz"
"version" "1.1.1"
"co@^4.6.0": "co@^4.6.0":
"integrity" "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" "integrity" "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
"resolved" "https://registry.npmjs.org/co/-/co-4.6.0.tgz" "resolved" "https://registry.npmjs.org/co/-/co-4.6.0.tgz"
@ -4343,10 +4355,10 @@
"resolved" "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz" "resolved" "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz"
"version" "3.2.4" "version" "3.2.4"
"follow-redirects@^1.0.0": "follow-redirects@^1.0.0", "follow-redirects@^1.14.7":
"integrity" "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==" "integrity" "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
"resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz" "resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz"
"version" "1.14.6" "version" "1.14.8"
"fork-ts-checker-webpack-plugin@^6.5.0": "fork-ts-checker-webpack-plugin@^6.5.0":
"integrity" "sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw==" "integrity" "sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw=="
@ -7318,7 +7330,7 @@
"strip-ansi" "^6.0.1" "strip-ansi" "^6.0.1"
"text-table" "^0.2.0" "text-table" "^0.2.0"
"react-dom@*", "react-dom@^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0", "react-dom@^17.0.2", "react-dom@>=16.8": "react-dom@*", "react-dom@^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0", "react-dom@^17.0.2", "react-dom@>=16", "react-dom@>=16.8":
"integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==" "integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA=="
"resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz"
"version" "17.0.2" "version" "17.0.2"
@ -7456,7 +7468,14 @@
"@tweenjs/tween.js" "^18.1.2" "@tweenjs/tween.js" "^18.1.2"
"resize-observer-polyfill" "^1.5.1" "resize-observer-polyfill" "^1.5.1"
"react@*", "react@^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0", "react@^16.8.3 || ^17", "react@^17.0.2", "react@>= 16", "react@>= 16.8", "react@>=16.8", "react@17.0.2": "react-toastify@^8.1.1":
"integrity" "sha512-KQa+j+JHjy69xpPYheaWUq3SjVw1sV2D7/QsXW6Tpo2x9HhUCvASezAMYDmLhfAYoSnaXUVnTNFAgZQA75SExQ=="
"resolved" "https://registry.npmjs.org/react-toastify/-/react-toastify-8.1.1.tgz"
"version" "8.1.1"
dependencies:
"clsx" "^1.1.1"
"react@*", "react@^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0", "react@^16.8.3 || ^17", "react@^17.0.2", "react@>= 16", "react@>= 16.8", "react@>=16", "react@>=16.8", "react@17.0.2":
"integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==" "integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA=="
"resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz" "resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz"
"version" "17.0.2" "version" "17.0.2"
@ -7508,7 +7527,17 @@
"indent-string" "^4.0.0" "indent-string" "^4.0.0"
"strip-indent" "^3.0.0" "strip-indent" "^3.0.0"
"redux@^4.0.0", "redux@^4.1.2": "redux-devtools-extension@^2.13.9":
"integrity" "sha512-cNJ8Q/EtjhQaZ71c8I9+BPySIBVEKssbPpskBfsXqb8HJ002A3KRVHfeRzwRo6mGPqsm7XuHTqNSNeS1Khig0A=="
"resolved" "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.9.tgz"
"version" "2.13.9"
"redux-thunk@^2.4.1":
"integrity" "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q=="
"resolved" "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz"
"version" "2.4.1"
"redux@^3.1.0 || ^4.0.0", "redux@^4", "redux@^4.0.0", "redux@^4.1.2":
"integrity" "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==" "integrity" "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw=="
"resolved" "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz" "resolved" "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz"
"version" "4.1.2" "version" "4.1.2"

Loading…
Cancel
Save