├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── images
│ └── google.png
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
└── src
├── About.js
├── App.css
├── App.js
├── App.test.js
├── Cart.js
├── Contact.js
├── ErrorPage.js
├── GlobalStyle.js
├── Helpers
└── FormatPrice.js
├── Home.js
├── Products.js
├── SingleProduct.js
├── components
├── AddToCart.js
├── CartAmountToggle.js
├── CartItem.js
├── FeatureProduct.js
├── FilterSection.js
├── Footer.js
├── GridView.js
├── Header.js
├── HeroSection.js
├── ListView.js
├── MyImage.js
├── Nav.js
├── PageNavigation.js
├── Product.js
├── ProductList.js
├── Services.js
├── Sort.js
├── Spinner.js
├── Stars.js
└── Trusted.js
├── context
├── cart_context.js
├── filter_context.js
└── productcontext.js
├── images
├── hero.jpg
├── loading.gif
└── logo.png
├── index.css
├── index.js
├── reducer
├── cartReducer.js
├── filterReducer.js
└── productReducer.js
├── reportWebVitals.js
├── setupTests.js
└── styles
├── Button.js
└── Container.js
/.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 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .env
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 | # Local Netlify folder
27 | .netlify
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ecommerce-react
2 | https://ecommerce-akash.netlify.app/
3 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ecom",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@auth0/auth0-react": "^1.10.2",
7 | "@testing-library/jest-dom": "^5.16.4",
8 | "@testing-library/react": "^13.3.0",
9 | "@testing-library/user-event": "^13.5.0",
10 | "axios": "^0.27.2",
11 | "mathjs": "^11.8.2",
12 | "react": "^18.2.0",
13 | "react-dom": "^18.2.0",
14 | "react-icons": "^4.10.1",
15 | "react-router-dom": "^6.3.0",
16 | "react-scripts": "5.0.1",
17 | "react-select": "^5.7.4",
18 | "styled-components": "^5.3.5",
19 | "web-vitals": "^2.1.4"
20 | },
21 | "scripts": {
22 | "start": "react-scripts start",
23 | "build": "react-scripts build",
24 | "test": "react-scripts test",
25 | "eject": "react-scripts eject"
26 | },
27 | "eslintConfig": {
28 | "extends": [
29 | "react-app",
30 | "react-app/jest"
31 | ]
32 | },
33 | "browserslist": {
34 | "production": [
35 | ">0.2%",
36 | "not dead",
37 | "not op_mini all"
38 | ],
39 | "development": [
40 | "last 1 chrome version",
41 | "last 1 firefox version",
42 | "last 1 safari version"
43 | ]
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akashm-2003/ecommerce-react/354c3371b5c99d3a58d3bd6e17440f3815f63901/public/favicon.ico
--------------------------------------------------------------------------------
/public/images/google.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akashm-2003/ecommerce-react/354c3371b5c99d3a58d3bd6e17440f3815f63901/public/images/google.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akashm-2003/ecommerce-react/354c3371b5c99d3a58d3bd6e17440f3815f63901/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akashm-2003/ecommerce-react/354c3371b5c99d3a58d3bd6e17440f3815f63901/public/logo512.png
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/src/About.js:
--------------------------------------------------------------------------------
1 |
2 | import React, { useContext } from 'react'
3 | import styled from 'styled-components'
4 | import HeroSection from './components/HeroSection'
5 | import {useProductContext} from './context/productcontext'
6 | const About = () => {
7 | const {myName}= useProductContext()
8 | const data={
9 | title:'Akash Ecommerce'
10 | }
11 | return (
12 |
13 | {myName}
14 |
15 |
16 | )
17 | }
18 | const Wrapper = styled.div`
19 |
20 | `;
21 | export default About
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | @media (prefers-reduced-motion: no-preference) {
11 | .App-logo {
12 | animation: App-logo-spin infinite 20s linear;
13 | }
14 | }
15 |
16 | .App-header {
17 | background-color: #282c34;
18 | min-height: 100vh;
19 | display: flex;
20 | flex-direction: column;
21 | align-items: center;
22 | justify-content: center;
23 | font-size: calc(10px + 2vmin);
24 | color: white;
25 | }
26 |
27 | .App-link {
28 | color: #61dafb;
29 | }
30 |
31 | @keyframes App-logo-spin {
32 | from {
33 | transform: rotate(0deg);
34 | }
35 | to {
36 | transform: rotate(360deg);
37 | }
38 | }
39 |
40 | .flex{
41 | display: flex;
42 | justify-content: end;
43 | align-items: center;
44 | }
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Home from "./Home";
3 | import About from "./About";
4 | import Products from "./Products";
5 | import Contact from "./Contact";
6 | import SingleProduct from "./SingleProduct";
7 | import Cart from "./Cart";
8 | import Error from "./ErrorPage";
9 | import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
10 | import { GlobalStyle } from "./GlobalStyle";
11 | import { ThemeProvider } from "styled-components";
12 | import Header from "./components/Header";
13 | import Footer from "./components/Footer";
14 | const theme = {
15 | colors: {
16 | heading: "rgb(24 24 29)",
17 | text: "rgba(29 ,29, 29, .8)",
18 | white: "#fff",
19 | black: " #212529",
20 | helper: "#8490ff",
21 |
22 | bg: "#F6F8FA",
23 | footer_bg: "#0a1435",
24 | btn: "rgb(98 84 243)",
25 | border: "rgba(98, 84, 243, 0.5)",
26 | hr: "#ffffff",
27 | gradient:
28 | "linear-gradient(0deg, rgb(132 144 255) 0%, rgb(98 189 252) 100%)",
29 | shadow:
30 | "rgba(0, 0, 0, 0.02) 0px 1px 3px 0px,rgba(27, 31, 35, 0.15) 0px 0px 0px 1px;",
31 | shadowSupport: " rgba(0, 0, 0, 0.16) 0px 1px 4px",
32 | },
33 | media: {
34 | mobile: "768px",
35 | tab: "998px",
36 | },
37 | };
38 | const App = () => {
39 | return (
40 |
41 |
42 |
43 |
44 |
45 |
46 | }>
47 | }>
48 | }>
49 | }>
50 | }>
51 | }>
52 | }>
53 |
54 |
55 |
56 |
57 |
58 | );
59 | };
60 |
61 | export default App;
62 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render( );
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/src/Cart.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 | import { useCartContext } from "./context/cart_context";
3 | import CartItem from "./components/CartItem";
4 | import { NavLink } from "react-router-dom";
5 | import { Button } from "./styles/Button";
6 | import FormatPrice from "./Helpers/FormatPrice";
7 | const Cart = () => {
8 | const { cart, clearCart, total_amount, shipping_fee } = useCartContext()
9 | return
10 | <>
11 | {cart.length !== 0 ?
12 |
13 |
Item
14 |
Price
15 |
Quantity
16 |
Subtotal
17 |
Remove
18 |
19 |
20 |
21 |
22 | {cart.map((curElem, index) => {
23 | return ;
24 | })}
25 |
26 |
27 |
28 |
29 | continue Shopping
30 |
31 |
32 | clear cart
33 |
34 |
35 |
36 | {/* order total_amount */}
37 |
38 |
39 |
40 |
subtotal:
41 |
42 |
43 |
44 |
45 |
46 |
shipping fee:
47 |
48 |
49 |
50 |
51 |
52 |
53 |
order total:
54 |
55 |
56 |
57 |
58 |
59 |
60 |
:
61 |
62 |
63 |
Shop Something
64 |
65 | continue Shopping
66 |
67 |
68 |
}
69 |
70 | >
71 | ;
72 | };
73 |
74 |
75 | // const EmptyDiv = styled.div`
76 | // display: grid;
77 | // place-items: center;
78 | // height: 50vh;
79 |
80 | // h3 {
81 | // font-size: 4.2rem;
82 | // text-transform: capitalize;
83 | // font-weight: 300;
84 | // }
85 | // `;
86 |
87 | const Wrapper = styled.section`
88 | padding: 9rem 0;
89 | .flexColumn{
90 | display: flex;
91 | flex-direction: column;
92 | justify-content: center;
93 | align-items: center;
94 | .emptyCartText{
95 | margin-bottom: 2rem;
96 | font-size: 2.5rem;
97 | }
98 | }
99 | .grid-four-column {
100 | grid-template-columns: repeat(4, 1fr);
101 | }
102 |
103 | .grid-five-column {
104 | grid-template-columns: repeat(4, 1fr) 0.3fr;
105 | text-align: center;
106 | align-items: center;
107 | }
108 | .cart-heading {
109 | text-align: center;
110 | text-transform: uppercase;
111 | }
112 | hr {
113 | margin-top: 1rem;
114 | }
115 | .cart-item {
116 | padding: 3.2rem 0;
117 | display: flex;
118 | flex-direction: column;
119 | gap: 3.2rem;
120 | }
121 |
122 | .cart-user--profile {
123 | display: flex;
124 | justify-content: flex-start;
125 | align-items: center;
126 | gap: 1.2rem;
127 | margin-bottom: 5.4rem;
128 |
129 | img {
130 | width: 8rem;
131 | height: 8rem;
132 | border-radius: 50%;
133 | }
134 | h2 {
135 | font-size: 2.4rem;
136 | }
137 | }
138 | .cart-user--name {
139 | text-transform: capitalize;
140 | }
141 | .cart-image--name {
142 | /* background-color: red; */
143 | align-items: center;
144 | display: grid;
145 | gap: 1rem;
146 | grid-template-columns: 0.4fr 1fr;
147 | text-transform: capitalize;
148 | text-align: left;
149 | img {
150 | max-width: 5rem;
151 | height: 5rem;
152 | object-fit: contain;
153 | color: transparent;
154 | }
155 |
156 | .color-div {
157 | display: flex;
158 | align-items: center;
159 | justify-content: flex-start;
160 | gap: 1rem;
161 |
162 | .color-style {
163 | width: 1.4rem;
164 | height: 1.4rem;
165 |
166 | border-radius: 50%;
167 | }
168 | }
169 | }
170 |
171 | .cart-two-button {
172 | margin-top: 2rem;
173 | display: flex;
174 | justify-content: space-between;
175 |
176 | .btn-clear {
177 | background-color: #e74c3c;
178 | }
179 | }
180 |
181 | .amount-toggle {
182 | display: flex;
183 | justify-content: center;
184 | align-items: center;
185 | gap: 2.4rem;
186 | font-size: 1.4rem;
187 |
188 | button {
189 | border: none;
190 | background-color: #fff;
191 | cursor: pointer;
192 | }
193 |
194 | .amount-style {
195 | font-size: 2.4rem;
196 | color: ${({ theme }) => theme.colors.btn};
197 | }
198 | }
199 |
200 | .remove_icon {
201 | font-size: 1.6rem;
202 | color: #e74c3c;
203 | cursor: pointer;
204 | }
205 |
206 | .order-total--amount {
207 | width: 100%;
208 | margin: 4.8rem 0;
209 | text-transform: capitalize;
210 | display: flex;
211 | flex-direction: column;
212 | justify-content: flex-end;
213 | align-items: flex-end;
214 |
215 | .order-total--subdata {
216 | border: 0.1rem solid #f0f0f0;
217 | display: flex;
218 | flex-direction: column;
219 | gap: 1.8rem;
220 | padding: 3.2rem;
221 | }
222 | div {
223 | display: flex;
224 | gap: 3.2rem;
225 | justify-content: space-between;
226 | }
227 |
228 | div:last-child {
229 | background-color: #fafafa;
230 | }
231 |
232 | div p:last-child {
233 | font-weight: bold;
234 | color: ${({ theme }) => theme.colors.heading};
235 | }
236 | }
237 |
238 | @media (max-width: ${({ theme }) => theme.media.mobile}) {
239 | .grid-five-column {
240 | grid-template-columns: 1.5fr 1fr 0.5fr;
241 | }
242 | .cart-hide {
243 | display: none;
244 | }
245 |
246 | .cart-two-button {
247 | margin-top: 2rem;
248 | display: flex;
249 | justify-content: space-between;
250 | gap: 2.2rem;
251 | }
252 |
253 | .order-total--amount {
254 | width: 100%;
255 | text-transform: capitalize;
256 | justify-content: flex-start;
257 | align-items: flex-start;
258 |
259 | .order-total--subdata {
260 | width: 100%;
261 | border: 0.1rem solid #f0f0f0;
262 | display: flex;
263 | flex-direction: column;
264 | gap: 1.8rem;
265 | padding: 3.2rem;
266 | }
267 | }
268 | }
269 | `;
270 | export default Cart;
--------------------------------------------------------------------------------
/src/Contact.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | const Contact = () => {
4 | return
5 | Contact Us
6 |
7 |
17 | ;
18 | };
19 | const Wrapper = styled.section`
20 | padding: 9rem 0 5rem 0;
21 | text-align: center;
22 |
23 | .container {
24 | margin-top: 6rem;
25 |
26 | .contact-form {
27 | max-width: 50rem;
28 | margin: auto;
29 |
30 | .contact-inputs {
31 | display: flex;
32 | flex-direction: column;
33 | gap: 3rem;
34 |
35 | input[type="submit"] {
36 | cursor: pointer;
37 | transition: all 0.2s;
38 |
39 | &:hover {
40 | background-color: ${({ theme }) => theme.colors.white};
41 | border: 1px solid ${({ theme }) => theme.colors.btn};
42 | color: ${({ theme }) => theme.colors.btn};
43 | transform: scale(0.9);
44 | }
45 | }
46 | }
47 | }
48 | }
49 | `;
50 | export default Contact;
--------------------------------------------------------------------------------
/src/ErrorPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components';
3 | import { Button } from './styles/Button';
4 | import { NavLink } from 'react-router-dom';
5 | const ErrorPage = () => {
6 | return (
7 |
8 |
9 |
10 |
404
11 |
Sorry, the page you tried cannot be found
12 |
The page you are looking for dosen't exist. How you got here is a mystery. But you can click the button below to go back to the homepage
13 |
14 |
Go Back to Home
15 |
16 |
17 |
18 | )
19 | }
20 | const Wrapper = styled.section`
21 | .flex{
22 | display: flex;
23 | justify-content: center;
24 | align-items: center;
25 | flex-direction: column;
26 | }
27 | .box{
28 | margin: 8rem 2rem;
29 | }
30 | `;
31 | export default ErrorPage
--------------------------------------------------------------------------------
/src/GlobalStyle.js:
--------------------------------------------------------------------------------
1 | import { createGlobalStyle } from "styled-components";
2 |
3 | export const GlobalStyle = createGlobalStyle`
4 |
5 | * {
6 | margin: 0;
7 | padding: 0;
8 | box-sizing: border-box;
9 | font-family: "Work Sans", sans-serif;
10 | }
11 |
12 |
13 | html {
14 | font-size: 62.5%;
15 | /* scroll-behavior: smooth; */
16 | /* 1rem = 10px */
17 | overflow-x: hidden;
18 | }
19 |
20 | body {
21 | overflow-x: hidden;
22 | scrollbar-color: rgb(98 84 243);
23 | scrollbar-width: thin;
24 | }
25 |
26 | body::-webkit-scrollbar {
27 | width: 1.5rem;
28 | }
29 |
30 | body::-webkit-scrollbar-track {
31 | background-color: rgb(24 24 29);
32 | }
33 |
34 | body::-webkit-scrollbar-thumb {
35 |
36 | background: #fff;
37 | border: 5px solid transparent;
38 | border-radius: 9px;
39 | background-clip: content-box;
40 | }
41 |
42 | h1,
43 | h2,
44 | h3,
45 | h4 {
46 | font-family: "Work Sans", sans-serif;
47 |
48 | }
49 |
50 | h1 {
51 | color: ${({ theme }) => theme.colors.heading};
52 | font-size: 6rem;
53 | font-weight: 900;
54 | }
55 |
56 | h2 {
57 | color: ${({ theme }) => theme.colors.heading};
58 | font-size: 4.4rem;
59 | font-weight: 300;
60 | white-space: normal;
61 |
62 | }
63 |
64 | h3 {
65 | font-size: 1.8rem;
66 | font-weight: 400;
67 | }
68 |
69 | p, button {
70 | color: ${({ theme }) => theme.colors.text};
71 | font-size: 1.65rem;
72 | line-height: 1.5;
73 | font-weight:400;
74 |
75 | }
76 |
77 | a {
78 | text-decoration: none;
79 | }
80 |
81 | li {
82 | list-style: none;
83 | }
84 |
85 |
86 | ${"" /* resuable code section */}
87 |
88 | .container {
89 | max-width: 120rem;
90 | margin: 0 auto;
91 | }
92 |
93 | .grid {
94 | display: grid;
95 | gap: 9rem;
96 | }
97 |
98 | .grid-two-column {
99 | grid-template-columns: repeat(2, 1fr);
100 |
101 | }
102 |
103 |
104 | .b{
105 | border: 1px solid red;
106 | }
107 | .grid-three-column {
108 | grid-template-columns: repeat(3, 1fr);
109 | }
110 |
111 | .grid-four-column{
112 | grid-template-columns: 1fr 1.2fr .5fr .8fr ;
113 | }
114 |
115 | .grid-five-column{
116 | grid-template-columns: repeat(5, 1fr);
117 | }
118 |
119 | .common-heading {
120 | font-size: 3.8rem;
121 | font-weight: 600;
122 | margin-bottom: 6rem;
123 | text-transform: capitalize;
124 | }
125 |
126 | .intro-data {
127 | margin-bottom: 0;
128 | text-transform: uppercase;
129 | color: #5138ee;
130 | }
131 |
132 | .caption {
133 | position: absolute;
134 | top: 15%;
135 | right: 10%;
136 | text-transform: uppercase;
137 | background-color: ${({ theme }) => theme.colors.bg};
138 | color: ${({ theme }) => theme.colors.helper};
139 | padding: 0.8rem 2rem;
140 | font-size: 1.2rem;
141 | border-radius: 2rem;
142 | }
143 |
144 | input, textarea{
145 | max-width: 50rem;
146 | color: ${({ theme }) => theme.colors.black};
147 | padding: 1.6rem 2.4rem;
148 | border: 1px solid ${({ theme }) => theme.colors.border};
149 | text-transform: uppercase;
150 | box-shadow: ${({ theme }) => theme.colors.shadowSupport};
151 | }
152 | input[type="submit"]{
153 | max-width: 16rem;
154 | margin-top: 2rem;
155 | background-color: ${({ theme }) => theme.colors.btn};
156 | color: ${({ theme }) => theme.colors.white};
157 | padding: 1.4rem 2.2rem;
158 | border-style: solid;
159 | border-width: .1rem;
160 | text-transform: uppercase;
161 | font-size: 1.8rem;
162 | cursor: pointer;
163 | }
164 |
165 | @media (max-width: ${({ theme }) => theme.media.tab}) {
166 | .container {
167 | max-width: 130rem;
168 | padding: 0 3.2rem;
169 | }
170 | }
171 |
172 | @media (max-width: ${({ theme }) => theme.media.mobile}) {
173 | html {
174 | font-size: 50%;
175 | }
176 |
177 | .grid{
178 | gap: 3.2rem;
179 | }
180 | .grid-two-column , .grid-three-column, .grid-four-column{
181 | grid-template-columns: 1fr;
182 | }
183 | }
184 |
185 | `;
186 |
--------------------------------------------------------------------------------
/src/Helpers/FormatPrice.js:
--------------------------------------------------------------------------------
1 |
2 | const FormatPrice = ({price}) => {
3 | return Intl.NumberFormat('en-IN',{style:'currency', currency:'INR', maximumFractionDigits:2}).format(price/100)
4 | }
5 |
6 | export default FormatPrice
--------------------------------------------------------------------------------
/src/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import HeroSection from './components/HeroSection';
4 | import Trusted from './components/Trusted';
5 | import Services from './components/Services';
6 | import FeatureProduct from './components/FeatureProduct';
7 | const Home = () => {
8 | const data={
9 | title:'Akash Store'
10 | }
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 | )
19 | }
20 | const Wrapper = styled.div`
21 |
22 | `;
23 | export default Home
--------------------------------------------------------------------------------
/src/Products.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "styled-components";
3 | import FilterSection from "./components/FilterSection";
4 | import ProductList from "./components/ProductList";
5 | import Sort from "./components/Sort";
6 | import { useFilterContext } from "./context/filter_context";
7 | const Products = () => {
8 | const {grid_view,filtered_products,setGridView}=useFilterContext();
9 | return
10 |
23 | ;
24 | };
25 |
26 | const Wrapper = styled.section`
27 | .grid-filter-column {
28 | grid-template-columns: 0.2fr 1fr;
29 | }
30 |
31 | @media (max-width: ${({ theme }) => theme.media.mobile}) {
32 | .grid-filter-column {
33 | grid-template-columns: 1fr;
34 | }
35 | }
36 | `;
37 |
38 | export default Products;
39 |
--------------------------------------------------------------------------------
/src/SingleProduct.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 | import { useParams } from "react-router-dom";
3 | import { useEffect } from "react";
4 | import { useProductContext } from "./context/productcontext";
5 | import PageNavigation from "./components/PageNavigation";
6 | import MyImage from "./components/MyImage";
7 | import FormatPrice from "./Helpers/FormatPrice";
8 | import { MdSecurity } from "react-icons/md";
9 | import { TbTruckDelivery, TbReplace } from "react-icons/tb";
10 | import Spinner from "./components/Spinner";
11 | import Stars from "./components/Stars";
12 | import AddToCart from "./components/AddToCart";
13 | const SingleProduct = () =>{
14 | // id: ID is alias name
15 | const {singleProduct,getSingleProduct,isSingleLoading}=useProductContext();
16 | const {id:productId} = useParams();
17 | const API =`https://api.pujakaitem.com/api/products`
18 | const runApi=async()=>{
19 | getSingleProduct(`${API}?id=${productId}`);
20 | }
21 | useEffect(() => {
22 | runApi()
23 | // eslint-disable-next-line
24 | },[])
25 |
26 | const {id,name,price,company,description,stock,reviews,stars,image}=singleProduct;
27 | return(
28 |
29 |
30 | {isSingleLoading? :
31 |
32 | {/* product imag */}
33 |
34 |
35 |
36 | {/* product data */}
37 |
38 |
{name}
39 |
40 |
41 | MRP:
42 |
43 |
44 |
45 |
46 |
47 | Deal of the Day:
48 |
49 | {description}
50 |
51 |
52 |
53 |
Free Delivery
54 |
55 |
56 |
57 |
58 |
30 Days Replacement
59 |
60 |
61 |
62 |
63 |
Akash Delivered
64 |
65 |
66 |
67 |
68 |
2 Year Warranty
69 |
70 |
71 |
72 |
73 |
Available:{stock>0?" In Stock":" Out of Stock"}
74 |
75 | ID : {id}
76 |
77 |
78 | Brand : {company}
79 |
80 |
81 |
82 |
83 | {stock&&}
84 |
85 |
86 |
}
87 |
88 | );
89 | }
90 |
91 | const Wrapper = styled.section`
92 | .container {
93 | padding: 9rem 0;
94 | }
95 | .product-data {
96 | display: flex;
97 | flex-direction: column;
98 | align-items: flex-start;
99 | justify-content: center;
100 | gap: 2rem;
101 |
102 | .product-data-warranty {
103 | width: 100%;
104 | display: flex;
105 | justify-content: space-between;
106 | align-items: center;
107 | border-bottom: 1px solid #ccc;
108 | margin-bottom: 1rem;
109 |
110 | .product-warranty-data {
111 | text-align: center;
112 |
113 | .warranty-icon {
114 | background-color: rgba(220, 220, 220, 0.5);
115 | border-radius: 50%;
116 | width: 4rem;
117 | height: 4rem;
118 | padding: 0.6rem;
119 | }
120 | p {
121 | font-size: 1.4rem;
122 | padding-top: 0.4rem;
123 | }
124 | }
125 | }
126 | .product-images{
127 | display:flex;
128 | align-items:center;
129 | }
130 | .product-data-price {
131 | font-weight: bold;
132 | }
133 | .product-data-real-price {
134 | color: ${({ theme }) => theme.colors.btn};
135 | }
136 | .product-data-info {
137 | display: flex;
138 | flex-direction: column;
139 | gap: 1rem;
140 | font-size: 1.8rem;
141 |
142 | span {
143 | font-weight: bold;
144 | }
145 | }
146 |
147 | hr {
148 | max-width: 100%;
149 | width: 90%;
150 | /* height: 0.2rem; */
151 | border: 0.1rem solid #000;
152 | color: red;
153 | }
154 | }
155 |
156 | .product-images {
157 | display: flex;
158 | justify-content: center;
159 | align-items: center;
160 | }
161 |
162 | @media (max-width: ${({ theme }) => theme.media.mobile}) {
163 | padding: 0 2.4rem;
164 | }
165 | `;
166 |
167 | export default SingleProduct;
168 |
--------------------------------------------------------------------------------
/src/components/AddToCart.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { FaCheck } from 'react-icons/fa'
3 | import { NavLink } from 'react-router-dom'
4 | import styled from 'styled-components'
5 | import { useCartContext } from '../context/cart_context'
6 | import { Button } from '../styles/Button'
7 | import CartAmountToggle from './CartAmountToggle'
8 | const AddToCart = ({ product }) => {
9 | const { id, colors, stock } = product
10 | const [mainColor, setMainColor] = useState(colors[0])
11 | const [amount, setAmount] = useState(1)
12 |
13 | const setDecrease = () => {
14 | amount > 1 ? setAmount(amount - 1) : setAmount(1)
15 | }
16 | const setIncrease = () => {
17 | amount < stock ? setAmount(amount + 1) : setAmount(stock)
18 | }
19 | const { addToCart } = useCartContext()
20 |
21 | return (
22 |
23 |
24 |
25 | colors :
26 | {colors.map((curColor, index) => {
27 | return (
28 | setMainColor(curColor)} >
33 | {mainColor === curColor ? : null}
34 |
35 | );
36 | })}
37 |
38 |
39 |
40 | {/* add to cart */}
41 |
42 | addToCart(id, mainColor, amount, product)} className="btn">
43 | Add TO Cart
44 |
45 |
46 | )
47 | }
48 | const Wrapper = styled.section`
49 | .colors p {
50 | display: flex;
51 | justify-content: flex-start;
52 | align-items: center;
53 | }
54 | .btnStyle {
55 | width: 2rem;
56 | height: 2rem;
57 | background-color: #000;
58 | border-radius: 50%;
59 | margin-left: 1rem;
60 | border: none;
61 | outline: none;
62 | opacity: 0.5;
63 | cursor: pointer;
64 |
65 | &:hover {
66 | opacity: 1;
67 | }
68 | }
69 |
70 | .active {
71 | opacity: 1;
72 | }
73 |
74 | .checkStyle {
75 | font-size: 1rem;
76 | color: #fff;
77 | }
78 |
79 | /* we can use it as a global one too */
80 | .amount-toggle {
81 | margin-top: 3rem;
82 | margin-bottom: 1rem;
83 | display: flex;
84 | justify-content: space-around;
85 | align-items: center;
86 | font-size: 1.4rem;
87 |
88 | button {
89 | border: none;
90 | background-color: #fff;
91 | cursor: pointer;
92 | }
93 |
94 | .amount-style {
95 | font-size: 2.4rem;
96 | color: ${({ theme }) => theme.colors.btn};
97 | }
98 | }
99 | `;
100 | export default AddToCart
--------------------------------------------------------------------------------
/src/components/CartAmountToggle.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { FaMinus, FaPlus } from 'react-icons/fa'
3 | const CartAmountToggle = ({amount,setDecrease,setIncrease}) => {
4 | return (
5 |
6 |
7 |
8 |
setDecrease()}>
9 |
{amount}
10 |
setIncrease()}>
11 |
12 |
13 |
14 | )
15 | }
16 |
17 | export default CartAmountToggle
--------------------------------------------------------------------------------
/src/components/CartItem.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import FormatPrice from "../Helpers/FormatPrice";
3 | import CartAmountToggle from "./CartAmountToggle";
4 | import { FaTrash } from "react-icons/fa";
5 | import { useCartContext } from "../context/cart_context";
6 |
7 | const CartItem = ({ id,mainColor:color, amount,product }) => {
8 | const {name,price,image,stock}=product
9 | const { removeItem,setAmount } = useCartContext();
10 | const setDecrease = () => {
11 | amount > 1 ? setAmount(id,amount - 1,color) : setAmount(id,1,color);
12 | };
13 |
14 | const setIncrease = () => {
15 | amount < stock ? setAmount(id,amount + 1,color) : setAmount(id,stock,color);
16 | };
17 |
18 | return (
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
35 |
36 | {/* price */}
37 |
42 |
43 | {/* Quantity */}
44 |
49 |
50 | {/* //Subtotal */}
51 |
56 |
57 |
58 | removeItem(id,color)} />
59 |
60 |
61 | );
62 | };
63 |
64 | export default CartItem;
--------------------------------------------------------------------------------
/src/components/FeatureProduct.js:
--------------------------------------------------------------------------------
1 | import { useProductContext } from "../context/productcontext";
2 | import Spinner from "./Spinner";
3 | import styled from "styled-components";
4 |
5 | import Product from "./Product";
6 | const FeatureProduct = () => {
7 | const { isLoading,featuredProducts} = useProductContext();
8 | // {isLoading ? : hello }
9 | return (
10 |
11 | {isLoading ? :
12 |
Check Now
13 |
Our Feature Service
14 |
15 | {
16 | featuredProducts.map((product) => {
17 | return
18 | })
19 | }
20 |
21 |
}
22 |
23 | )
24 | }
25 | const Wrapper = styled.section`
26 | padding: 9rem 0;
27 | background-color: ${({ theme }) => theme.colors.bg};
28 |
29 | .container {
30 | max-width: 120rem;
31 | }
32 |
33 |
34 | `;
35 | export default FeatureProduct
--------------------------------------------------------------------------------
/src/components/FilterSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useFilterContext } from '../context/filter_context';
3 | import styled from 'styled-components';
4 | import { Button } from '../styles/Button';
5 | const FilterSection = () => {
6 | const { filter: { text, category, color }, updateFilterValue, all_products } = useFilterContext();
7 |
8 | // map is used to get only that particular data of object
9 | // filter is used to get the entire object data
10 | const getUniqueData = (data, type) => {
11 | let newVal = data.map((item) => item[type]);
12 | if (type === 'colors') {
13 | newVal = ["all", ...new Set(newVal.flat(1))];
14 | return newVal;
15 | }
16 | else {
17 | newVal = ["all", ...new Set(newVal)];
18 | return newVal;
19 | }
20 | }
21 | // const getUniqueColor = (data, type) => {
22 | // let newVal = data.map((item) => item[type]);
23 | // if(type==='colors'){
24 | // newVal = ["all", ...new Set(newVal.flat(1))];
25 | // return newVal;
26 | // }
27 | // else{
28 | // newVal = ["all", ...new Set(newVal)];
29 | // return newVal;
30 | // }
31 | // }
32 | // we need unique category data from all products
33 | const categoryData = getUniqueData(all_products, 'category');
34 | const companyData = getUniqueData(all_products, 'company');
35 | const colorsData = getUniqueData(all_products, 'colors');
36 | return (
37 |
38 |
39 |
e.preventDefault()}>
40 | { updateFilterValue(e.target.value, 'text') }}
46 | />
47 |
48 |
49 |
50 |
51 |
Category
52 |
53 | {categoryData.map((curElem, index) => {
54 | return (
55 | { updateFilterValue(curElem, 'category') }}>
62 | {curElem}
63 |
64 | );
65 | })}
66 |
67 |
68 |
69 |
70 |
Company
71 |
72 |
73 |
78 | {companyData.map((curElem, index) => {
79 | return (
80 | { updateFilterValue(curElem, 'company') }}>
81 | {curElem}
82 |
83 | );
84 | })}
85 |
86 |
87 |
88 |
89 |
90 |
Colors
91 |
92 |
93 | {colorsData.map((curColor, index) => {
94 | return (
95 |
103 | {color === curColor ? "" : null}
104 |
105 | );
106 | })}
107 |
108 |
109 |
110 | { updateFilterValue('', 'clear') }}>Clear Filters
111 |
112 |
113 | )
114 | }
115 | const Wrapper = styled.section`
116 | padding: 5rem 0;
117 | display: flex;
118 | flex-direction: column;
119 | gap: 3rem;
120 |
121 | h3 {
122 | padding: 2rem 0;
123 | font-size: bold;
124 | }
125 |
126 | .filter-search {
127 | input {
128 | padding: 0.6rem 1rem;
129 | width: 80%;
130 | }
131 | }
132 |
133 | .filter-category {
134 | div {
135 | display: flex;
136 | flex-direction: column;
137 | align-items: flex-start;
138 | gap: 1.4rem;
139 |
140 | button {
141 | border: none;
142 | background-color: ${({ theme }) => theme.colors.white};
143 | text-transform: capitalize;
144 | cursor: pointer;
145 |
146 | &:hover {
147 | color: ${({ theme }) => theme.colors.btn};
148 | }
149 | }
150 |
151 | .active {
152 | border-bottom: 1px solid #000;
153 | color: ${({ theme }) => theme.colors.btn};
154 | }
155 | }
156 | }
157 |
158 |
159 | .filter-company--select {
160 | padding: 0.3rem 1.2rem;
161 | font-size: 1.6rem;
162 | color: ${({ theme }) => theme.colors.text};
163 | text-transform: capitalize;
164 | }
165 |
166 | .filter-color-style {
167 | display: flex;
168 | justify-content: center;
169 | }
170 |
171 | .color-all--style {
172 | background-color: transparent;
173 | text-transform: capitalize;
174 | border: none;
175 | cursor: pointer;
176 | }
177 | .btnStyle {
178 | width: 2rem;
179 | height: 2rem;
180 | background-color: #000;
181 | border-radius: 50%;
182 | margin-left: 1rem;
183 | border: none;
184 | outline: none;
185 | opacity: 0.5;
186 | cursor: pointer;
187 |
188 | &:hover {
189 | opacity: 1;
190 | }
191 | }
192 |
193 | .active {
194 | opacity: 1;
195 | }
196 |
197 | .checkStyle {
198 | font-size: 1rem;
199 | color: #fff;
200 | }
201 |
202 | .filter_price {
203 | input {
204 | margin: 0.5rem 0 1rem 0;
205 | padding: 0;
206 | box-shadow: none;
207 | cursor: pointer;
208 | }
209 | }
210 |
211 | .filter-shipping {
212 | display: flex;
213 | align-items: center;
214 | gap: 1rem;
215 | }
216 |
217 | .filter-clear .btn {
218 | background-color: #ec7063;
219 | color: #000;
220 | }
221 | @media (max-width: ${({ theme }) => theme.media.mobile}) {
222 | .filter-category {
223 | div {
224 | flex-direction: row;
225 | }
226 | }
227 | }
228 | `;
229 | export default FilterSection
--------------------------------------------------------------------------------
/src/components/Footer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 | import { Button } from '../styles/Button';
4 | import { NavLink } from 'react-router-dom';
5 | import { FaDiscord, FaInstagram, FaYoutube } from "react-icons/fa";
6 | const Footer = () => {
7 | return (
8 |
9 |
10 |
11 |
12 |
Ready to get started?
13 | Talk to us today
14 |
15 |
16 |
17 | Get Started
18 |
19 |
20 |
21 |
22 | {/* footer section */}
23 |
72 |
73 | )
74 | }
75 | const Wrapper = styled.section`
76 | margin-top: 2rem;
77 | footer{
78 | background: ${({ theme }) => theme.colors.footer_bg};
79 | padding-top:13rem;
80 | padding-bottom: 2rem;
81 | width: 100vw;
82 | h3 {
83 | color: ${({ theme }) => theme.colors.hr};
84 | margin-bottom: 2.4rem;
85 | }
86 | .footer-social--icons {
87 | display: flex;
88 | gap: 2rem;
89 |
90 | div {
91 | padding: 1rem;
92 | border-radius: 50%;
93 | border: 2px solid ${({ theme }) => theme.colors.white};
94 | height: 5rem;
95 | .icons {
96 | color: ${({ theme }) => theme.colors.white};
97 | font-size: 2.4rem;
98 | position: relative;
99 | cursor: pointer;
100 |
101 | }
102 | }
103 | }
104 | }
105 | .footer-bottom--section {
106 | padding-top: 9rem;
107 |
108 | hr {
109 | margin-bottom: 2rem;
110 | color: ${({ theme }) => theme.colors.hr};
111 | height: 0.1px;
112 | }
113 | }
114 | .contact-short {
115 | max-width: 60vw;
116 | margin: auto;
117 | padding: 5rem 10rem;
118 | background-color: ${({ theme }) => theme.colors.bg};
119 | border-radius: 1rem;
120 | box-shadow: ${({ theme }) => theme.colors.shadowSupport};
121 | transform: translateY(50%);
122 |
123 | .grid div:last-child {
124 | justify-self: end;
125 | align-self: center;
126 | }
127 | }
128 | @media (max-width: ${({ theme }) => theme.media.mobile}) {
129 | .contact-short {
130 | max-width: 80vw;
131 | margin: 4.8rem auto;
132 | transform: translateY(0%);
133 | text-align: center;
134 |
135 | .grid div:last-child {
136 | justify-self: center;
137 | }
138 | }
139 |
140 | footer {
141 | padding: 9rem 0 2rem 0;
142 | }
143 |
144 | .footer-bottom--section {
145 | padding-top: 4.8rem;
146 | }
147 | }
148 | `;
149 | export default Footer
--------------------------------------------------------------------------------
/src/components/GridView.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Product from './Product'
3 | import styled from 'styled-components'
4 | const GridView = ({filtered_products}) => {
5 | return (
6 |
7 |
8 | {filtered_products.map((product)=>{
9 | return
10 | })}
11 |
12 |
13 |
14 | )
15 | }
16 |
17 | const Wrapper = styled.section`
18 |
19 | background-color: ${({ theme }) => theme.colors.bg};
20 | .grid{
21 | gap:1rem;
22 | padding:2rem;
23 | }
24 | .container {
25 | max-width: 120rem;
26 | }
27 |
28 |
29 | `
30 | export default GridView
--------------------------------------------------------------------------------
/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 | import React from 'react'
3 | import { NavLink } from "react-router-dom";
4 | import Nav from "./Nav";
5 | import logo from '../images/logo.png'
6 | const Header = () => {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 | )
15 | }
16 |
17 | const MainHeader = styled.header`
18 |
19 | padding: 0 4.8rem;
20 | height: 10rem;
21 | background-color: ${({ theme }) => theme.colors.bg};
22 | display: flex;
23 | justify-content: space-between;
24 | align-items: center;
25 | position: relative;
26 |
27 | .logo {
28 | height: 4rem;
29 | }
30 |
31 | `;
32 | export default Header
--------------------------------------------------------------------------------
/src/components/HeroSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { NavLink } from 'react-router-dom';
3 | import styled from 'styled-components'
4 | import {Button} from '../styles/Button'
5 | import heroImage from '../images/hero.jpg'
6 | const HeroSection = ({data}) => {
7 | const {title}=data;
8 | return (
9 |
10 |
11 |
12 |
13 |
{title}
14 |
15 | Welcome to
16 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Excepturi laboriosam cumque, dolore nesciunt facere eveniet incidunt minus voluptatibus aut libero dolor unde similique alias soluta possimus, tempore modi sunt explicabo
17 |
18 |
19 | Shop Now
20 |
21 |
22 | {/* HeroSection Image */}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | )
32 | }
33 | const Wrapper = styled.section`
34 | padding: 12rem 0;
35 |
36 | img {
37 | min-width: 10rem;
38 | height: 10rem;
39 | }
40 |
41 | .hero-section-data {
42 | p {
43 | margin: 2rem 0;
44 | }
45 |
46 | h1 {
47 | text-transform: capitalize;
48 | font-weight: bold;
49 | }
50 |
51 | .intro-data {
52 | margin-bottom: 0;
53 | }
54 | }
55 |
56 | .hero-section-image {
57 | width: 100%;
58 | height: auto;
59 | display: flex;
60 | justify-content: center;
61 | align-items: center;
62 | }
63 | figure {
64 | position: relative;
65 |
66 | &::after {
67 | content: "";
68 | width: 60%;
69 | height: 80%;
70 | background-color: rgba(81, 56, 238, 0.4);
71 | position: absolute;
72 | left: 50%;
73 | top: -5rem;
74 | z-index: -1;
75 | }
76 | }
77 | .img-style {
78 | width: 100%;
79 | height: auto;
80 | }
81 |
82 | @media (max-width: ${({ theme }) => theme.media.mobile}) {
83 | .grid {
84 | gap: 10rem;
85 | }
86 |
87 | figure::after {
88 | content: "";
89 | width: 50%;
90 | height: 100%;
91 | left: 0;
92 | top: 10%;
93 | /* bottom: 10%; */
94 | background-color: rgba(81, 56, 238, 0.4);
95 | }
96 | }
97 | `;
98 | export default HeroSection
--------------------------------------------------------------------------------
/src/components/ListView.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components';
3 | import FormatPrice from '../Helpers/FormatPrice';
4 | import { Button } from '../styles/Button';
5 | import { NavLink } from 'react-router-dom';
6 | const ListView = ({filtered_products}) => {
7 | return (
8 |
9 |
10 | {filtered_products.map((curElem) => {
11 | const { id, name, image, price, description } = curElem;
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
{name}
21 |
22 |
23 |
24 |
{description.slice(0, 90)}...
25 |
Add to cart
26 |
27 |
28 |
29 | );
30 | })}
31 |
32 |
33 | )
34 | }
35 | const Wrapper = styled.section`
36 | padding: 4rem 0;
37 |
38 | .container {
39 | max-width: 120rem;
40 | }
41 |
42 | .grid {
43 | gap: 3.2rem;
44 | }
45 |
46 | figure {
47 | width: auto;
48 | display: flex;
49 | justify-content: center;
50 | // align-items: center;
51 | position: relative;
52 | overflow: hidden;
53 | transition: all 0.5s linear;
54 | &::after {
55 | content: "";
56 | position: absolute;
57 | top: 0;
58 | left: 0;
59 | width: 0%;
60 | height: 100%;
61 | background-color: rgba(0, 0, 0, 0.5);
62 | transition: all 0.2s linear;
63 | cursor: pointer;
64 | }
65 | &:hover::after {
66 | width: 100%;
67 | }
68 | &:hover img {
69 | transform: scale(1.2);
70 | }
71 | img {
72 | max-width: 90%;
73 | margin-top: 1.5rem;
74 | height: 20rem;
75 | transition: all 0.2s linear;
76 | }
77 | }
78 |
79 | .card {
80 | border: 0.1rem solid rgb(170 170 170 / 40%);
81 |
82 | .card-data {
83 | padding: 0 2rem;
84 | }
85 |
86 | h3 {
87 | margin: 2rem 0;
88 | font-weight: 300;
89 | font-size: 2.4rem;
90 | text-transform: capitalize;
91 | }
92 |
93 | .btn {
94 | margin: 2rem 0;
95 | background-color: rgb(0 0 0 / 0%);
96 | border: 0.1rem solid rgb(98 84 243);
97 | display: flex;
98 | justify-content: center;
99 | align-items: center;
100 | color: rgb(98 84 243);
101 |
102 | &:hover {
103 | background-color: rgb(98 84 243);
104 | }
105 |
106 | &:hover a {
107 | color: #fff;
108 | }
109 | a {
110 | color: rgb(98 84 243);
111 | font-size: 1.4rem;
112 | }
113 | }
114 |
115 | .btn-main .btn:hover {
116 | color: #fff;
117 | }
118 | }
119 | `;
120 | export default ListView
--------------------------------------------------------------------------------
/src/components/MyImage.js:
--------------------------------------------------------------------------------
1 | import React,{useState} from 'react'
2 | import styled from 'styled-components';
3 | const MyImage = ({img=[{url:""}]}) => {
4 | const [mainImg,setMainImg]=React.useState(img[0]);
5 | return (
6 |
7 |
8 | {
9 | img.map((currElm,index)=>{
10 | return(
11 |
12 | {
13 | setMainImg(currElm)
14 | }} />
15 |
16 | )
17 | })
18 | }
19 |
20 |
21 | {/* {2nd column} */}
22 |
23 |
24 |
25 |
26 | )
27 | }
28 | const Wrapper = styled.section`
29 | display: grid;
30 | grid-template-columns: 0.4fr 1fr;
31 | gap: 1rem;
32 |
33 | .grid {
34 | flex-direction: row;
35 | justify-items: center;
36 | align-items: center;
37 | width: 100%;
38 | gap: 1rem;
39 | /* order: 2; */
40 |
41 | img {
42 | max-width: 100%;
43 | max-height: 100%;
44 | background-size: cover;
45 | object-fit: contain;
46 | cursor: pointer;
47 | box-shadow: ${({ theme }) => theme.colors.shadow};
48 | }
49 | }
50 |
51 | .main-screen {
52 | display: grid;
53 | place-items: center;
54 | order: 1;
55 | img {
56 | max-width: 100%;
57 | height: auto;
58 | box-shadow: ${({ theme }) => theme.colors.shadow};
59 | }
60 | }
61 | .grid-four-column {
62 | grid-template-columns: 1fr;
63 | grid-template-rows: repeat(4, 1fr);
64 | }
65 |
66 | @media (max-width: ${({ theme }) => theme.media.mobile}) {
67 | display: flex;
68 | flex-direction: column;
69 | order: 1;
70 |
71 | .grid-four-column {
72 | grid-template-rows: 1fr;
73 | grid-template-columns: repeat(4, 1fr);
74 | }
75 | }
76 | `;
77 |
78 | export default MyImage
--------------------------------------------------------------------------------
/src/components/Nav.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { NavLink } from "react-router-dom";
3 | import styled from "styled-components";
4 | import { FiShoppingCart } from "react-icons/fi";
5 | import { CgMenu, CgClose } from "react-icons/cg";
6 | import { useCartContext } from "../context/cart_context";
7 |
8 | const Nav = () => {
9 | const [menuIcon, setMenuIcon] = useState();
10 | const {total_items}=useCartContext()
11 |
12 | return (
13 |
14 |
15 |
16 |
17 | setMenuIcon(false)}>
21 | Home
22 |
23 |
24 |
25 | setMenuIcon(false)}>
29 | About
30 |
31 |
32 |
33 | setMenuIcon(false)}>
37 | Products
38 |
39 |
40 |
41 | setMenuIcon(false)}>
45 | Contact
46 |
47 |
48 |
49 |
50 |
51 | {total_items}
52 |
53 |
54 |
55 |
56 | {/* two button for open and close of menu */}
57 |
58 | setMenuIcon(true)}/>
59 | setMenuIcon(false)} className="mobile-nav-icon close-outline"/>
60 |
61 |
62 |
63 | );
64 | };
65 | const NavStyle = styled.nav`
66 | .navbar-lists {
67 | display: flex;
68 | gap: 4.8rem;
69 | align-items: center;
70 |
71 | .navbar-link {
72 | &:link,
73 | &:visited {
74 | display: inline-block;
75 | text-decoration: none;
76 | font-size: 1.8rem;
77 | font-weight: 500;
78 | text-transform: uppercase;
79 | color: ${({ theme }) => theme.colors.black};
80 | transition: color 3s linear;
81 | }
82 |
83 | &:hover,
84 | &:active {
85 | color: ${({ theme }) => theme.colors.helper};
86 | }
87 | }
88 | }
89 |
90 | .mobile-navbar-btn {
91 | display: none;
92 | background-color: transparent;
93 | cursor: pointer;
94 | border: none;
95 | }
96 |
97 | .mobile-nav-icon[name="close-outline"] {
98 | display: none;
99 | }
100 |
101 | .close-outline {
102 | display: none;
103 | }
104 |
105 | .cart-trolley--link {
106 | position: relative;
107 |
108 | .cart-trolley {
109 | position: relative;
110 | font-size: 3.2rem;
111 | }
112 |
113 | .cart-total--item {
114 | width: 2.4rem;
115 | height: 2.4rem;
116 | position: absolute;
117 | background-color: #000;
118 | color: #000;
119 | border-radius: 50%;
120 | display: grid;
121 | place-items: center;
122 | top: -20%;
123 | left: 70%;
124 | background-color: ${({ theme }) => theme.colors.helper};
125 | }
126 | }
127 |
128 | .user-login--name {
129 | text-transform: capitalize;
130 | }
131 |
132 | .user-logout,
133 | .user-login {
134 | font-size: 1.4rem;
135 | padding: 0.8rem 1.4rem;
136 | }
137 |
138 | @media (max-width: ${({ theme }) => theme.media.mobile}) {
139 | .mobile-navbar-btn {
140 | display: inline-block;
141 | z-index: 9999;
142 | border: ${({ theme }) => theme.colors.black};
143 |
144 | .mobile-nav-icon {
145 | font-size: 4.2rem;
146 | color: ${({ theme }) => theme.colors.black};
147 | }
148 | }
149 |
150 | .active .mobile-nav-icon {
151 | display: none;
152 |
153 | font-size: 4.2rem;
154 | position: absolute;
155 | top: 30%;
156 | right: 10%;
157 | color: ${({ theme }) => theme.colors.black};
158 | z-index: 9999;
159 | }
160 |
161 | .active .close-outline {
162 | display: inline-block;
163 | }
164 |
165 | .navbar-lists {
166 | width: 100vw;
167 | height: 100vh;
168 | position: absolute;
169 | top: 0;
170 | left: 0;
171 | background-color: #fff;
172 |
173 | display: flex;
174 | justify-content: center;
175 | align-items: center;
176 | flex-direction: column;
177 |
178 | visibility: hidden;
179 | opacity: 0;
180 | transform: translateX(100%);
181 | /* transform-origin: top; */
182 | transition: all 0.5s linear;
183 | }
184 |
185 | .active .navbar-lists {
186 | visibility: visible;
187 | opacity: 1;
188 | transform: translateX(0);
189 | z-index: 999;
190 | transform-origin: right;
191 | transition: all 0.5s linear;
192 |
193 | .navbar-link {
194 | font-size: 4.2rem;
195 | }
196 | }
197 | .cart-trolley--link {
198 | position: relative;
199 |
200 | .cart-trolley {
201 | position: relative;
202 | font-size: 5.2rem;
203 | }
204 |
205 | .cart-total--item {
206 | width: 4.2rem;
207 | height: 4.2rem;
208 | font-size: 2rem;
209 | }
210 | }
211 |
212 | .user-logout,
213 | .user-login {
214 | font-size: 2.2rem;
215 | padding: 0.8rem 1.4rem;
216 | }
217 | }
218 | `;
219 | export default Nav;
--------------------------------------------------------------------------------
/src/components/PageNavigation.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { NavLink } from 'react-router-dom';
3 | import styled from 'styled-components';
4 | const PageNavigation = ({title}) => {
5 | return (
6 |
7 | Home /{title}
8 |
9 |
10 | )
11 | }
12 | const Wrapper = styled.section`
13 | height:10rem,
14 | background-color: ${({ theme }) => theme.colors.bg};
15 | display: flex;
16 | justify-content: flex-start;
17 | font-size: 3.2rem;
18 | padding-left: 1.2rem;
19 | padding-top: 1.2rem;
20 | NavLink{
21 | font-size:3.2rem;
22 | }
23 | `;
24 |
25 | export default PageNavigation
--------------------------------------------------------------------------------
/src/components/Product.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Button } from "../styles/Button";
3 | import { NavLink, useNavigate } from 'react-router-dom';
4 | import FormatPrice from '../Helpers/FormatPrice';
5 | import styled from 'styled-components';
6 | const Product = (product) => {
7 | const {id,name,price,image,category} = product
8 |
9 | const navigate =useNavigate()
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 | {category}
18 |
19 |
20 |
21 |
{name}
22 | {}
23 |
24 |
25 | navigate('/singleproduct/${id}')}>Add to cart
26 |
27 |
28 |
29 |
30 |
31 |
32 | )
33 | }
34 | const Wrapper = styled.section`
35 |
36 | figure {
37 | width: auto;
38 | display: flex;
39 | justify-content: center;
40 | align-items: center;
41 | position: relative;
42 | overflow: hidden;
43 | transition: all 0.5s linear;
44 | &::after {
45 | content: "";
46 | position: absolute;
47 | top: 0;
48 | left: 0;
49 | width: 0%;
50 | height: 100%;
51 | background-color: rgba(0, 0, 0, 0.5);
52 | transition: all 0.2s linear;
53 | cursor: pointer;
54 | }
55 | &:hover::after {
56 | width: 100%;
57 | }
58 | &:hover img {
59 | transform: scale(1.2);
60 | }
61 | img {
62 | max-width: 90%;
63 | margin-top: 1.5rem;
64 | height: 20rem;
65 | transition: all 0.2s linear;
66 | }
67 |
68 | .caption {
69 | position: absolute;
70 | top: 15%;
71 | right: 10%;
72 | text-transform: uppercase;
73 | background-color: ${({ theme }) => theme.colors.bg};
74 | color: ${({ theme }) => theme.colors.helper};
75 | padding: 0.8rem 2rem;
76 | font-size: 1.2rem;
77 | border-radius: 2rem;
78 | }
79 | }
80 |
81 | .card {
82 | background-color: #fff;
83 | border-radius: 1rem;
84 |
85 | .card-data {
86 | padding: 0 2rem;
87 | }
88 |
89 | .card-data-flex {
90 | margin: 2rem 0;
91 | display: flex;
92 | justify-content: space-between;
93 | align-items: center;
94 | }
95 |
96 | h3 {
97 | color: ${({ theme }) => theme.colors.text};
98 | text-transform: capitalize;
99 | }
100 |
101 | .card-data--price {
102 | color: ${({ theme }) => theme.colors.helper};
103 | }
104 |
105 | .btn {
106 | margin: 2rem auto;
107 | background-color: rgb(0 0 0 / 0%);
108 | border: 0.1rem solid rgb(98 84 243);
109 | display: flex;
110 | justify-content: center;
111 | align-items: center;
112 |
113 | &:hover {
114 | background-color: rgb(98 84 243);
115 | }
116 |
117 | &:hover a {
118 | color: #fff;
119 | }
120 | a {
121 | color: rgb(98 84 243);
122 | font-size: 1.4rem;
123 | }
124 | }
125 | }
126 | `
127 | export default Product
--------------------------------------------------------------------------------
/src/components/ProductList.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import { useProductContext } from '../context/productcontext'
4 | import Spinner from './Spinner'
5 | import GridView from './GridView'
6 | import ListView from './ListView'
7 | const ProductList = ({grid_view,filtered_products}) => {
8 | const {isLoading} =useProductContext();
9 | return (
10 |
11 | {isLoading? :grid_view?: }
12 |
13 |
14 | )
15 | }
16 | const Wrapper = styled.section`
17 |
18 | background-color: ${({ theme }) => theme.colors.bg};
19 | .grid{
20 | gap:1rem;
21 | padding:2rem;
22 | }
23 | .container {
24 | max-width: 120rem;
25 | }
26 |
27 |
28 | `
29 | export default ProductList
--------------------------------------------------------------------------------
/src/components/Services.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import {RiSecurePaymentLine } from "react-icons/ri"
4 | import {TbTruckDelivery} from "react-icons/tb"
5 | import {MdSecurity} from "react-icons/md"
6 | import {GiReceiveMoney} from "react-icons/gi"
7 | const Services = () => {
8 | return (
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Super Fast and Free Delivery
16 |
17 |
18 |
19 |
20 |
21 |
22 |
Non-contact Shipping
23 |
24 |
25 |
26 |
27 |
28 |
Money-back Guaranteed
29 |
30 |
31 |
32 |
33 |
34 |
35 |
Super Secure Payment System
36 |
37 |
38 |
39 |
40 |
41 | )
42 | }
43 | const Wrapper = styled.div`
44 | padding: 9rem 0;
45 |
46 | .grid {
47 | gap: 4.8rem;
48 | }
49 |
50 | .services-1,
51 | .services-2,
52 | .services-3 {
53 | width: auto;
54 | height: 30rem;
55 | display: flex;
56 | flex-direction: column;
57 | justify-content: center;
58 | align-content: center;
59 | background: ${({ theme }) => theme.colors.bg};
60 | text-align: center;
61 | border-radius: 2rem;
62 | box-shadow: rgba(0, 0, 0, 0.05) 0px 1px 2px 0px;
63 | }
64 |
65 | .services-2 {
66 | gap: 4rem;
67 | background-color: transparent;
68 | box-shadow: none;
69 |
70 | .services-colum-2 {
71 | background: ${({ theme }) => theme.colors.bg};
72 | display: flex;
73 | flex-direction: row;
74 | flex: 1;
75 | justify-content: center;
76 | align-items: center;
77 | border-radius: 2rem;
78 | box-shadow: rgba(0, 0, 0, 0.05) 0px 1px 2px 0px;
79 |
80 | div {
81 | display: flex;
82 | flex-direction: row;
83 | justify-content: center;
84 | align-items: center;
85 | gap: 1rem;
86 | }
87 | }
88 | }
89 |
90 | h3 {
91 | margin-top: 1.4rem;
92 | font-size: 2rem;
93 | }
94 |
95 | .icon {
96 | /* font-size: rem; */
97 | width: 8rem;
98 | height: 8rem;
99 | padding: 2rem;
100 | border-radius: 50%;
101 | background-color: #fff;
102 | color: #5138ee;
103 | }
104 | `;
105 | export default Services
--------------------------------------------------------------------------------
/src/components/Sort.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import styled from 'styled-components'
3 | import Select from 'react-select';
4 | import { BsFillGridFill, BsList } from "react-icons/bs";
5 | import { useFilterContext } from '../context/filter_context';
6 |
7 | const options = [
8 | { value: 'lowest', label: 'Price(lowest)' },
9 | { value: 'highest', label: 'Price(highest)' },
10 | { value: 'a-z', label: 'Name(Ascending)' },
11 | { value: 'z-a', label: 'Name(Descending)' },
12 | ];
13 | const customStyles = {
14 | option: (defaultStyles, state) => ({
15 | ...defaultStyles,
16 | color: state.isSelected ? "#000" : "#000",
17 | backgroundColor: state.isSelected ? "grey" : "#fff"
18 | }),
19 |
20 | control: (defaultStyles) => ({
21 | ...defaultStyles,
22 | border: "1px solid #000",
23 | borderRadius: "8px",
24 | boxShadow: "none",
25 | }),
26 | // singleValue: (defaultStyles) => ({ ...defaultStyles, color: "#111" }),
27 | };
28 |
29 | const Sort = ({ grid_view, setGridView, filtered_products }) => {
30 | const [selectedOption, setSelectedOption] = useState({value: 'lowest', label: 'Lowest'});
31 | const {sorting} = useFilterContext();
32 | useEffect(() => {
33 | sorting(selectedOption.value)
34 | },[selectedOption])
35 | return (
36 |
37 |
38 | { setGridView(true) }}>
39 |
40 |
41 | { setGridView(false) }}>
42 |
43 |
44 |
45 |
46 |
{filtered_products.length} products available
47 |
48 |
58 |
59 | )
60 | }
61 | const Wrapper = styled.section`
62 | display: flex;
63 | justify-content: space-between;
64 | align-items: center;
65 | margin-top: 5rem;
66 | margin-bottom: 5rem;
67 | .sorting-list--grid {
68 | display: flex;
69 | gap: 2rem;
70 |
71 | .sort-btn {
72 | padding: 0.8rem;
73 | border: none;
74 | display: flex;
75 | justify-content: center;
76 | align-items: center;
77 | cursor: pointer;
78 | }
79 |
80 | .icon {
81 | font-size: 1.6rem;
82 | }
83 | .active {
84 | background-color: ${({ theme }) => theme.colors.black};
85 | color: #fff;
86 | }
87 | }
88 |
89 | .sort-selection .sort-selection--style {
90 | padding: 0.5rem;
91 | cursor: pointer;
92 |
93 | .sort-select--option {
94 | padding: 0.5rem 0;
95 | cursor: pointer;
96 | height: 2rem;
97 | padding: 10px;
98 | }
99 | }
100 |
101 | .sort-selection--style{
102 | heigth:1rem;
103 | min-width: 10rem;
104 | width:20vh;
105 | }
106 | `;
107 |
108 | export default Sort
--------------------------------------------------------------------------------
/src/components/Spinner.js:
--------------------------------------------------------------------------------
1 |
2 | import React from 'react'
3 | import spinner from '../images/loading.gif'
4 | const Spinner = () => {
5 | return (
6 |
7 |
8 |
9 | )
10 | }
11 |
12 | export default Spinner
--------------------------------------------------------------------------------
/src/components/Stars.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { FaStar, FaStarHalfAlt } from 'react-icons/fa'
3 | import {AiOutlineStar} from 'react-icons/ai'
4 | import styled from 'styled-components'
5 | const Stars = ({stars, reviews}) => {
6 |
7 |
8 | const ratingStar= Array.from({length:5},(elem,index)=> {
9 | let number = index +0.5
10 | return(
11 |
12 | {stars>=index+1? :stars>=number? : }
13 |
14 | )
15 | }
16 | )
17 | return (
18 |
19 |
20 | {ratingStar}
21 |
22 |
{reviews} customer reviews
23 |
24 |
25 | )
26 | }
27 | const Wrapper = styled.section`
28 | .icon-style {
29 | display: flex;
30 | gap: 0.2rem;
31 | align-items: center;
32 | justify-content: flex-start;
33 |
34 | .icon {
35 | font-size: 2rem;
36 | color: orange;
37 | }
38 |
39 | .empty-icon {
40 | font-size: 2.6rem;
41 | }
42 | p {
43 | margin: 0;
44 | padding-left: 1.2rem;
45 | }
46 | }
47 | `;
48 |
49 | export default Stars
--------------------------------------------------------------------------------
/src/components/Trusted.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | const Trusted = () => {
4 | return (
5 |
6 |
7 |
Trusted by 1000+ Brands
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | )
28 | }
29 | const Wrapper = styled.section`
30 | padding: 9rem 0;
31 | background-color: ${({ theme }) => theme.colors.bg};
32 |
33 | .brand-section {
34 | padding: 12rem 0 0 0;
35 | }
36 | h3 {
37 | text-align: center;
38 | text-transform: capitalize;
39 | color: ${({ theme }) => theme.colors.text};
40 | font-size: 2rem;
41 | font-weight: bold;
42 | }
43 |
44 | img {
45 | min-width: 10rem;
46 | height: 10rem;
47 | }
48 |
49 | .brand-section-slider {
50 | margin-top: 3.2rem;
51 | display: flex;
52 | justify-content: space-between;
53 | align-items: center;
54 | flex-direction: row;
55 | }
56 |
57 | @media (max-width: ${({ theme }) => theme.media.mobile}) {
58 | .brand-section-slider {
59 | margin-top: 3.2rem;
60 | display: grid;
61 | grid-template-columns: 1fr 1fr;
62 | /* background-color: red; */
63 | text-align: center;
64 | }
65 | }
66 | `;
67 | export default Trusted
--------------------------------------------------------------------------------
/src/context/cart_context.js:
--------------------------------------------------------------------------------
1 | import { createContext,useContext,useReducer } from "react";
2 | import reducer from "../reducer/cartReducer";
3 | const CartContext= createContext();
4 | const initialState={
5 | cart:[],
6 | total_items:0,
7 | total_amount:0,
8 | shipping_fee:50000,
9 | }
10 | const CartProvider = ({children}) => {
11 | const [state,dispatch]=useReducer(reducer,initialState)
12 | const addToCart=(id,mainColor,amount,product)=>{
13 | console.log(product);
14 | dispatch({type:'ADD_TO_CART',payload:{id,mainColor,amount,product}})
15 | }
16 | const setAmount=(id,amount,color)=>{
17 | dispatch({type:'AMOUNT_TOGGLE',payload:{id,amount,color}})
18 | }
19 | const removeItem=(id,color)=>{
20 | dispatch({type:'REMOVE_ITEM',payload:{id,color}})
21 | }
22 | const clearCart=()=>{
23 | dispatch({type:'CLEAR_CART'})
24 | }
25 | return (
26 |
27 | {children}
28 |
29 | )
30 | }
31 |
32 | const useCartContext = () => {
33 | return useContext(CartContext)
34 | }
35 |
36 | export {CartProvider,useCartContext}
--------------------------------------------------------------------------------
/src/context/filter_context.js:
--------------------------------------------------------------------------------
1 | import { createContext, useContext, useEffect, useReducer } from "react";
2 | import { useProductContext } from "./productcontext";
3 |
4 | import reducer from "../reducer/filterReducer";
5 |
6 | const FilterContext = createContext();
7 |
8 |
9 | const initialState = {
10 | filtered_products: [],
11 | all_products: [],
12 | grid_view: true,
13 | sorting_value: "lowest",
14 | filter: {
15 | text: "",
16 | category: "all",
17 | company: "all",
18 | color: "all"
19 | }
20 | }
21 | const FilterContextProvider = ({ children }) => {
22 |
23 | const { products } = useProductContext();
24 | const [state, dispatch] = useReducer(reducer, initialState);
25 | const setGridView = (setGrid) => {
26 | return dispatch({ type: "SET_GRID_VIEW", payload: setGrid })
27 | }
28 |
29 | const sorting = (filter) => {
30 | return dispatch({ type: "GET_SORT_VALUE", payload:filter })
31 | }
32 | const updateFilterValue = (value, name) => {
33 | return dispatch({ type: "UPDATE_FILTER_VALUE", payload: { value, name } })
34 | }
35 | useEffect(() => {
36 | dispatch({ type: "USE_FILTER_SECTION" ,payload:products})
37 | dispatch({type:'SORTING_PRODUCTS'})
38 | }, [products, state.filter, state.sorting_value])
39 | useEffect(() => {
40 | dispatch({ type: "LOAD_FILTER_PRODUCTS", payload: products })
41 | }, [products])
42 | return (
43 |
44 | {children}
45 |
46 | )
47 | }
48 |
49 | const useFilterContext = () => {
50 | return useContext(FilterContext);
51 | }
52 |
53 | export { FilterContextProvider, useFilterContext }
--------------------------------------------------------------------------------
/src/context/productcontext.js:
--------------------------------------------------------------------------------
1 | // create a context
2 | // create a provider
3 | import { createContext ,useContext, useEffect, useReducer } from "react";
4 | import axios from "axios";
5 | import reducer from "../reducer/productReducer";
6 | // create a consumer
7 | const AppContext = createContext();
8 |
9 |
10 | const API = "https://api.pujakaitem.com/api/products"
11 | const initialState = {
12 | isLoading: false,
13 | isError: false,
14 | products: [],
15 | featuredProducts: [],
16 | isSingleLoading: false,
17 | singleProduct: {}
18 | }
19 |
20 | // Here the children is App component
21 | // Important to add App component in index.js
22 | const AppProvider = ({ children }) => {
23 |
24 | const [state, dispatch] = useReducer(reducer, initialState);
25 |
26 | const getProducts = async (url) => {
27 | dispatch({type:"SET_LOADING"})
28 | try{
29 | const response = await axios.get(url);
30 | const products = await response.data;
31 | dispatch({type:"SET_API_DATA" , payload:products})
32 | }
33 | catch(error){
34 | dispatch({type:"API_ERROR"})
35 | }
36 | }
37 | // My second Api call for single product
38 | const getSingleProduct = async (url)=>{
39 | dispatch({type:"SET_SINGLE_LOADING"})
40 | try {
41 | const response = await axios.get(url)
42 | const singleProduct = await response.data;
43 | dispatch({type:"SET_SINGLE_PRODUCT", payload:singleProduct})
44 | } catch (error) {
45 | dispatch({type:"SET_SINGLE_ERROR"})
46 | }
47 | }
48 |
49 | useEffect(() => {
50 | getProducts(API);
51 | },[])
52 |
53 | return (
54 |
55 | {children}
56 |
57 | );
58 | }
59 |
60 | // Custom hooks
61 | const useProductContext = () => {
62 | return useContext(AppContext);
63 | }
64 |
65 | export {AppProvider, AppContext,useProductContext};
--------------------------------------------------------------------------------
/src/images/hero.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akashm-2003/ecommerce-react/354c3371b5c99d3a58d3bd6e17440f3815f63901/src/images/hero.jpg
--------------------------------------------------------------------------------
/src/images/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akashm-2003/ecommerce-react/354c3371b5c99d3a58d3bd6e17440f3815f63901/src/images/loading.gif
--------------------------------------------------------------------------------
/src/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akashm-2003/ecommerce-react/354c3371b5c99d3a58d3bd6e17440f3815f63901/src/images/logo.png
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import "./index.css";
4 | import App from "./App";
5 | import reportWebVitals from "./reportWebVitals";
6 | import { AppProvider } from "./context/productcontext";
7 | import {FilterContextProvider} from "./context/filter_context";
8 | import { CartProvider } from "./context/cart_context";
9 | const root = ReactDOM.createRoot(document.getElementById("root"));
10 |
11 | root.render(
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | );
20 |
21 | // If you want to start measuring performance in your app, pass a function
22 | // to log results (for example: reportWebVitals(console.log))
23 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
24 | reportWebVitals();
25 |
--------------------------------------------------------------------------------
/src/reducer/cartReducer.js:
--------------------------------------------------------------------------------
1 |
2 | const cartReducer = (state,action) => {
3 | if(action.type==='ADD_TO_CART'){
4 | let {id,mainColor,amount,product}=action.payload
5 | const price=product.price*10
6 | return {...state,total_items:state.total_items+1,total_amount:state.total_amount+price*amount,cart:[...state.cart,{id,mainColor,amount,product}]};
7 | }
8 | if(action.type==='AMOUNT_TOGGLE'){
9 | let {id,amount,color}=action.payload
10 | const product=state.cart.find((curItem)=>curItem.id===id).product.price*10
11 | const productPrice=product*amount
12 | const prevProductPrice=state.cart.find((curItem)=>curItem.id===id).product.price*10*state.cart.find((curItem)=>curItem.id===id).amount
13 | const prevAmount=state.cart.find((curItem)=>curItem.id===id).amount
14 | return {...state,total_items:state.total_items-prevAmount+amount,total_amount:state.total_amount+productPrice-prevProductPrice,cart:state.cart.map((curItem)=>{
15 | if(curItem.id===id &&curItem.mainColor===color){
16 | return {...curItem,amount}
17 | }
18 | return curItem
19 | })}
20 | }
21 | if(action.type==='REMOVE_ITEM'){
22 | let {id,color}=action.payload
23 | const productPrice=state.cart.find((curItem)=>curItem.id===id).product.price*state.cart.find((curItem)=>curItem.id===id).amount*10
24 | const prevAmount=state.cart.find((curItem)=>curItem.id===id).amount*10
25 | return {...state,total_items:state.total_items-prevAmount,total_amount:state.total_amount-productPrice,cart:state.cart.filter((curItem)=>curItem.id!==id || curItem.mainColor!==color)}
26 | }
27 | if(action.type==='CLEAR_CART'){
28 | return {...state,cart:[]}
29 | }
30 | }
31 |
32 | export default cartReducer
--------------------------------------------------------------------------------
/src/reducer/filterReducer.js:
--------------------------------------------------------------------------------
1 | const filterReducer = (state, action) => {
2 |
3 | switch (action.type) {
4 |
5 | case "LOAD_FILTER_PRODUCTS":
6 | return {
7 | ...state,
8 | filtered_products: [...action.payload],
9 | all_products: [...action.payload]
10 | }
11 | case "SET_GRID_VIEW":
12 | return {
13 | ...state,
14 | grid_view: action.payload
15 | }
16 | case "GET_SORT_VALUE":
17 | return {
18 | ...state,
19 | sorting_value: action.payload,
20 | };
21 | case "SORTING_PRODUCTS":
22 | let newSortData;
23 | const { filtered_products, sorting_value } = state;
24 | let tempSortProduct = [...filtered_products];
25 | const sortingProducts = (a, b) => {
26 | if (sorting_value === "lowest") {
27 | return a.price - b.price;
28 | }
29 |
30 | if (sorting_value === "highest") {
31 | return b.price - a.price;
32 | }
33 |
34 | if (sorting_value === "a-z") {
35 | return a.name.localeCompare(b.name);
36 | }
37 |
38 | if (sorting_value === "z-a") {
39 | return b.name.localeCompare(a.name);
40 | }
41 | }
42 | newSortData = tempSortProduct.sort(sortingProducts);
43 | return {
44 | ...state,
45 | filtered_products: newSortData
46 | };
47 | case 'UPDATE_FILTER_VALUE':
48 | const { value, name } = action.payload;
49 | if (name === 'clear') {
50 | return {
51 | ...state,
52 | filter: {
53 | text: "",
54 | category: "all",
55 | company: "all",
56 | color: "all"
57 | }
58 | }
59 | }
60 | return {
61 | ...state,
62 | filter: {
63 | ...state.filter,
64 | [name]: value
65 | }
66 | }
67 |
68 | case 'USE_FILTER_SECTION':
69 | let all_products = action.payload;
70 | let tempFilterProduct = [...all_products];
71 | const { text, category, company, color } = state.filter;
72 | if (text) {
73 | tempFilterProduct = tempFilterProduct.filter((product) => {
74 | return product.name.toLowerCase().includes(text);
75 | })
76 | }
77 | if (category !== "all") {
78 | tempFilterProduct = tempFilterProduct.filter(
79 | (curElem) => curElem.category === category
80 | );
81 | }
82 |
83 | if (company !== "all") {
84 | tempFilterProduct = tempFilterProduct.filter(
85 | (curElem) => curElem.company.toLowerCase() === company.toLowerCase()
86 | );
87 | }
88 |
89 | // if (color) {
90 | // tempFilterProduct = tempFilterProduct.filter((curElem) =>
91 | // curElem.colors.includes(color)
92 | // );
93 | // }
94 |
95 | return {
96 | ...state,
97 | filtered_products: tempFilterProduct
98 | };
99 |
100 | default:
101 | return state;
102 | }
103 | }
104 |
105 | export default filterReducer;
--------------------------------------------------------------------------------
/src/reducer/productReducer.js:
--------------------------------------------------------------------------------
1 | const ProductReducer =(state, action) =>{
2 | if(action.type === "SET_LOADING"){
3 | return {...state, isLoading:true,isError:true}
4 | }
5 | if(action.type === "SET_API_DATA"){
6 | const featureData= action.payload.filter((item) => item.featured === true);
7 | return {...state, featuredProducts:featureData, isLoading:false, products:action.payload}
8 | }
9 | if(action.type === "API_ERROR"){
10 | return {...state, isLoading:false, isError:true}
11 | }
12 | if(action.type === "SET_SINGLE_LOADING")
13 | {
14 | return {...state, isSingleLoading:true,isError:true}
15 | }
16 | if(action.type === "SET_SINGLE_PRODUCT"){
17 | return {...state, isSingleLoading:false, singleProduct:action.payload}
18 | }
19 | if(action.type === "SET_SINGLE_ERROR"){
20 | return {...state, isSingleLoading:false, isError:true}
21 | }
22 | }
23 |
24 | export default ProductReducer;
--------------------------------------------------------------------------------
/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/src/styles/Button.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | export const Button = styled.button`
4 | text-decoration: none;
5 | max-width: auto;
6 | background-color: rgb(98 84 243);
7 | color: rgb(255 255 255);
8 | padding: 1.4rem 2.4rem;
9 | border: none;
10 | text-transform: uppercase;
11 | text-align: center;
12 | cursor: pointer;
13 | transition: all 0.3s ease;
14 | -webkit-transition: all 0.3s ease 0s;
15 | -moz-transition: all 0.3s ease 0s;
16 | -o-transition: all 0.3s ease 0s;
17 |
18 | &:hover,
19 | &:active {
20 | box-shadow: 0 2rem 2rem 0 rgb(132 144 255 / 30%);
21 | box-shadow: ${({ theme }) => theme.colors.shadowSupport};
22 | transform: scale(0.96);
23 | }
24 |
25 | a {
26 | text-decoration: none;
27 | color: rgb(255 255 255);
28 | font-size: 1.8rem;
29 | }
30 | `;
31 |
--------------------------------------------------------------------------------
/src/styles/Container.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | export const Container = styled.div`
4 | width: 100%;
5 | padding: 0rem 12rem;
6 | `;
7 |
--------------------------------------------------------------------------------