reza added something

temp
Reza_ashrafi 3 years ago
parent 133361b9e0
commit 32a2a7e0c9
  1. 9
      src/components/Button/index.js
  2. 49
      src/components/Dialog/index.js
  3. 17
      src/components/Input/index.js
  4. 43
      src/components/Loading/index.js
  5. 12
      src/components/Loading/index.scss
  6. 2
      src/components/ProductStatusCard/index.js
  7. 2
      src/components/Radio/index.js
  8. 49
      src/components/ReverseMap/index.js
  9. 1
      src/components/Select/index.js
  10. 18
      src/components/VodProduct/index.js
  11. 4
      src/views/404/index.js
  12. 227
      src/views/Address/index.js
  13. 33
      src/views/DeliveryForm/Address/index.js
  14. 6
      src/views/DeliveryForm/TransportMethod/index.js
  15. 2
      src/views/Home/Desktop/index.js
  16. 4
      src/views/Product/Desktop/ProductOverAll/index.js
  17. 2
      src/views/Products/index.js
  18. 60
      src/views/ShoppingCart/Product/index.js
  19. 46
      src/views/ShoppingCart/index.js
  20. 2
      src/views/Video/index.js
  21. 86
      tailwind.config.js

@ -1,4 +1,5 @@
import React from "react";
import Loading from "../Loading";
export default function Button({
title,
@ -11,13 +12,11 @@ export default function Button({
selectable,
active,
borderType,
twPaddings,
customStyle,
radius
loading,
}) {
return (
<button
className={`${radius == false ? '' : 'rounded-md'} ${twPaddings? twPaddings : 'py-3'} ${customStyle} justify-center text-sm lg:text-tiny cursor-pointer lg:py-4 ${
className={`rounded-md flex py-3 justify-center text-sm lg:text-tiny cursor-pointer lg:py-4 ${
selectable ? (active ? "bg-black" : backgroundColor) : backgroundColor
} ${selectable ? (active ? "text-blueC0" : color) : color} ${
selectable ? (active ? "bg-blue-100" : bgOpacity) : bgOpacity
@ -32,7 +31,7 @@ export default function Button({
}}
onClick={() => onClick()}
>
{title}
{loading ? <Loading size={2} color="bg-green-500" /> : title}
</button>
);
}

@ -0,0 +1,49 @@
import React from "react";
import { connect } from "react-redux";
export const Dialog = ({ dialog }) => {
const { text, type, setOpen, accept, bg, color } = dialog;
return (
<div
className="z-50 w-screen h-full fixed top-0 right-0 backdrop-filter blur-sm flex justify-center items-center"
onClick={() => setOpen(false)}
>
<div className={`flex flex-col items-center ${bg} backdrop-filter backdrop-blur-xl rounded-md p-5 shadow-2xl`} style={{minWidth: 300}}>
{/* {type === "confirm" && (
<div className="w-full flex justify-end text-sm text-bla">exit</div>
)} */}
<p className={`text-tiny ${color} w-full mb-8 leading-7`}>{text}</p>
{type === "confirm" && (
<div className="flex flex-row gap-4 w-full">
<button
className="py-2.5 w-1/2 shadow-md rounded-sm bg-blueC0 text-white"
onClick={() => accept()}
>
باشه
</button>
<button
className="py-2.5 w-1/2 shadow-md rounded-sm bg-redFF1 text-white"
onClick={() => setOpen(false)}
>
بیخیال
</button>
</div>
)}
{type === "alert" && (
<div className="flex flex-row gap-4 w-full">
<button
className="py-2.5 w-full shadow-md rounded-sm bg-blueC0 text-white"
onClick={() => setOpen(false)}
>
باشه
</button>
</div>
)}
</div>
</div>
);
};
const mapStateToProps = (state) => ({});
export default connect(mapStateToProps)(Dialog);

@ -19,14 +19,13 @@ const inputStatusHandler = (value, focus, status, primary, success, danger) => {
if (status) {
return success;
} else {
return danger;
return;
}
}
}
};
export default function Input(props) {
const [value, setValue] = useState("");
const [focusToggle, setFocusToggle] = useState(false);
const {
@ -44,6 +43,7 @@ export default function Input(props) {
regex,
direction,
width,
value,
} = props;
return (
@ -93,6 +93,7 @@ export default function Input(props) {
],
" "
)}
value={value}
style={{ direction: direction }}
onChange={(e) =>
onChange(name, (e.target.value = regex(e.target.value)))
@ -101,7 +102,7 @@ export default function Input(props) {
onBlur={() => (!value ? setFocusToggle(false) : setFocusToggle(true))}
maxLength={maxLength}
/>
{!status && value && (
{/* {!status && value && (
<img
src={danger}
alt={langDetector(lang, "اشتباه", "wrong")}
@ -113,8 +114,8 @@ export default function Input(props) {
" "
)}
/>
)}
{status && value && (
)} */}
{/* {status && value && (
<img
src={tick}
alt={langDetector(lang, "درست", "right")}
@ -126,7 +127,7 @@ export default function Input(props) {
" "
)}
/>
)}
)} */}
{value && !status && (
<span
@ -150,7 +151,7 @@ export default function Input(props) {
{message}
</span>
)}
{value && (
{/* {value && (
<span
className={_.join(
[
@ -171,7 +172,7 @@ export default function Input(props) {
>
{value.length + "/" + maxLength}
</span>
)}
)} */}
</div>
);
}

@ -0,0 +1,43 @@
import React, { useState, useEffect } from "react";
import "./index.scss";
function Loading({ size, color }) {
const [dots, setDots] = useState({});
useEffect(() => {
setTimeout(() => {
setDots({ ...dots, one: true });
}, 50);
setTimeout(() => {
setDots({ ...dots, one : true, two: true });
}, 500);
setTimeout(() => {
setDots({ ...dots, one : true, two: true, three: true });
}, 950);
}, []);
return (
<div className="flex items-center gap-0.5">
<span
className={`w-${size} h-${size} rounded-full ${color} ${
dots?.one ? "loading-animation" : ""
}`}
></span>
<span
className={`w-${size} h-${size} rounded-full ${color} ${
dots?.two ? "loading-animation" : ""
}`}
></span>
<span
className={`w-${size} h-${size} rounded-full ${color} ${
dots?.three ? "loading-animation" : ""
}`}
></span>
</div>
);
}
export default Loading;
Loading.defaultProps = {
size: 2,
};

@ -0,0 +1,12 @@
.loading-animation{
animation: loading 0.6s infinite;
}
@keyframes loading{
0%{
opacity: 0.5;
}
100%{
opacity: 1;
}
}

@ -22,6 +22,7 @@ const ProductStatusCard = ({
userId,
isLogin,
pushToCart,
loading,
}) => {
return (
<section className="w-full">
@ -69,6 +70,7 @@ const ProductStatusCard = ({
width="100%"
color={"text-white"}
selectable={true}
loading={loading}
onClick={() =>
isLogin
? pushToCart({

@ -4,7 +4,7 @@ import "./index.scss";
export default function Radio(props) {
return (
<div className="radio flex items-center">
<input id="radio-1" name={props.name} type="radio" />
<input id="radio-1" name={props.name} type="radio" checked={props.active} />
<label htmlFor="radio-1" className="radio-label text-xs">
{/* {props.label} */}
</label>

@ -0,0 +1,49 @@
import React, { useState } from "react";
import Mapir from "mapir-react-component";
const X_API_KEY = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjkyODE4ODI0N2FhMjdlYTMyMzVlYzRiOWUxZDI3NTQyZTNjYmI3ZjQzY2Q2NGQzYjdkYjU1NmY3NDM5YzU2NzUyNzMxMjAzYzMwOTliYTFiIn0.eyJhdWQiOiIxNjk2MSIsImp0aSI6IjkyODE4ODI0N2FhMjdlYTMyMzVlYzRiOWUxZDI3NTQyZTNjYmI3ZjQzY2Q2NGQzYjdkYjU1NmY3NDM5YzU2NzUyNzMxMjAzYzMwOTliYTFiIiwiaWF0IjoxNjQ0MzE3MDA5LCJuYmYiOjE2NDQzMTcwMDksImV4cCI6MTY0NjgyMjYwOSwic3ViIjoiIiwic2NvcGVzIjpbImJhc2ljIl19.Gckmd77Vw-wmsaztsmVmjYmfp4zXRSy2f0tXS-1p7IY8VJmvCCrk64y7WvCLbH0YfGZI9rG9ZUi5hRJDDGXu70l1ZafCYq2-EkMzcbx-PGTTq2bHGNZujF4ur1xtGoXd2kwGuldiR_6SJdqYLHcupbscFI7hHaQnkN1xWJ-L8476ZOKzUgiBvwH9uElGZXwD6SwfXoGW_R38_isrnfTXKfW9PPixyLaN3404tcjOU1r02HIurrplXlIKRKG9CVXxKsESfJJ8trwtZw6O4erxrnisxfL0VwAR7l69P6KcFb57vvM4j4hKFqxUDr4YvSq1qOTt3urYbAKehhvoiLhZxw";
const Map = Mapir.setToken({
transformRequest: (url) => {
return {
url: url,
headers: {
"x-api-key":X_API_KEY,
"Mapir-SDK": "reactjs",
},
};
},
});
const ReverseMap = ({ setAddress }) => {
const [markerArray, setMarkerArray] = useState([]);
const [coord, setCoord] = useState([51.42, 35.72]);
function reverseFunction(map, e) {
let url = `https://map.ir/reverse/no?lat=${e.lngLat.lat}&lon=${e.lngLat.lng}`;
fetch(url, {
headers: {
"Content-Type": "application/json",
"x-api-key": X_API_KEY,
},
})
.then((response) => response.json())
.then((data) => setAddress(data.address));
const array = [];
array.push(
<Mapir.Marker
coordinates={[e.lngLat.lng, e.lngLat.lat]}
anchor="bottom"
/>
);
setMarkerArray(array);
}
return (
<Mapir center={coord} Map={Map} onClick={reverseFunction}>
{markerArray}
</Mapir>
);
};
export default ReverseMap;

@ -41,4 +41,5 @@ export default Select;
Select.defaultProps = {
options: ["Really", "Option 2", "Option 3"],
borderColor : 'border-gray-300'
};

@ -1,6 +1,6 @@
import React, { useEffect, useState } from "react";
import {Link} from 'react-router-dom';
import separate from '../../utils/separate';
import { Link } from "react-router-dom";
import separate from "../../utils/separate";
import StarRating from "../StarRating";
import ReactTooltip from "react-tooltip";
@ -68,7 +68,7 @@ const VodProduct = ({
<>
{/* product UI Design */}
<Link
to={'/videos/' + video?.bookId}
to={"/videos/" + video?.id}
className="flex flex-wrap sm:flex-nowrap justify-around"
style={{ direction: "rtl" }}
>
@ -146,7 +146,7 @@ const VodProduct = ({
</h2>
{console.log(video?.gradeId)}
<span className={`text-sm font-light text-blueC0`}>
{ 'پایه' + ' ' + grades[video?.gradeId]}
{"پایه" + " " + grades[video?.gradeId]}
</span>
</div>
{productContent && (
@ -175,9 +175,7 @@ const VodProduct = ({
: "flex"
}`}
>
<span className="text-xs text-borderColor ml-2">
</span>
<span className="text-xs text-borderColor ml-2"></span>
{/* {discountPrice && (
<p className="line-through text-xs text-borderColor">
@ -185,12 +183,12 @@ const VodProduct = ({
</p>
)} */}
</div>
{/* <p
<p
className={`text-base font-semibold text-left`}
>
{separate(video?.price) + ' '}
{separate(video?.product[2]?.price) + ' '}
<span>تومان</span>
</p> */}
</p>
</div>
{/* add to cart */}
{addToCartHolder && (

@ -19,9 +19,9 @@ function NotFound({ headerOptions, setHeaderOptions }) {
</h1>
<img src={notFoundImage} alt="404" className="mt-10" />
<p className="text-base dark:text-white mt-12 leading-7">
وای!!
اوه!!
<br />
صفحه ای که بدنبال آن بودهاید دیگر وجود ندارد :(
دوست من، اشتباه اومدی
</p>
</div>
);

@ -1,12 +1,37 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { publicApi } from "../../redux/actions";
import { publicApi, userAddress } from "../../redux/actions";
import onInput from "../../utils/onInput";
import Input from "../../components/Input";
import Select from "../../components/Select";
import Button from "../../components/Button";
import ReverseMap from "../../components/ReverseMap";
import Dialog from "../../components/Dialog";
export const Address = ({ city, province, getCity, getProvince }) => {
//assets
import dropdownIcon from "../../assets/icons/dropdown-blue.svg";
export const Address = ({
city,
province,
getCity,
getProvince,
provinces,
cities,
createAddress,
loading,
setPhase,
}) => {
const [addressFields, setAddressFields] = useState({});
const [mapAddress, setMapAddress] = useState(null);
const [dialog, setDialog] = useState({
text: null,
type: null,
setOpen: null,
accept: null,
color: null,
open: null,
});
useEffect(() => {
if (province.length <= 1) {
@ -16,11 +41,144 @@ export const Address = ({ city, province, getCity, getProvince }) => {
useEffect(() => {
if (addressFields?.provinceId) {
getCity({ provinceId: addressFields?.provinceId });
getCity({
provinceId: provinces.filter(
(province) => province.name === addressFields?.provinceId
)[0].id,
});
}
}, [addressFields]);
const onChange = (name, value) => {};
const onChange = (name, value) => {
console.log("1");
setAddressFields({ ...addressFields, [name]: value });
};
const submit = () => {
const {
firstName,
lastName,
cellphone,
phone,
address,
provinceId,
cityId,
postalCode,
} = addressFields;
if (!firstName) {
setDialog({
text: "نام خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-black bg-opacity-60",
color: "text-white",
open: true,
});
return;
}
if (!lastName) {
setDialog({
text: "نام خانوادگی خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-black bg-opacity-60",
color: "text-white",
open: true,
});
return;
}
if (!cellphone) {
setDialog({
text: "شماره موبایل خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-black bg-opacity-60",
color: "text-white",
open: true,
});
return;
}
if (!phone) {
setDialog({
text: "شماره تلفن خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-black bg-opacity-60",
color: "text-white",
open: true,
});
return;
}
if (!provinceId) {
setDialog({
text: "نام استان خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-black bg-opacity-60",
color: "text-white",
open: true,
});
return;
}
if (!cityId) {
setDialog({
text: "نام شهرستان خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-black bg-opacity-60",
color: "text-white",
open: true,
});
return;
}
if (!postalCode) {
setDialog({
text: "کد پستی خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-black bg-opacity-60",
color: "text-white",
open: true,
});
return;
}
if (!mapAddress) {
setDialog({
text: "آدرس خود را از روی نقشه انتخاب کن",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-black bg-opacity-60",
color: "text-white",
open: true,
});
return;
}
createAddress({
firstName,
lastName,
cellphone,
phone,
address: mapAddress,
provinceId: provinces.filter(
(province) => province.name === provinceId
)[0].id,
cityId: cities.filter((city) => city.name === cityId)[0]?.id,
postalCode,
location: null,
});
setPhase("deliveryForm");
};
const Header = ({ title, text }) => {
return (
@ -33,9 +191,26 @@ export const Address = ({ city, province, getCity, getProvince }) => {
return (
<div
className="flex flex-row-reverse flex-1 pb-20 gap-5 divide-x divide-solid divide-gray-200"
style={{ minHeight: "calc(100vh - 500px)" }}
// style={{ minHeight: "calc(100vh - 500px)" }}
>
<div className="flex flex-col w-1/2"></div>
<div className="flex flex-col w-1/2 px-4">
<div
className="w-full overflow-hidden rounded-md mb-6"
style={{ height: "calc(100vh / 2)" }}
>
<ReverseMap setAddress={(val) => setMapAddress(val)} />
</div>
<Input
width="100%"
label={"ادرس انتخاب شده در نقشه"}
regex={(val) => onInput.numberOnly(val)}
name="address"
onChange={(name, value) => setMapAddress(value)}
value={mapAddress}
align="text-right"
direction="rtl"
/>
</div>
<div className="flex flex-col w-1/2 pl-4">
<Header
title="اطلاعات هویتی"
@ -80,16 +255,18 @@ export const Address = ({ city, province, getCity, getProvince }) => {
value={addressFields?.cellphone}
align="text-right"
direction="ltr"
maxLength={11}
/>
<Input
width="50%"
label={"شماره تلفن"}
regex={(val) => onInput.numberOnly(val)}
name="tellphone"
name="phone"
onChange={(name, value) => onChange(name, value)}
value={addressFields?.lastName}
value={addressFields?.phone}
align="text-right"
direction="ltr"
maxLength={11}
/>
</div>
<br />
@ -116,13 +293,39 @@ export const Address = ({ city, province, getCity, getProvince }) => {
width="50%"
label={"کد پستی"}
regex={(val) => onInput.numberOnly(val)}
name="tellphone"
name="postalCode"
onChange={(name, value) => onChange(name, value)}
value={addressFields?.lastName}
value={addressFields?.postalCode}
align="text-right"
direction="ltr"
maxLength={10}
/>
<div className="flex w-full items-end mt-8 flex-col">
<div className="flex flex-col items-cente w-2/5">
<Button
loading={loading}
title="ثبت آدرس"
backgroundColor="bg-blueC0"
border={{ color: "#196EC055", width: "1px" }}
width="100%"
color="text-white"
onClick={() => submit()}
/>
<button
className="bg-transparent mt-4 text-tiny text-blueC0 py-3 flex flex-row justify-center items-center"
onClick={() => setPhase("deliveryForm")}
>
بازگشت
<img
src={dropdownIcon}
alt=""
className="w-4 transform rotate-90"
/>
</button>
</div>
</div>
</div>
{dialog.open && <Dialog dialog={dialog} />}
</div>
);
};
@ -130,11 +333,15 @@ export const Address = ({ city, province, getCity, getProvince }) => {
const mapStateToProps = (state) => ({
province: state.publicApi.province,
city: state.publicApi.city,
provinces: state.publicApi.provinces,
cities: state.publicApi.cities,
loading: state.userAddress.loading,
});
const mapDispatchToProps = {
getProvince: publicApi.getProvince,
getCity: publicApi.getCity,
createAddress: userAddress.add,
};
export default connect(mapStateToProps, mapDispatchToProps)(Address);

@ -1,11 +1,19 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import Button from "../../../components/Button";
import Radio from "../../../components/Radio";
function Address({ addresses, isDark, isMobile, setPhase }) {
const [activeAddress, setActiveAddress] = useState(addresses[0]);
const Location = ({ address }) => {
const [activeAddress, setActiveAddress] = useState([]);
useEffect(() => {
if(addresses?.length > 0){
setActiveAddress(addresses[0]);
}
},[addresses]);
const Location = ({ address, active }) => {
return isMobile ? (
<button
className={`flex flex-row border-2 border-solid items-center w-full px-3 py-4 rounded-md mt-4 transition-all duration-500 dark:bg-opacity-5 ${
@ -37,9 +45,10 @@ function Address({ addresses, isDark, isMobile, setPhase }) {
? "bg-blueFD border-blueC0"
: "bg-grayF9 border-gray45"
}`}
onClick={() => setActiveAddress(address)}
>
<div className="flex flex-row gap-3 w-2/3">
<Radio />
<div className="flex flex-row gap-3 flex-1">
<Radio active={active} />
<div className="flex flex-1 flex-col">
<li className="text-right text-sm text-blue52 dark:text-white leading-4">
آدرس:&nbsp;{address.address}
@ -50,9 +59,9 @@ function Address({ addresses, isDark, isMobile, setPhase }) {
</li>
</div>
</div>
<div className="flex flex-col w-1/3">
<div className="flex flex-col">
<li className="text-right text-sm text-blue52 dark:text-white">
نام تحویل گیرنده:&nbsp;{address.receiver}
نام تحویل گیرنده:&nbsp;{address.firstName + ' ' + address.lastName}
</li>
<li className="text-right text-sm text-blue52 dark:text-white mt-3">
شماره تماس:&nbsp;{address.cellphone}
@ -63,7 +72,9 @@ function Address({ addresses, isDark, isMobile, setPhase }) {
};
return isMobile ? (
<section className="mt-2">
<strong className="font-medium dark:text-white lg:text-tiny">انتخاب آدرس</strong>
<strong className="font-medium dark:text-white lg:text-tiny">
انتخاب آدرس
</strong>
<ul className="list-none p-0 m-0 flex flex-col">
{addresses.map((address, index) => (
<Location address={address} key={index} />
@ -86,7 +97,11 @@ function Address({ addresses, isDark, isMobile, setPhase }) {
<strong className="font-medium dark:text-white">انتخاب آدرس</strong>
<ul className="list-none p-0 m-0 flex flex-col">
{addresses.map((address, index) => (
<Location address={address} key={index} />
<Location
address={address}
key={index}
active={activeAddress === address}
/>
))}
</ul>
<div className="w-full flex flex-row justify-between items-center mt-4">

@ -41,7 +41,7 @@ function TransportMethod({ transportMethods, isDark, isMobile }) {
</button>
) : (
<button
className={`flex flex-col border border-solid items-center px-2 py-3 rounded-md mt-4 relative transition-all duration-500 w-1/3 ${
className={`flex flex-col border border-solid items-center px-2 py-3 rounded-md mt-4 relative transition-all duration-500 w-2/5 ${
activeMethod === method
? "bg-blueFD border-blueC0 dark:bg-opacity-5"
: "bg-grayF9 border-grayDB dark:bg-opacity-5"
@ -49,7 +49,7 @@ function TransportMethod({ transportMethods, isDark, isMobile }) {
onClick={() => setActiveMethod(method)}
>
<strong
className={`text-sm transition-all duration-500 ${
className={`text-tiny transition-all duration-500 ${
activeMethod === method
? "text-blueC0 dark:text-white"
: "text-blue52 dark:text-white"
@ -58,7 +58,7 @@ function TransportMethod({ transportMethods, isDark, isMobile }) {
{method.name}
</strong>
<span
className={`text-xs transition-all duration-500 mt-2 ${
className={`text-sm transition-all duration-500 mt-2 ${
activeMethod === method
? "text-blueC0 dark:text-white"
: "text-blue52 dark:text-white"

@ -52,7 +52,7 @@ const DesktopHome = ({ grades, getBooks, books }) => {
];
useEffect(() => {
getBooks();
getBooks({vod : true});
},[]);
return (

@ -27,6 +27,7 @@ export const ProductOverAll = ({
pushToCart,
headerOptions,
setHeaderOptions,
loading,
}) => {
const [type, setType] = useState("1");
return (
@ -116,7 +117,7 @@ export const ProductOverAll = ({
</div>
</div>
<div className="flex flex-col w-1/3">
<ProductStatusCard price={book?.product[type]?.price} id={book?.product[type]?.id} />
<ProductStatusCard price={book?.product[type]?.price} id={book?.product[type]?.id} loading={loading} />
</div>
</header>
</div>
@ -128,6 +129,7 @@ const mapStateToProps = (state) => ({
grades: state.publicApi.grades,
isDark: state.publicApi.isDark,
userId: state.user.status.id,
loading : state.userProduct.loading
});
const mapDispatchToProps = {

@ -34,7 +34,7 @@ export const Products = ({
};
useEffect(() => {
getList();
getList({vod : true});
setHeaderOptions(headerOptions);
}, []);

@ -1,13 +1,15 @@
import React from "react";
import { connect } from "react-redux";
import { userProduct } from "../../../redux/actions";
import separate from "../../../utils/separate";
import Loading from "../../../components/Loading";
// assets
import bookImage from "../../../assets/images/zist-11.svg";
import exitIcon from "../../../assets/icons/exit.svg";
import deleteIcon from "../../../assets/icons/delete.svg";
function Product({ product, grades, pushToCart, isMobile }) {
function Product({ product, grades, pushToCart, isMobile, loading }) {
return isMobile ? (
<div className="flex flex-row justify-between py-5 border-b border-solid border-grayDB dark:border-gray45">
<div className="flex flex-row">
@ -60,7 +62,11 @@ function Product({ product, grades, pushToCart, isMobile }) {
+
</button>
<span className="mx-2.5 font-semibold text-md text-blueC0">
{product.count}
{loading ? (
<Loading size={2} color="bg-green-500" />
) : (
product.count
)}
</span>
<button
className="rounded-md pt-2 pb-1.5 px-3 border border-solid border-grayDB text-grayDB dark:border-blueC0 dark:text-blueC0"
@ -84,7 +90,7 @@ function Product({ product, grades, pushToCart, isMobile }) {
</div>
) : (
<div className="flex flex-row w-full gap-10 py-4 border-b border-solid border-gray-200">
<div className="w-1/2 flex flex-row">
<div className="w-3/4 flex flex-row">
<img
src={"https://dnvn.ir/api/v1/file/" + product?.product?.book?.fileIds}
className="rounded-md w-20"
@ -103,6 +109,12 @@ function Product({ product, grades, pushToCart, isMobile }) {
{product?.productType === 2 ? "نسخه فیزیکی" : "نسخه دیجیتال"}
</div>
</div>
<div className="flex flex-row items-center pl-4 mt-6">
<strong className="font-semibold text-xl text-blue5F dark:text-white">
&nbsp;{separate(product?.product?.price * product.count)}
&nbsp;&nbsp;تومان
</strong>
</div>
</div>
</div>
<div className="w-1/4 flex flex-row items-center">
@ -118,26 +130,12 @@ function Product({ product, grades, pushToCart, isMobile }) {
>
+
</button>
<span className="mx-2.5 font-semibold text-lg text-blueC0">
{product.count}
<span className="mx-2.5 font-semibold text-lg text-blueC0 w-8 flex justify-center">
{loading ? <Loading size={2} color="bg-green-500" /> : product.count}
</span>
<button
className="rounded-md pt-2 pb-1.5 px-3 border border-solid border-grayDB text-grayDB dark:border-blueC0 dark:text-blueC0 text-lg"
onClick={() =>
pushToCart({
productId: product?.productId,
userId: product?.userId,
count: -1,
})
}
>
-
</button>
</div>
<div className="w-1/4 flex flex-row items-center justify-end pl-4">
<strong className="font-semibold text-md text-blue5F dark:text-white">
&nbsp;{product?.product?.price}&nbsp;&nbsp;تومان
</strong>
{
<>
{product.count === 1 ? (
<img
onClick={() =>
pushToCart(
@ -152,8 +150,24 @@ function Product({ product, grades, pushToCart, isMobile }) {
}
src={deleteIcon}
alt="delete"
className="border border-red-800 border-solid p-1 w-8 bg-red-100 rounded-md mr-4 cursor-pointer"
className="border border-red-800 border-solid p-1 w-8 bg-red-100 rounded-md cursor-pointer"
/>
) : (
<button
className="rounded-md pt-2 pb-1.5 px-3 border border-solid border-blueC0 text-blueC0 dark:border-blueC0 dark:text-blueC0 text-lg"
onClick={() =>
pushToCart({
productId: product?.productId,
userId: product?.userId,
count: -1,
})
}
>
-
</button>
)}
</>
}
</div>
</div>
);

@ -1,6 +1,7 @@
import React, { useState, useEffect } from "react";
import { userProduct, userFactor, publicApi } from "../../redux/actions";
import separate from '../../utils/separate';
import { toast } from "react-toastify";
import DeliveryForm from "../DeliveryForm";
import Product from "./Product";
import Address from "../Address";
@ -28,6 +29,8 @@ function ShoppingCart({
headerOptions,
setHeaderOptions,
desktopContentTransform,
userProducts,
loading,
}) {
const [phase, setPhase] = useState("products");
@ -37,8 +40,15 @@ function ShoppingCart({
setHeaderOptions(headerOptions);
}, []);
const productsLength = userProducts?.filter(
(product) => product.condition < 2
)?.length;
const next = {
products: () => setPhase("deliveryForm"),
products: () =>
productsLength
? setPhase("deliveryForm")
: toast.info("ابتدا یک محصول را به سبد خرید خود اضافه کنید."),
deliveryForm: () => console.log("Go to shaparak"),
profile: () => {
console.log("Set profile");
@ -50,20 +60,19 @@ function ShoppingCart({
return (
<div className="w-full flex flex-col">
<header className="w-full flex flex-row gap-10">
<strong className="w-1/2 pb-2 border-b border-solid border-gray-200 text-gray70 text-sm font-normal">
<strong className="w-3/4 pb-2 border-b border-solid border-gray-200 text-gray70 text-sm font-normal">
کالاهای انتخابی{" "}
</strong>
<strong className="w-1/4 pb-2 border-b border-solid border-gray-200 text-gray70 text-sm font-normal">
تعداد سفارش
</strong>
<strong className="w-1/4 pb-2 border-b border-solid border-gray-200 text-gray70 text-sm font-normal">
مبلغ
</strong>
</header>
<ul className="w-full mt-2 list-none p-0">
{list.map(
(product, index) =>
product.condition < 2 && <Product key={index} product={product} />
product.condition < 2 && (
<Product loading={loading} key={index} product={product} />
)
)}
</ul>
</div>
@ -94,7 +103,7 @@ function ShoppingCart({
color: !isDark ? (type === "error" ? "#F1420D" : "#246E8A") : "",
}}
>
{value}
{separate(value)}
<span
style={{
color: !isDark ? (type === "error" ? "#F1420D" : "#246E8A") : "",
@ -109,7 +118,11 @@ function ShoppingCart({
};
const layouts = {
products: <Table />,
products: productsLength ? (
<Table />
) : (
<strong className="text-blueC0">سبد خرید شما خالی است.</strong>
),
deliveryForm: <DeliveryForm setPhase={setPhase} />,
address: <Address setPhase={setPhase} />,
};
@ -173,22 +186,24 @@ function ShoppingCart({
{phase !== "address" && (
<div
className="flex flex-col w-1/4 p-10 bg-grayF9 border border-solid border-grayDB rounded-md px-4 py-4"
style={{ height: "fit-content" }}
style={{ height: "fit-content", minWidth: 350}}
>
<div className="flex flex-col w-full border-t py-2 border-gray-300 border-b">
<PriceStatus
name="مبلغ سبد خرید"
value={factorInfo?.sumPrice}
value={productsLength ? factorInfo?.sumPrice : 0}
type="normal"
/>
<PriceStatus
name="میزان تخفیف"
value={factorInfo?.offPrice}
value={productsLength ? factorInfo?.offPrice : 0}
type="error"
/>
<PriceStatus
name="مالیات بر ارزش افزوده"
value={Math.floor(factorInfo?.sumPrice * 0.009)}
value={
productsLength ? Math.floor(factorInfo?.sumPrice * 0.009) : 0
}
type="error"
/>
</div>
@ -197,7 +212,7 @@ function ShoppingCart({
جمع کل سبد خرید
</strong>
<p className="font-medium text-greenBA text-xl dark:text-white">
{factorInfo?.payPrice}
{separate(productsLength ? factorInfo?.payPrice : 0)}
<span className="font-medium text-greenBA text-sm mr-2">
تومان
</span>
@ -247,6 +262,7 @@ function ShoppingCart({
width="100%"
color="text-white"
onClick={next[phase]}
// loading={loading}
/>
{phase === "deliveryForm" && (
<button
@ -276,6 +292,8 @@ const mapStateToProps = (state) => ({
user: state.user.status,
hasPhysical: state.userProduct.hasPhysical,
desktopContentTransform: state.publicApi.desktopContentTransform,
userProducts: state.userProduct.list,
loading: state.userProduct.loading
});
const mapDispatchToProps = {

@ -143,7 +143,7 @@ function Video({
<div className="w-3/12 flex flex-col">
<div className="w-full flex flex-col pr-2 py-2 border-0">
<h1 className="text-blue5F mb-3 font-semibold text-xl dark:text-white">
{book?.name}
{'دوره ویدئویی' + ' ' + book?.name}
</h1>
<div className="text-blueC0 text-sm dark:text-greenBA">
{"پایه" + " " + grades[book?.gradeId]}

@ -4,54 +4,52 @@ module.exports = {
theme: {
backgroundColor: (theme) => ({
...theme("colors"),
blueC0: "#196EC0",
blueB0: "#517AB0",
blue90: "#235A90",
blueCB: "#98B2CB",
blueEB: "#2B8DEB",
blueFF: "#E8FCFF",
blueFF1: "#E9F0FF",
blueFD: "#F6F9FD",
blueFD1 : "#F4F8FD",
blueFFOP : "rgba(6, 146, 255, 0.36)",
redFF: "#FFE6E6",
redFF1: "#FF2020",
red19: "#C01919",
yellow2: "#FDFFDA",
yellow3: "#EFFF00",
gray36: "#363636",
orange1: "#FF6600",
greenBA: "#06BACE",
green1: "#00FF80",
gray20: "#202020",
gray2077: "#20202077",
gray2C: "#2C2C2C",
gray36: "#363636",
gray50: "#505050",
grayDB: "#DBDBDB",
grayE3: "#E3E3E3",
grayEE: "#EEEEEE",
grayF9: "#F9F9F9",
grayF4: "#EBF0F4",
grayF7: "#F7F7F7"
blueC0: "#196EC0", //در سبد خرید - دکمه ادامه فرآیند
blueB0: "#517AB0", // صفحه هوم دسکتاپ - زیر اسلایدر متن لیست محصولات
blue90: "#235A90", // نقطه های مشخص کننده صفحه در دسکتاپ انیمیشن حالت خاموش
blueCB: "#98B2CB", // صفحه فعال سازی کتاب دیجیتال دکمه فعال سازی با کد QR
blueEB: "#2B8DEB", // نوار پروگرس مقدار داخلی که داره پر میشه
blueFF: "#E8FCFF", // در موبایل صفحه ویديو رنگ پس زمینه لیست فصل ها
blueFF1: "#E9F0FF", // در صفحه نمایش ویديو پس زمینه پلی لیست
blueFD: "#F6F9FD", // در صفحه فعال سازی کتاب پس زمینه هشدار
blueFD1 : "#F4F8FD", // در صفحه فعال سازی هدر بالای سایت
blueFFOP : "rgba(6, 146, 255, 0.36)", // در صفحه محصولات دکمه پاک کردن فیلترها در سایدبار
redFF: "#FFE6E6", // در انیمیشن موبایل که میاد کد رو اسکن کنه نتیجه اسکن پس زمینه پی دی اف
redFF1: "#FF2020", // در آیکن همبرگری نقطه نوتیف
red19: "#C01919", // در صفحه محصول رنگ متن مشاهده نمونه
yellow2: "#FDFFDA", // در انیمیشن موبایل که برای اسکن کد میاد نتیجه اسکن پس زمینه لینک ها
yellow3: "#EFFF00", // خط زیر متن یادگیری در دیزاین موبایل پابلیک صفحه هوم
gray36: "#363636", // در حالت دارک صفحه موبایل پس زمینه دکمه های کیو آر و ای آز در هدر
orange1: "#FF6600", // خط زیر متن کنارتونیم در دیزاین موبایل پابلیک صفحه هوم
greenBA: "#06BACE", // در سرچ اصلی سایت رنگ تکست تایتل محصولات و صفحات
green1: "#00FF80", // خط زیر متن یادگیری جذاب در دیزاین موبایل پابلیک صفحه هوم
gray20: "#202020", // هیچ جا
gray2077: "#20202077", // در صفحه محصولات حالت دارک صفحه محصولات پس زمینه سرچ
gray2C: "#2C2C2C", // هیچ جا
gray50: "#505050", // در صفحه اسکن کیو آر رنگ پس زمینه ی روی عکس
grayE3: "#E3E3E3", // رنگ پس زمینه لپ تاپ در صفحه هوم موبایل که نشون دهنده ریسپانسیو بودن سایت ماست
grayEE: "#EEEEEE", // رنگ پس زمینه موبایل در صفحه هوم موبایل که نشون دهنده ریسپانسیو بودن سایت ماس
grayF9: "#F9F9F9", // رنگ پس زمینه قیمت محصول و گارنتی و فلان در سبد خرید
grayF4: "#EBF0F4", // در صفحه محصولات رنگ پس زمینه عکس کتاب
grayF7: "#F7F7F7" // رنگ پس زمینه باکس اضافه کردن به سبد خرید در صفحه محصول
}),
textColor: (theme) => ({
...theme("colors"),
primary: "#235A90",
blueC0: "#196EC0",
blueC01: "#1999C0",
blueE8: "#2E81E8",
blue52: "#132F52",
blue5F: "#05335F",
blueB9: "#86A0B9",
green71: "#067182",
greenBA: "#06BACE",
red5F: "#5F1A05",
red19: "#C01919",
yellow1: "#5F5F05",
gray1: "#333333",
gray70: "#707070",
grayDB: "#DBDBDB",
blueC0: "#196EC0", //در سبد خرید - دکمه ادامه فرآیند
blueC01: "#1999C0", // هیچ جا
blueE8: "#2E81E8", // در صفحه محصول متن به من کمک کن انتخاب کنم
blue52: "#132F52", // در باکس اضافه کردن به سبد خرید رنگ متن با خرید این محصول فلان تومن سود کن
blue5F: "#05335F", // رنگ لینکها در هدر بالای سایت
blueB9: "#86A0B9", // در موبایل تب پایین صفحه رنگ متن صفحات
green71: "#067182", // در دسکتاپ انیمیشن قسمت برگزاری آزمون تکست زمان بافیمانده
greenBA: "#06BACE", // در سرچ اصلی سایت رنگ تکست تایتل محصولات و صفحات
red5F: "#5F1A05", // در انیمیشن موبایل که میاد کد رو اسکن کنه نتیجه اسکن متن پی دی اف
red19: "#C01919", // در صفحه محصول رنگ متن مشاهده نمونه
yellow1: "#5F5F05", // در انیمیشن موبایل که برای اسکن کد میاد نتیجه اسکن رنگ متن لینک ه
gray1: "#333333", // رنگ متن سرچ در صفحه محصولات موبایل
gray70: "#707070", // رنگ متن تایتل لیست لینک ها در فوتر سایت
grayDB: "#DBDBDB", // در دراور موبایل رنگ متن شماره موبایل کاربر در حالت دارک
}),
// height: (theme) =>( {
// sm: '8px',

Loading…
Cancel
Save