├── src ├── App.css ├── index.css ├── Store │ ├── index.js │ └── slices │ │ └── cart-slice.js ├── App.jsx ├── main.jsx ├── components │ ├── Header.jsx │ ├── CartItem.jsx │ └── ProductItem.jsx ├── Home │ └── index.jsx ├── Cart │ └── index.jsx └── assets │ └── react.svg ├── .vscode └── extensions.json ├── postcss.config.js ├── vite.config.js ├── tailwind.config.js ├── .gitignore ├── index.html ├── README.md ├── .eslintrc.cjs ├── package.json └── public └── vite.svg /src/App.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "bradlc.vscode-tailwindcss" 4 | ] 5 | } -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /src/Store/index.js: -------------------------------------------------------------------------------- 1 | import {configureStore} from "@reduxjs/toolkit"; 2 | import cartReducer from "./slices/cart-slice"; 3 | const store=configureStore({ 4 | reducer:{ 5 | cart: cartReducer 6 | } 7 | }) 8 | export default store; -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: [ 4 | "./index.html", 5 | "./src/**/*.{js,ts,jsx,tsx}", 6 | ], 7 | theme: { 8 | extend: {}, 9 | }, 10 | plugins: [], 11 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Shopping Cart 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import "./App.css"; 2 | import { Routes, Route } from "react-router-dom"; 3 | import Home from "./Home"; 4 | import Cart from "./Cart"; 5 | import Header from "./components/Header"; 6 | function App() { 7 | return ( 8 |
9 |
10 |
11 |
12 | 13 | } /> 14 | } /> 15 | 16 |
17 | ); 18 | } 19 | 20 | export default App; 21 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | import "./index.css"; 5 | import { BrowserRouter } from "react-router-dom"; 6 | import { Provider } from "react-redux"; 7 | import store from "./Store/index.js"; 8 | ReactDOM.createRoot(document.getElementById("root")).render( 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /src/Store/slices/cart-slice.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | const initialState = []; 3 | const cartSlice = createSlice({ 4 | name: "cart", 5 | initialState, 6 | reducers: { 7 | addToCart(state, action) { 8 | state.push(action.payload); 9 | }, 10 | removeFromCart(state, action) { 11 | return state.filter((item) => item.id !== action.payload); 12 | }, 13 | }, 14 | }); 15 | 16 | export const { addToCart,removeFromCart } = cartSlice.actions; 17 | export default cartSlice.reducer; 18 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:react/recommended', 7 | 'plugin:react/jsx-runtime', 8 | 'plugin:react-hooks/recommended', 9 | ], 10 | ignorePatterns: ['dist', '.eslintrc.cjs'], 11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 12 | settings: { react: { version: '18.2' } }, 13 | plugins: ['react-refresh'], 14 | rules: { 15 | 'react/jsx-no-target-blank': 'off', 16 | 'react-refresh/only-export-components': [ 17 | 'warn', 18 | { allowConstantExport: true }, 19 | ], 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /src/components/Header.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | export default function Header() { 3 | return ( 4 |
5 | 20 |
21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shopping-cart", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@reduxjs/toolkit": "^2.2.3", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0", 16 | "react-icons": "^5.0.1", 17 | "react-loader-spinner": "^6.1.6", 18 | "react-redux": "^9.1.0", 19 | "react-router-dom": "^6.22.3" 20 | }, 21 | "devDependencies": { 22 | "@types/react": "^18.2.66", 23 | "@types/react-dom": "^18.2.22", 24 | "@vitejs/plugin-react": "^4.2.1", 25 | "autoprefixer": "^10.4.19", 26 | "eslint": "^8.57.0", 27 | "eslint-plugin-react": "^7.34.1", 28 | "eslint-plugin-react-hooks": "^4.6.0", 29 | "eslint-plugin-react-refresh": "^0.4.6", 30 | "postcss": "^8.4.38", 31 | "tailwindcss": "^3.4.3", 32 | "vite": "^5.2.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/components/CartItem.jsx: -------------------------------------------------------------------------------- 1 | import { useDispatch } from "react-redux" 2 | import { removeFromCart } from "../Store/slices/cart-slice" 3 | 4 | export default function CartItem({item}) { 5 | const dispatch=useDispatch() 6 | function handleRemoveCart(){ 7 | dispatch(removeFromCart(item?.id)) 8 | } 9 | return
10 |
11 |
12 | {item?.title} 13 |
14 |

{item.title}

15 |

Price: {item?.price}

16 | 17 |
18 | 19 |
20 |
21 | 27 |
28 |
29 | 30 | 31 | 32 |
33 | 34 | } -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ProductItem.jsx: -------------------------------------------------------------------------------- 1 | import { useDispatch, useSelector } from "react-redux"; 2 | import { addToCart, removeFromCart } from "../Store/slices/cart-slice"; 3 | const ProductItem = ({ product }) => { 4 | const dispatch = useDispatch(); 5 | const{cart}=useSelector(state=>state); 6 | function handleAddToCart() { 7 | dispatch(addToCart(product)); 8 | } 9 | function handleRemoveCart() { 10 | dispatch(removeFromCart(product.id)) 11 | } 12 | return ( 13 |
14 |
15 |
16 | {product?.title} 21 |
22 |
23 |

24 | {product?.title} 25 |

26 |
27 |
28 | 34 |
35 |
36 |
37 | ); 38 | }; 39 | 40 | export default ProductItem; 41 | -------------------------------------------------------------------------------- /src/Home/index.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { Circles } from "react-loader-spinner"; 3 | import ProductItem from "../components/ProductItem"; 4 | 5 | export default function Home() { 6 | const [prouducts, setProducts] = useState([]); 7 | const [loading, setLoading] = useState(false); 8 | const [error, setError] = useState(null); 9 | 10 | async function fetchProuducts() { 11 | try { 12 | setLoading(true); 13 | const response = await fetch("https://fakestoreapi.com/products"); 14 | const data = await response.json(); 15 | setProducts(data); 16 | setLoading(false); 17 | } catch (error) { 18 | setError(error); 19 | setLoading(false) 20 | } 21 | } 22 | useEffect(() => { 23 | fetchProuducts(); 24 | },[]); 25 | return ( 26 |
27 | {loading ? ( 28 |
32 | 38 |
39 | ): 40 |
41 | {prouducts && prouducts.length > 0 ? ( 42 | prouducts.map((item) => ) 43 | ) : ( 44 |

No products found

45 | )} 46 |
47 | } 48 |
49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /src/Cart/index.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { useSelector } from "react-redux"; 3 | import { Link } from "react-router-dom"; 4 | import CartItem from "../components/CartItem"; 5 | export default function Cart() { 6 | const [totalCart, setTotalCart] = useState(0); 7 | const { cart } = useSelector((state) => state); 8 | 9 | useEffect(() => { 10 | setTotalCart(cart.reduce((acc, curr) => acc + curr.price, 0)); 11 | }, [cart]); 12 | 13 | return ( 14 |
15 | {cart && cart.length > 0 ? ( 16 | <> 17 |
18 |
19 | {cart.map((product) => ( 20 | 21 | ))} 22 |
23 |
24 |
25 |
26 |

27 | You Cart Summary{" "} 28 |

29 |

30 | 31 | Total Items 32 | 33 | {cart.length} 34 |

35 |

36 | 37 | Total Amount 38 | 39 | {totalCart} 40 |

41 |
42 |
43 | 44 | ) : ( 45 |
46 |

47 | Your cart is empty 48 |

{" "} 49 | 50 | 53 | 54 |
55 | )} 56 |
57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /src/assets/react.svg: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------