reza added some option to dashboard

temp
Reza_ashrafi 3 years ago
parent fa7f68e45b
commit 2bffd0fbbf
  1. 6
      src/components/BottomNavigation/index.js
  2. 27
      src/components/FloatingButton/index.js
  3. 3
      src/components/FloatingButton/plus.svg
  4. 5
      src/components/Footer/index.js
  5. 2
      src/redux/reducers/book.js
  6. 20
      src/router.js
  7. 36
      src/views/Address/index.js
  8. 11
      src/views/Contact/index.js
  9. 49
      src/views/Contact/layouts/Ticket.js
  10. 2
      src/views/Contact/layouts/index.scss
  11. 26
      src/views/Dashboard/index.js
  12. 115
      src/views/Dashboard/layouts/Main/Addresses/index.js
  13. 10
      src/views/Dashboard/layouts/Main/Addresses/menu.svg
  14. 15
      src/views/Dashboard/layouts/Main/index.js
  15. 10
      src/views/Dashboard/layouts/SidebarMenu/address.svg
  16. 6
      src/views/Dashboard/layouts/SidebarMenu/favorites.svg
  17. 40
      src/views/Dashboard/layouts/SidebarMenu/index.js
  18. 7
      src/views/Dashboard/layouts/SidebarMenu/myBooks.svg
  19. 10
      src/views/Dashboard/layouts/SidebarMenu/myVideos.svg
  20. 7
      src/views/Dashboard/layouts/SidebarMenu/orders.svg
  21. 8
      src/views/Favorites/book.svg
  22. 7
      src/views/Favorites/bookmark.svg
  23. 63
      src/views/Favorites/index.js
  24. 41
      src/views/Product/Desktop/ProductOverAll/index.js
  25. 26
      src/views/Product/Desktop/index.js
  26. 84
      src/views/Products/layouts/Desktop/Main.js
  27. 14
      src/views/Profile/index.js
  28. 6
      src/views/ShoppingCart/Code/index.js
  29. 6
      src/views/Video/components/Desktop/Table.js
  30. 38
      src/views/Video/index.js

@ -82,15 +82,15 @@ BottomNavigation.defaultProps = {
},
{
id: 3,
name: "آزمون",
link: "/test",
name: "سبد خرید",
link: "/cart",
activeIcon: activeTestIcon,
deactiveIcon: deactiveTestIcon,
},
{
id: 4,
name: "حساب کاربری",
link: "/profile",
link: "/dashboard",
activeIcon: activeProfileIcon,
deactiveIcon: deactiveProfileIcon,
},

@ -0,0 +1,27 @@
import React from "react";
import { connect } from "react-redux";
//assets
import plusIcon from "./plus.svg";
export const FloatingButton = ({ action, position, icon }) => {
return (
<button
onClick={() => action()}
className={`fixed bg-blueC0 w-20 h-20 rounded-full transform transition-all hover:scale-110 active:scale-90 flex justify-center items-center shadow-xl z-10`}
style={position}
>
<img src={icon} alt="" className="w-7" style={{transform: 'translateX(-0px) translateY(3px)'}} />
</button>
);
};
const mapStateToProps = (state) => ({});
const mapDispatchToProps = {};
export default connect(mapStateToProps, mapDispatchToProps)(FloatingButton);
FloatingButton.defaultProps = {
icon: plusIcon,
};

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="36" viewBox="0 0 14 36">
<text id="_" data-name="+" transform="translate(14 24)" fill="#fff" font-size="24" font-family="IRANSansX-Medium, IRANSansX" font-weight="500"><tspan x="-13.44" y="0">+</tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 277 B

@ -14,7 +14,7 @@ const FooterDesign1 = ({ color, bg, items, hasHeader }) => {
return (
<>
{hasHeader ? (
<div className=" bg-gray-100 w-full">
<div className=" bg-gray-100 w-full z-20">
<div className="w-11/12 mx-auto flex items-center justify-between py-6 text-blue52">
<div className="flex items-center">
<div className="flex items-center ml-8 ">
@ -50,7 +50,7 @@ const FooterDesign1 = ({ color, bg, items, hasHeader }) => {
</div>
) : null}
<footer
className={`flex flex-col bg-gray-200 py-16 md:flex-row justify-around items-start md:items-start relative shadow-md ${bg}`}
className={`flex flex-col bg-gray-200 py-16 md:flex-row justify-around items-start md:items-start relative shadow-md z-20 ${bg}`}
>
<div className="w-11/12 flex justify-between">
<div className="flex flex-row gap-10">
@ -174,4 +174,5 @@ FooterDesign1.defaultProps = {
],
bg: "bg-white",
color: "text-gray-600",
hasHeader : true
};

@ -10,7 +10,7 @@ const initialState = {
filterResult: [],
subjects: [],
levels: [],
sortFilters: ["محبوب ترین", "جدیدترین"],
sortFilters: ["محبوب ترین", "جدیدترین", "ارزان ترین"],
selectedVideo: null,
gradeFilterBooks: null,
sortFilterCourse: null,

@ -96,7 +96,7 @@ function Router({ isDark, isMobile, headerOptions, dialog }) {
/>
}
/>
<Route path="/profile" exact element={<Auth page="profile" />} />
{/* <Route path="/profile" exact element={<Auth page="profile" />} /> */}
<Route
path="/products"
exact
@ -337,7 +337,23 @@ function Router({ isDark, isMobile, headerOptions, dialog }) {
/>
}
/>
<Route path="/dashboard" exact element={<Dashboard />} />
<Route
path="/dashboard"
exact
element={
<Dashboard
headerOptions={{
logo: true,
hamburgerMenu: true,
qr: true,
title: false,
shown: true,
menu: false,
back: false,
}}
/>
}
/>
<Route
path="/ar"
exact

@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { publicApi, userAddress } from "../../redux/actions";
import { publicApi, userAddress, dialog } from "../../redux/actions";
import onInput from "../../utils/onInput";
import Input from "../../components/Input";
import Select from "../../components/Select";
@ -26,17 +26,10 @@ export const Address = ({
cityLoading,
isMobile,
isDark,
setDialog
}) => {
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) {
@ -74,10 +67,7 @@ export const Address = ({
setDialog({
text: "نام خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-white dark:bg-black dark:bg-opacity-30",
color: "text-gray70 dark:text-white",
open: true,
});
return;
@ -86,10 +76,7 @@ export const Address = ({
setDialog({
text: "نام خانوادگی خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-white dark:bg-black dark:bg-opacity-30",
color: "text-gray70 dark:text-white",
open: true,
});
return;
@ -98,10 +85,7 @@ export const Address = ({
setDialog({
text: "شماره موبایل خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-white dark:bg-black dark:bg-opacity-30",
color: "text-gray70 dark:text-white",
open: true,
});
return;
@ -110,10 +94,7 @@ export const Address = ({
setDialog({
text: "شماره تلفن خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-white dark:bg-black dark:bg-opacity-30",
color: "text-gray70 dark:text-white",
open: true,
});
return;
@ -122,10 +103,7 @@ export const Address = ({
setDialog({
text: "نام استان خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-white dark:bg-black dark:bg-opacity-30",
color: "text-gray70 dark:text-white",
open: true,
});
return;
@ -134,10 +112,7 @@ export const Address = ({
setDialog({
text: "نام شهرستان خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-white dark:bg-black dark:bg-opacity-30",
color: "text-gray70 dark:text-white",
open: true,
});
return;
@ -146,10 +121,7 @@ export const Address = ({
setDialog({
text: "کد پستی خود را وارد کنید.",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-white dark:bg-black dark:bg-opacity-30",
color: "text-gray70 dark:text-white",
open: true,
});
return;
@ -158,10 +130,7 @@ export const Address = ({
setDialog({
text: "آدرس خود را از روی نقشه انتخاب کن",
type: "alert",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => {},
bg: "bg-white dark:bg-black dark:bg-opacity-30",
color: "text-gray70 dark:text-white",
open: true,
});
return;
@ -423,6 +392,7 @@ const mapDispatchToProps = {
getProvince: publicApi.getProvince,
getCity: publicApi.getCity,
createAddress: userAddress.add,
setDialog : dialog.set,
};
export default connect(mapStateToProps, mapDispatchToProps)(Address);

@ -2,11 +2,12 @@ import React, { useEffect } from "react";
import { connect } from "react-redux";
import { publicApi } from "../../redux/actions";
import Ticket from './layouts/Ticket';
import Ticket from "./layouts/Ticket";
import Header from "../Activation/components/Header";
import NotFound from "../Faq/components/NotFound";
import Info from "./layouts/Info";
import Map from "../../components/Map";
import Divider from "../../components/Divider";
//assets
import contactBgImage from "./contact-bg.svg";
@ -47,10 +48,11 @@ function Contact({ headerOptions, setHeaderOptions, info, isMobile, isDark }) {
<div className="w-1/3">
<Ticket />
</div>
<div className="w-1/3 flex flex-col">
<div className="w-1/3 flex flex-col justify-between">
{Object.keys(info).map((item, index) => (
<Info info={info[item]} key={index} />
))}
<Divider type="vertical" />
<NotFound
title={""}
subTitle={
@ -59,7 +61,10 @@ function Contact({ headerOptions, setHeaderOptions, info, isMobile, isDark }) {
link="/faq"
/>
</div>
<div className="w-1/3 rounded-md overflow-hidden" style={{height:'400px'}}>
<div
className="w-1/3 rounded-md overflow-hidden"
style={{ height: "400px" }}
>
<Map />
</div>
</div>

@ -55,7 +55,7 @@ export const Ticket = ({
accept: () => {},
open: true,
});
}else if(!ticket?.unit){
} else if (!ticket?.unit) {
setDialog({
text: "واحد مورد نظر خود را وارد نکرده اید.",
type: "alert",
@ -82,7 +82,7 @@ export const Ticket = ({
{!status && (
<>
<Input
width="55%"
width="100%"
label="نام و نام خانوادگی"
name="name"
onChange={(name, value) => setTicket({ name, value })}
@ -90,7 +90,7 @@ export const Ticket = ({
regex={(val) => val}
/>
<Input
width="55%"
width="100%"
label="شماره تماس"
name="cellphone"
onChange={(name, value) => setTicket({ name, value })}
@ -104,31 +104,36 @@ export const Ticket = ({
options={status && myProductList?.length ? opt : opt.slice(0, 3)}
name="unit"
onChange={(name, value) => setTicket({ name, value })}
width={"w-10/12"}
width={"w-full"}
backgroundColor={isDark ? "dark:bg-transparent dark:text-white" : ""}
fill={isDark ? "fill-white" : "fill-gray-600"}
/>
{ticket?.unit === "واحد محتوایی" && (
<Select
name="bookId"
options={[
...new Set(
myProductList?.map((item) => [
item?.product?.book?.id,
`${item?.product?.book.name} پایه ${
Object.values(grades)[item.product.book.gradeId]
}`,
]) || []
),
]}
onChange={(name, value) => setTicket({ name, value })}
width={"w-10/12"}
backgroundColor={isDark ? "dark:bg-transparent dark:text-white" : ""}
fill={isDark ? "fill-white" : "fill-gray-600"}
/>
<>
<div className="mt-2"></div>
<Select
name="bookId"
options={[
...new Set(
myProductList?.map((item) => [
item?.product?.book?.id,
`${item?.product?.book.name} پایه ${
Object.values(grades)[item.product.book.gradeId]
}`,
]) || []
),
]}
onChange={(name, value) => setTicket({ name, value })}
width={"w-full"}
backgroundColor={
isDark ? "dark:bg-transparent dark:text-white" : ""
}
fill={isDark ? "fill-white" : "fill-gray-600"}
/>
</>
)}
<Input
width="85%"
width="100%"
name="subject"
onChange={(name, value) => setTicket({ name, value })}
value={ticket?.subject || ""}

@ -3,7 +3,7 @@
color: gray !important;
margin: 10px auto;
width: 100%;
height: 50px;
height: 100px;
border-radius: 10px;
border: 2px dashed #d1d1d1;
position: relative;

@ -1,18 +1,15 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { publicApi } from "../../redux/actions";
//components
import Sidebar from "./layouts/SidebarMenu";
import Main from "./layouts/Main";
import Dialog from "../../components/Dialog";
export const Dashboard = ({ isMobile }) => {
const [dialog, setDialog] = useState({
text: null,
type: null,
setOpen: null,
accept: null,
color: null,
open: null,
});
export const Dashboard = ({ isMobile, headerOptions, setHeaderOptions }) => {
useEffect(() => {
setHeaderOptions(headerOptions);
},[]);
const [page, setPage] = useState("userItems");
@ -21,9 +18,8 @@ export const Dashboard = ({ isMobile }) => {
) : (
<div className="w-full">
<div className="gap-5 w-full h-screen pt-20 mx-auto flex flex-row bg-transparent justify-end">
<Sidebar page={page} setPage={setPage} setDialog={setDialog} dialog={dialog} />
<Sidebar page={page} setPage={setPage} />
<Main page={page} />
{dialog.open && <Dialog dialog={dialog} />}
</div>
</div>
);
@ -33,6 +29,8 @@ const mapStateToProps = (state) => ({
isMobile: state.publicApi.isMobile,
});
const mapDispatchToProps = {};
const mapDispatchToProps = {
setHeaderOptions: publicApi.setHeaderOptions,
};
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);

@ -0,0 +1,115 @@
import React from "react";
import { connect } from "react-redux";
import { userAddress, userFactor } from "../../../../../redux/actions";
//components
import Button from "../../../../../components/Button";
import FloatingButton from "../../../../../components/FloatingButton";
//assets
import menuIcon from "./menu.svg";
const ProfileAddress = ({
addresses,
update,
getList,
userId,
userAddressId,
getFactorInfo,
loading,
isMobile,
isDark,
}) => {
React.useEffect(() => {
getFactorInfo({ userId });
getList();
}, []);
return (
<div className={`flex-1 ${isMobile ? "" : "w-1/2"} mx-auto`}>
<div className={`p-0 m-0 flex flex-col mb-4`}>
{addresses.map((address, index) => (
<Location
address={address}
key={index}
userId={userId}
active={userAddressId === address?.id}
isDark={isDark}
update={update}
/>
))}
</div>
<FloatingButton
action={() => {}}
position={{ right: isMobile ? "" : 350, bottom: 50 }}
/>
</div>
);
};
const Location = ({ address, active, userId, isDark, update }) => {
return (
<div
className={`flex items-center w-full px-3 py-4 rounded-md mt-2 border-2 border-solid ${
active
? "border-gray-300 bg-blueC0 bg-opacity-5"
: "border-green-400 bg-white"
}`}
onClick={() =>
active ? {} : update({ userAddressId: address.id, userId })
}
>
<div className="flex flex-1 flex-col mr-2">
{active && (
<div className="w-full flex justify-between mb-3">
<div className="flex items-center">
<strong className="text-base">آدرس انتخابی شما</strong>
<span className="mr-4 text-sm">فعال</span>
</div>
<img src={menuIcon} alt="" className="w-6" />
</div>
)}
<div className="flex w-full">
<div className="flex flex-col flex-1 mb-4">
<span className="mb-2 leading-6">
{"آدرس:" + " " + address.address}
</span>
<span className="mb-2 leading-6">
{"نام:" + " " + address.firstName + " " + address.lastName}
</span>
<span className="mb-2 leading-6">
{"کد پستی:" + " " + address.postalCode}
</span>
<span className="mb-2 leading-6">
{"شماره تماس:" + " " + address.cellphone}
</span>
</div>
</div>
<Button
title="مشاهده روی نقشه"
backgroundColor={isDark ? "bg-blueC0" : "bg-blueC0"}
border={{ color: isDark ? "#ffffff55" : "#196EC055", width: "0px" }}
width="100%"
color={"text-white"}
onClick={() => {}}
/>
</div>
</div>
);
};
const mapStateToProps = (state) => ({
userId: state.user.status?.id,
userAddressId: state.userFactor.info?.userAddressId,
addresses: state.userAddress.list,
isMobile: state.publicApi.isMobile,
isDark: state.publicApi.isDark,
});
const mapDispatchToProps = {
getFactorInfo: userFactor.info,
update: userFactor.update,
getList: userAddress.list,
};
export default connect(mapStateToProps, mapDispatchToProps)(ProfileAddress);

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="vuesax_linear_more" data-name="vuesax/linear/more" transform="translate(0 24) rotate(-90)">
<g id="more">
<path id="Vector" d="M2,0A2,2,0,1,0,4,2,2.006,2.006,0,0,0,2,0Z" transform="translate(3 10)" fill="#07612c"/>
<path id="Vector-2" data-name="Vector" d="M2,0A2,2,0,1,0,4,2,2.006,2.006,0,0,0,2,0Z" transform="translate(17 10)" fill="#07612c"/>
<path id="Vector-3" data-name="Vector" d="M2,0A2,2,0,1,0,4,2,2.006,2.006,0,0,0,2,0Z" transform="translate(10 10)" fill="#07612c"/>
<path id="Vector-4" data-name="Vector" d="M0,0H24V24H0Z" fill="#07612c" opacity="0"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 707 B

@ -4,17 +4,26 @@ import { publicApi } from "../../../../redux/actions";
import Orders from "../../../Orders";
import UserItems from "../Main/UserItems";
import MyBooks from './MyBooks';
import MyBooks from "./MyBooks";
import Ticket from "../../../Contact/layouts/Ticket";
import Favorites from "../../../Favorites/index";
import Addresses from "./Addresses";
export const Main = ({ setHeaderOptions, page }) => {
useEffect(() => {
setHeaderOptions({ shown: true });
}, []);
const views = {
orders: <Orders />,
mybooks : <MyBooks />,
mybooks: <MyBooks />,
userItems: <UserItems />,
setTicket: (
<div className="w-1/2">
<Ticket />
</div>
),
favorites : <Favorites />,
addresses : <Addresses />
};
return (
<div

@ -0,0 +1,10 @@
<svg id="arrow-square" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="Group" transform="translate(5.34 6.75)">
<path id="Vector" d="M0,6.53V4.57A4.569,4.569,0,0,1,4.57,0H6.53" transform="translate(6.8 1.79)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-2" data-name="Vector" d="M0,0H1.96A4.569,4.569,0,0,1,6.53,4.57V8.7" transform="translate(0.28 1.8)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-3" data-name="Vector" d="M1.8,0,0,1.8,1.8,3.6" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-4" data-name="Vector" d="M0,0,1.8,1.8,0,3.6" transform="translate(11.52)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
</g>
<path id="Vector-5" data-name="Vector" d="M7,20h6c5,0,7-2,7-7V7c0-5-2-7-7-7H7C2,0,0,2,0,7v6C0,18,2,20,7,20Z" transform="translate(2 2)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-6" data-name="Vector" d="M0,0H24V24H0Z" fill="none" opacity="0"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -0,0 +1,6 @@
<svg id="archive-add" xmlns="http://www.w3.org/2000/svg" width="25.5" height="25.5" viewBox="0 0 25.5 25.5">
<path id="Vector" d="M5.313,0H0" transform="translate(10.094 11.316)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-2" data-name="Vector" d="M0,0V5.313" transform="translate(12.75 8.723)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-3" data-name="Vector" d="M14.344,0H4.1A4.111,4.111,0,0,0,0,4.1V19.072c0,1.912,1.371,2.72,3.049,1.8l5.185-2.879a2.251,2.251,0,0,1,1.987,0l5.185,2.879c1.679.935,3.049.128,3.049-1.8V4.1A4.127,4.127,0,0,0,14.344,0Z" transform="translate(3.528 2.125)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-4" data-name="Vector" d="M0,0H25.5V25.5H0Z" fill="none" opacity="0"/>
</svg>

After

Width:  |  Height:  |  Size: 925 B

@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react";
import Avatar from "../../../../components/Avatar";
import { connect } from "react-redux";
import {useNavigate} from "react-router-dom";
import { publicApi, user } from "../../../../redux/actions";
import { publicApi, user, dialog } from "../../../../redux/actions";
import "./index.scss";
@ -12,6 +12,11 @@ import moon from "./moon.svg";
import sms from "./sms.svg";
import userEdit from "./user-edit.svg";
import dropdownIcon from "../../../../assets/icons/dropdown-blue.svg";
import myVideosIcon from "./myVideos.svg";
import myBooksIcon from "./myBooks.svg";
import ordersIcon from "./orders.svg";
import favoritesIcon from "./favorites.svg";
import addressIcon from "./address.svg";
const SidebarMenu = ({
profile,
@ -23,8 +28,7 @@ const SidebarMenu = ({
setPage,
logout,
setDialog,
dialog,
isLogin
isLogin,
}) => {
const navigate = useNavigate();
const [toggleList, setToggleList] = useState({
@ -86,23 +90,35 @@ const SidebarMenu = ({
const buttons = [
{
icon: null,
icon: myBooksIcon,
title: "کتاب های من",
onClick: () => setPage("mybooks"),
name: "mybooks",
},
{
icon: null,
icon: myVideosIcon,
title: "ویدئوهای من",
onClick: () => setPage("myvideos"),
name: "myvideos",
},
{
icon: null,
icon: ordersIcon,
title: "سفارشات",
onClick: () => setPage("orders"),
name: "orders",
},
{
icon: favoritesIcon,
title: "علاقمندی ها",
onClick: () => setPage("favorites"),
name: "favorites",
},
{
icon: addressIcon,
title: "آدرس ها",
onClick: () => setPage("addresses"),
name: "addresses",
},
{ icon: moon, title: "حالت شب", onClick: () => {}, name: "dark" },
{
icon: logoutIcon,
@ -112,10 +128,7 @@ const SidebarMenu = ({
setDialog({
text: "میخوای تنهامون بذاری؟",
type: "confirm",
setOpen: (val) => setDialog({ ...dialog, open: val }),
accept: () => logout(),
bg: "bg-white bg-opacity-10",
color: "text-green4F",
open: true,
}),
name: "logout",
@ -129,10 +142,10 @@ const SidebarMenu = ({
},[isLogin]);
return (
<div
className="bg-gray-50 py-5 border-l-2 pl-4 pr-8 shadow-sm border-gray-300 border-solid overflow-y-scroll no-scrollbar divide-y divide-solid divide-gray-200"
className="bg-gray-50 py-5 border-l-2 pl-4 pr-2 shadow-sm border-gray-300 border-solid overflow-y-scroll no-scrollbar divide-y divide-solid divide-gray-200"
style={{
height: "calc(100vh - 80px)",
minWidth: 400,
minWidth: 300,
}}
>
{/* profile */}
@ -146,7 +159,6 @@ const SidebarMenu = ({
list={support.list}
title={support.title}
name={support.name}
active={true}
icon={support.icon}
active={dashboardOptions.support}
/>
@ -154,7 +166,6 @@ const SidebarMenu = ({
list={profile.list}
title={profile.title}
name={profile.name}
active={true}
icon={profile.icon}
active={dashboardOptions.profile}
/>
@ -193,6 +204,7 @@ const mapStateToProps = (state) => ({
const mapDispatchToProps = {
setDashboardOptions: publicApi.setDashboardOptions,
logout: user.logout,
setDialog : dialog.set,
};
export default connect(mapStateToProps, mapDispatchToProps)(SidebarMenu);
@ -211,7 +223,7 @@ SidebarMenu.defaultProps = {
title: "پشتیبانی",
notification: null,
list: [
{ title: "تیکت ها", value: "tickets" },
{ title: "ثبت نظر", value: "setTicket" },
],
},
};

@ -0,0 +1,7 @@
<svg id="book" xmlns="http://www.w3.org/2000/svg" width="24" height="23.746" viewBox="0 0 24 23.746">
<path id="Vector" d="M20,13.886V1.98A1.959,1.959,0,0,0,17.83.017h-.06A19.029,19.029,0,0,0,10.7,2.355l-.17.109a1.121,1.121,0,0,1-1.06,0l-.25-.148A18.935,18.935,0,0,0,2.16.007,1.957,1.957,0,0,0,0,1.97V13.886a2.036,2.036,0,0,0,1.74,1.953l.29.039a25.941,25.941,0,0,1,7.44,2.407l.04.02a1.094,1.094,0,0,0,.96,0,25.705,25.705,0,0,1,7.46-2.427l.33-.039A2.036,2.036,0,0,0,20,13.886Z" transform="translate(2 2.662)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-2" data-name="Vector" d="M0,0V15" transform="translate(12 5.236)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-3" data-name="Vector" d="M2.25,0H0" transform="translate(17.705 8.4)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-4" data-name="Vector" d="M3,0H0" transform="translate(16.918 11.369)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-5" data-name="Vector" d="M0,0H24V23.746H0Z" transform="translate(24 23.746) rotate(180)" 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="24.613" height="21.519" viewBox="0 0 24.613 21.519">
<g id="Group_2005" data-name="Group 2005" transform="translate(0.75 0.75)">
<g id="vuesax_linear_music-playlist" data-name="vuesax/linear/music-playlist">
<g id="music-playlist" transform="translate(0)">
<path id="Vector" d="M17.335,20.019H5.778c-3.467,0-5.778-2-5.778-6.673V6.673C0,2,2.311,0,5.778,0H17.335c3.467,0,5.778,2,5.778,6.673v6.673C23.113,18.017,20.8,20.019,17.335,20.019Z" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
</g>
</g>
<path id="Vector-2" data-name="Vector" d="M0,3.572V2.108C0,.23,1.329-.538,2.951.4l1.268.732,1.268.732c1.622.939,1.622,2.476,0,3.415L4.22,6.011l-1.268.732C1.329,7.681,0,6.913,0,5.035V3.572Z" transform="translate(8.204 6.438)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 961 B

@ -0,0 +1,7 @@
<svg id="bag-2" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path id="Vector" d="M0,5.662v-.97A4.773,4.773,0,0,1,4.06.022,4.5,4.5,0,0,1,9,4.5v1.38" transform="translate(7.5 2.008)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-2" data-name="Vector" d="M5.751,14h6c4.02,0,4.74-1.61,4.95-3.57l.75-6c.27-2.44-.43-4.43-4.7-4.43h-8C.481,0-.219,1.99.051,4.43l.75,6C1.011,12.39,1.731,14,5.751,14Z" transform="translate(3.249 8)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
<path id="Vector-3" data-name="Vector" d="M.495.5H.5" transform="translate(15.001 11.5)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
<path id="Vector-4" data-name="Vector" d="M.495.5H.5" transform="translate(8 11.5)" fill="none" stroke="#37a865" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
<path id="Vector-5" data-name="Vector" d="M0,0H24V24H0Z" fill="none" opacity="0"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 60 KiB

@ -0,0 +1,7 @@
<svg id="vuesax_linear_archive-add" data-name="vuesax/linear/archive-add" xmlns="http://www.w3.org/2000/svg" width="29.778" height="29.778" viewBox="0 0 29.778 29.778">
<g id="archive-add" transform="translate(0)">
<path id="Vector" d="M16.75,0H4.789A4.8,4.8,0,0,0,0,4.789V22.272c0,2.233,1.6,3.176,3.561,2.1l6.055-3.362a2.628,2.628,0,0,1,2.32,0l6.055,3.362c1.96,1.092,3.561.149,3.561-2.1V4.789A4.819,4.819,0,0,0,16.75,0Z" transform="translate(4.119 2.482)" fill="#37a865"/>
<path id="Vector-2" data-name="Vector" d="M0,0H29.778V29.778H0Z" fill="none" opacity="0"/>
<path id="Vector-3" data-name="Vector" d="M6.2,0H0" transform="translate(11.787 13.214)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 776 B

@ -0,0 +1,63 @@
import React from "react";
import { connect } from "react-redux";
//assets
import bookImage from "./book.svg";
import bookmarkIcon from "./bookmark.svg";
const Favorites = ({ bookmarkList, isMobile }) => {
const Bookmark = ({ bookmark }) => {
return (
<div className="lg:w-1/2 xl:w-1/3 p-2 mb-4">
<div
className={`flex justify-between px-3.5 py-2 border-2 border-gray-300 border-solid rounded-md relative`}
>
<div className={"flex w-full"}>
<img src={bookmark.image} alt="" className="w-1/5" />
<div className={`flex flex-col mr-2 pt-2`}>
<strong className="text-base text-gray1">{bookmark.name}</strong>
<span className="text-sm mt-2 text-green7B font-bold">{bookmark.grade}</span>
</div>
</div>
<img src={bookmarkIcon} alt="" className="w-7 absolute left-2 top-2" />
</div>
</div>
);
};
return (
<div className="flex flex-row flex-wrap">
{bookmarkList.map((bookmark, index) => (
<Bookmark key={index} bookmark={bookmark} />
))}
</div>
);
};
const mapStateToProps = (state) => ({
loading: state.userFactor.loading,
isMobile: state.publicApi.isMobile,
});
const mapDispatchToProps = {};
export default connect(mapStateToProps, mapDispatchToProps)(Favorites);
Favorites.defaultProps = {
bookmarkList: [
{
name: "کتاب آموزشی علوم تجربی",
grade: "پایه ششم ابتدایی",
image: bookImage,
},
{
name: "کتاب آموزشی علوم تجربی",
grade: "پایه ششم ابتدایی",
image: bookImage,
},
{
name: "کتاب آموزشی علوم تجربی",
grade: "پایه ششم ابتدایی",
image: bookImage,
},
],
};

@ -6,6 +6,8 @@ import Button from "../../../../components/Button";
import StarRating from "../../../../components/StarRating";
import ProductImages from "../../../../components/ProductImage";
import ProductStatusCard from "../../../../components/ProductStatusCard";
import ProductTab from "../../../../components/ProductTab";
import Table from "../../../Video/components/Desktop/Table";
//assets
import arrow from "../../../../assets/icons/dropdown-blue.svg";
@ -13,7 +15,7 @@ import arrow from "../../../../assets/icons/dropdown-blue.svg";
export const ProductOverAll = ({ book, grades, isDark, loading }) => {
const [type, setType] = useState("1");
return (
<div className="w-full">
<div className="w-full flex flex-col">
<header className={`w-full flex flex-row justify-between gap-5`}>
<ProductImages images={book?.fileIds} />
<div className="flex flex-col w-1/2 divide-y divide-solid divide-gray-200">
@ -29,7 +31,8 @@ export const ProductOverAll = ({ book, grades, isDark, loading }) => {
<StarRating value={book?.rate || 4} />
</div>
<div className="p-2 border-0 border-solid border-r border-gray-100 text-sm text-gray-400">
بیش از {book?.product[type]?.suggestedCounter} نفر امتیاز داده اند
بیش از {book?.product[type]?.suggestedCounter} نفر امتیاز داده
اند
</div>
</div>
</div>
@ -96,7 +99,11 @@ export const ProductOverAll = ({ book, grades, isDark, loading }) => {
className="bg-blueC0 text-green7B bg-opacity-5 font-semibold text-tiny rounded-md border border-solid border-blueC0 w-2/3 py-4 text-center flex flex-row items-center justify-center"
>
مشاهده دوره ویدیویی این محصول
<img src={arrow} alt="" className="mr-2 transform rotate-90 w-5" />
<img
src={arrow}
alt=""
className="mr-2 transform rotate-90 w-5"
/>
</Link>
</div>
</div>
@ -113,6 +120,34 @@ export const ProductOverAll = ({ book, grades, isDark, loading }) => {
/>
</div>
</header>
{book?.product[type]?.properties?.length > 0 && (
<ProductTab
tabs={[
{
title: "مشخصات",
components: (
<Table specifications={book?.product[type]?.properties} />
),
},
{
title: "نقد و بررسی",
components: (
<div className="bg-gray-100 rounded-md mt-4 w-full flex justify-center items-center h-40 text-green4F text-tiny">
این بخش فعلا قابل دسترسی نیست.
</div>
),
},
{
title: "پرسش و پاسخ",
components: (
<div className="bg-gray-100 rounded-md mt-4 w-full flex justify-center items-center h-40 text-green4F text-tiny">
این بخش فعلا قابل دسترسی نیست.
</div>
),
},
]}
/>
)}
</div>
);
};

@ -2,12 +2,10 @@ import React, { useEffect } from "react";
//components
import ProductOverAll from "./ProductOverAll";
import ProductTab from "../../../components/ProductTab";
import ProductSuggestions from "../../../components/ProductSuggestion";
import Rate from "../Rate";
import Comments from "../../../components/Comments";
import QandA from "../../../components/QandA";
import Table from "../../Video/components/Desktop/Table";
const DesktopProductLayout = () =>{
@ -17,30 +15,6 @@ const DesktopProductLayout = () =>{
return (
<div className="w-11/12 flex flex-col overflow-y-hidden mt-3 mb-64 items-center">
<ProductOverAll />
<ProductTab
tabs={[
{
title: "مشخصات",
components: <Table />,
},
{
title: "نقد و بررسی",
components: (
<div className="bg-gray-100 rounded-md mt-4 w-full flex justify-center items-center h-40 text-green4F text-tiny">
این بخش فعلا قابل دسترسی نیست.
</div>
),
},
{
title: "پرسش و پاسخ",
components: (
<div className="bg-gray-100 rounded-md mt-4 w-full flex justify-center items-center h-40 text-green4F text-tiny">
این بخش فعلا قابل دسترسی نیست.
</div>
),
},
]}
/>
<div className="w-full">
<ProductSuggestions />
</div>

@ -7,8 +7,15 @@ import Product from "../../../../components/Product";
import VodProduct from "../../../../components/VodProduct";
import Loading from "../../../../components/Loading";
import { book, publicApi } from "../../../../redux/actions";
import moment from "jalali-moment";
export const Main = ({ books, grades, sortMethods, filterOptions }) => {
export const Main = ({
books,
grades,
sortMethods,
filterOptions,
setFilterOptions,
}) => {
const [filterLoading, setFilterLoading] = useState(false);
useEffect(() => {
@ -27,6 +34,7 @@ export const Main = ({ books, grades, sortMethods, filterOptions }) => {
let byGradeFilter;
let bySubjectFilter;
let byAvailableFilter;
let bySortFilter;
if (grade) {
byGradeFilter = books?.filter((book) => grades[book?.gradeId] === grade);
} else {
@ -48,8 +56,27 @@ export const Main = ({ books, grades, sortMethods, filterOptions }) => {
} else {
byAvailableFilter = bySubjectFilter;
}
if (sort) {
if (sort === "ارزان ترین") {
bySortFilter = byAvailableFilter?.sort(
(a, b) => a.product[type].price - b.product[type].price
);
} else if (sort === "محبوب ترین") {
bySortFilter = byAvailableFilter?.sort(
(a, b) => a.product[type].rate - b.product[type].rate
);
} else if (sort === "جدیدترین") {
bySortFilter = byAvailableFilter?.sort(
(a, b) => moment(a.createdAt) - moment(b.createdAt)
);
} else {
bySortFilter = byAvailableFilter;
}
} else {
bySortFilter = byAvailableFilter;
}
return type === 2
? byAvailableFilter?.map((item, index) => (
? bySortFilter?.map((item, index) => (
<VodProduct
video={item}
key={index}
@ -58,7 +85,7 @@ export const Main = ({ books, grades, sortMethods, filterOptions }) => {
grades={grades}
/>
))
: byAvailableFilter?.map((product, index) => (
: bySortFilter?.map((product, index) => (
<>
{(productType ? productType === "کتاب دیجیتال" : true) && (
<Link
@ -95,9 +122,12 @@ export const Main = ({ books, grades, sortMethods, filterOptions }) => {
};
return (
<div className="flex flex-col w-3/4 relative pb-20 min-h-screen" style={{minWidth: 'calc(100% * 3 / 4)'}}>
<div
className="flex flex-col w-3/4 pb-20 min-h-screen"
style={{ minWidth: "calc(100% * 3 / 4)" }}
>
<div className="flex w-full bg-blue rounded-lg border border-solid border-gray-200 p-2 items-center my-1.5 justify-center text-blue52">
<div className="flex text-sm items-center mx-2">
<div className="flex text-sm items-center mr-2 ml-4">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
@ -163,30 +193,41 @@ export const Main = ({ books, grades, sortMethods, filterOptions }) => {
{sortMethods?.map((item, index) => (
<li
key={index}
className="text-sm rounded text-black py-2 px-3 transition-all duration-700 hover:bg-greenBA hover:bg-opacity-5 hover:text-greenBA cursor-pointer"
className={`text-sm rounded text-black py-2 px-3 transition-all font-semibold duration-300 cursor-pointer ${
filterOptions.sort === item ? "bg-greenBA text-white" : ""
}`}
onClick={() =>
filterOptions.sort !== item
? setFilterOptions({ ...filterOptions, sort: item })
: setFilterOptions({ ...filterOptions, sort: null })
}
>
{item}
</li>
))}
</ul>
</div>
{(filterOptions?.productType
? filterOptions.productType === "دوره ویدئویی"
: true) && (
<ScrollingCarousel className="py-3 max-w-full">{Items(2)}</ScrollingCarousel>
)}
<div className="flex flex-col w-full relative">
{filterLoading && (
<div
className="w-full flex justify-center items-center bg-white bg-opacity-70 z-20 backdrop-filter backdrop-blur-xl absolute left-0 top-0"
style={{ height: "calc(100vh - 180px)" }}
>
<Loading size={4} color="bg-green-400" />
</div>
)}
{(filterOptions?.productType
? filterOptions.productType === "دوره ویدئویی"
: true) && (
<ScrollingCarousel className="py-3 max-w-full">
{Items(2)}
</ScrollingCarousel>
)}
<div className="w-full flex flex-row flex-wrap mt-0 border-t-2 border-solid border-gray-100 overflow-y-hidden gap-4 justify-evenly pt-3">
{Items(1)}
</div>
{filterLoading && (
<div
className="w-full flex justify-center items-center bg-white bg-opacity-20 backdrop-filter backdrop-blur-xl absolute left-0 top-0"
style={{ height: "calc(100vh - 80px)" }}
>
<Loading size={4} color="bg-green-400" />
<div className="w-full flex flex-row flex-wrap mt-0 border-t-2 border-solid border-gray-100 overflow-y-hidden gap-4 justify-evenly pt-3">
{Items(1)}
</div>
)}
</div>
</div>
);
};
@ -205,6 +246,7 @@ const mapStateToProps = (state) => ({
const mapDispatchToProps = {
getList: book.list,
setHeaderOptions: publicApi.setHeaderOptions,
setFilterOptions: book.setFilterOptions,
};
export default connect(mapStateToProps, mapDispatchToProps)(Main);

@ -0,0 +1,14 @@
import React from 'react'
import { connect } from 'react-redux'
export const Profile = ({}) => {
return (
<div>Profile</div>
)
}
const mapStateToProps = (state) => ({})
const mapDispatchToProps = {}
export default connect(mapStateToProps, mapDispatchToProps)(Profile)

@ -10,14 +10,14 @@ function Code({ codeId, setCodeId, userId, factorId }) {
}
return (
<form className="flex w-full flex-row border border-blueC0 border-solid rounded-md mt-3 mb-4 overflow-hidden lg:w-2/5 lg:mt-5">
<div className="flex w-full flex-row border border-blueC0 border-solid rounded-md mt-3 mb-4 overflow-hidden lg:w-2/5 lg:mt-5">
<input
type="text"
className="border-0 flex-1 text-right pr-3 font-medium text-tiny dark:bg-gray2077 placeholder:text-blue5F dark:text-white outline-none lg:text-base lg:font-bold"
placeholder={"کد تخفیف دارید ؟"}
/>
<button className={"py-3 px-4 lg:py-4 text-tiny bg-blueC0 text-white border border-blueC0 border-solid lg:font-bold"} onClick={setOff}>ثبت کد</button>
</form>
<button className={"py-3 px-4 lg:py-4 text-tiny bg-blueC0 text-white border border-blueC0 border-solid lg:font-bold"} onClick={() => setOff()}>ثبت کد</button>
</div>
);
}

@ -14,19 +14,19 @@ const persian = {
const Table = ({ specifications }) => {
return (
<ul className="w-full">
{Object.keys(specifications).map((specification, index) => (
{specifications?.map((property, index) => (
<li className="flex my-3 cursor-pointer group" key={index}>
<div
className=" bg-grayF9 rounded px-3 py-4 ml-2 text-greenBA text-sm group-hover:bg-blueC0 group-hover:bg-opacity-10"
style={{ flex: 2 }}
>
{persian[specification]}
{property.description}
</div>
<div
className="bg-grayF9 rounded px-3 py-4 text-sm group-hover:bg-blueC0 group-hover:bg-opacity-10"
style={{ flex: 8 }}
>
{specifications[specification]}
{property.value}
</div>
</li>
))}

@ -5,12 +5,15 @@ import { Link } from "react-router-dom";
import { publicApi, userProduct } from "../../redux/actions";
import location from "../../utils/location";
import separate from "../../utils/separate";
//components
import Season from "./components/Season";
import Videos from "./components/Desktop/Videos";
import StarRating from "../../components/StarRating";
import Button from "../../components/Button";
import ProductTab from "../../components/ProductTab";
import Table from "./components/Desktop/Table";
import Comments from "../../components/Comments";
//assets
import tickIcon from "../../components/ProductStatusCard/tick-circle.svg";
@ -117,7 +120,13 @@ function Video({
},
{
title: "مشخصات",
components: <Table />,
components: (
<Table
specifications={
book?.product[2]?.properties.length > 0 || []
}
/>
),
},
{
title: "نقد و بررسی",
@ -144,35 +153,39 @@ function Video({
<h1 className="text-blue5F mb-3 font-semibold text-xl dark:text-white">
{"دوره ویدئویی" + " " + book?.product[2]?.name}
</h1>
<div className="text-blueC0 text-sm dark:text-greenBA">
<div className="text-blueC0 text-tiny dark:text-greenBA font-bold">
{"پایه" + " " + grades[book?.gradeId]}
</div>
<div className="flex justify-end">
<div className="p-2">
<StarRating value={book?.rate || 4} />
<StarRating value={book?.product[2]?.rate || 4} />
</div>
<div className="p-2 border-0 border-solid border-r border-gray-100 text-sm text-gray-400">
بیش از 160 نفر امتیاز داده اند
بیش از {book?.product[2]?.suggestedCounter} نفر امتیاز داده اند
</div>
</div>
</div>
<div className="bg-grayF9 w-full flex flex-col rounded-md divide-y divide-solid divide-gray-200 mb-4">
<div className="flex flex-row justify-center items-center w-full gap-5 my-5">
<div className="bg-grayF9 w-full flex flex-col rounded-md divide-y divide-solid divide-gray-200 mb-4 px-4">
<div className="flex flex-row items-center w-full gap-5 my-5">
<img src={tickIcon} alt="" className="w-9" />
<p className="text-blue52 text-sm font-light">{`توسعه خرید توسط ${
book?.recommendedPeople || 4234
<p className="text-blue52 text-sm font-light">{`توصیه خرید توسط ${
book?.product[2]?.suggestedCounter
} نفر`}</p>
</div>
<div className="flex flex-col w-full py-4 px-4">
<div className="flex flex-row items-center justify-center gap-2">
<strong className="text-blueC0 text-xl">
<strong className="text-blueC0 text-5xl">
{separate(book?.product[2]?.price)}
</strong>
<span className="text-sm text-gray-500">تومان</span>
</div>
<p className="text-gray-500 text-xs text-center mt-2 mb-4">
با خرید این کالا 540.000 صرفه جویی کنید
</p>
{book?.product[2]?.fakePrice ? (
<p className="text-gray-500 text-xs text-center mt-2 mb-4">
با خرید این کالا 540.000 صرفه جویی کنید
</p>
) : (
<div className="mb-4"></div>
)}
<Button
title="اضافه کردن به سبد خرید"
backgroundColor={isDark ? "bg-blueC0" : "bg-blueC0"}
@ -204,6 +217,7 @@ function Video({
</Link>
</div>
</header>
<Comments indent={false} />
</div>
);
}

Loading…
Cancel
Save