├── .gitignore
├── .prettierrc
├── README.md
├── craco.config.js
├── package.json
├── public
├── _redirects
├── favicon-32x32.png
├── favicon.ico
├── index.html
├── manifest.json
├── robots.txt
└── shop.png
├── src
├── App.js
├── App.scss
├── assets
│ ├── coupon.png
│ ├── delete.png
│ ├── delivery.png
│ ├── frontpage.svg
│ ├── shop.svg
│ ├── uempty_cart.svg
│ └── wishlist.png
├── components
│ ├── Aboutus
│ │ ├── Aboutus.jsx
│ │ ├── bike.svg
│ │ ├── delivered.svg
│ │ ├── qual.svg
│ │ ├── rating.svg
│ │ └── undraw_profile_pic_ic5t.svg
│ ├── AddressPage
│ │ ├── AddressCard.jsx
│ │ ├── AddressForm.jsx
│ │ ├── AddressModal.js
│ │ ├── AddressPage.jsx
│ │ ├── OrderSuccess.jsx
│ │ └── SelectAddress.jsx
│ ├── Cart.jsx
│ ├── Categories
│ │ ├── Categories.jsx
│ │ ├── CategoryCard.jsx
│ │ └── CircularCard.jsx
│ ├── Footer
│ │ ├── Async.svg
│ │ ├── Footer.css
│ │ ├── Footer.jsx
│ │ └── wave.svg
│ ├── Home.jsx
│ ├── LandingPageItems
│ │ ├── Banner.jsx
│ │ ├── Container.jsx
│ │ ├── ItemCard.jsx
│ │ ├── Items.jsx
│ │ └── LandingPageItems.jsx
│ ├── Loading.js
│ ├── Navbar.jsx
│ ├── OrderPage
│ │ ├── EmptyOrder.jsx
│ │ ├── OrderItem.jsx
│ │ ├── Orderpage.jsx
│ │ └── RatingStars.jsx
│ ├── ProductDetails
│ │ └── ProductDetails.js
│ ├── Products
│ │ ├── Card.js
│ │ └── ProductsList.js
│ ├── ToastContainer.js
│ ├── Wishlist
│ │ ├── EmptyWishlist.jsx
│ │ ├── Wishlist.jsx
│ │ ├── WishlistCard.jsx
│ │ └── icon.svg
│ ├── cart.scss
│ └── icons
│ │ └── navIcon.js
├── config
│ ├── axios.config.js
│ └── myLog.js
├── images
│ ├── categories-accessories.jpg
│ ├── categories-cosmetics.jpg
│ ├── categories-electronics.jfif
│ ├── categories-footwear.jpg
│ ├── categories-home-decor.jpg
│ ├── categories-kids-wear.jpg
│ ├── categories-mens-clothing.jpg
│ ├── categories-womens-clothing.jpg
│ └── order-images
│ │ ├── deliveredicon.svg
│ │ ├── emptyOrder.svg
│ │ └── successfulorder.svg
├── index.js
├── index.scss
├── redux
│ ├── slices
│ │ ├── Cartslice.js
│ │ ├── addressSlice.js
│ │ ├── orderSlice.js
│ │ ├── productSlice.js
│ │ └── whishlistSlice.js
│ └── store.js
├── services
│ ├── addresses.js
│ ├── api.js
│ ├── orders.js
│ ├── products.js
│ └── wishlist.js
└── styles
│ ├── home.scss
│ └── productList.scss
├── tailwind.config.js
├── tailwindcss-config.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .env
8 |
9 | # testing
10 | /coverage
11 |
12 | # production
13 | /build
14 |
15 | # misc
16 | .DS_Store
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
26 | package-lock.json
27 | /.vscode
28 | /build
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "es5",
4 | "endOfLine": "lf"
5 | }
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Async Store
2 |
3 |
4 |
5 |
6 |
7 |
8 | [](https://app.netlify.com/sites/asyncstore/deploys)
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ##
17 |
18 | - [Shop Now](https://asyncstore.netlify.app/)
19 | - [Demo](https://drive.google.com/file/d/1zP8nYBfEcFiyl37Is-a_EL7TYttcOYjh/view?usp=sharing)
20 |
21 | ## Screenshot
22 |
23 | 
24 | 
25 | 
26 | 
27 |
28 | ## Contributers
29 |
30 | - [Sukhseerat](https://github.com/Sukhseerat-Kaur)
31 | - [VivekBcloud](https://github.com/VivekBcloud)
32 | - [Ashirbad](https://github.com/ashirbad29)
33 | - [Shrey](https://github.com/signifershrey)
34 | - [harsh](https://github.com/harsh010501)
35 | - [Arun](https://github.com/Arunsahu07)
36 | - [Swaijot ](https://github.com/swag1223)
37 |
--------------------------------------------------------------------------------
/craco.config.js:
--------------------------------------------------------------------------------
1 | // craco.config.js
2 | module.exports = {
3 | style: {
4 | postcss: {
5 | plugins: [require('tailwindcss'), require('autoprefixer')],
6 | },
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "async-ecommerce",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@craco/craco": "^6.2.0",
7 | "@headlessui/react": "^1.4.0",
8 | "@heroicons/react": "^1.0.4",
9 | "@material-ui/core": "^4.12.3",
10 | "@material-ui/icons": "^4.11.2",
11 | "@material-ui/lab": "^4.0.0-alpha.60",
12 | "@reduxjs/toolkit": "^1.6.1",
13 | "@testing-library/jest-dom": "^5.11.4",
14 | "@testing-library/react": "^11.1.0",
15 | "@testing-library/user-event": "^12.1.10",
16 | "axios": "^0.21.1",
17 | "fontawesome": "^5.6.3",
18 | "prettier": "^2.3.2",
19 | "react": "^17.0.2",
20 | "react-dom": "^17.0.2",
21 | "react-fontawesome": "^1.7.1",
22 | "react-hot-toast": "^2.1.0",
23 | "react-modal": "^3.14.3",
24 | "react-redux": "^7.2.4",
25 | "react-router-dom": "^5.2.0",
26 | "react-scripts": "4.0.3",
27 | "react-scroll": "^1.8.3",
28 | "redux": "^4.1.1",
29 | "sass": "^1.38.0",
30 | "web-vitals": "^1.0.1"
31 | },
32 | "scripts": {
33 | "start": "craco start",
34 | "build": "craco build",
35 | "test": "craco test",
36 | "eject": "react-scripts eject",
37 | "watch:css": "postcss src/styles/tailwind.css -o src/styles/output.css"
38 | },
39 | "eslintConfig": {
40 | "extends": [
41 | "react-app",
42 | "react-app/jest"
43 | ]
44 | },
45 | "browserslist": {
46 | "production": [
47 | ">0.2%",
48 | "not dead",
49 | "not op_mini all"
50 | ],
51 | "development": [
52 | "last 1 chrome version",
53 | "last 1 firefox version",
54 | "last 1 safari version"
55 | ]
56 | },
57 | "devDependencies": {
58 | "autoprefixer": "^9",
59 | "postcss": "^7",
60 | "postcss-cli": "^8.3.1",
61 | "tailwindcss": "npm:@tailwindcss/postcss7-compat"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/public/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
--------------------------------------------------------------------------------
/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/public/favicon-32x32.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
14 | Async Store
15 |
16 |
17 | You need to enable JavaScript to run this app.
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/public/shop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/public/shop.png
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Suspense } from 'react';
2 | import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
3 | import Navbar from './components/Navbar';
4 |
5 | import Loading from './components/Loading';
6 | import './App.scss';
7 | import ToastContainer from './components/ToastContainer';
8 |
9 | // Dynamic Imports
10 | const Home = React.lazy(() => import('./components/Home'));
11 | const Aboutus = React.lazy(() => import('./components/Aboutus/Aboutus'));
12 | const ProductsList = React.lazy(() =>
13 | import('./components/Products/ProductsList')
14 | );
15 | const Orderpage = React.lazy(() => import('./components/OrderPage/Orderpage'));
16 | const Wishlist = React.lazy(() => import('./components/Wishlist/Wishlist'));
17 | const Cart = React.lazy(() => import('./components/Cart'));
18 | const ProductDetails = React.lazy(() =>
19 | import('./components/ProductDetails/ProductDetails')
20 | );
21 | const OrderSuccess = React.lazy(() =>
22 | import('./components/AddressPage/OrderSuccess')
23 | );
24 | const AddressPage = React.lazy(() =>
25 | import('./components/AddressPage/AddressPage')
26 | );
27 |
28 | function App() {
29 | return (
30 |
31 |
32 |
33 |
34 |
35 | }>
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | );
50 | }
51 |
52 | export default App;
53 |
--------------------------------------------------------------------------------
/src/App.scss:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@100;400&display=swap');
2 |
3 | body {
4 | &::-webkit-scrollbar {
5 | width: 8px;
6 | background-color: #d9d0e8;
7 | border-radius: 5px;
8 | overflow: hidden;
9 | }
10 | &::-webkit-scrollbar-thumb {
11 | background-color: #a39cb1;
12 | // border-radius: 5px;
13 | }
14 | }
15 |
16 | .custom-scroll {
17 | &::-webkit-scrollbar {
18 | width: 8px;
19 | background-color: #d9d0e8;
20 | border-radius: 5px;
21 | overflow: hidden;
22 | }
23 | &::-webkit-scrollbar-thumb {
24 | background-color: #a39cb1;
25 | border-radius: 5px;
26 | }
27 | }
28 | .App {
29 | // background-color: #f5f3f7;
30 | font-family: 'Montserrat', sans-serif;
31 | box-sizing: border-box;
32 | }
33 |
34 | .App-header {
35 | min-height: 100vh;
36 | display: flex;
37 | flex-direction: column;
38 | align-items: center;
39 | justify-content: center;
40 | font-size: calc(10px + 2vmin);
41 | color: #000;
42 | }
43 |
44 | .categories-electronics {
45 | background: url(./images/categories-electronics.jfif) no-repeat center
46 | center/cover;
47 | }
48 |
49 | .categories-mens-clothing {
50 | background: url(./images/categories-mens-clothing.jpg) no-repeat center
51 | center/cover;
52 | }
53 |
54 | .categories-womens-clothing {
55 | background: url(./images/categories-womens-clothing.jpg) no-repeat center
56 | center/cover;
57 | }
58 |
59 | .categories-kids-wear {
60 | background: url(./images/categories-kids-wear.jpg) no-repeat center
61 | center/cover;
62 | }
63 |
64 | .categories-footwear {
65 | background: url(./images/categories-footwear.jpg) no-repeat top center/cover;
66 | }
67 |
68 | .categories-accessories {
69 | background: url(./images/categories-accessories.jpg) no-repeat center
70 | center/cover;
71 | }
72 |
73 | .categories-home-decor {
74 | background: url(./images/categories-home-decor.jpg) no-repeat center
75 | center/cover;
76 | }
77 |
78 | .categories-cosmetics {
79 | background: url(./images/categories-cosmetics.jpg) no-repeat center
80 | center/cover;
81 | }
82 |
83 | .navbar-link {
84 | color: black;
85 | font-size: 1.275rem;
86 | font-weight: 500;
87 | // margin: 0px 3px 0px 3px;
88 | padding: 3px 2px;
89 | text-decoration: none;
90 | position: relative;
91 |
92 | &:after {
93 | bottom: -4px;
94 | content: '';
95 | display: block;
96 | height: 2px;
97 | left: 0;
98 | position: absolute;
99 | background: rgba(236, 72, 153, 1);
100 | opacity: 0.6;
101 | transition: width 0.6s ease 0s, opacity 0.6s ease 0s;
102 | width: 0;
103 | }
104 |
105 | &:hover:after {
106 | width: 100%;
107 | opacity: 0.9;
108 | }
109 | }
110 | .active-class {
111 | color: rgba(236, 72, 153, 1);
112 | }
113 |
--------------------------------------------------------------------------------
/src/assets/coupon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/src/assets/coupon.png
--------------------------------------------------------------------------------
/src/assets/delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/src/assets/delete.png
--------------------------------------------------------------------------------
/src/assets/delivery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/src/assets/delivery.png
--------------------------------------------------------------------------------
/src/assets/shop.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/assets/uempty_cart.svg:
--------------------------------------------------------------------------------
1 | empty_cart
--------------------------------------------------------------------------------
/src/assets/wishlist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/src/assets/wishlist.png
--------------------------------------------------------------------------------
/src/components/Aboutus/Aboutus.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import good from './qual.svg';
3 | import bike from './bike.svg';
4 | import review from './rating.svg';
5 | import onmywad from './delivered.svg';
6 | import Footer from '../Footer/Footer';
7 | import profile from './undraw_profile_pic_ic5t.svg';
8 |
9 | const Aboutus = () => {
10 | return (
11 | <>
12 |
13 | Our Story
14 |
15 |
16 |
17 | Providing our customers with a sophisticated ecommerce retail
18 | shopping experience. Our products coupled with a relaxed and
19 | gourmet atmosphere appeals to a wide variety of customers. With
20 | top-rated selections in fine quality clothing products, cosmetic
21 | products,and other accessories, Async Store is committed to
22 | providing the best merchandise selection at the lowest possible
23 | prices.
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | 2.7K
36 |
37 |
Visitors
38 |
39 |
40 |
41 | 1.8K
42 |
43 |
Subscribes
44 |
45 |
46 |
47 | 150
48 |
49 |
Orders
50 |
51 |
52 |
53 | 500
54 |
55 |
Products
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | Made to Create Good
70 |
71 |
72 | We design outdoor products to help you create good moments that
73 | become lasting memories.
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | Free Shipping & Returns
82 |
83 |
84 | Free shipping and returns on all orders in India.
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | 200+ 5 Star Reviews
94 |
95 |
96 | Ingenious, quality products designed to last for a long time.
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | We Deliver Happiness
105 |
106 |
107 | We design outdoor products to help you create good moments that
108 | become lasting memories.
109 |
110 |
111 |
112 |
113 |
114 | {/* testimonials */}
115 |
116 |
117 | Testimonials
118 |
119 |
120 |
121 |
122 |
123 |
129 |
130 |
131 |
132 | I bought for a TShirt for my small sister.Overall design &
133 | colours are attractive. Value for money.
134 |
135 |
136 |
141 |
142 |
143 | Swetabh Singh
144 |
145 | Customer
146 |
147 |
148 |
149 |
150 |
151 |
152 |
158 |
159 |
160 |
161 | The jewellery products are very beautiful and afforable.
162 |
163 |
164 |
169 |
170 |
171 | Mohit Singh
172 |
173 | Customer
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 | >
183 | );
184 | };
185 |
186 | export default Aboutus;
187 |
--------------------------------------------------------------------------------
/src/components/Aboutus/bike.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Aboutus/delivered.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Aboutus/qual.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Aboutus/rating.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Aboutus/undraw_profile_pic_ic5t.svg:
--------------------------------------------------------------------------------
1 | profile pic
--------------------------------------------------------------------------------
/src/components/AddressPage/AddressCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useDispatch } from 'react-redux';
3 | import { removeAddress, setSelected } from '../../redux/slices/addressSlice';
4 | import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';
5 | const AddressCard = ({ storedAddress, idx, openModal }) => {
6 | const { name, address1, address2, pincode, state, district, mobileno } =
7 | storedAddress;
8 | const dispatch = useDispatch();
9 |
10 | return (
11 |
12 |
{name}
13 |
14 |
15 | {address1} {address2} {district}
16 |
17 | {district} {state} {pincode}
18 |
19 |
20 | {'Mobile: '}
21 | {mobileno}
22 |
23 |
24 | Pay on Delivery
25 | available
26 |
27 |
28 | {
31 | const d = { val: storedAddress, id: idx };
32 | dispatch(setSelected(d));
33 | openModal();
34 | }}
35 | >
36 | EDIT
37 |
38 | dispatch(removeAddress(idx))}
41 | >
42 | REMOVE
43 |
44 |
45 |
46 | );
47 | };
48 |
49 | export default AddressCard;
50 |
--------------------------------------------------------------------------------
/src/components/AddressPage/AddressForm.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { useDispatch, useSelector } from 'react-redux';
3 | import {
4 | addAddress,
5 | setSelected,
6 | updateAddress,
7 | } from '../../redux/slices/addressSlice';
8 |
9 | const AddressForm = ({ setIsOpen }) => {
10 | const dispatch = useDispatch();
11 | const selectedAddress = useSelector(
12 | (state) => state.addressData.selectedAddress
13 | );
14 | const [inputs, setInputs] = useState(
15 | selectedAddress.length !== 0
16 | ? {
17 | name: selectedAddress.val.name,
18 | mobileno: selectedAddress.val.mobileno,
19 | address1: selectedAddress.val.address1,
20 | address2: selectedAddress.val.address2,
21 | pincode: selectedAddress.val.pincode,
22 | state: selectedAddress.val.state,
23 | district: selectedAddress.val.district,
24 | }
25 | : {
26 | name: '',
27 | mobileno: '',
28 | address1: '',
29 | address2: '',
30 | pincode: '',
31 | state: '',
32 | district: '',
33 | }
34 | );
35 | return (
36 |
140 | );
141 | };
142 |
143 | export default AddressForm;
144 |
--------------------------------------------------------------------------------
/src/components/AddressPage/AddressModal.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Modal from 'react-modal';
3 | import AddressForm from './AddressForm';
4 |
5 | const customStyles = {
6 | content: {
7 | top: '50%',
8 | left: '50%',
9 | right: 'auto',
10 | bottom: 'auto',
11 | marginRight: '-50%',
12 | transform: 'translate(-50%, -50%)',
13 | },
14 | };
15 |
16 | // Make sure to bind modal to your appElement (https://reactcommunity.org/react-modal/accessibility/)
17 | Modal.setAppElement(document.getElementById('root'));
18 |
19 | export default function AddressModal() {
20 | const [modalIsOpen, setIsOpen] = React.useState(false);
21 |
22 | function openModal() {
23 | setIsOpen(true);
24 | }
25 |
26 | function afterOpenModal() {
27 | // references are now sync'd and can be accessed.
28 | }
29 |
30 | function closeModal() {
31 | setIsOpen(false);
32 | }
33 |
34 | return (
35 |
36 |
Open Modal
37 |
44 |
45 | close
46 |
47 |
48 |
49 |
50 | );
51 | }
52 |
--------------------------------------------------------------------------------
/src/components/AddressPage/AddressPage.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { useDispatch, useSelector } from 'react-redux';
3 | import AddressForm from './AddressForm';
4 | import CloseIcon from '@material-ui/icons/Close';
5 | import Modal from 'react-modal';
6 | import { setAllAddress, setSelected } from '../../redux/slices/addressSlice';
7 | import { Link } from 'react-router-dom';
8 | import SelectAddress from './SelectAddress';
9 | import { loadAddresses } from '../../services/addresses';
10 | import { addOrder } from '../../redux/slices/orderSlice';
11 | import { clearCart } from '../../redux/slices/Cartslice';
12 | import toast from 'react-hot-toast';
13 |
14 |
15 | const customStyles = {
16 | content: {
17 | top: '55%',
18 | left: '50%',
19 | right: 'auto',
20 | bottom: 'auto',
21 | marginRight: '-50%',
22 | transform: 'translate(-50%, -50%)',
23 | padding: "20px ",
24 | border:"none",
25 | width: "100vw",
26 | // backgroundColor: "rgba(0,0,0,0.3)",
27 | background : 'linear-gradient(282.39deg , #e3f3ff 9.07% , #f7e7ef 81% )',
28 |
29 |
30 |
31 | },
32 | };
33 |
34 | // Make sure to bind modal to your appElement (https://reactcommunity.org/react-modal/accessibility/)
35 | Modal.setAppElement(document.getElementById('root'));
36 |
37 | const AddressPage = () => {
38 | const [modalIsOpen, setIsOpen] = React.useState(false);
39 |
40 | function openModal() {
41 | setIsOpen(true);
42 | }
43 |
44 | function afterOpenModal() {
45 | // references are now sync'd and can be accessed.
46 | }
47 |
48 | function closeModal() {
49 | setIsOpen(false);
50 | }
51 | const { storedAddresses } = useSelector((s) => s.addressData);
52 | console.log('check this', storedAddresses);
53 | const dispatch = useDispatch();
54 | const cart = useSelector((state) => state.cart);
55 | const numberOfCartItems = cart.length;
56 | let totalPrice = 0;
57 | useEffect(() => {
58 | dispatch(setAllAddress(loadAddresses()));
59 | }, [dispatch]);
60 | cart.forEach((item, idx) => {
61 | totalPrice += item.price * (item.quantity + 1);
62 | });
63 | return (
64 |
68 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | Select Delivery Address
84 |
85 |
86 |
87 |
88 | {storedAddresses.length === 0 ? (
89 |
90 | Nothing here...
91 |
92 | ) : (
93 |
94 |
98 |
99 | )}
100 |
101 | {
103 | dispatch(setSelected([]));
104 |
105 | openModal();
106 | }}
107 | className="w-2/5 mt-6 rounded border-pink-300 border-4 p-1 text-xl font-semibold text-pink-500 hover:text-gray-100 hover:bg-pink-500 hover:border-pink-500"
108 | >
109 | ADD NEW ADDRESS
110 |
111 |
112 |
113 |
114 |
115 |
116 | PRICE DETAILS ({`${numberOfCartItems} Items`})
117 |
118 |
119 | TOTAL MRP:
120 | {` ${totalPrice.toFixed(2)}₹`}
121 |
122 |
123 | DISCOUNT ON MRP:
124 |
125 | -₹ {(totalPrice / 10).toFixed(2)}
126 |
127 |
128 |
129 | COUPON DISCOUNT: 0₹
130 |
131 |
132 | Convenience Fee: {' '}
133 | FREE
134 |
135 |
136 | TOTAL AMOUNT: {' '}
137 | {(totalPrice - totalPrice / 10).toFixed(2)}₹
138 |
139 | {storedAddresses.length === 0 ? (
140 |
{
142 | dispatch(setSelected([]));
143 |
144 | openModal();
145 | }}
146 | className="w-full mt-6 rounded p-1 text-2xl font-semibold bg-pink-500 text-gray-100 hover:bg-pink-600 hover:shadow-md"
147 | >
148 | ADD ADDRESS
149 |
150 | ) : (
151 |
152 |
{
155 | const cartWithDate = cart.map((item) => {
156 | const date = new Date();
157 | const dateData = date.toUTCString().slice(0, 17);
158 | return { ...item, date: dateData };
159 | });
160 | toast('Order placed successfully', { icon: '🥰' });
161 | dispatch(addOrder(cartWithDate));
162 | dispatch(clearCart());
163 | }}
164 | >
165 | PLACE ORDER
166 |
167 |
168 | )}
169 |
170 |
171 |
172 |
173 |
174 | );
175 | };
176 |
177 | export default AddressPage;
178 |
--------------------------------------------------------------------------------
/src/components/AddressPage/OrderSuccess.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | import successfulorder from '../../images/order-images/successfulorder.svg';
4 |
5 | const OrderSuccess = () => {
6 | return (
7 |
11 |
20 |
21 |
22 | Order Placed Successfully
23 |
24 |
25 |
26 |
27 | CONTINUE SHOPPING
28 |
29 |
30 |
31 | );
32 | };
33 |
34 | export default OrderSuccess;
35 |
--------------------------------------------------------------------------------
/src/components/AddressPage/SelectAddress.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withStyles } from '@material-ui/core/styles';
3 | import { pink } from '@material-ui/core/colors';
4 | import Radio from '@material-ui/core/Radio';
5 | import AddressCard from './AddressCard';
6 |
7 | const GreenRadio = withStyles({
8 | root: {
9 | color: pink[300],
10 | '&$checked': {
11 | color: pink[500],
12 | },
13 | },
14 | checked: {},
15 | })((props) => );
16 |
17 | export default function SelectAddress({ availableAddress, openModal }) {
18 | const [selectedValue, setSelectedValue] = React.useState(0);
19 |
20 | const handleChange = (event) => {
21 | setSelectedValue(parseInt(event.target.value));
22 | };
23 |
24 | return (
25 |
26 | {availableAddress.map((storedAddress, idx) => {
27 | return (
28 |
43 | );
44 | })}
45 |
46 | );
47 | }
48 |
--------------------------------------------------------------------------------
/src/components/Cart.jsx:
--------------------------------------------------------------------------------
1 | import deliveryIcon from '../assets/delivery.png';
2 | import couponIcon from '../assets/coupon.png';
3 | import bagIcon from '../assets/uempty_cart.svg';
4 | import { Link } from 'react-router-dom';
5 | import { removeItem, incItem, decItem } from '../redux/slices/Cartslice';
6 | import delIcon from '../assets/delete.png';
7 | import { useDispatch, useSelector } from 'react-redux';
8 | import './cart.scss';
9 | export default function Cart() {
10 | const dispatch = useDispatch();
11 | const selectedItem = useSelector((state) => state.cart);
12 | let totalPrice = 0;
13 | return (
14 |
15 |
16 | {1 > 0 ? (
17 |
18 | {selectedItem.length > 0 ? (
19 |
20 |
21 |
22 | {selectedItem.map((item, idx) => {
23 | totalPrice += item.price * (item.quantity + 1);
24 | return (
25 |
26 |
27 |
32 |
33 |
34 |
35 |
36 |
37 | {item.title}
38 |
39 |
{
44 | dispatch(removeItem(item.id));
45 | console.log(item.id);
46 | }}
47 | />
48 |
49 |
50 | {item.description.slice(0, 75)}
51 |
52 |
53 |
54 | ₹ {item.price * (item.quantity + 1).toFixed(2)}
55 |
56 |
57 |
58 | {(
59 | (item.price / 10 + item.price) *
60 | (item.quantity + 1)
61 | ).toFixed(2)}
62 |
63 |
64 |
(10% off)
65 |
66 |
67 |
68 |
69 | QUANTITY :{' '}
70 | {
77 | dispatch(incItem(item.id));
78 | }}
79 | >
80 | +
81 |
82 | {item.quantity + 1}
83 | dispatch(decItem(item.id))}
90 | >
91 | -
92 |
93 |
94 |
95 |
96 |
97 |
98 |
103 |
104 | Delivery expected 30 august !
105 | FREE
106 |
107 |
108 |
109 |
110 |
111 | );
112 | })}
113 |
118 |
119 | CONTINUE SHOPPING
120 |
121 |
122 |
123 |
124 |
125 | Apply coupon{' '}
126 | DEVSNEST10 to avail
127 | flat 10% off on
128 | your first order{' '}
129 |
130 |
131 |
136 |
Apply for coupon
137 |
141 |
142 |
143 |
144 | Congratualtions !! your order is eligible for
145 | FREE shipping!
146 |
147 |
148 |
149 | Bag subtotal
150 | {totalPrice.toFixed(2)}₹
151 |
152 |
153 | Shipping charge
154 | FREE
155 |
156 |
157 | Discount MRP
158 |
159 | -{(totalPrice / 10).toFixed(2)}₹
160 |
161 |
162 |
163 | Total MRP
164 | {totalPrice.toFixed(2)}
165 |
166 |
167 | You will save {(totalPrice / 10).toFixed(2)}₹ on this
168 | order
169 |
170 |
171 |
172 | PLACE YOUR ORDER
173 |
174 |
175 |
176 |
177 |
178 |
179 | ) : (
180 |
181 |
182 |
183 |
184 | Your bag is empty! Let’s fill it up shall we?
185 |
186 |
187 |
188 |
189 | CONTINUE SHOPPING
190 |
191 |
192 |
193 |
194 |
195 | VIEW WISHLIST
196 |
197 |
198 |
199 |
200 |
201 | )}
202 |
203 | ) : null}
204 |
205 |
206 | );
207 | }
208 |
--------------------------------------------------------------------------------
/src/components/Categories/Categories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-scroll';
3 |
4 | import CategoryCard from './CategoryCard';
5 |
6 | const Categories = () => {
7 | return (
8 |
9 |
CATEGORIES
10 |
11 |
12 |
16 |
17 |
18 |
19 |
23 |
24 |
25 |
26 |
30 |
31 |
32 |
33 |
37 |
38 |
39 |
40 |
41 |
45 |
46 |
47 |
48 |
49 |
53 |
54 |
55 |
56 |
57 |
58 |
62 |
63 |
64 |
65 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | );
76 | };
77 |
78 | export default Categories;
79 |
80 | // flex flex-wrap justify-around items-center
81 |
--------------------------------------------------------------------------------
/src/components/Categories/CategoryCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import CircularCard from './CircularCard';
3 |
4 | const CategoryCard = ({ class_name, category_type }) => {
5 | return (
6 |
7 |
8 |
{category_type}
9 |
10 | );
11 | };
12 |
13 | export default CategoryCard;
14 |
--------------------------------------------------------------------------------
/src/components/Categories/CircularCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const CircularCard = ({ class_name, image }) => {
4 | return (
5 |
8 | );
9 | };
10 |
11 | export default CircularCard;
12 |
--------------------------------------------------------------------------------
/src/components/Footer/Async.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/components/Footer/Footer.css:
--------------------------------------------------------------------------------
1 | .container{
2 | display: flex;
3 | justify-content: space-around;
4 | }
5 |
6 | .custom-shape-divider-bottom-1629698163 {
7 | position: absolute;
8 | bottom: 0;
9 | left: 0;
10 | width: 100%;
11 | overflow: hidden;
12 | line-height: 0;
13 | transform: rotate(180deg);
14 | }
15 |
16 | .custom-shape-divider-bottom-1629698163 svg {
17 | position: relative;
18 | display: block;
19 | width: calc(122% + 1.3px);
20 | height: 126px;
21 | }
22 |
23 | .custom-shape-divider-bottom-1629698163 .shape-fill {
24 | fill: #D381C9;
25 | }
--------------------------------------------------------------------------------
/src/components/Footer/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './Footer.css';
3 | import InstagramIcon from '@material-ui/icons/Instagram';
4 | import FacebookIcon from '@material-ui/icons/Facebook';
5 | import YouTubeIcon from '@material-ui/icons/YouTube';
6 | import TwitterIcon from '@material-ui/icons/Twitter';
7 | import waves from './wave.svg'
8 |
9 | const Footer = () => {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 | A sync Store
17 |
18 |
23 |
24 | Suscribe
25 |
26 |
27 |
28 |
29 |
Contact Us
30 |
31 |
Phone: +1 (0) 000 0000 001
32 | Email: asyncteam@outlook.com
33 |
34 | Address:1234 Street Name City, AA 99999
35 |
36 |
37 |
38 |
39 | {/* {} */}
40 |
71 |
72 |
73 | Copyright © Team Async. All Rights Reserved
74 |
75 |
76 | );
77 | };
78 |
79 | export default Footer;
80 |
--------------------------------------------------------------------------------
/src/components/Footer/wave.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/components/Home.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import Categories from './Categories/Categories';
3 | import { useDispatch } from 'react-redux';
4 | import { loadProducts } from '../redux/slices/productSlice';
5 | import ItemsDisplay from './LandingPageItems/LandingPageItems';
6 | import Footer from './Footer/Footer';
7 | import Banner from './LandingPageItems/Banner';
8 |
9 |
10 | const Home = () => {
11 | const dispatch = useDispatch();
12 |
13 | useEffect(() => {
14 | dispatch(loadProducts());
15 | // eslint-disable-next-line react-hooks/exhaustive-deps
16 | }, []);
17 | return (
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | );
26 | };
27 |
28 | export default Home;
29 |
--------------------------------------------------------------------------------
/src/components/LandingPageItems/Banner.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | import frontpage from '../../assets/frontpage.svg';
4 |
5 | const Banner = () => {
6 | return (
7 |
8 |
9 |
10 | A sync Store
11 |
12 |
13 | The perfect place to shop
14 |
15 |
16 |
17 | Shop now
18 |
19 |
20 |
21 |
22 |
23 | );
24 | };
25 |
26 | export default Banner;
27 |
--------------------------------------------------------------------------------
/src/components/LandingPageItems/Container.jsx:
--------------------------------------------------------------------------------
1 | import ItemCard from "./ItemCard"
2 |
3 | const Container = ({ items }) => {
4 | return (
5 | < >
6 |
7 |
8 |
9 | {items.map((obj, idx) => {
10 | return
11 | })}
12 |
13 |
14 |
15 | >
16 | );
17 |
18 | };
19 |
20 | export default Container;
--------------------------------------------------------------------------------
/src/components/LandingPageItems/ItemCard.jsx:
--------------------------------------------------------------------------------
1 | const ItemCard = ({ imageurl, description }) => {
2 | return (
3 | <>
4 |
8 |
9 |
10 | {description}
11 |
12 |
Starting from Rs. 499
13 |
14 | >
15 | );
16 | };
17 |
18 | export default ItemCard;
19 |
--------------------------------------------------------------------------------
/src/components/LandingPageItems/Items.jsx:
--------------------------------------------------------------------------------
1 | import Container from './Container';
2 |
3 | const Items = ({ category , id}) => {
4 | return (
5 |
6 |
7 |
8 | {category.heading}
9 |
10 |
ViewMore
11 |
12 |
13 |
14 | );
15 | };
16 |
17 | export default Items;
18 |
--------------------------------------------------------------------------------
/src/components/LandingPageItems/LandingPageItems.jsx:
--------------------------------------------------------------------------------
1 | import Items from './Items';
2 |
3 | function ItemsDisplay() {
4 | const itemList = [
5 | {
6 | heading: "Women's Clothing",
7 | items: [
8 | {
9 | description: 'Casuals',
10 | imageurl:
11 | 'https://images.unsplash.com/photo-1503342217505-b0a15ec3261c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1050&q=80',
12 | },
13 |
14 | {
15 | description: 'Track Suits',
16 | imageurl:
17 | "https://images.unsplash.com/photo-1562572159-4efc207f5aff?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=375&q=80",
18 | },
19 |
20 | {
21 | description: 'Formals',
22 | imageurl:
23 | "https://images.unsplash.com/photo-1614786269829-d24616faf56d?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=975&q=80",
24 | },
25 |
26 | {
27 | description: 'Ethnic Wear',
28 | imageurl:
29 | "https://i.etsystatic.com/16963724/r/il/636079/2735675734/il_794xN.2735675734_r2l1.jpg",
30 | },
31 |
32 | {
33 | description: 'Shirt & Jean',
34 | imageurl:
35 | 'https://images.unsplash.com/photo-1614251056216-f748f76cd228?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=334&q=80',
36 | },
37 | ],
38 | },
39 |
40 | {
41 | heading: "Men's Clothing",
42 | items: [
43 | {
44 | description: 'Formals',
45 | imageurl:
46 | "https://images.pexels.com/photos/6976004/pexels-photo-6976004.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
47 | },
48 | {
49 | description: 'Casuals',
50 | imageurl:
51 | "https://images.pexels.com/photos/2896359/pexels-photo-2896359.jpeg?cs=srgb&dl=pexels-ayaka-kato-2896359.jpg&fm=jpg",
52 | },
53 |
54 | {
55 | description: 'T-Shirts',
56 | imageurl:
57 | "https://cdn.discordapp.com/attachments/825361446358614096/878704383993446440/photo-1506634572416-48cdfe530110.png",
58 | },
59 |
60 | {
61 | description: 'Blazers',
62 | imageurl:
63 | "https://images.unsplash.com/photo-1530735038726-a73fd6e6a349?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=334&q=80",
64 | },
65 |
66 |
67 | {
68 | description: 'Jackets',
69 | imageurl:
70 | "https://images.unsplash.com/photo-1611006328160-064054b4e718?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=334&q=80",
71 | },
72 | ],
73 | },
74 |
75 | {
76 | heading: "Kids Wear",
77 | items: [
78 | {
79 | description: 'Dresses',
80 | imageurl:"https://s2.best-wallpaper.net/wallpaper/iphone/1710/Happy-child-girl-play-bubbles-summer-grass_iphone_320x480.jpg",
81 | },
82 | {
83 | description: 'Dungarees',
84 | imageurl:
85 | "https://images.unsplash.com/photo-1570545917537-873e36d4f64a?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80",
86 | },
87 |
88 | {
89 | description: 'Sports Wear',
90 | imageurl:
91 | "https://images.unsplash.com/photo-1440288736878-766bd5839edb?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1053&q=80",
92 | },
93 |
94 | {
95 | description: 'Party Look',
96 | imageurl:
97 | "https://s1.1zoom.me/big0/467/Boys_Bench_Jeans_Glance_475822.jpg",
98 | },
99 |
100 | {
101 | description: 'Casuals',
102 | imageurl:
103 | "https://images.unsplash.com/photo-1497340525489-441e8427c980?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1000&q=80"
104 |
105 | },
106 | ],
107 | },
108 |
109 | {
110 | heading: "Footwear",
111 | items: [
112 | {
113 | description: 'Casual Shoes',
114 | imageurl:
115 | "https://images.unsplash.com/photo-1619058772977-358b473720bf?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80",
116 | },
117 | {
118 | description: 'Jordans',
119 | imageurl:
120 | "https://images.unsplash.com/photo-1602033693387-3531914e7185?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=2087&q=80",
121 | },
122 |
123 | {
124 | description: 'Mojaris',
125 | imageurl:
126 | "https://images.unsplash.com/photo-1534653299134-96a171b61581?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=582&q=80",
127 | },
128 |
129 | {
130 | description: 'Formal Shoes',
131 | imageurl:
132 | "https://images.unsplash.com/photo-1614252235316-8c857d38b5f4?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=888&q=80",
133 | },
134 |
135 | {
136 | description: 'Sport Shoes',
137 | imageurl:
138 | "https://images.unsplash.com/photo-1565121715276-7d32d0977b6e?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=913&q=80"
139 | },
140 | ],
141 | },
142 |
143 | {
144 | heading: "Accessories",
145 | items: [
146 | {
147 | description: 'Sunglasses',
148 | imageurl:
149 | "https://images.unsplash.com/photo-1555617117-08d2a80f6aa9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80",
150 | },
151 | {
152 | description: 'Hand Bags',
153 | imageurl:
154 | "https://images.unsplash.com/photo-1597358371607-5987dd7da3d6?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=668&q=80",
155 | },
156 |
157 | {
158 | description: 'Watches',
159 | imageurl:
160 | "https://images.unsplash.com/photo-1620625515032-6ed0c1790c75?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1000&q=80",
161 | },
162 |
163 | {
164 | description: 'Bracelets',
165 | imageurl:
166 | "https://images.unsplash.com/photo-1608543837770-dbad30f0e7c9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80",
167 | },
168 |
169 | {
170 | description: 'Jewellery',
171 | imageurl:
172 | "https://images.unsplash.com/photo-1620441090373-f6977a23fa0b?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=750&q=80"
173 | },
174 | ],
175 | },
176 |
177 | {
178 | heading: "Electronics",
179 | items: [
180 | {
181 | description: 'Headphones',
182 | imageurl:
183 | "https://images.unsplash.com/photo-1618366712010-f4ae9c647dcb?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80",
184 | },
185 | {
186 | description: 'Camera',
187 | imageurl:
188 | "https://images.unsplash.com/photo-1500634245200-e5245c7574ef?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80",
189 | },
190 |
191 | {
192 | description: 'iPhone',
193 | imageurl:
194 | "https://images.unsplash.com/photo-1592899677977-9c10ca588bbd?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=883&q=80",
195 | },
196 |
197 | {
198 | description: 'Grinder',
199 | imageurl:
200 | "https://images.unsplash.com/photo-1585237672814-8f85a8118bf6?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=865&q=80",
201 | },
202 | {
203 | description: 'Laptop',
204 | imageurl:
205 | "https://images.unsplash.com/photo-1541807084-5c52b6b3adef?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80",
206 | },
207 | ],
208 | },
209 |
210 | {
211 | heading: "Home Decor",
212 | items: [
213 | {
214 | description: 'Furniture',
215 | imageurl:
216 | "https://images.unsplash.com/photo-1603204077167-2fa0397f591f?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80",
217 | },
218 | {
219 | description: 'Planters',
220 | imageurl:
221 | "https://images.unsplash.com/photo-1615884241095-305d10e66980?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80",
222 | },
223 |
224 | {
225 | description: 'Rugs & Mirror',
226 | imageurl:
227 | "https://images.unsplash.com/photo-1618220179428-22790b461013?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=882&q=80",
228 | },
229 |
230 | {
231 | description: 'Chairs',
232 | imageurl:
233 | "https://images.unsplash.com/photo-1625296048730-ada61dcf378b?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=975&q=80",
234 | },
235 |
236 | {
237 | description: 'Cabinets',
238 | imageurl:
239 | "https://images.unsplash.com/photo-1616046229478-9901c5536a45?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80",
240 | },
241 | ],
242 | },
243 |
244 | {
245 | heading: "Cosmetics",
246 | items: [
247 | {
248 | description: 'Makeup',
249 | imageurl:
250 | "https://images.unsplash.com/photo-1522338242992-e1a54906a8da?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80",
251 | },
252 | {
253 | description: 'SkinCare',
254 | imageurl:
255 | "https://images.unsplash.com/photo-1608611518492-dbf85f5bbcb8?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80",
256 | },
257 |
258 | {
259 | description: 'Foundation',
260 | imageurl:
261 | "https://images.unsplash.com/photo-1557205465-f3762edea6d3?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=934&q=80",
262 | },
263 |
264 | {
265 | description: 'Mascara',
266 | imageurl:
267 | "https://images.unsplash.com/photo-1584051022121-6ee465f21b5d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=934&q=80",
268 | },
269 |
270 | {
271 | description: 'Perfumes',
272 | imageurl:
273 | "https://images.unsplash.com/photo-1610461888750-10bfc601b874?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=944&q=80",
274 | },
275 | ],
276 | },
277 |
278 |
279 | ];
280 | return (
281 | <>
282 | {itemList.map((category, index) => {
283 | return ;
284 | })}
285 | >
286 | );
287 | }
288 |
289 | export default ItemsDisplay;
290 |
--------------------------------------------------------------------------------
/src/components/Loading.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Loading = () => {
4 | return (
5 |
13 | );
14 | };
15 |
16 | export default Loading;
17 |
--------------------------------------------------------------------------------
/src/components/Navbar.jsx:
--------------------------------------------------------------------------------
1 | import { Disclosure } from '@headlessui/react';
2 | import { MenuIcon, XIcon } from '@heroicons/react/outline';
3 | import { NavLink } from 'react-router-dom';
4 | import { AsyncIcon, CartIcon, FavIcon } from './icons/navIcon';
5 | const navigation = [
6 | { name: 'Product', current: true },
7 | // { name: 'Categories', current: false },
8 | { name: 'Orders', current: false },
9 | { name: 'Aboutus', current: false },
10 | ];
11 |
12 | function classNames(...classes) {
13 | return classes.filter(Boolean).join(' ');
14 | }
15 |
16 | export default function Navbar() {
17 | return (
18 | <>
19 |
20 |
29 | {({ open }) => (
30 | <>
31 |
32 |
33 |
34 | {/* Mobile menu button*/}
35 |
36 | Open main menu
37 | {open ? (
38 |
39 | ) : (
40 |
41 | )}
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | {/*
50 | Logo
51 | className= */}
52 |
53 |
54 |
55 | {navigation.map((item, idx) => (
56 |
62 |
63 | {item.name}
64 |
65 |
66 | ))}
67 |
68 |
69 |
70 |
71 | {/* Fav Icon */}
72 |
77 |
78 |
79 |
84 | {/* Cart Icon */}
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | {navigation.map((item, idx) => (
94 |
99 |
107 | {item.name}
108 |
109 |
110 | ))}
111 |
112 |
113 | >
114 | )}
115 |
116 | >
117 | );
118 | }
119 |
--------------------------------------------------------------------------------
/src/components/OrderPage/EmptyOrder.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | import emptyOrder from '../../images/order-images/emptyOrder.svg';
4 |
5 | const EmptyOrder = () => {
6 | return (
7 |
11 |
20 |
21 |
22 | You haven't placed any order yet!
23 |
24 |
25 | Order section is empty. After placing order, You can track them from
26 | here!
27 |
28 |
29 |
30 |
31 | START SHOPPING
32 |
33 |
34 |
35 | );
36 | };
37 |
38 | export default EmptyOrder;
39 |
--------------------------------------------------------------------------------
/src/components/OrderPage/OrderItem.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import DeliveryIcon from '../../images/order-images/deliveredicon.svg';
3 | import ArrowForwardIosOutlinedIcon from '@material-ui/icons/ArrowForwardIosOutlined';
4 | import RatingStars from './RatingStars';
5 | import { Link } from 'react-router-dom';
6 | const OrderItem = ({ item, idx }) => {
7 | return (
8 |
9 |
10 |
11 |
12 |
Delivered
13 |
{`On ${item.date}`}
14 |
15 |
16 |
17 |
18 |
23 |
24 |
25 |
26 | {item.title}
27 |
28 |
29 | {item.description.slice(0, 50)}
30 |
31 | {item.size ? (
32 |
Size: {item.size}
33 | ) : null}
34 |
35 | Quantity: {item.quantity + 1}
36 |
37 |
38 |
39 |
47 |
48 |
49 |
50 |
51 |
52 | );
53 | };
54 |
55 | export default OrderItem;
56 |
--------------------------------------------------------------------------------
/src/components/OrderPage/Orderpage.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { useDispatch, useSelector } from 'react-redux';
3 | import { getAllorders } from '../../redux/slices/orderSlice';
4 | import { loadOrders } from '../../services/orders';
5 | import EmptyOrder from './EmptyOrder';
6 | import OrderItem from './OrderItem';
7 |
8 | const Orderpage = () => {
9 | const dispatch = useDispatch();
10 | const [showAllOrders, setShowAllOrders] = useState(false);
11 | useEffect(() => {
12 | dispatch(getAllorders(loadOrders()));
13 | // setShowAllOrders(false);
14 | }, [dispatch]);
15 | const orderData = useSelector((state) => state.orders);
16 | const orders = [...orderData].reverse();
17 | return (
18 | <>
19 | {orders.length === 0 ? (
20 |
21 | ) : (
22 |
23 |
24 |
25 | Showing All Orders
26 |
27 |
28 | {showAllOrders
29 | ? orders.map((item, idx) => {
30 | return ;
31 | })
32 | : orders.slice(0, 3).map((item, idx) => {
33 | return ;
34 | })}
35 |
36 | {showAllOrders ? null : (
37 |
setShowAllOrders((s) => true)}
41 | >
42 | VIEW MORE
43 |
44 | )}
45 |
46 | Showing 1-1 of 1
47 |
48 |
49 |
50 | )}
51 | >
52 | );
53 | };
54 |
55 | export default Orderpage;
56 |
--------------------------------------------------------------------------------
/src/components/OrderPage/RatingStars.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import FavoriteBorderOutlinedIcon from '@material-ui/icons/FavoriteBorderOutlined';
3 | import FavoriteOutlinedIcon from '@material-ui/icons/FavoriteOutlined';
4 |
5 | const Star = ({ marked, starId }) => {
6 | return marked ? (
7 |
8 |
12 |
13 | ) : (
14 |
15 |
19 |
20 | );
21 | };
22 |
23 | const StarRating = ({ ratingVal }) => {
24 | const [rating, setRating] = useState(parseInt(ratingVal) || 0);
25 | const [selection, setSelection] = React.useState(0);
26 |
27 | const hoverOver = (event) => {
28 | let val = 0;
29 | if (event && event.target && event.target.getAttribute('data-star-id'))
30 | val = event.target.getAttribute('data-star-id');
31 | setSelection(val);
32 | };
33 | return (
34 |
35 | Rate Product
36 |
hoverOver(null)}
38 | onClick={(e) =>
39 | setRating(e.target.getAttribute('data-star-id') || rating)
40 | }
41 | onMouseOver={hoverOver}
42 | >
43 | {Array.from({ length: 5 }, (v, i) => (
44 | = i + 1 : rating >= i + 1}
48 | />
49 | ))}
50 |
51 |
52 | );
53 | };
54 |
55 | export default StarRating;
56 |
--------------------------------------------------------------------------------
/src/components/ProductDetails/ProductDetails.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { useParams } from 'react-router-dom';
3 | import { useDispatch, useSelector } from 'react-redux';
4 | import { getProductDetails } from '../../redux/slices/productSlice';
5 | import Loading from '../Loading';
6 | import { Star } from '@material-ui/icons';
7 | import toast from 'react-hot-toast';
8 |
9 | import { addItem } from '../../redux/slices/Cartslice';
10 | import { addToWhishlist } from '../../redux/slices/whishlistSlice';
11 |
12 | const sizes = ['S', 'M', 'L', 'XL', 'XXL'];
13 | const has_sizes = [`kids' wear`, `women clothing`, 'men clothing', 'footware'];
14 |
15 | const ProductDetails = () => {
16 | const [size, setSize] = useState(null);
17 | const { currentProduct } = useSelector((state) => state.products);
18 | const dispatch = useDispatch();
19 | const { id } = useParams();
20 |
21 | const cartItems = useSelector((state) => state.cart);
22 |
23 | useEffect(() => {
24 | dispatch(getProductDetails(id));
25 | }, [id, dispatch]);
26 |
27 | if (!currentProduct) {
28 | return ;
29 | }
30 |
31 | console.log(currentProduct.category);
32 |
33 | return (
34 |
35 |
36 |
37 |
38 |
39 |
40 |
{currentProduct.title}
41 |
42 | {currentProduct.description}
43 |
44 |
45 | {currentProduct.rating}
46 |
47 | 520 ratings
48 |
49 |
50 |
51 |
₹ {currentProduct.price}
52 |
53 | ₹{2 * currentProduct.price}{' '}
54 |
55 | (50% OFF)
56 |
57 |
58 |
59 | {has_sizes.includes(currentProduct.category) && (
60 |
61 |
SELECT SIZE
62 |
63 | {sizes.map((val, idx) => (
64 |
setSize(val)}
68 | style={{
69 | color: val === size ? 'white' : '#000',
70 | backgroundColor:
71 | val === size ? 'rgb(236, 72, 153)' : 'transparent',
72 | borderRadius: '50%',
73 | }}
74 | >
75 | {val}
76 |
77 | ))}
78 |
79 |
80 | )}
81 |
82 |
83 | {
86 | let have = cartItems.some(
87 | (val) => val.id === currentProduct.id
88 | );
89 | if (have) {
90 | toast.error('Item already in cart', {
91 | icon: '🙄',
92 | });
93 |
94 | return;
95 | }
96 |
97 | dispatch(addItem({ ...currentProduct, size }));
98 | toast.success('Item Added to cart', {
99 | icon: '😍',
100 | });
101 | }}
102 | >
103 | ADD TO CART
104 |
105 | {
108 | dispatch(addToWhishlist(currentProduct));
109 | }}
110 | >
111 | ADD TO WISHLIST
112 |
113 |
114 |
115 |
116 |
117 | );
118 | };
119 |
120 | export default ProductDetails;
121 |
--------------------------------------------------------------------------------
/src/components/Products/Card.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useState } from 'react';
3 | import { useDispatch } from 'react-redux';
4 | import { Link } from 'react-router-dom';
5 | import '../../styles/productList.scss';
6 | import { addToWhishlist } from '../../redux/slices/whishlistSlice';
7 |
8 | const Card = ({ val }) => {
9 | const [visible, setVisible] = useState(false);
10 | const dispatch = useDispatch();
11 | return (
12 |
13 |
14 |
setVisible(true)}
17 | onMouseLeave={() => setVisible(false)}
18 | >
19 |
20 |
21 |
22 |
23 |
24 |
25 | {val.title.length > 20 ? (
26 | {val.title.slice(0, 21)}...
27 | ) : (
28 | {val.title}
29 | )}
30 |
31 |
32 | {val.description.length > 28 ? (
33 | {val.description.slice(0, 20)}...
34 | ) : (
35 | {val.description}
36 | )}
37 |
38 |
39 |
₹ {val.price}
40 |
( 50% OFF )
41 |
42 |
43 |
44 |
setVisible(true)}
49 | onMouseLeave={() => setVisible(false)}
50 | >
51 | {
54 | dispatch(addToWhishlist(val));
55 | }}
56 | >
57 | WISHLIST
58 |
59 |
60 |
61 | );
62 | };
63 |
64 | export default Card;
65 |
--------------------------------------------------------------------------------
/src/components/Products/ProductsList.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { useDispatch, useSelector } from 'react-redux';
3 | import { loadProducts } from '../../redux/slices/productSlice';
4 | import Footer from '../Footer/Footer';
5 | import Loading from '../Loading';
6 |
7 | import Card from './Card';
8 |
9 | const ProductsList = () => {
10 | const { products, isLoading } = useSelector((state) => state.products);
11 | const dispatch = useDispatch();
12 | const [category, setCategory] = useState([]);
13 | const [categoryList, setCategoryList] = useState([]);
14 |
15 | useEffect(() => {
16 | dispatch(loadProducts());
17 | }, [dispatch]);
18 |
19 | useEffect(() => {
20 | const createCategory = () => {
21 | const set = new Set(products.map((val) => val.category.toLowerCase()));
22 | setCategoryList([...set]);
23 | };
24 | if (!isLoading) {
25 | createCategory();
26 | }
27 | }, [isLoading, products]);
28 |
29 | if (isLoading) return ;
30 | return (
31 |
32 |
33 | {categoryList.map((val, idx) => (
34 | {
40 | const has = category.includes(val);
41 | if (has) setCategory((s) => s.filter((item) => item !== val));
42 | else setCategory((s) => [...s, val]);
43 | }}
44 | >
45 | {val}
46 |
47 | ))}
48 |
49 |
50 | {products
51 | .filter(
52 | (item) => category.includes(item.category) || category.length === 0
53 | )
54 | .map((val, idx) => {
55 | return ;
56 | })}
57 |
58 |
59 |
60 | );
61 | };
62 |
63 | export default ProductsList;
64 |
--------------------------------------------------------------------------------
/src/components/ToastContainer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Toaster } from 'react-hot-toast';
3 |
4 | const ToastContainer = () => {
5 | return ;
6 | };
7 |
8 | export default ToastContainer;
9 |
--------------------------------------------------------------------------------
/src/components/Wishlist/EmptyWishlist.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import icon from './icon.svg';
3 | import { Link } from 'react-router-dom';
4 |
5 | const EmptyWishlist = () => {
6 | return (
7 |
8 |
9 |
10 | YOUR WISHLIST IS EMPTY
11 |
12 |
13 | Add the items you like to your wishlist. Review them anytime and
14 | easily move them to the cart.
15 |
16 |
17 |
18 |
19 | CONTINUE SHOPPING
20 |
21 |
22 |
23 |
24 | );
25 | };
26 |
27 | export default EmptyWishlist;
28 |
--------------------------------------------------------------------------------
/src/components/Wishlist/Wishlist.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import WishlistCard from './WishlistCard';
3 | import { useDispatch, useSelector } from 'react-redux';
4 | import EmptyWishlist from './EmptyWishlist';
5 | import { getWishlist } from '../../redux/slices/whishlistSlice';
6 | import { loadWishlist } from '../../services/wishlist';
7 |
8 | const Wishlist = () => {
9 | const dispatch = useDispatch();
10 | useEffect(() => {
11 | dispatch(getWishlist(loadWishlist()));
12 | }, [dispatch]);
13 |
14 | const wishlist = useSelector((state) => state.wishlist);
15 |
16 | return (
17 |
18 | {wishlist.length > 0 ? (
19 |
20 |
21 |
22 | MY WISHLIST {'\u00a0\u00a0'}
23 | {wishlist.length} items
24 |
25 |
26 | {wishlist.map((productObj, index) => {
27 | return ;
28 | })}
29 |
30 |
31 |
32 | ) : (
33 |
34 | )}
35 |
36 | );
37 | };
38 |
39 | export default Wishlist;
40 |
--------------------------------------------------------------------------------
/src/components/Wishlist/WishlistCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import HighlightOffRoundedIcon from '@material-ui/icons/HighlightOffRounded';
3 | import { useDispatch } from 'react-redux';
4 | import { removeFromWhishlist } from '../../redux/slices/whishlistSlice';
5 | import { addItem } from '../../redux/slices/Cartslice';
6 |
7 | const WishlistCard = ({ productObj }) => {
8 | const dispatch = useDispatch();
9 | return (
10 |
11 |
12 |
13 |
dispatch(removeFromWhishlist(productObj.id))}
17 | />
18 |
23 |
24 |
25 |
26 |
27 | {productObj.title.length > 20 ? (
28 | {productObj.title.slice(0, 21)}...
29 | ) : (
30 | {productObj.title}
31 | )}
32 |
33 |
34 |
₹ {productObj.price}
35 |
36 | ₹ 2000
37 |
38 |
39 | ( 50% OFF )
40 |
41 |
42 |
43 |
44 |
45 | {
48 | dispatch(removeFromWhishlist(productObj.id));
49 | dispatch(addItem(productObj));
50 | }}
51 | >
52 | MOVE TO CART
53 |
54 |
55 |
56 | );
57 | };
58 |
59 | export default WishlistCard;
60 |
--------------------------------------------------------------------------------
/src/components/cart.scss:
--------------------------------------------------------------------------------
1 | .shopping-btn {
2 | color: white;
3 | background-color: rgb(255, 23, 68);
4 | padding: 10px 12px;
5 | margin-right: 3%;
6 | border-radius: 20px;
7 | font-weight: 700;
8 | }
9 |
10 | .continue-shoppings {
11 | border: 2px solid black;
12 | padding: 6px 12px;
13 | margin-left: 1%;
14 | border-radius: 20px;
15 | font-weight: 700;
16 | width: fit-content;
17 | align-self: center;
18 | margin: 3% auto;
19 | }
20 |
21 | .cart-item-title {
22 | font-weight: 700;
23 | margin-top: 3%;
24 | }
25 | .discounted-price {
26 | font-weight: 700;
27 | }
28 | .cart-item-price {
29 | margin: 1% 0;
30 | }
31 | .discounted-price {
32 | font-weight: 800;
33 | }
34 |
35 | .off-span {
36 | font-weight: 500;
37 | color: rgb(236, 72, 153);
38 | }
39 | .saved-product-btn {
40 | color: rgb(255, 23, 68);
41 | padding: 8px 10px;
42 | border-radius: 20px;
43 | font-weight: 700;
44 | box-sizing: border-box;
45 | border: 2px solid rgb(255, 23, 68);
46 | font-size: 1.2rem;
47 | }
48 | .del-icon {
49 | height: 2rem;
50 | margin-right: 5%;
51 | margin-top: 1%;
52 | }
53 | .cart-item-container {
54 | text-align: center;
55 | height: 80vh;
56 | }
57 | .empty-bag {
58 | display: inline-block;
59 | width: 80vmin;
60 | margin: 0 auto;
61 | }
62 | .cart-btn {
63 | width: 100%;
64 | text-align: center;
65 | margin-top: 1%;
66 | }
67 | .cart-empty-msg {
68 | font-size: 1.4rem;
69 | font-weight: 700;
70 | }
71 | .cart-item {
72 | width: 45vw;
73 | display: flex;
74 | align-items: center;
75 | border-radius: 10px;
76 | margin: 20px 0;
77 | background-color: #fafafa;
78 | padding-top: 4px;
79 | padding-right: 2%;
80 | }
81 | .cart-item-image {
82 | display: inline-block;
83 | width: 100%;
84 | height: 100%;
85 | }
86 | .cart-item-image-container {
87 | display: inline-block;
88 | width: 33vh;
89 | height: 33vh;
90 | margin: 0 3%;
91 | margin-right: 7%;
92 | border-radius: 5px;
93 | }
94 | .actual-price {
95 | margin-left: 3%;
96 | text-decoration: line-through;
97 | }
98 | .off-info {
99 | margin-top: 1%;
100 | text-align: center;
101 | }
102 | .off-highlight {
103 | font-weight: 700;
104 | }
105 | .wishlist-container {
106 | font-weight: 600;
107 | opacity: 0.8;
108 | margin: 10px 0;
109 | }
110 | .shipping-charge {
111 | opacity: 0.7;
112 | }
113 | .delivery-icon {
114 | margin-right: 2%;
115 | width: 10%;
116 | height: 10%;
117 | }
118 |
119 | .free-tag {
120 | color: rgb(204, 25, 115);
121 | font-weight: 600;
122 | }
123 | .delivery-info {
124 | display: flex;
125 | align-items: center;
126 | }
127 | .devider {
128 | display: flex;
129 | width: 80vw;
130 | flex-wrap: wrap;
131 | margin: 0 auto;
132 | }
133 | .coupon-container {
134 | justify-content: space-around;
135 | align-items: center;
136 | font-weight: 600;
137 | background-color: white;
138 | width: fit-content;
139 | display: flex;
140 | margin: 5% auto;
141 | margin-top: 7%;
142 | width: 100%;
143 | margin-bottom: 4%;
144 | background-color: rgb(241, 181, 241);
145 | padding: 2%;
146 | }
147 | .coupon-icon {
148 | width: 10%;
149 | }
150 | .coupon-input {
151 | border: none;
152 | width: 30%;
153 | padding: 0 12px;
154 | font-weight: 600;
155 | color: blue;
156 | }
157 | .icons {
158 | display: flex;
159 | justify-content: space-around;
160 | padding: 0;
161 | margin: 0;
162 | }
163 | .bag-total,
164 | .bag-subtotal,
165 | .product-discount,
166 | .shipping-charge {
167 | display: flex;
168 | justify-content: space-between;
169 | }
170 | .bag-total *,
171 | .bag-subtotal *,
172 | .product-discount *,
173 | .shipping-info,
174 | .save-money,
175 | .shipping-charge * {
176 | margin: 1% 3%;
177 | font-weight: 600;
178 | }
179 | .bag-total {
180 | font-weight: 700;
181 | }
182 | .cart-curr-status {
183 | background-color: white;
184 | margin: 0 auto;
185 | margin-top: 1%;
186 | text-align: center;
187 | border-radius: 5px;
188 | padding: 5%;
189 | background-color: #fafafa;
190 | min-height: max-content;
191 | width: 100%;
192 | }
193 | .place-order {
194 | padding: 3px 20%;
195 | }
196 | .cart-info {
197 | margin: 0 auto;
198 | position: sticky;
199 | position: -webkit-sticky;
200 | top: 110px;
201 | height: max-content;
202 | width: 25vw;
203 | }
204 | .cart-item-field {
205 | margin: 2% 0;
206 | height: max-content;
207 | }
208 |
209 | .cart-item-field::-webkit-scrollbar {
210 | width: 0;
211 | }
212 | .cart-item-info-box {
213 | height: 100%;
214 | display: flex;
215 | flex-direction: column;
216 | justify-content: space-around;
217 | }
218 | .inc-btn,
219 | .dec-btn {
220 | font-weight: 800;
221 | margin: 8px 12px;
222 | padding: 0 15px;
223 | font-weight: 600;
224 | }
225 | .qnt-wl * {
226 | font-weight: 600;
227 | }
228 | .price-del {
229 | display: flex;
230 | justify-content: space-between;
231 | }
232 | .min,
233 | .max {
234 | opacity: 0.7;
235 | }
236 |
237 | @media screen and (max-width: 1000px) {
238 | .cart-item {
239 | width: 70vw;
240 | height: fit-content;
241 | }
242 |
243 | .cart-info {
244 | width: 70vw;
245 | }
246 | }
247 |
--------------------------------------------------------------------------------
/src/components/icons/navIcon.js:
--------------------------------------------------------------------------------
1 | export const CartIcon = () => {
2 | return (
3 |
19 | );
20 | };
21 |
22 | export const FavIcon = () => {
23 | return (
24 | <>
25 |
32 |
38 |
39 | >
40 | );
41 | };
42 |
43 | export const AsyncIcon = () => {
44 | return (
45 |
46 |
53 |
57 |
61 |
65 |
69 |
73 |
77 |
81 |
85 |
89 |
93 |
97 |
98 |
99 | );
100 | };
101 |
--------------------------------------------------------------------------------
/src/config/axios.config.js:
--------------------------------------------------------------------------------
1 | import Axios from 'axios';
2 |
3 | import { API_BASE_URL } from '../services/api';
4 | import myLog from './myLog';
5 |
6 | const axios = Axios.create({
7 | baseURL: API_BASE_URL,
8 | headers: {
9 | 'Content-Type': 'application/vnd.api+json',
10 | },
11 | });
12 |
13 | axios.interceptors.request.use((request) => {
14 | myLog(
15 | `------------------ \nRequest to ${request.method.toUpperCase()} ${
16 | request.url
17 | } with params`,
18 | request.params,
19 | `and data`,
20 | request.data
21 | );
22 | return request;
23 | });
24 |
25 | axios.interceptors.response.use((response) => {
26 | myLog(
27 | `------------------ \nResponse from ${response.config.method.toUpperCase()} ${
28 | response.config.url
29 | } with params`,
30 | response.config.params,
31 | `and data`,
32 | response.config.data,
33 | `and got response data ->`,
34 | response.data
35 | );
36 | return response;
37 | });
38 |
39 | export default axios;
40 |
--------------------------------------------------------------------------------
/src/config/myLog.js:
--------------------------------------------------------------------------------
1 | export default function myLog(...message) {
2 | if (process.env.NODE_ENV !== 'production') {
3 | console.log(...message);
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/images/categories-accessories.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/src/images/categories-accessories.jpg
--------------------------------------------------------------------------------
/src/images/categories-cosmetics.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/src/images/categories-cosmetics.jpg
--------------------------------------------------------------------------------
/src/images/categories-electronics.jfif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/src/images/categories-electronics.jfif
--------------------------------------------------------------------------------
/src/images/categories-footwear.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/src/images/categories-footwear.jpg
--------------------------------------------------------------------------------
/src/images/categories-home-decor.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/src/images/categories-home-decor.jpg
--------------------------------------------------------------------------------
/src/images/categories-kids-wear.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/src/images/categories-kids-wear.jpg
--------------------------------------------------------------------------------
/src/images/categories-mens-clothing.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/src/images/categories-mens-clothing.jpg
--------------------------------------------------------------------------------
/src/images/categories-womens-clothing.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/src/images/categories-womens-clothing.jpg
--------------------------------------------------------------------------------
/src/images/order-images/deliveredicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.scss';
4 | import App from './App';
5 | import store from './redux/store';
6 | import { Provider } from 'react-redux';
7 |
8 | ReactDOM.render(
9 |
10 |
11 |
12 |
13 | ,
14 | document.getElementById('root')
15 | );
16 |
--------------------------------------------------------------------------------
/src/index.scss:
--------------------------------------------------------------------------------
1 | /* ./src/index.css */
2 | @tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;
5 |
6 | body {
7 | margin: 0;
8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
10 | sans-serif;
11 | -webkit-font-smoothing: antialiased;
12 | -moz-osx-font-smoothing: grayscale;
13 | background-color: #f5f3f7;
14 | }
15 |
16 | code {
17 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
18 | monospace;
19 | }
20 |
--------------------------------------------------------------------------------
/src/redux/slices/Cartslice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from '@reduxjs/toolkit';
2 | function cartInitialState()
3 | {
4 | if(localStorage.getItem("items")===null)
5 | return []
6 | return JSON.parse( localStorage.getItem("items"))
7 | }
8 | export const cartSlice = createSlice({
9 | name: 'cart',
10 | initialState: cartInitialState(),
11 | reducers: {
12 | addItem: (state, action) => {
13 | localStorage.setItem("items",JSON.stringify([...state ,action.payload]));
14 | return [...state, action.payload];
15 | },
16 | removeItem: (state, action) =>{
17 |
18 | const newState= state.filter((item) => {
19 | return item.id !== action.payload;
20 | })
21 | localStorage.setItem("items",JSON.stringify(newState))
22 | return newState
23 | },
24 | clearCart: () => [],
25 | incItem: (state, action) => {
26 | const newState = state.map((item) => {
27 | if (item.id === action.payload && item.quantity !== 4)
28 | return { ...item, quantity: item.quantity + 1 };
29 | return item;
30 | });
31 | localStorage.setItem("items",JSON.stringify(newState))
32 | return newState;
33 | },
34 | decItem: (state, action) => {
35 | const newState = state.map((item) => {
36 | if (item.id === action.payload && item.quantity !== 0)
37 | return { ...item, quantity: item.quantity - 1 };
38 | return item;
39 | });
40 | localStorage.setItem("items",JSON.stringify(newState))
41 | return newState;
42 | },
43 | },
44 | });
45 | export const { addItem, removeItem, clearCart, incItem, decItem } =
46 | cartSlice.actions;
47 | export default cartSlice.reducer;
48 |
--------------------------------------------------------------------------------
/src/redux/slices/addressSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from '@reduxjs/toolkit';
2 | import { storeAddressses } from '../../services/addresses';
3 |
4 | const initialState = {
5 | storedAddresses: [],
6 | selectedAddress: [],
7 | };
8 |
9 | export const addressSlice = createSlice({
10 | name: 'address',
11 | initialState: initialState,
12 | reducers: {
13 | setAllAddress: (state, action) => {
14 | return { ...action.payload };
15 | },
16 | addAddress: (state, action) => {
17 | state.storedAddresses = [...state.storedAddresses, action.payload];
18 | storeAddressses(state);
19 | },
20 | removeAddress: (state, action) => {
21 | state.storedAddresses = state.storedAddresses.filter(
22 | (item, idx) => idx !== action.payload
23 | );
24 | storeAddressses(state);
25 | },
26 | updateAddress: (state, action) => {
27 | state.storedAddresses = state.storedAddresses.map((currAddress, idx) => {
28 | if (idx === action.payload.id) return action.payload.val;
29 | return currAddress;
30 | });
31 | storeAddressses(state);
32 | },
33 | setSelected: (state, action) => {
34 | state.selectedAddress = action.payload;
35 | },
36 | },
37 | });
38 | export const {
39 | addAddress,
40 | removeAddress,
41 | setAllAddress,
42 | updateAddress,
43 | setSelected,
44 | } = addressSlice.actions;
45 |
46 | export default addressSlice.reducer;
47 |
--------------------------------------------------------------------------------
/src/redux/slices/orderSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from '@reduxjs/toolkit';
2 | import { storeOrders } from '../../services/orders';
3 |
4 | export const orderSlice = createSlice({
5 | name: 'orders',
6 | initialState: [],
7 | reducers: {
8 | getAllorders: (state, action) => {
9 | return [...action.payload];
10 | },
11 | addOrder: (state, action) => {
12 | const newState = [...state, ...action.payload];
13 | storeOrders(newState);
14 | return newState;
15 | },
16 | },
17 | });
18 | export const { getAllorders, addOrder } = orderSlice.actions;
19 |
20 | export default orderSlice.reducer;
21 |
--------------------------------------------------------------------------------
/src/redux/slices/productSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
2 | import { getAllProducts, getSpecificProduct } from '../../services/products';
3 |
4 | const initialState = {
5 | isLoading: false,
6 | products: [],
7 | currentProduct: null,
8 | };
9 |
10 | export const loadProducts = createAsyncThunk(
11 | 'products/loadProducts',
12 | async () => {
13 | const data = await getAllProducts();
14 | return data;
15 | }
16 | );
17 |
18 | export const getProductDetails = createAsyncThunk(
19 | 'products/getSingleProduct',
20 | async (id) => {
21 | const data = await getSpecificProduct(id);
22 | return data;
23 | }
24 | );
25 |
26 | const productSlice = createSlice({
27 | name: 'productSlice',
28 | initialState: initialState,
29 | reducers: {
30 | resetCurrentProduct: (state) => {
31 | state.currentProduct = null;
32 | },
33 |
34 | toggleLoading: (state) => {
35 | state.isLoading = !state.isLoading;
36 | },
37 | },
38 |
39 | extraReducers: (cases) => {
40 | cases
41 | .addCase(loadProducts.pending, (state, action) => {
42 | state.isLoading = true;
43 | })
44 | .addCase(loadProducts.fulfilled, (state, action) => {
45 | state.isLoading = false;
46 | state.products = [...action.payload];
47 | })
48 | .addCase(getProductDetails.pending, (state, action) => {
49 | state.isLoading = true;
50 | })
51 | .addCase(getProductDetails.fulfilled, (state, action) => {
52 | state.isLoading = false;
53 | state.currentProduct = action.payload;
54 | });
55 | },
56 | });
57 |
58 | export const { resetCurrentProduct, toggleLoading } = productSlice.actions;
59 | export default productSlice.reducer;
60 |
--------------------------------------------------------------------------------
/src/redux/slices/whishlistSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from '@reduxjs/toolkit';
2 | import { storeWishlist } from '../../services/wishlist';
3 | import toast from 'react-hot-toast';
4 |
5 | const whishlistSlice = createSlice({
6 | name: 'whishlistSlice',
7 | initialState: [],
8 | reducers: {
9 | addToWhishlist: (state, action) => {
10 | for (let item of state) {
11 | if (item.id === action.payload.id) {
12 | toast.success('Item already in wishlist', {
13 | icon: '😶',
14 | });
15 | return state;
16 | }
17 | }
18 | toast.success('Item added to wishlist', {
19 | icon: '👏',
20 | });
21 | const newState = [...state, action.payload];
22 | storeWishlist(newState);
23 | return newState;
24 | },
25 | removeFromWhishlist: (state, action) => {
26 | const newState = state.filter((item) => item.id !== action.payload);
27 | storeWishlist(newState);
28 | return newState;
29 | },
30 | clearWhishlist: (state) => {
31 | return [];
32 | },
33 | getWishlist: (state, action) => {
34 | return [...action.payload];
35 | },
36 | },
37 | });
38 |
39 | export const {
40 | addToWhishlist,
41 | removeFromWhishlist,
42 | clearWhishlist,
43 | getWishlist,
44 | } = whishlistSlice.actions;
45 |
46 | export default whishlistSlice.reducer;
47 |
--------------------------------------------------------------------------------
/src/redux/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from '@reduxjs/toolkit';
2 | import ordersReducer from './slices/orderSlice';
3 | import productSlice from './slices/productSlice';
4 | import cartSlice from './slices/Cartslice';
5 | import whishlistSlice from './slices/whishlistSlice';
6 | import addressSlice from './slices/addressSlice';
7 |
8 | const store = configureStore({
9 | reducer: {
10 | orders: ordersReducer,
11 | products: productSlice,
12 | cart: cartSlice,
13 | wishlist: whishlistSlice,
14 | addressData: addressSlice,
15 | },
16 | });
17 |
18 | export default store;
19 |
--------------------------------------------------------------------------------
/src/services/addresses.js:
--------------------------------------------------------------------------------
1 | export const loadAddresses = () => {
2 | const data = localStorage.getItem('addresses');
3 | let storedAddress = JSON.parse(data);
4 | if (!storedAddress)
5 | storedAddress = {
6 | storedAddresses: [],
7 | selectedAddress: [],
8 | };
9 | return storedAddress;
10 | };
11 |
12 | export const storeAddressses = (data) => {
13 | const storeData = JSON.stringify(data);
14 | localStorage.setItem('addresses', storeData);
15 | };
16 |
--------------------------------------------------------------------------------
/src/services/api.js:
--------------------------------------------------------------------------------
1 | import myLog from '../config/myLog';
2 |
3 | export const API_BASE_URL = process.env.REACT_APP_API_URL;
4 | myLog(`using api base url:`, API_BASE_URL);
5 |
6 | export const API_ENDPOINTS = {
7 | GET_PRODUCTS: `/all`,
8 | GET_SINGLE_PRODUCT: '/get',
9 | CATEGORY: '/category',
10 | };
11 |
--------------------------------------------------------------------------------
/src/services/orders.js:
--------------------------------------------------------------------------------
1 | export const loadOrders = () => {
2 | const data = localStorage.getItem('orders');
3 | let storedOrderList = JSON.parse(data);
4 | if (!storedOrderList) storedOrderList = [];
5 | return storedOrderList;
6 | };
7 |
8 | export const storeOrders = (data) => {
9 | console.log('called to store order locally');
10 | const storeData = JSON.stringify(data);
11 | localStorage.setItem('orders', storeData);
12 | };
13 |
--------------------------------------------------------------------------------
/src/services/products.js:
--------------------------------------------------------------------------------
1 | import axios from '../config/axios.config';
2 | import { API_ENDPOINTS } from './api';
3 |
4 | export const getAllProducts = async () => {
5 | const response = await axios.get(API_ENDPOINTS.GET_PRODUCTS);
6 | return response.data;
7 | };
8 |
9 | export const getSpecificProduct = async (id) => {
10 | const response = await axios.get(`${API_ENDPOINTS.GET_SINGLE_PRODUCT}/${id}`);
11 | return response.data;
12 | };
13 |
--------------------------------------------------------------------------------
/src/services/wishlist.js:
--------------------------------------------------------------------------------
1 | export const loadWishlist = () => {
2 | const data = localStorage.getItem('wishlist');
3 | let storedWishlist = JSON.parse(data);
4 | if (!storedWishlist) storedWishlist = [];
5 | return storedWishlist;
6 | };
7 |
8 | export const storeWishlist = (data) => {
9 | const storeData = JSON.stringify(data);
10 | localStorage.setItem('wishlist', storeData);
11 | };
12 |
--------------------------------------------------------------------------------
/src/styles/home.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-Asyncc/async-ecommerce/857adc7456789f57b8fe85a8bb495f31ba3a2dd0/src/styles/home.scss
--------------------------------------------------------------------------------
/src/styles/productList.scss:
--------------------------------------------------------------------------------
1 | .hover-span {
2 | display: none;
3 | }
4 |
5 | .hover-active {
6 | display: block;
7 | background-color: #f5f3f7;
8 | left: 0;
9 | bottom: 35px;
10 | z-index: 9;
11 | }
12 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
3 | darkMode: false, // or 'media' or 'class'
4 | theme: {
5 | extend: {
6 | screens: {
7 | lgCustom: '1100px',
8 | xlCustom: '1340px',
9 | },
10 | outline: {
11 | pink: '2px solid #f9a8d400',
12 | },
13 | },
14 | },
15 | variants: {
16 | extend: {},
17 | },
18 | plugins: [],
19 | };
20 |
--------------------------------------------------------------------------------
/tailwindcss-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | purge: [],
3 | darkMode: false, // or 'media' or 'class'
4 | theme: {
5 | extend: {},
6 | },
7 | variants: {
8 | extend: {},
9 | },
10 | plugins: [],
11 | }
12 |
--------------------------------------------------------------------------------