reza added some features

temp
Reza_ashrafi 3 years ago
parent 0b973829ec
commit bf42375d40
  1. 1
      package.json
  2. 14
      src/App.js
  3. 4
      src/App.scss
  4. BIN
      src/assets/icons/arrow-left-green.png
  5. BIN
      src/assets/icons/arrow-left.png
  6. 5
      src/assets/icons/bottom-home-active.svg
  7. 9
      src/assets/icons/bottom-products-deactive.svg
  8. 5
      src/assets/icons/bottom-profile-deactive.svg
  9. 8
      src/assets/icons/bottom-test-deactive.svg
  10. 10
      src/assets/icons/bottom-video-deactive.svg
  11. BIN
      src/assets/icons/dropdown.png
  12. 91
      src/components/BottomNavigation/index.js
  13. 2
      src/components/Button/index.js
  14. BIN
      src/components/Input/danger.png
  15. 171
      src/components/Input/index.js
  16. 60
      src/components/Input/index.scss
  17. BIN
      src/components/Input/tick.png
  18. 8
      src/components/Navbar/index.js
  19. 32
      src/components/PrivateRouter/index.js
  20. 21
      src/components/Textarea/index.js
  21. 63
      src/components/Textarea/index.scss
  22. 84
      src/components/Timer/index.js
  23. 8
      src/components/Timer/index.scss
  24. 24
      src/redux/actions/userFactor.js
  25. 28
      src/redux/actions/userProduct.js
  26. 18
      src/redux/reducers/scroll.js
  27. 2
      src/redux/reducers/user.js
  28. 28
      src/redux/reducers/userFactor.js
  29. 33
      src/redux/reducers/userProduct.js
  30. 11
      src/router.js
  31. 282
      src/utils/onInput.js
  32. 33
      src/views/Auth/Login/index.js
  33. 262
      src/views/Auth/Login/index.scss
  34. 61
      src/views/Auth/Profile/Birthdate/index.js
  35. 118
      src/views/Auth/Profile/Birthdate/index.scss
  36. 36
      src/views/Auth/Profile/Document/index.js
  37. 52
      src/views/Auth/Profile/Document/index.scss
  38. 27
      src/views/Auth/Profile/GenderSwitch/index.js
  39. 44
      src/views/Auth/Profile/GenderSwitch/index.scss
  40. 9
      src/views/Auth/Profile/MultipleSelector/index.js
  41. 10
      src/views/Auth/Profile/MultipleSelector/index.scss
  42. 27
      src/views/Auth/Profile/Upload/index.js
  43. 61
      src/views/Auth/Profile/Upload/index.scss
  44. 450
      src/views/Auth/Profile/index.js
  45. 166
      src/views/Auth/Profile/index.scss
  46. 8
      src/views/Auth/SignUp/assets/logo.svg
  47. 118
      src/views/Auth/SignUp/index.js
  48. 320
      src/views/Auth/SignUp/index.scss
  49. 24
      src/views/Auth/index.js
  50. 3
      src/views/Auth/index.scss
  51. 1
      src/views/Home/Landscape/index.js
  52. 4
      src/views/Home/Portrait/Private/Blogs/index.js
  53. 12
      src/views/Home/Portrait/Private/Shop/index.js
  54. 26
      src/views/Product/index.js
  55. 42
      src/views/ShoppingCart/index.js
  56. 1
      tailwind.config.js
  57. 117
      yarn.lock

@ -10,6 +10,7 @@
"@testing-library/user-event": "^12.1.10",
"@trendyol-js/react-carousel": "^2.0.0",
"axios": "^0.24.0",
"jalali-moment": "^3.3.10",
"jol-player": "^2.5.0",
"lodash": "^4.17.21",
"react": "^17.0.2",

@ -1,5 +1,7 @@
import "./App.scss";
import { Provider } from "react-redux";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import store from "./redux/store";
import Router from "./router";
@ -7,6 +9,18 @@ function App({theme}) {
return (
<Provider store={store}>
<Router />
<ToastContainer
position="top-right"
theme="colored"
autoClose={2000}
hideProgressBar={true}
newestOnTop={true}
closeOnClick
rtl={true}
pauseOnFocusLoss
draggable
pauseOnHover
/>
</Provider>
);
}

@ -91,3 +91,7 @@
max-width: 1480px;
}
}
.Toastify *{
font-size: 13px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

@ -0,0 +1,5 @@
<svg id="home-2" xmlns="http://www.w3.org/2000/svg" width="33.58" height="33.579" viewBox="0 0 33.58 33.579">
<path id="Vector" d="M9.822,1.151,2.281,7.027A6.658,6.658,0,0,0,0,11.672V22.04a5.912,5.912,0,0,0,5.89,5.9h16.2a5.909,5.909,0,0,0,5.89-5.89V11.868a6.609,6.609,0,0,0-2.518-4.827L16.818.983A6.278,6.278,0,0,0,9.822,1.151Z" transform="translate(2.798 2.823)" fill="#06bace"/>
<path id="Vector-2" data-name="Vector" d="M0,6.693V0" transform="translate(16.79 18.778)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-3" data-name="Vector" d="M0,0H33.58V33.579H0Z" fill="none" opacity="0"/>
</svg>

After

Width:  |  Height:  |  Size: 668 B

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="35.135" height="34.763" viewBox="0 0 35.135 34.763">
<g id="book" transform="translate(0 0)">
<path id="Vector" d="M29.279,20.329V2.9A2.869,2.869,0,0,0,26.1.025h-.088a27.857,27.857,0,0,0-10.35,3.422l-.249.159a1.641,1.641,0,0,1-1.552,0L13.5,3.39A27.72,27.72,0,0,0,3.162.011,2.864,2.864,0,0,0,0,2.885V20.329a2.981,2.981,0,0,0,2.547,2.859l.425.058a37.976,37.976,0,0,1,10.892,3.524l.059.029a1.6,1.6,0,0,0,1.405,0,37.631,37.631,0,0,1,10.921-3.552l.483-.058A2.981,2.981,0,0,0,29.279,20.329Z" transform="translate(2.928 3.898)" fill="none" stroke="#86a0b9" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-2" data-name="Vector" d="M0,0V21.959" transform="translate(17.567 7.666)" fill="none" stroke="#86a0b9" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-3" data-name="Vector" d="M3.294,0H0" transform="translate(25.919 12.298)" fill="none" stroke="#86a0b9" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-4" data-name="Vector" d="M4.392,0H0" transform="translate(24.767 16.643)" fill="none" stroke="#86a0b9" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-5" data-name="Vector" d="M0,0H35.135V34.763H0Z" transform="translate(35.135 34.763) rotate(180)" fill="none" opacity="0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1,5 @@
<svg id="profile" xmlns="http://www.w3.org/2000/svg" width="31.192" height="31.192" viewBox="0 0 31.192 31.192">
<path id="Vector" d="M5.978,11.528a2.363,2.363,0,0,0-.429,0,5.777,5.777,0,1,1,.429,0Z" transform="translate(9.825 2.599)" fill="none" stroke="#86a0b9" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-2" data-name="Vector" d="M2.359,1.784c-3.145,2.105-3.145,5.537,0,7.629a12.693,12.693,0,0,0,13.01,0c3.145-2.105,3.145-5.537,0-7.629A12.752,12.752,0,0,0,2.359,1.784Z" transform="translate(6.947 17.139)" fill="none" stroke="#86a0b9" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-3" data-name="Vector" d="M0,0H31.192V31.192H0Z" transform="translate(31.192 31.192) rotate(180)" fill="none" opacity="0"/>
</svg>

After

Width:  |  Height:  |  Size: 800 B

@ -0,0 +1,8 @@
<svg id="task-square" xmlns="http://www.w3.org/2000/svg" width="33.323" height="32.317" viewBox="0 0 33.323 32.317">
<path id="Vector" d="M7.069,0H0" transform="translate(8.933 11.957)" fill="none" stroke="#86a0b9" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-2" data-name="Vector" d="M0,2.02.9,3.03,3.584,0" transform="translate(21.063 9.931)" fill="none" stroke="#86a0b9" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-3" data-name="Vector" d="M7.069,0H0" transform="translate(8.933 21.383)" fill="none" stroke="#86a0b9" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-4" data-name="Vector" d="M0,2.02.9,3.03,3.584,0" transform="translate(21.063 19.357)" fill="none" stroke="#86a0b9" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-5" data-name="Vector" d="M18.159,26.931H9.778C2.794,26.931,0,24.238,0,17.505V9.426C0,2.693,2.794,0,9.778,0h8.381c6.984,0,9.778,2.693,9.778,9.426v8.079C27.936,24.238,25.143,26.931,18.159,26.931Z" transform="translate(2.693 2.693)" fill="none" stroke="#86a0b9" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-6" data-name="Vector" d="M33.323,0H0V32.317H33.323Z" fill="none" opacity="0"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="34.395" height="29.991" viewBox="0 0 34.395 29.991">
<g id="Group_374" data-name="Group 374" transform="translate(0.75 0.75)">
<g id="vuesax_linear_music-playlist" data-name="vuesax/linear/music-playlist" transform="translate(0)">
<g id="music-playlist" transform="translate(0 0)">
<path id="Vector" d="M24.671,28.491H8.224C3.29,28.491,0,25.642,0,18.994V9.5C0,2.849,3.29,0,8.224,0H24.671C29.606,0,32.9,2.849,32.9,9.5v9.5C32.9,25.642,29.606,28.491,24.671,28.491Z" fill="none" stroke="#86a0b9" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
</g>
</g>
<path id="Vector-2" data-name="Vector" d="M0,5.083V3C0,.327,1.892-.766,4.2.57L6.005,1.612,7.811,2.653c2.308,1.336,2.308,3.523,0,4.86L6.005,8.554,4.2,9.6C1.892,10.932,0,9.839,0,7.166V5.083Z" transform="translate(11.677 9.162)" fill="none" stroke="#86a0b9" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

@ -0,0 +1,91 @@
import React, { useState } from "react";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import activeHomeIcon from "../../assets/icons/bottom-home-active.svg";
import deactiveProductsIcon from "../../assets/icons/bottom-products-deactive.svg";
import deactiveVideoIcon from "../../assets/icons/bottom-video-deactive.svg";
import deactiveProfileIcon from "../../assets/icons/bottom-profile-deactive.svg";
import deactiveTestIcon from "../../assets/icons/bottom-test-deactive.svg";
export const BottomNavigation = ({ pages, isDark }) => {
const [activeLink, setActiveLink] = useState("/");
const Tab = ({ page }) => {
return (
<Link
to={page.link}
className="flex flex-col justify-center itemms-center"
onClick={() => setActiveLink(page.link)}
>
<img
className="w-8 h-8 mx-auto"
src={activeLink === page.link ? page.activeIcon : page.deactiveIcon}
alt=""
/>
<span className="text-blueB9 text-xs text-center font-bold mt-1">
{page.name}
</span>
</Link>
);
};
return (
<>
<footer
className="w-full flex flex-row justify-around items-center fixed bottom-0 left-0 py-2 z-20 lg:hidden"
style={{ background: isDark ? "hsla(209, 39%, 28%, 1)" : "#E8FCFF" }}
>
{pages.map((page, index) => (
<Tab page={page} key={index} />
))}
</footer>
</>
);
};
const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark,
});
const mapDispatchToProps = {};
export default connect(mapStateToProps, mapDispatchToProps)(BottomNavigation);
BottomNavigation.defaultProps = {
pages: [
{
id: 0,
name: "صفحه اصلی",
link: "/",
activeIcon: activeHomeIcon,
deactiveIcon: "",
},
{
id: 1,
name: "محصولات",
link: "/products",
activeIcon: "",
deactiveIcon: deactiveProductsIcon,
},
{
id: 2,
name: "ویدئو",
link: "/vod",
activeIcon: "",
deactiveIcon: deactiveVideoIcon,
},
{
id: 3,
name: "آزمون",
link: "/test",
activeIcon: "",
deactiveIcon: deactiveTestIcon,
},
{
id: 4,
name: "حساب کاربری",
link: "/profile",
activeIcon: "",
deactiveIcon: deactiveProfileIcon,
},
],
};

@ -7,6 +7,7 @@ export default function Button({
border,
width,
bgOpacity,
onClick,
}) {
return (
<button
@ -15,6 +16,7 @@ export default function Button({
border: `${border.width} solid ${border.color}`,
width: width,
}}
onClick={() => onClick()}
>
{title}
</button>

Binary file not shown.

After

Width:  |  Height:  |  Size: 860 B

@ -0,0 +1,171 @@
import React, { useState } from "react";
import _ from "lodash";
import "./index.scss";
import tick from "./tick.png";
import danger from "./danger.png";
const langDetector = (lang, option1, option2) => {
return lang === "fa" ? option1 : option2;
};
const inputStatusHandler = (value, focus, status, primary, success, danger) => {
if (!focus) {
return "";
} else {
if (!value) {
return primary;
} else {
if (status) {
return success;
} else {
return danger;
}
}
}
};
export default function Input(props) {
const [value, setValue] = useState("");
const [focusToggle, setFocusToggle] = useState(false);
const { lang, theme, inputMode, label, status, maxLength, message } = props;
const onChange = (val) => {
setValue(val);
};
return (
<div
className={_.join(
["input flex flex-col relative my-2", langDetector(lang, "fa", "en")],
" "
)}
>
<label
className={_.join(
[
"absolute top-1/2 transform -translate-y-1/2 text-gray-500 bg-white px-2 text-xs transition-all duration-300",
langDetector(lang, "right-2", "left-2"),
inputStatusHandler(
value,
focusToggle,
status,
"input__labelFocus",
"input__labelSuccess",
"input__labelDanger"
),
],
" "
)}
onClick={() => setFocusToggle(true)}
>
{label}
</label>
<input
type="text"
inputMode={inputMode}
className={_.join(
[
"flex-1 border border-gray-500 rounded-md outline-none py-3 px-4 text-xs",
inputStatusHandler(
value,
focusToggle,
status,
"input__inputActive",
"input__inputSuccess",
"input__inputDanger"
),
"transition",
],
" "
)}
onChange={(e) => onChange(e.target.value)}
value={value}
onFocus={() => setFocusToggle(true)}
onBlur={() => !value ? setFocusToggle(false) : setFocusToggle(true)}
maxLength={maxLength}
/>
{!status && value && (
<img
src={danger}
alt={langDetector(lang, "اشتباه", "wrong")}
className={_.join(
[
"w-4 h-4 absolute top-1/2 transform -translate-y-1/2",
langDetector(lang, "left-2", "right-2"),
],
" "
)}
/>
)}
{status && value && (
<img
src={tick}
alt={langDetector(lang, "درست", "right")}
className={_.join(
[
"w-4 h-4 absolute top-1/2 transform -translate-y-1/2",
langDetector(lang, "left-2", "right-2"),
],
" "
)}
/>
)}
{value && !status && (
<span
className={_.join(
[
"input__message text-xs absolute -bottom-5",
langDetector(lang, "right-2", "left-2"),
inputStatusHandler(
value,
focusToggle,
status,
"",
"input__messageSuccess",
"input__messageDanger"
),
"transition",
],
" "
)}
>
{message}
</span>
)}
{value && (
<span
className={_.join(
[
"input__length absolute -bottom-5 text-xs",
langDetector(lang, "left-2", "right-2"),
inputStatusHandler(
value,
focusToggle,
status,
"",
"input__lengthSuccess",
"input__lengthDanger"
),
"transition",
],
" "
)}
>
{value.length + "/" + maxLength}
</span>
)}
</div>
);
}
Input.defaultProps = {
lang : 'fa',
inputMode : 'numeric',
label : 'label',
status : '',
maxLength : '',
message : '',
}

@ -0,0 +1,60 @@
$primary: #196EC0;
$gray: #dbdbdb;
$danger: #E00A0A;
$success: #23C933;
.input {
&__labelFocus{
top: 0px !important;
font-size: 9px !important;
color: $primary !important;
}
&__labelDanger{
top: 0px !important;
font-size: 9px !important;
color: $danger !important;
}
&__labelSuccess{
top: 0px !important;
font-size: 9px !important;
color: $success !important;
}
&__inputActive{
border-color: $primary !important;
}
&__inputSuccess{
border-color: $success !important;
}
&__inputDanger{
border-color: $danger !important;
}
&__message{
&Success{
color: $success;
}
&Danger{
color: $danger;
}
}
&__length{
&Success{
color: $success;
}
&Danger{
color: $danger;
}
}
}
.en {
direction: ltr;
text-align: left;
}
.fa {
direction: rtl;
text-align: right;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

@ -12,7 +12,7 @@ import arBlueIcon from "../../assets/icons/ar-blue.svg";
import hamburgerIcon from "../../assets/icons/hamburger.svg";
import hamburgerBlueIcon from "../../assets/icons/hamburger-blue.svg";
function Navbar({ pages, isDark, isLogin }) {
function Navbar({ pages, isDark}) {
const [top, setTop] = useState(false);
useEffect(() => {
if (window.scrollY === 0) {
@ -80,7 +80,7 @@ function Navbar({ pages, isDark, isLogin }) {
>
<img src={logoIcon} className="w-6 h-8" />
</Link>
{isLogin && (
<div className="flex flex-row items-center">
<Link
to="/qr"
@ -121,16 +121,14 @@ function Navbar({ pages, isDark, isLogin }) {
/>
</Link>
</div>
)}
</div>
{/* portrait end */}
){/* portrait end */}
</div>
);
}
const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark,
isLogin: state.user.status,
});
export default connect(mapStateToProps, {})(Navbar);

@ -0,0 +1,32 @@
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";
const PrivateRouter = ({
component: Component,
restricted,
status,
customPage,
...rest
}) => {
return (
<Route
{...rest}
render={(props) =>
restricted ? (
<Redirect to="/" />
) : (
<Component page={customPage} />
)
}
/>
);
};
export default connect(
(state) => ({
status: state.user.status,
}),
{}
)(PrivateRouter);

@ -0,0 +1,21 @@
import React from "react";
import _ from "lodash";
export default function Textarea({ placeholder, theme }) {
const light = theme === "light";
return (
<>
<textarea
className={_.join(
[
"custom-textarea",
light ? "custom-textarea-light" : "custom-textarea-dark",
],
" "
)}
rows={6}
placeholder={placeholder}
/>
</>
);
}

@ -0,0 +1,63 @@
.custom-textarea {
width: 100%;
padding: 10px 12px;
border-radius: 10px;
margin-top: 10px;
&-light {
border: 1px solid $green;
background-color: white;
color: $gray5;
}
&-dark {
border: 1px solid $gray2;
background-color: black;
color: white;
}
&::placeholder {
color: #a2a2a2;
}
&:focus {
border: 1px solid $green1;
outline: none;
&::placeholder {
color: $green1;
}
}
}
@media screen and (min-width: 1441px) {
.custom-textarea {
font-size: 16px;
&::placeholder {
font-size: 16px;
}
}
}
@media screen and (min-width: 1008px) and (max-width: 1440px) {
.custom-textarea {
font-size: calc(100vw / 110);
&::placeholder {
font-size: calc(100vw / 110);
}
}
}
@media screen and (min-width: 641px) and (max-width: 1007px) {
.custom-textarea {
font-size: calc(100vw / 40);
&::placeholder {
font-size: calc(100vw / 40);
}
}
}
@media screen and (max-width: 640px) {
.custom-textarea {
font-size: calc(100vw / 30);
&::placeholder {
font-size: calc(100vw / 30);
}
}
}

@ -0,0 +1,84 @@
import { Component } from "react";
const maxDesktopSize = 1250;
const maxMobileSize = 550;
const fontSize = {
desktop: {
div: window.innerWidth > maxDesktopSize ? 12 : window.innerWidth / 95,
},
mobile: {
div: window.innerWidth > maxMobileSize ? 12 : window.innerWidth / 30,
},
};
export default class Timer extends Component {
constructor(props) {
super(props);
this.state = {
time: {
h: 0,
m: 0,
s: 0,
},
seconds : props.seconds,
flag: true,
};
this.timer = 0;
this.startTimer = this.startTimer.bind(this);
this.countDown = this.countDown.bind(this);
}
secondsToTime(secs) {
let hours = Math.floor(secs / (60 * 60));
let divisor_for_minutes = secs % (60 * 60);
let minutes = Math.floor(divisor_for_minutes / 60);
let divisor_for_seconds = divisor_for_minutes % 60;
let seconds = Math.ceil(divisor_for_seconds);
let obj = {
h: hours,
m: minutes,
s: seconds,
};
return obj;
}
componentDidMount() {
this.startTimer();
let timeLeftVar = this.secondsToTime(this.state.seconds);
this.setState({ time: timeLeftVar });
}
startTimer() {
if (this.timer === 0 && this.state.seconds > 0) {
this.timer = setInterval(this.countDown, 1000);
}
}
countDown = async () => {
// Remove one second, set state so a re-render happens.
let seconds = this.state.seconds - 1;
this.setState({
time: this.secondsToTime(seconds),
seconds: seconds,
});
if (seconds === 0) {
this.props.refresh(true);
}
};
componentWillUnmount() {
clearInterval(this.timer);
}
render() {
return (
<>
<div className="timer">
{this.state.time ? this.state.time.m : ''}:{this.state.time ? this.state.time.s : ''}
</div>
</>
);
}
}

@ -0,0 +1,8 @@
.timer {
flex-direction: row;
direction: rtl !important;
margin-right: 10px;
margin-left: 10px;
color: $green2;
font-family: numeralLight;
}

@ -1,5 +1,29 @@
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) => {

@ -1,9 +1,33 @@
import proxy from "../proxy";
const userProduct = {
addVOD:
list:
(data = {}) =>
async (dispatch) => {
await proxy.get("userProduct/list", data, { dispatch });
},
info:
(data = {}) =>
async (dispatch) =>
await proxy.post("userProduct/addVOD", data, { 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;

@ -24,9 +24,11 @@ const initialState = {
2.5 * height
),
page2VideoPosition:
prevScroll > 4 * height
window.scrollY > 4 * height
? scroll.videoLinearFormula(4 * height)
: scroll.videoLinearFormula(prevScroll),
: window.scrollY > height
? scroll.videoLinearFormula(window.scrollY)
: null,
page2VideoTopPosition:
prevScroll > 3 * height
? scroll.linearFormula(3 * height, 70, 50, 2.8 * height, 3 * height)
@ -154,7 +156,11 @@ export default function scrollAction(state = initialState, action) {
},
};
case "scroll/page3/top":
return { ...state, page3TopPosition: scroll.homeScrollHandler(4), testTranslateY : -101 };
return {
...state,
page3TopPosition: scroll.homeScrollHandler(4),
testTranslateY: -101,
};
case "scroll/page3/testTranslateY":
return {
...state,
@ -168,7 +174,11 @@ export default function scrollAction(state = initialState, action) {
page3TopPosition: 0,
};
case "scroll/page4/top":
return { ...state, page4TopPosition: scroll.homeScrollHandler(5), page3TestTranslateY : 100 };
return {
...state,
page4TopPosition: scroll.homeScrollHandler(5),
page3TestTranslateY: 100,
};
default:
return state;
}

@ -1,7 +1,7 @@
import proxy from "../proxy";
import { toast } from "react-toastify";
const initialState = {
status: proxy.status() || true,
status: proxy.status() || false,
loading: false,
error: null,
list: null,

@ -11,16 +11,34 @@ const initialState = {
export default function userFactor(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "userFactor/myList":
return { ...state, loading: false, list: data, error: null };
//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/add":
// toast.success("درخواست شما با موفقیت انجام شد.");
// return { ...state, loading: false, error: null, sum: data.payPrice };
case "userFactor/deleteUserOffCode":
return { ...state, loading: false, error: null };
case "userFactor/paymentVOD":

@ -1,12 +1,43 @@
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/addVOD":
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 };

@ -3,21 +3,23 @@ import { BrowserRouter, Routes, Route } from "react-router-dom";
import { connect } from "react-redux";
import Navbar from "./components/Navbar";
import BG from "./components/BG";
import BottomNavigation from "./components/BottomNavigation";
import _ from "lodash";
import Home from "./views/Home";
import Auth from "./views/Auth";
import Products from "./views/Products";
import Product from "./views/Product";
import ShoppingCart from "./views/ShoppingCart";
// import VideoTube from "./views/Home/VideoTube";
function Router({ isDark }) {
function Router({ isDark, isLogin }) {
return (
<div className={_.join([isDark ? "dark" : ""], " ")}>
<div
className={_.join(
[
"min-h-screen min-w-screen rtl overflow-x-hidden py-20 lg:py-0",
"min-h-screen min-w-screen rtl overflow-x-hidden pt-20 lg:py-0",
isDark ? "" : "bg-white",
],
" "
@ -26,8 +28,12 @@ function Router({ isDark }) {
<BrowserRouter>
<Navbar />
<BG />
<BottomNavigation />
<Routes>
<Route path="/" exact element={<Home />} />
<Route path="/login" exact element={<Auth page="login" />} />
<Route path="/signup" exact element={<Auth page="signup" />} />
<Route path="/profile" exact element={<Auth page="profile" />} />
<Route path="/products" exact element={<Products />} />
<Route path="/cart" exact element={<ShoppingCart />} />
<Route path="/products/:id" exact element={<Product />} />
@ -48,6 +54,7 @@ function Router({ isDark }) {
const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark,
isLogin: state.user.status
});
export default connect(mapStateToProps, {})(Router);

@ -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,33 @@
import React, { useState, useRef, useEffect } from "react";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import onInput from "../../../utils/onInput";
import { user } from "../../../redux/actions";
import _ from "lodash";
//assets
function Login({ login, theme, ...props }) {
const [loginFields, setSignUpFiels] = useState(undefined);
const onChange = (name, value) => {
setSignUpFiels({ ...loginFields, [name]: value });
};
useEffect(() => {}, []);
return (
<div
className={_.join(
[
"flex flex-col items-center justify-center w-screen h-screen relative",
],
" "
)}
>
</div>
);
}
export default connect(() => ({}), { login: user.login })(Login);

@ -0,0 +1,262 @@
.login {
&-light {
.MuiFormControl-root label{
background-color: white !important;
}
b{
color: $gray5 !important;
}
.login {
&__back {
a {
color: black !important;
}
}
&__options {
color: $gray9;
a {
color: $green4;
}
}
}
}
&__options {
color: #b5b5b5;
a {
color: $green4;
}
}
button[type="submit"] {
margin-top: 25px;
background-color: $green4;
color: white;
padding: 10px 0px;
border: 0px;
border-radius: 10px;
}
img {
// transform: rotate(-90deg);
}
.MuiButtonBase-root {
padding: 0px !important;
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
}
}
@media screen and (min-width: 1441px) {
.login {
section {
width: 410px;
b {
color: white;
font-size: 16px;
margin-bottom: 30px;
font-weight: 500;
p {
font-size: 16px;
}
}
button {
font-size: 17px;
}
}
&__info {
width: 350px;
margin: 40px auto 0px;
text-align: center;
color: white;
font-size: 14px;
a {
color: $green4;
}
}
&__back {
margin-bottom: 60px;
img {
transform: rotate(-90deg);
}
a {
color: white;
font-size: 13px;
}
}
&__options {
div {
font-size: 13px;
}
a {
font-size: 13px;
}
}
}
}
@media screen and (min-width: 1008px) and (max-width: 1440px) {
.login {
section {
width: 350px;
transform: scale(0.9);
b {
color: white;
font-size: calc(100vw / 80);
margin-bottom: 30px;
font-weight: 500;
}
button {
font-size: calc(100vw / 80);
}
}
&__info {
width: 300px;
margin: 40px auto 0px;
text-align: center;
color: white;
font-size: calc(100vw / 110);
a {
color: $green4;
}
}
&__back {
margin-bottom: 40px;
img {
transform: rotate(-90deg);
}
a {
color: white;
font-size: calc(100vw / 110);
}
}
&__options {
div {
font-size: calc(100vw / 110);
}
a {
font-size: calc(100vw / 110);
}
}
}
}
@media screen and (min-width: 641px) and (max-width: 1007px) {
.login {
.footer {
display: none !important;
}
section {
// background-color: red;
width: 90%;
max-width: 700px;
height: calc(100% - 60px);
justify-content: center;
b {
color: white;
font-size: calc(100vw / 30);
margin-bottom: 30px;
font-weight: 500;
}
button {
font-size: calc(100vw / 30);
width: 100%;
max-width: 400px;
margin: 50px auto 0px;
}
}
&__info {
width: 300px;
margin: 40px auto 0px;
text-align: center;
color: white;
font-size: calc(100vw / 40);
a {
color: $green4;
}
}
&__back {
position: fixed;
top: 100px;
margin-bottom: 40px;
left: 30px;
a {
color: white;
font-size: calc(100vw / 110);
}
img {
width: 50px;
}
}
&__options {
padding-top: 20px;
div {
font-size: calc(100vw / 40);
}
a {
font-size: calc(100vw / 45);
}
}
}
}
@media screen and (max-width: 640px) {
.login {
section {
// background-color: red;
width: 90%;
max-width: 400px;
height: calc(100% - 60px);
// transform: scale(0.9);
justify-content: center;
// align-items: center;
b {
color: white;
font-size: calc(100vw / 18);
margin-bottom: 30px;
font-weight: 500;
}
button {
margin-top: 25px;
font-size: calc(100vw / 25);
}
}
&__info {
width: 300px;
margin: 40px auto 0px;
text-align: center;
color: white;
font-size: calc(100vw / 30);
a {
color: $green4;
}
}
&__back {
position: fixed;
top: 70px;
left: 20px;
margin-bottom: 40px;
a {
color: white;
font-size: calc(100vw / 110);
}
img {
width: 40px;
// transform: scale()
}
}
&__options {
div {
font-size: calc(100vw / 30);
}
a {
font-size: calc(100vw / 30);
}
}
}
}

@ -0,0 +1,61 @@
import React, { useState } from "react";
import onInput from "../../../../utils/onInput";
import Input from "../../../../components/Input/index";
import moment from "jalali-moment";
export default function Birthdate({ defaultValue, name, ...props }) {
let momentDate = moment(defaultValue[name]);
let isvalid = momentDate.isValid();
const day = isvalid ? momentDate.format("jDD") : null,
month = isvalid ? momentDate.format("jMM") : null,
year = isvalid ? momentDate.format("jYYYY") : null;
const [state, setState] = useState({ day, month, year });
const onChange = (_name, value) => {
let _state = { ...state, [_name]: value };
setState(_state);
props.onChange(
name,
moment
.from(`${_state.year}/${_state.month}/${_state.day}`, "fa", "YYYY/M/D")
.locale("en")
);
};
return (
<div className="birthdate d-flex justify-content-between align-items-center">
<label>تاریخ تولد</label>
<div className="mobile-birthdate__date d-flex align-items-center">
<Input
variant="standard"
name="day"
placeholder="روز"
maxLength={2}
onInput={onInput.dayHandler}
onChange={onChange}
defaultValue={state}
/>
<span>/</span>
<Input
variant="standard"
name="month"
placeholder="ماه"
maxLength={2}
onInput={onInput.monthHandler}
onChange={onChange}
defaultValue={state}
/>
<span>/</span>
<Input
variant="standard"
name="year"
placeholder="سال"
maxLength={4}
onInput={onInput.yearHandler}
onChange={onChange}
defaultValue={state}
/>
</div>
</div>
);
}

@ -0,0 +1,118 @@
.birthdate {
width: 100%;
border-radius: 10px;
padding: 0px 10px;
border: 1px solid $gray1;
margin: 10px 0px;
label {
width: fit-content;
color: #ccc;
font-weight: 100;
}
span {
color: #bfbfbf;
margin: 0px 5px;
}
input {
border: none !important;
background-color: rgba(204, 204, 204, 0.098);
color: $green4;
max-width: 40px;
text-align: center !important;
direction: ltr;
margin: 0px 5px !important;
border: none;
&:focus {
outline: 0px;
border: 0px;
}
&::placeholder {
color: $gray1;
}
}
//INPUT
.MuiOutlinedInput-notchedOutline {
border : none !important;
}
.MuiOutlinedInput-input {
padding: 5px !important;
&:focus {
border: none !important;
border-radius: 0px !important;
}
}
}
@media screen and (min-width: 1441px) {
.birthdate {
label {
font-size: 14px !important;
}
span {
font-size: 16px;
}
input {
font-size: 16px;
&::placeholder {
font-size: 16px;
}
}
}
}
@media screen and (min-width: 1008px) and (max-width: 1440px) {
.birthdate {
label {
font-size: calc(100vw / 120) !important;
}
span {
font-size: calc(100vw / 90);
}
input {
font-size: calc(100vw / 90);
&::placeholder {
font-size: calc(100vw / 90);
}
}
}
}
@media screen and (min-width: 640px) and (max-width: 1007px) {
.birthdate {
label {
font-size: calc(100vw / 40) !important;
}
span {
font-size: calc(100vw / 35);
}
input {
font-size: calc(100vw / 20);
margin: 0px 5px !important;
&::placeholder {
font-size: calc(100vw / 30);
}
}
}
}
@media screen and (max-width: 640px) {
.birthdate {
label {
font-size: calc(100vw / 35) !important;
}
span {
font-size: calc(100vw / 35);
}
input {
font-size: calc(100vw / 20);
&::placeholder {
font-size: calc(100vw / 30);
}
}
}
}

@ -0,0 +1,36 @@
import React from "react";
export default function Document({ defaultValue, name, onChange }) {
return (
<div className="mobile-auth-profile__document d-flex justify-content-center align-items-center mb-3">
{defaultValue.docFileIds === "" ? (
<>
<input
type="file"
name={name}
onChange={(e) => onChange(name, e.target.files[0])}
/>
<span>گواهی تدریس خود را آپلود کنید.</span>
</>
) : (
<>
<input
type="file"
name="file"
onChange={(e) => onChange(name, e.target.files[0])}
/>
<span
style={{
width: "100%",
textAlign: "center",
margin: "auto",
}}
>
{/* {defaultValue.docFileIds.name ||
"گواهی تدریس ثبت شده و درحال بررسی می باشد"} */}
</span>
</>
)}
</div>
);
}

@ -0,0 +1,52 @@
.mobile-auth-profile {
&__document {
margin: 10px auto;
width: 100%;
height: 50px;
border-radius: 10px;
border: 2px dashed $gray1;
position: relative;
input {
width: 100%;
height: 100%;
position: absolute;
left: 0px;
top: 0px;
opacity: 0;
}
img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%;
}
span {
color: #afafaf;
font-family: numeralLight;
}
}
}
@media screen and (min-width: 1441px){
span{
font-size: 14px;
}
}
@media screen and (min-width: 1008px) and (max-width: 1440px){
span{
font-size: calc(100vw / 100);
}
}
@media screen and (min-width: 641px) and (max-width: 1007px){
span{
font-size: calc(100vw / 45);
}
}
@media screen and (max-width: 640px){
span{
font-size: calc(100vw / 30);
}
}

@ -0,0 +1,27 @@
import React from "react";
export default function GenderSwitch({
onChange,
name,
options,
selectedOption,
label,
}) {
return (
<div className="gender d-flex justify-content-between align-items-center">
<div
className={selectedOption === 2 && "gender__active"}
onClick={() => onChange(name, 2)}
>
{options[0]}
</div>
<div
className={selectedOption === 1 && "gender__active"}
onClick={() => onChange(name, 1)}
>
{options[1]}
</div>
</div>
);
}

@ -0,0 +1,44 @@
.gender {
width: 100%;
margin-bottom: 10px;
div {
border-radius: 10px;
font-family: numeralLight;
padding: 13px 0px;
width: 45%;
text-align: center;
cursor: pointer;
color: #ccc;
background-color: black;
border: 1px solid $gray1;
}
&__active{
background-color: $green4 !important;
color: white !important;
border: none !important;
}
}
@media screen and (min-width: 1441px) {
.gender{
font-size: 16px;
}
}
@media screen and (min-width: 1008px) and (max-width: 1440px) {
.gender{
font-size: calc(100vw / 90);
}
}
@media screen and (min-width: 641px) and (max-width: 1007px) {
.gender{
font-size: calc(100vw / 40);
}
}
@media screen and (max-width: 640px) {
.gender{
font-size: calc(100vw / 30);
}
}

@ -0,0 +1,9 @@
import React from "react";
export default function MultipleSelector({align, onChange, selectedOptions, options, defaultValue, label, name,}) {
return (
<></>
);
}

@ -0,0 +1,10 @@
.mobile-multiple-selector {
width: 100%;
border-radius: 10px;
padding: 9px 10px;
border: 1px solid $gray6 !important;
margin: 0px !important;
.MuiInput-formControl {
margin: 9px 0px 8px !important;
}
}

@ -0,0 +1,27 @@
import React from "react";
export default function Upload({ name, value, onChange, label }) {
return (
<div className="profile-upload d-flex justify-content-center align-items-center mb-3">
<>
{value === null ? (
<></>
) : (
<img
src={
value.name
? URL.createObjectURL(value)
: window.baseURL + "file/" + value
}
alt={"کاربر"}
/>
)}
<input
type="file"
name={name}
onChange={(e) => onChange(e.target.name, e.target.files[0])}
/>
</>
</div>
);
}

@ -0,0 +1,61 @@
.profile-upload {
width: 100px;
height: 100px;
border-radius: 50%;
margin-top: 15px auto 0px;
// border: 2px dotted #ccc;
position: relative;
cursor: pointer;
background-color: $gray8;
img{
width: 100%;
height: 100%;
border-radius: 50%;
}
input {
width: 100%;
height: 100%;
opacity: 0;
position: absolute;
left: 0px;
top: 0px;
z-index: 50;
}
span {
color: $blue1;
font-family: numeralLight;
height: 20px;
position: absolute;
left: 0px;
top: calc(50% - 10px);
width: 100%;
text-align: center;
z-index: 10;
}
}
@media screen and (min-width: 1441px) {
.profile-upload {
}
}
@media screen and (min-width: 1008px) and (max-width: 1440px) {
.profile-upload {
}
}
@media screen and (min-width: 641px) and (max-width: 1007px) {
.profile-upload {
width: 80px;
height: 80px;
}
}
@media screen and (max-width: 640px) {
.profile-upload {
width : 80px;
height : 80px;
}
}

@ -0,0 +1,450 @@
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import onInput from "../../../utils/onInput";
import { user, file, publicApi } from "../../../redux/actions";
import { connect } from "react-redux";
import Select from "../../../components/Select";
import Input from "../../../components/Input";
import TextArea from "../../../components/Textarea";
import Upload from "./Upload";
import Gender from "./GenderSwitch";
import Birthdate from "./Birthdate";
import MultipleSelector from "./MultipleSelector";
import Document from "./Document";
function Profile({
profile,
uploads,
getProvince,
getCity,
setDone,
upload,
setProfile,
province,
provinceList,
cityList,
}) {
let navigate = useNavigate();
const [render, setRender] = useState(false);
const [formData, setFormData] = useState({
file: uploads["file"] || profile.picFileId || null,
picFileId: uploads["file"] || profile.picFileId || null,
docFileIds: uploads["docFileIds"] || profile.docFileIds || "",
firstName: profile.firstName || "",
lastName: profile.lastName || "",
password: profile.password || "",
username: profile.username || "",
address: profile.address || "",
email: profile.email || "",
birthDate: profile.birthDate || "",
gender: profile.gender || 1,
status: profile.status || 1,
nationalId: profile.nationalId || "",
phone: profile.phone || "",
schools: profile.schools || null,
zoneId: profile.zoneId || "",
schoolId: profile.schoolId || "",
postalCode: profile.postalCode || "",
gradeIds: profile.gradeIds || [],
provinceId: profile.provinceId || null,
cityId: profile.cityId || null,
});
useEffect(() => {
getProvince();
getCity({ provinceId: profile.provinceId });
}, []);
useEffect(() => {
if (setDone) {
navigate("/");
}
}, [setDone]);
const grades = [
{
name: "پیش دبستانی",
value: 0,
},
{
name: "اول",
value: 1,
},
{
name: "دوم",
value: 2,
},
{
name: "سوم",
value: 3,
},
{
name: "چهارم",
value: 4,
},
{
name: "پنجم",
value: 5,
},
{
name: "ششم",
value: 6,
},
{
name: "هفتم",
value: 7,
},
{
name: "هشتم",
value: 8,
},
{
name: "نهم",
value: 9,
},
{
name: "دهم",
value: 10,
},
{
name: "یازدهم",
value: 11,
},
{
name: "دوازدهم",
value: 12,
},
];
const onChange = (name, value) => {
if (name === "provinceId") {
getCity({ provinceId: value });
setFormData({ ...formData, cityId: null, [name]: value });
} else if (name === "status") {
setFormData({
...formData,
gradeIds: formData.gradeIds?.slice(0, 1) || [],
[name]: value,
});
} else if (name === "docFileIds") {
upload({ file: value, target: name });
setFormData({ ...formData, [name]: value });
} else if (name === "file") {
upload({ file: value, target: name });
setFormData({ ...formData, [name]: value });
} else {
setFormData({ ...formData, [name]: value });
}
};
const onSubmit = async () => {
const {
firstName,
lastName,
username,
//cellphone,
password,
postalCode,
address,
email,
phone,
picFileId,
gender,
nationalId,
birthDate,
schools,
gradeIds,
status,
provinceId,
cityId,
docFileIds,
} = formData;
const data = {
firstName: firstName || profile.firstName,
lastName: lastName || profile.lastName,
username: username || profile.username,
cellphone: profile.cellphone,
password: password || profile.password,
postalCode: postalCode || profile.postalCode,
address: address || profile.address,
email: email || profile.email,
phone: phone || profile.phone,
nationalId: nationalId || profile.nationalId,
picFileId: uploads["file"] || picFileId || profile.picFileId,
gender: gender || profile.gender,
birthDate: birthDate || profile.birthDate,
schools: schools || profile.schools,
gradeIds: gradeIds || profile.gradeIds,
status: status || profile.status,
provinceId: provinceId || profile.provinceId,
cityId: cityId || profile.cityId,
docFileIds: uploads["docFileIds"] || docFileIds || profile.docFileIds,
};
await setProfile(data);
};
// if (setDone) return <Navigate path="/" />;
return (
<div className="profile main d-flex justify-content-center">
<main>
<header className="d-flex align-items-center justify-content-between">
<div>
<h1>حساب کاربری</h1>
<p>لطفا مشخصات خود را به صورت کامل نمایید.</p>
</div>
<div className="mobile justify-content-center">
<Upload
name="file"
value={formData.file}
onChange={onChange}
label="فایل"
/>
</div>
</header>
<div className="profile__box d-flex" onSubmit={(e) => onSubmit()}>
<div className="profile__box--section">
<div className="mb-2 desktop justify-content-center">
<Upload
name="file"
value={formData.file}
onChange={onChange}
label="فایل"
/>
</div>
<div className="mb-2">
<Input
name="firstName"
label="نام"
align="right"
onInput={onInput.persianOnly}
defaultValue={formData}
onChange={onChange}
// ref={usernameInput}
/>
</div>
<div className="mb-2">
<Input
name="lastName"
label="نام خانوادگی"
align="right"
defaultValue={formData}
onChange={onChange}
onInput={onInput.persianOnly}
/>
</div>
<div className="mb-2">
<Input
name="username"
label="نام کاربری"
defaultValue={formData}
onChange={onChange}
align="left"
onInput={onInput.englishAndNumberWithoutSpace}
/>
</div>
<div className="mb-2">
<Gender
options={["دختر", "پسر"]}
name="gender"
selectedOption={formData.gender}
onChange={onChange}
label=""
/>
</div>
<div className="mb-2">
<Input
name="nationalId"
label="کد ملی/اتباع"
align="left"
maxLength={13}
defaultValue={formData}
onChange={onChange}
onInput={onInput.numberOnly}
/>
</div>
<div className="mb-2">
<Birthdate
defaultValue={formData}
name="birthDate"
onChange={onChange}
/>
</div>
<div className="mb-2">
<Input
name="password"
label="رمز عبور"
onChange={onChange}
align="left"
onInput={onInput.englishAndNumberWithoutSpace}
/>
</div>
</div>
<div className="profile__box--section">
<div className="mb-2" style={{ minWidth: "100%" }}>
<Gender
options={["معلم", "دانش آموز"]}
name="status"
label={"عنوان"}
selectedOption={formData.status}
onChange={onChange}
/>
</div>
{formData.status === 1 ? (
<div className="mb-2">
<Select
options={grades}
name="gradeIds"
label={"پایه تحصیلی"}
selectedOptions={formData.gradeIds}
onChange={onChange}
/>
</div>
) : null}
{formData.status === 2 ? (
<div className="mb-2">
<MultipleSelector
options={grades}
name="gradeIds"
label={"پایه تحصیلی"}
selectedOptions={formData.gradeIds}
onChange={onChange}
align="right"
defaultValue={profile}
/>
</div>
) : null}
{formData.status === "دانش آموز" && formData.gradeIds > 9 ? (
<div className="mb-2">
<Select
options={[
"ریاضی",
"تجربی",
"انسانی",
"فنی حرفهای",
"کاردانش",
"معارف",
]}
name="field"
label={"رشته تحصیلی"}
selectedOptions={formData.gradeIds}
onChange={onChange}
/>
</div>
) : null}
{console.log(province)}
<div className="mb-2" style={{ minWidth: "100%" }}>
<Select
options={provinceList}
name="provinceId"
label={"استان"}
selectedOptions={formData.provinceId}
onChange={onChange}
/>
</div>
<div className="mb-2">
<Select
options={cityList}
name="cityId"
label={"شهرستان"}
selectedOptions={formData.cityId}
onChange={onChange}
/>
</div>
{/* <div className="mb-2">
<Select
options={["chaharbagh", "mahalat"]}
name="zoneId"
label={"شهر/روستا"}
/>
</div> */}
{formData.status == 1 ? (
<div className="mb-2">
<Input
name="schools"
label={"نام مدرسه"}
defaultValue={formData}
onInput={onInput.persianOnly}
onChange={onChange}
/>
</div>
) : null}
{formData.status == 2 ? (
<div className="mb-2">
<Input
name="schools"
label={"محل تدریس"}
defaultValue={formData}
onInput={onInput.persianOnly}
onChange={onChange}
/>
</div>
) : null}
{formData.status == 2 ? (
<Document
onChange={onChange}
defaultValue={formData}
name="docFileIds"
/>
) : null}
<div className="mb-2">
<Input
name="postalCode"
label={"کد پستی"}
align="left"
onChange={onChange}
maxLength={10}
inputMode="numeric"
defaultValue={formData}
onInput={onInput.numberOnly}
/>
</div>
<div className="mb-2">
<TextArea
placeholder={"آدرس محل سکونت"}
name="address"
defaultValue={formData}
onChange={onChange}
/>
</div>
<div className="profile__box--form__footer d-flex justify-content-center">
<button onClick={() => onSubmit()}>ذخیره</button>
</div>
</div>
</div>
</main>
</div>
);
}
export default connect(
(state) => ({
profile: state.user.status,
setDone: state.user.setDone,
loading: state.user.loading,
uploading: state.file.loading,
uploads: state.file.uploads,
provinceList: state.publicApi.province,
cityList: state.publicApi.city,
}),
{
getProfile: user.getProfile,
setProfile: user.setProfile,
upload: file.upload,
getProvince: publicApi.getProvince,
getCity: publicApi.getCity,
}
)(Profile);
Profile.defaultProps = {
user: {
name: "اکبر",
icon: "",
description: "",
},
};

@ -0,0 +1,166 @@
@import './Birthdate/index.scss';
@import './Document/index.scss';
@import './GenderSwitch/index.scss';
@import './MultipleSelector/index.scss';
@import './Upload/index.scss';
.MuiOutlinedInput-input {
font-family: numeralLight !important;
}
.profile {
scrollbar-width: 0px;
padding: 50px 20px 0px;
&::-webkit-scrollbar {
display: none;
}
header {
margin: 30px 0px;
h1 {
margin-top: 15px;
font-family: numeralMedium;
color: white;
letter-spacing: -1px;
}
p {
font-family: numeralLight;
color: white;
text-align: justify;
}
}
&__box {
width: 100%;
border: 1px solid $gray1;
border-radius: 20px;
&--section {
width: 45%;
}
.MuiMenu-list,
.MuiFormControl-root {
width: 100%;
margin: 10px auto !important;
scrollbar-width: 0px !important;
&::-webkit-scrollbar {
display: none !important;
width: 0px !important;
}
option {
font-family: numeralLight !important;
}
.MuiSelect-iconOutlined {
display: none;
}
.MuiSelect-outlined.MuiSelect-outlined {
padding-right: 15px;
}
color: $gray7 !important;
}
button {
margin-top: 20px;
margin-bottom: 50px;
font-family: numeralLight;
border: 0px;
background-color: $green3;
border-radius: 7px;
color: white;
padding: 12px 0px;
width: 100%;
}
}
}
@media screen and (min-width: 1441px) {
.profile {
h1{
font-size: 30px;
}
p{
font-size: 14px;
}
button {
font-size: 21px;
}
header {
}
&__box {
flex-direction: row;
justify-content: space-around;
padding: 30px 10px;
margin-bottom: 50px;
}
}
}
@media screen and (min-width: 1008px) and (max-width: 1440px) {
.profile {
h1{
font-size: calc(100vw / 50);
}
p{
font-size: calc(100vw / 90);
}
button {
font-size: calc(100vw / 70);
}
&__box {
padding: 30px 10px;
flex-direction: row;
justify-content: space-around;
margin-bottom: 50px;
}
}
}
@media screen and (min-width: 641px) and (max-width: 1007px) {
.profile {
padding: 50px 100px 10px;
button {
font-size: calc(100vw / 40);
}
header {
margin: 0px;
margin-top: 30px;
h1{
font-size: calc(100vw / 35);
}
p{
font-size: calc(100vw / 55);
}
}
&__box {
flex-direction: column;
border: none;
&--section {
width: 100%;
}
}
}
}
@media screen and (max-width: 640px) {
.profile {
padding: 0px 10px;
button {
font-size: calc(100vw / 30);
}
header {
margin: 0px;
margin-top: 70px;
h1{
font-size: calc(100vw / 20);
}
p{
font-size: calc(100vw / 35);
}
}
&__box {
flex-direction: column;
border: none;
&--section {
width: 100%;
}
}
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

@ -0,0 +1,118 @@
import React, { useState, useRef, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import Input from "../../../components/Input";
import Button from "../../../components/Button";
import Timer from "../../../components/Timer";
import onInput from "../../../utils/onInput";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import { user } from "../../../redux/actions";
import _ from "lodash";
//assets
import logoIcon from "./assets/logo.svg";
function SignUp({ sendOtp, sendPhoneNumber, loginFlag, theme }) {
const [level, setLevel] = useState("phonenumber");
const [signUpFields, setSignUpFiels] = useState(null);
const [error, setError] = useState("");
const [resend, setResend] = useState(false);
const navigate = useNavigate();
const onChange = (name, value) => {
setSignUpFiels({ ...signUpFields, [name]: value });
};
const checkPhoneNumber = () => {
if (
signUpFields?.cellphone?.slice(0, 2) === "09" &&
signUpFields?.cellphone.length === 11
) {
setLevel("otp");
setResend(false);
sendPhoneNumber({ cellphone: signUpFields?.cellphone });
setError(undefined);
} else {
setError("شماره موبایل خود را چک کنید.");
}
};
const checkOtp = () => {
if (signUpFields?.otp?.length === 4) {
sendOtp({
cellphone: signUpFields?.cellphone,
otp: signUpFields?.otp,
userToken: "2",
applicationToken: "22",
});
setError(undefined);
} else {
setError("کد وارد شده را چک کنید.");
}
};
const otpInput = useRef();
const numberInput = useRef();
useEffect(() => {
// numberInput.current.focus();
}, []);
useEffect(() => {
if (signUpFields?.otp?.length === 4) {
sendOtp({
cellphone: signUpFields?.cellphone,
otp: signUpFields?.otp,
userToken: "2",
applicationToken: "22",
});
}
}, [signUpFields]);
useEffect(() => {
if (level === "phonenumber") {
// numberInput.current.focus();
} else {
// otpInput.current.focus();
}
}, [level]);
useEffect(() => {
if (loginFlag) {
navigate("/");
}
}, [loginFlag]);
const light = theme === "light";
return (
<div
className="flex flex-col items-center justify-center w-screen p-4 transform -translate-y-20"
style={{ height: "calc(100vh - 80px)" }}
>
<img src={logoIcon} alt="" className="" />
<strong className="w-full leading-6 dark:text-white mt-10">
سلام <br /> خوش برگشتی!
</strong>
<form className="w-full flex flex-col mt-10">
<Input label={"شماره موبایل"} />
<br/>
<Button
title="ادامه فرایند خرید"
backgroundColor="bg-blueC0"
border={{ color: "#196EC055", width: "1px" }}
width="100%"
color="text-white"
/>
</form>
</div>
);
}
export default connect(
(state) => ({
loginFlag: state.user.setLogin,
}),
{
sendOtp: user.otp_login,
sendPhoneNumber: user.otp,
}
)(SignUp);

@ -0,0 +1,320 @@
.signup {
width: 100%;
height: 100vh;
position: relative;
font-family: numeralLight;
&__back{
img{
width: 40px;
}
}
&-light {
b {
color: $gray5 !important;
}
input {
background-color: white;
border: 1px solid $green1;
color: $gray5;
&::placeholder {
color: $gray9;
}
&:focus {
border: 1px solid $green4;
&::placeholder {
color: $green4;
}
}
}
.signup {
&__info {
color: $gray5;
a {
color: $green4;
}
}
&__back {
a {
color: $gray5;
font-size: 13px;
}
}
}
}
&-dark {
input {
background-color: $gray8;
border: 1px solid $gray;
color: white;
&:focus {
border: 1px solid $green4;
&::placeholder {
color: $green4;
}
}
}
.signup {
&__info {
color: white;
a {
color: $green4;
}
}
&__back {
a {
color: white;
}
}
}
}
img {
// transform: rotate(-90deg);
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
}
button[type="submit"] {
margin-top: 25px;
background-color: $green4;
color: white;
padding: 10px 0px;
border: 0px;
border-radius: 10px;
}
}
@media screen and (min-width: 1441px) {
.signup {
section {
width: 410px;
b {
color: white;
font-size: 16px;
margin-bottom: 30px;
font-weight: 500;
line-height: 1.7;
p {
}
}
input {
text-align: center;
border-radius: 8px;
font-size: 20px;
padding: 8px 0px;
direction: ltr;
&:focus {
&::placeholder {
opacity: 0.3;
}
}
}
button {
margin-top: 25px;
font-size: 17px;
}
}
&__info {
width: 350px;
margin: 30px auto 0px;
text-align: center;
font-size: 13px;
}
&__back {
margin-bottom: 60px;
a {
font-size: 13px;
}
.desktop {
img {
transform: rotate(-90deg);
}
}
}
&__error {
margin-top: 10px;
color: $red1;
font-size: 14px;
}
}
}
@media screen and (min-width: 1008px) and (max-width: 1440px) {
.signup {
section {
width: 350px;
b {
color: white;
font-size: calc(100vw / 90);
margin-bottom: 30px;
font-weight: 500;
p {
// font-size: calc(100vw / 140) !important;
}
}
input {
text-align: center;
border-radius: 8px;
font-size: calc(100vw / 75);
padding: 8px 0px;
direction: ltr;
&:focus {
&::placeholder {
opacity: 0.3;
}
}
}
button {
margin-top: 25px;
font-size: calc(100vw / 80);
}
}
&__info {
width: 300px;
margin: 20px auto 0px;
text-align: center;
font-size: calc(100vw / 110);
}
&__back {
margin-bottom: 50px;
a {
font-size: calc(100vw / 110);
}
.desktop {
img {
transform: rotate(-90deg);
}
}
}
&__error {
margin-top: 10px;
color: $red1;
font-size: calc(100vw / 110);
}
}
}
@media screen and (min-width: 641px) and (max-width: 1007px) {
.signup {
.footer {
display: none !important;
}
section {
width: 90%;
max-width: 700px;
height: calc(100% - 60px);
justify-content: center;
b {
color: white;
font-size: calc(100vw / 35);
margin-bottom: 70px;
font-weight: 500;
p {
// font-size: calc(100vw / 30) !important;
}
}
input {
text-align: center;
border-radius: 8px;
font-size: calc(100vw / 30);
padding: 10px 14px;
direction: ltr;
&:focus {
&::placeholder {
opacity: 0.3;
}
}
}
button {
font-size: calc(100vw / 30);
width: 100%;
max-width: 400px;
margin: 50px auto 0px;
}
}
&__info {
width: 400px;
margin: 20px auto 0px;
text-align: center;
font-size: calc(100vw / 40);
}
&__back {
position: fixed;
top: 100px;
left: 30px;
margin-bottom: 50px;
a {
font-size: calc(100vw / 110);
}
img {
width: 50px;
}
}
&__error {
margin-top: 10px;
color: $red1;
font-size: calc(100vw / 110);
}
}
}
@media screen and (max-width: 640px) {
.signup {
section {
width: 90%;
max-width: 400px;
height: calc(100% - 60px);
justify-content: center;
b {
color: white;
font-size: calc(100vw / 25);
margin-bottom: 30px;
font-weight: 500;
p {
// font-size: calc(100vw / 30) !important;
}
}
input {
text-align: center;
border-radius: 8px;
font-size: calc(100vw / 22);
padding: 10px 14px;
direction: ltr;
&:focus {
&::placeholder {
opacity: 0.3;
}
}
}
button {
margin-top: 20px;
font-size: calc(100vw / 24);
padding: 12px 0px;
border: 0px;
border-radius: 10px;
}
}
&__info {
width: 300px;
margin: 30px auto 0px;
text-align: center;
font-size: calc(100vw / 30);
line-height: 1.5;
}
&__back {
position: fixed;
top: 70px;
left: 20px;
margin-bottom: 50px;
a {
font-size: calc(100vw / 110);
}
}
&__error {
margin-top: 10px;
color: $red1;
font-size: calc(100vw / 30);
}
}
}

@ -0,0 +1,24 @@
import React, {useState, useEffect} from 'react';
import SignUp from './SignUp/index';
import Profile from './Profile/index';
import Login from './Login/index';
import {connect} from 'react-redux';
function Auth(props) {
const [page, setPage] = useState(props.page);
useEffect(() => {
setPage(() => props.page);
},[props.page]);
return (
<>
{ page === 'signup' && <SignUp theme={props.theme} /> }
{ page === 'login' && <Login theme={props.theme} setPage={setPage} /> }
{ page === 'profile' && <Profile theme={props.theme} /> }
</>
)
}
export default connect((state) => ({
theme : state.publicApi.theme,
}))(Auth);

@ -0,0 +1,3 @@
@import './Login/index.scss';
@import './Profile/index.scss';
@import './SignUp/index.scss';

@ -28,6 +28,7 @@ function Home({
// initialState
useEffect(() => {
window.addEventListener("scroll", () => {
const scrollY = window.scrollY;
localStorage.setItem("prevScroll", scrollY);

@ -43,8 +43,8 @@ const Blog = ({ blog }) => {
background: `url(https://dnvn.ir/api/v1/file/${blog?.fileIds})`,
backgroundPosition: "contain",
backgroundSize: "100% 100%",
minWidth: "calc(100vw / 1.3)",
minHeight: "calc(100vw / 1.3 * 2 / 3)",
width: 280,
minHeight: 220,
}}
>
<div className="w-11/12 bg-white rounded-md shadow-md flex flex-col transform translate-y-1/2 p-2 dark:bg-gray36">

@ -16,9 +16,9 @@ function Shop({ list, getList, grades, isDark }) {
<div className="w-full flex flex-col rounded-md py-4 overflow-hidden">
<Header title="فروشگاه" link="/products" />
<ul
className="list-none w-full overflow-x-scroll pt-3 flex flex-col flex-wrap"
className="list-none w-full overflow-x-scroll mt-3 flex flex-col flex-wrap"
style={{
maxHeight: "calc(100vh / 3 + 12px)",
height: 320,
}}
>
{list.map((book, index) => (
@ -45,8 +45,8 @@ const Book = ({ book, index }) => {
alt=""
className="rounded-sm"
style={{
minWidth: "calc(100vh / 3 * 3 / 5)",
maxHeight: "calc(100vh / 3)",
width: 200,
height: 303,
}}
/>
) : (
@ -55,8 +55,8 @@ const Book = ({ book, index }) => {
alt=""
className="rounded-sm"
style={{
minWidth: "calc(100vh / 6 * 3 / 5)",
maxHeight: "calc(100vh / 6 - 5px)",
width: 100,
height: 148,
marginBottom: index % 2 !== 0 ? "8px" : "0px",
}}
/>

@ -1,13 +1,23 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { book } from "../../redux/actions";
import { toast } from "react-toastify";
import { book, userProduct } from "../../redux/actions";
import proxy from "../../redux/proxy";
import location from "../../utils/location";
import Button from "../../components/Button";
import Header from "../../components/Header";
import Comment from "./Comment";
import Rate from "./Rate";
export const Product = ({ productType, getInfo, book, grades, isDark }) => {
export const Product = ({
productType,
getInfo,
book,
grades,
isDark,
userId,
pushToCart,
}) => {
useEffect(() => {
getInfo({ id: location.getId() });
}, []);
@ -69,6 +79,15 @@ export const Product = ({ productType, getInfo, book, grades, isDark }) => {
</div>
<div className="w-full flex flex-row justify-between items-center mt-4">
<Button
onClick={() =>
proxy.status()
? pushToCart({
productId: book.product[1].id,
userId: userId,
count: 1,
})
: toast.info("ابتدا وارد حساب کاربری خود شوید.")
}
title="خرید با قیمت 245.000 تومان"
backgroundColor="bg-blueC0"
border={{ color: "#196EC055", width: "1px" }}
@ -127,9 +146,10 @@ const mapStateToProps = (state) => ({
book: state.book.info,
grades: state.publicApi.grades,
isDark: state.publicApi.isDark,
userId: state.user.status.id,
});
const mapDispatchToProps = { getInfo: book.info };
const mapDispatchToProps = { getInfo: book.info, pushToCart: userProduct.add };
export default connect(mapStateToProps, mapDispatchToProps)(Product);

@ -1,7 +1,11 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { userProduct, userFactor } from "../../redux/actions";
import Product from "./Product";
import Code from "./Code";
import Button from "../../components/Button";
//assets
import alertIcon from "../../assets/icons/alert.svg";
import { connect } from "react-redux";
@ -22,7 +26,21 @@ const PriceStatus = ({ name, value, type, isDark }) => {
);
};
function ShoppingCart({ isDark }) {
function ShoppingCart({
isDark,
list,
payPrice,
factorInfo,
userId,
hasPhysical,
getList,
getInfo,
getFactorInfo,
payFactor
}) {
useEffect(() => {
},[]);
return (
<div className="w-full flex flex-col px-4">
{[0, 1].map((product, index) => (
@ -50,8 +68,12 @@ function ShoppingCart({ isDark }) {
/>
</div>
<div className="flex flex-row justify-between items-center w-full py-3">
<strong className="font-medium text-sm dark:text-white">جمع کل سبد خرید</strong>
<p className="font-medium text-greenBA text-xs dark:text-white">235.000 تومان</p>
<strong className="font-medium text-sm dark:text-white">
جمع کل سبد خرید
</strong>
<p className="font-medium text-greenBA text-xs dark:text-white">
235.000 تومان
</p>
</div>
<div
className="w-full rounded-md flex flex-row justify-center items-center py-2.5 px-3 my-5"
@ -75,8 +97,18 @@ function ShoppingCart({ isDark }) {
const mapStateToProps = (state) => ({
isDark: state.publicApi.isDark,
list: state.userProduct.list,
payPrice: state.userProduct.sum,
factorInfo: state.userFactor.info,
userId: state.user.status.id,
hasPhysical: state.userProduct.hasPhysical,
});
const mapDispatchToProps = {};
const mapDispatchToProps = {
getList: userProduct.list,
getInfo: userProduct.info,
getFactorInfo: userFactor.info,
payFactor: userFactor.payment,
};
export default connect(mapStateToProps, mapDispatchToProps)(ShoppingCart);

@ -33,6 +33,7 @@ module.exports = {
blueE8: "#2E81E8",
blue52: "#132F52",
blue5F: "#05335F",
blueB9 : "#86A0B9",
green71: "#067182",
greenBA: "#06BACE",
red5F: "#5F1A05",

@ -3236,6 +3236,11 @@ char-regex@^1.0.2:
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
chardet@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
check-types@^11.1.1:
version "11.1.2"
resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.1.2.tgz#86a7c12bf5539f6324eb0e70ca8896c0e38f3e2f"
@ -3335,6 +3340,18 @@ clean-stack@^2.0.0:
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
cli-cursor@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
dependencies:
restore-cursor "^3.1.0"
cli-width@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
cliui@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
@ -3450,6 +3467,11 @@ commander@^4.1.1:
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
commander@^7.0.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
commander@^8.0.0:
version "8.3.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
@ -4976,6 +4998,15 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
external-editor@^3.0.3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
dependencies:
chardet "^0.7.0"
iconv-lite "^0.4.24"
tmp "^0.0.33"
extglob@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
@ -5042,6 +5073,13 @@ figgy-pudding@^3.5.1:
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e"
integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==
figures@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
dependencies:
escape-string-regexp "^1.0.5"
file-entry-cache@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
@ -5770,7 +5808,7 @@ human-signals@^1.1.1:
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
iconv-lite@0.4.24:
iconv-lite@0.4.24, iconv-lite@^0.4.24:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
@ -5929,6 +5967,25 @@ ini@^1.3.5:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
inquirer@^7.1.0:
version "7.3.3"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003"
integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==
dependencies:
ansi-escapes "^4.2.1"
chalk "^4.1.0"
cli-cursor "^3.1.0"
cli-width "^3.0.0"
external-editor "^3.0.3"
figures "^3.0.0"
lodash "^4.17.19"
mute-stream "0.0.8"
run-async "^2.4.0"
rxjs "^6.6.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
through "^2.3.6"
internal-ip@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907"
@ -6393,6 +6450,15 @@ istanbul-reports@^3.0.2:
html-escaper "^2.0.0"
istanbul-lib-report "^3.0.0"
jalali-moment@^3.3.10:
version "3.3.10"
resolved "https://registry.yarnpkg.com/jalali-moment/-/jalali-moment-3.3.10.tgz#10cb4c2080925a41ee8c72862ba63f6b5fb04743"
integrity sha512-hyNsDJXB23MHLnZWPXY+Mu0zsrp+B+KzabyqPP0oGcMsEGp8yMpeVledOY+B/DrIOVeRY7JLz8b3lyJ3/vajsQ==
dependencies:
commander "^7.0.0"
inquirer "^7.1.0"
moment "^2.26.0"
jest-changed-files@^26.6.2:
version "26.6.2"
resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0"
@ -7521,6 +7587,11 @@ modern-normalize@^1.1.0:
resolved "https://registry.yarnpkg.com/modern-normalize/-/modern-normalize-1.1.0.tgz#da8e80140d9221426bd4f725c6e11283d34f90b7"
integrity sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA==
moment@^2.26.0:
version "2.29.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@ -7561,6 +7632,11 @@ multicast-dns@^6.0.1:
dns-packet "^1.3.1"
thunky "^1.0.2"
mute-stream@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
nan@^2.12.1:
version "2.15.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee"
@ -7971,6 +8047,11 @@ os-browserify@^0.3.0:
resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=
os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
p-each-series@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a"
@ -9768,6 +9849,14 @@ resolve@^2.0.0-next.3:
is-core-module "^2.2.0"
path-parse "^1.0.6"
restore-cursor@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
dependencies:
onetime "^5.1.0"
signal-exit "^3.0.2"
ret@~0.1.10:
version "0.1.15"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
@ -9868,6 +9957,11 @@ rsvp@^4.8.4:
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==
run-async@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
@ -9882,6 +9976,13 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
rxjs@^6.6.0:
version "6.6.7"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
dependencies:
tslib "^1.9.0"
safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
@ -10865,6 +10966,11 @@ through2@^2.0.0:
readable-stream "~2.3.6"
xtend "~4.0.1"
through@^2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
thunky@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
@ -10882,6 +10988,13 @@ timsort@^0.3.0:
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
dependencies:
os-tmpdir "~1.0.2"
tmp@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
@ -10995,7 +11108,7 @@ tsconfig-paths@^3.11.0:
minimist "^1.2.0"
strip-bom "^3.0.0"
tslib@^1.8.1:
tslib@^1.8.1, tslib@^1.9.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==

Loading…
Cancel
Save