├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── _redirects ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── App.css ├── App.js ├── Assets │ └── Screenshots │ │ └── Screenshot_01.jpg ├── Components │ ├── Card │ │ ├── index.js │ │ └── styles.module.css │ ├── Container │ │ └── index.js │ ├── Navbar │ │ ├── CartButton │ │ │ ├── index.js │ │ │ └── styles.module.css │ │ ├── MenuButton │ │ │ ├── index.js │ │ │ └── styles.module.css │ │ ├── index.js │ │ └── styles.module.css │ └── Spinner │ │ ├── index.js │ │ └── styles.module.css ├── Config │ └── navbarItemList.js ├── Context │ ├── AuthContext.js │ ├── CartContext.js │ ├── FavoriteContext.js │ └── ProductContext.js ├── Pages │ ├── Auth │ │ ├── Signin │ │ │ ├── index.js │ │ │ └── styles.module.css │ │ └── Signup │ │ │ ├── index.js │ │ │ ├── styles.module.css │ │ │ └── validations.js │ ├── Cart │ │ ├── index.js │ │ └── styles.module.css │ ├── Error404 │ │ ├── index.js │ │ └── styles.module.css │ ├── Favorites │ │ ├── index.js │ │ └── styles.module.css │ ├── ProductDetail │ │ ├── index.js │ │ └── styles.module.css │ ├── Products │ │ ├── index.js │ │ └── styles.module.css │ └── ProtectedRoute.js ├── index.css └── index.js └── tailwind.config.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 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Alper Tugriçeri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | [![MIT License][license-shield]](https://github.com/Atugriceri/e-commerce-react-app/blob/main/LICENSE) 5 | [![LinkedIn][linkedin-shield]](https://www.linkedin.com/in/alpertugriceri/) 6 | 7 | 8 |
9 |
10 | 11 | Logo 12 | 13 |

E-Commerce-React-App

14 | 15 |

16 | Shopping site project that includes basic processes such as adding to cart, adding to favorites, product listing and product detail page, which should be on an e-commerce site. 17 |
18 |
19 | View Demo 20 |

21 |
22 | 23 | 24 |
25 | Table of Contents 26 |
    27 |
  1. 28 | About The Project 29 | 32 |
  2. 33 |
  3. Getting Started
  4. 34 |
  5. Usage
  6. 35 |
  7. Roadmap
  8. 36 |
  9. License
  10. 37 |
  11. Contact
  12. 38 |
  13. Acknowledgments
  14. 39 |
40 |
41 | 42 | 43 | ## About The Project 44 | 45 | ![PROJECT_SCREENSHOT_01](./src/Assets/Screenshots/Screenshot_01.jpg) 46 | 47 | An e-commerce site with basic shopping functions. You can list the products according to their categories, go to the detail page of the relevant product, add the product to your favorites and to the cart, together with the captured product data. 48 | 49 | The project was developed in conjunction with React.js, including Context, Hooks, and Life Cycles Methods. Styled with Tailwind CSS. 50 | 51 |

(back to top)

52 | 53 | 54 | ### Built With 55 | 56 | * [React.js](https://reactjs.org/) 57 | * [Tailwind CSS](https://tailwindui.com/) 58 | * [Axios](https://www.npmjs.com/package/axios) 59 | * [Fake Store Api](https://fakestoreapi.com/) 60 | 61 |

(back to top)

62 | 63 | 64 | 65 | ## Getting Started 66 | 67 | - Fork the project and clone it locally. 68 | - In the project directory, ou can follow the steps below to download the dependencies: 69 | - Install with npm: 70 | ```sh 71 | npm i 72 | ``` 73 | - Install with yarn: 74 | ```sh 75 | yarn 76 | ``` 77 | - In the project directory, you can run: 78 | - Run with npm: 79 | ```sh 80 | npm run 81 | ``` 82 | - Run with yarn: 83 | ```sh 84 | yarn start 85 | ``` 86 | 87 |

(back to top)

88 | 89 | ## Usage 90 | 91 | You can list the products by clicking on the categories, add and remove the products to the cart and favorites. You can view the products you have added to the cart and favorites on the cart and favorites pages. 92 | 93 | [See it live!](https://atugriceri-e-commerce-react-app.netlify.app/) 94 | 95 |

(back to top)

96 | 97 | ## Roadmap 98 | 99 | - [x] Fetching product data, listing by categories and product detail page. 100 | - [x] Add to favorites and favorites page. 101 | - [x] Add to cart and cart page. 102 | - [ ] Responsive Design 103 | - [ ] Navbar 104 | - [ ] Card 105 | - [ ] Complete the sign in and sign up process. 106 | - [ ] Create order page. 107 | 108 |

(back to top)

109 | 110 | ## License 111 | 112 | Distributed under the MIT License. See `LICENSE.txt` for more information. 113 | 114 |

(back to top)

115 | 116 | 117 | ## Contact 118 | 119 | Alper Tugriçeri - [Linkedin](https://www.linkedin.com/in/alpertugriceri/) - alpertugriceri@gmail.com 120 | 121 | Project Link: [https://github.com/Atugriceri/e-commerce-react-app](https://github.com/Atugriceri/e-commerce-react-app) 122 | 123 |

(back to top)

124 | 125 | 126 | 127 | ## Acknowledgments 128 | 129 | * [Hero Icons](https://heroicons.com/) 130 | 131 |

(back to top)

132 | 133 | 134 | 135 | 136 | 137 | [license-shield]: https://img.shields.io/github/license/othneildrew/Best-README-Template.svg?style=for-the-badge 138 | [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555 -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e-commerce-react-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@headlessui/react": "^1.5.0", 7 | "@heroicons/react": "^1.0.6", 8 | "@testing-library/jest-dom": "^5.16.2", 9 | "@testing-library/react": "^12.1.4", 10 | "@testing-library/user-event": "^13.5.0", 11 | "axios": "^0.26.1", 12 | "firebase": "^9.6.8", 13 | "react": "^17.0.2", 14 | "react-dom": "^17.0.2", 15 | "react-router-dom": "^6.2.2", 16 | "react-scripts": "5.0.0", 17 | "web-vitals": "^2.1.4" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": [ 27 | "react-app", 28 | "react-app/jest" 29 | ] 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.2%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | }, 43 | "devDependencies": { 44 | "autoprefixer": "^10.4.2", 45 | "postcss": "^8.4.8", 46 | "tailwindcss": "^3.0.23" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atugriceri/e-commerce-react-app/2b77667538c9b40acd44c064f2da5076bb966bd3/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atugriceri/e-commerce-react-app/2b77667538c9b40acd44c064f2da5076bb966bd3/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atugriceri/e-commerce-react-app/2b77667538c9b40acd44c064f2da5076bb966bd3/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/App.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './App.css' 3 | import { Routes, Route } from 'react-router-dom' 4 | import Navbar from './Components/Navbar' 5 | import Signin from './Pages/Auth/Signin' 6 | import Signup from './Pages/Auth/Signup' 7 | import Products from './Pages/Products' 8 | import Error404 from './Pages/Error404' 9 | import Container from './Components/Container' 10 | import ProductDetail from './Pages/ProductDetail' 11 | import Cart from './Pages/Cart' 12 | import Favorites from './Pages/Favorites' 13 | 14 | function App() { 15 | return ( 16 |
17 | 18 | 19 | 20 | } /> 21 | } /> 22 | } /> 23 | } /> 24 | } /> 25 | } /> 26 | } /> 27 | } /> 28 | 29 | 30 |
31 | ) 32 | } 33 | 34 | export default App -------------------------------------------------------------------------------- /src/Assets/Screenshots/Screenshot_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atugriceri/e-commerce-react-app/2b77667538c9b40acd44c064f2da5076bb966bd3/src/Assets/Screenshots/Screenshot_01.jpg -------------------------------------------------------------------------------- /src/Components/Card/index.js: -------------------------------------------------------------------------------- 1 | import styles from './styles.module.css' 2 | import { StarIcon, ShoppingCartIcon, HeartIcon } from '@heroicons/react/solid' 3 | import { Link } from 'react-router-dom' 4 | 5 | const Card = ({ 6 | item, 7 | addToFavorite, 8 | findFavoriteItem, 9 | addToCart, 10 | findCartItem, 11 | }) => { 12 | 13 | return ( 14 |
15 |
16 | 26 | 27 |
28 | 29 |
30 | 31 |
32 |
33 |

34 | 35 | Brand, 36 | {" "} 37 | {item.title} 38 |

39 |
40 |
41 | {[...Array(Math.round(item.rating.rate))].map((e, i) => ( 42 |
59 |
60 |
61 | $ 62 | {Math.trunc(item.price)} 63 | {parseInt((item.price % 1).toFixed(2).substring(2)) !== 0 ? ( 64 | 65 | {parseInt((item.price % 1).toFixed(2).substring(2))} 66 | 67 | ) : ( 68 | "" 69 | )} 70 |
71 |
72 |
73 | 89 |
90 |
91 |
92 |
93 | ) 94 | } 95 | 96 | export default Card -------------------------------------------------------------------------------- /src/Components/Card/styles.module.css: -------------------------------------------------------------------------------- 1 | /***** CARD STYLES START *****/ 2 | 3 | .card { 4 | @apply 5 | w-full 6 | sm:w-1/2 7 | md:w-1/2 8 | xl:w-1/4 9 | p-4 10 | } 11 | 12 | .cardLink { 13 | @apply 14 | block 15 | shadow-sm 16 | hover:shadow-md 17 | border-2 18 | border-zinc-900/10 19 | shadow-zinc-900/10 20 | rounded-md 21 | overflow-hidden 22 | h-full 23 | } 24 | 25 | /***** CARD HEADER STYLES START *****/ 26 | 27 | .cardHeader { 28 | @apply 29 | relative 30 | pb-64 31 | overflow-hidden 32 | shadow-sm 33 | } 34 | 35 | /***** FAVORITES BUTTON STYLES START *****/ 36 | 37 | .favButton, .removeFavButton { 38 | @apply 39 | h-6 40 | w-6 41 | m-2 42 | ml-auto 43 | } 44 | 45 | .favButton { 46 | @apply 47 | text-zinc-900/80 48 | hover:text-red-500 49 | flex 50 | } 51 | 52 | .removeFavButton { 53 | @apply 54 | text-red-500 flex 55 | } 56 | 57 | /***** FAVORITES BUTTON STYLES END *****/ 58 | 59 | /***** CARD IMAGE STYLES START *****/ 60 | 61 | .cardImg { 62 | @apply 63 | absolute 64 | inset-0 65 | max-h-56 66 | w-full 67 | object-contain 68 | my-4 69 | px-4 70 | } 71 | 72 | .cardLink img { 73 | transition: transform .3s ease-in-out; 74 | } 75 | 76 | .cardLink img:hover { 77 | transform: scale(1.02) 78 | } 79 | 80 | /***** CARD IMAGE STYLES START *****/ 81 | 82 | /***** CARD HEADER STYLES END *****/ 83 | 84 | /***** CARD BODY STYLES START *****/ 85 | 86 | .cardBody { 87 | @apply 88 | p-4 89 | h-full 90 | flex 91 | flex-1 92 | flex-col 93 | text-sm 94 | text-zinc-900/80 95 | } 96 | 97 | .cardBody .brand, .cardTitle { 98 | @apply 99 | mt-1 100 | mb-2 101 | } 102 | 103 | .brand { 104 | @apply 105 | font-bold 106 | hover:text-blue-600 107 | } 108 | 109 | .cardTitle { 110 | @apply 111 | font-light 112 | truncate 113 | } 114 | 115 | /***** STAR ICON STYLES START *****/ 116 | 117 | .rating { 118 | @apply 119 | flex 120 | flex-row 121 | mb-2 122 | } 123 | 124 | .rating .starIcon, .emptyStarIcon { 125 | @apply 126 | h-4 127 | w-4 128 | my-auto 129 | } 130 | 131 | .starIcon { 132 | @apply 133 | text-yellow-300 134 | } 135 | 136 | .emptyStarIcon { 137 | @apply 138 | text-zinc-900/80 139 | } 140 | 141 | /***** STAR ICON STYLES END *****/ 142 | 143 | /***** PRICE STYLES START *****/ 144 | 145 | .priceSub, .priceTop { 146 | @apply 147 | text-zinc-900/80 148 | } 149 | 150 | .priceSub { 151 | @apply 152 | font-extralight 153 | text-xs 154 | inline-block 155 | align-sub 156 | } 157 | 158 | .priceTop { 159 | @apply 160 | font-normal 161 | text-lg 162 | mx-0.5 163 | inline-block 164 | align-text-top 165 | } 166 | 167 | /***** PRICE STYLES END *****/ 168 | 169 | /***** ADD TO CART BUTTON STYLES START *****/ 170 | 171 | .addToCart { 172 | @apply 173 | mx-auto 174 | text-center 175 | w-full 176 | mt-2 177 | } 178 | 179 | .addToCartButton, .removeButton { 180 | @apply 181 | inline-flex 182 | justify-center 183 | w-full 184 | rounded-md 185 | shadow-sm 186 | shadow-zinc-900/10 187 | text-sm 188 | text-zinc-50 189 | px-2 190 | py-2 191 | hover:bg-yellow-300 192 | } 193 | 194 | .addToCartButton { 195 | @apply 196 | bg-blue-600 197 | } 198 | 199 | .removeButton { 200 | @apply 201 | bg-red-600 202 | } 203 | 204 | .shoppingCartIcon { 205 | @apply 206 | my-auto 207 | h-5 208 | w-6 209 | } 210 | 211 | .buttonText { 212 | @apply 213 | font-bold 214 | } 215 | 216 | /***** ADD TO CART BUTTON STYLES END *****/ 217 | 218 | /***** CARD BODY STYLES END *****/ 219 | 220 | /***** CARD STYLES END *****/ -------------------------------------------------------------------------------- /src/Components/Container/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Container = (props) => { 4 | return ( 5 |
6 | {props.children} 7 |
8 | ) 9 | } 10 | 11 | export default Container -------------------------------------------------------------------------------- /src/Components/Navbar/CartButton/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styles from './styles.module.css' 3 | import { Link } from 'react-router-dom' 4 | import { ShoppingCartIcon } from "@heroicons/react/outline" 5 | import { useCart } from '../../../Context/CartContext' 6 | 7 | const CartButton = () => { 8 | const {items} = useCart() 9 | 10 | return ( 11 |
12 |
13 | 14 |
24 |
25 | ) 26 | } 27 | 28 | export default CartButton -------------------------------------------------------------------------------- /src/Components/Navbar/CartButton/styles.module.css: -------------------------------------------------------------------------------- 1 | .cartMenu { 2 | @apply 3 | relative 4 | text-left 5 | lg:inline-block 6 | } 7 | 8 | .cartButton { 9 | @apply 10 | py-2 11 | pr-2 12 | flex 13 | bg-transparent 14 | text-zinc-900/80 15 | } 16 | 17 | .cartIcon { 18 | @apply 19 | my-auto 20 | h-10 21 | w-10 22 | relative 23 | } 24 | 25 | .cartCount { 26 | @apply 27 | bg-red-600 28 | rounded-full 29 | w-[14px] 30 | h-[14px] 31 | text-[10px] 32 | text-center 33 | flex 34 | justify-center 35 | text-zinc-50 36 | absolute 37 | top-2 38 | pt-[0.5px] 39 | font-bold 40 | left-8 41 | } -------------------------------------------------------------------------------- /src/Components/Navbar/MenuButton/index.js: -------------------------------------------------------------------------------- 1 | import { Fragment } from 'react' 2 | import { Link } from 'react-router-dom' 3 | import { Menu, Transition } from '@headlessui/react' 4 | import { ChevronDownIcon } from '@heroicons/react/solid' 5 | import { 6 | UserCircleIcon, 7 | LogoutIcon, 8 | } from '@heroicons/react/outline' 9 | import styles from './styles.module.css' 10 | import { useAuth } from '../../../Context/AuthContext' 11 | import NAVIGATION from '../../../Config/navbarItemList' 12 | 13 | const MenuButton = () => { 14 | const { loggedIn, currentUser, setIsSubmitting, logout } = useAuth() 15 | 16 | const handleLogout = async () => { 17 | setIsSubmitting(true) 18 | try { 19 | await logout() 20 | } catch { 21 | alert("Error") 22 | } 23 | setIsSubmitting(false) 24 | } 25 | 26 | return ( 27 |
28 | {!loggedIn && ( 29 | 30 |
31 | 32 | 47 |
48 | 49 | 58 | 59 |
60 | {!loggedIn && 61 | NAVIGATION.map( 62 | ({ 63 | id, 64 | name, 65 | link, 66 | icon, 67 | loggedIn, 68 | underlined, 69 | onclick, 70 | }) => ( 71 | 72 | {({ active }) => ( 73 |
78 | 90 | {icon} 91 | {name} 92 | 93 |
94 | )} 95 |
96 | ) 97 | )} 98 |
99 |
100 |
101 |
102 | )} 103 | 104 | {loggedIn && ( 105 | 106 |
107 | 108 | 123 |
124 | 125 | 134 | 135 |
136 | {loggedIn && 137 | NAVIGATION.map( 138 | ({ 139 | id, 140 | name, 141 | link, 142 | icon, 143 | loggedIn, 144 | underlined, 145 | onclick, 146 | }) => ( 147 | 148 | {({ active }) => ( 149 |
154 | 166 | {icon} 167 | {name} 168 | 169 |
170 | )} 171 |
172 | ) 173 | )} 174 | 175 | 176 | {({ active }) => ( 177 |
178 | 187 |
194 | )} 195 |
196 |
197 |
198 |
199 |
200 | )} 201 |
202 | ) 203 | } 204 | 205 | export default MenuButton 206 | -------------------------------------------------------------------------------- /src/Components/Navbar/MenuButton/styles.module.css: -------------------------------------------------------------------------------- 1 | .menu { 2 | @apply 3 | relative 4 | text-left 5 | lg:inline-block 6 | z-40 7 | } 8 | 9 | .menuButton { 10 | @apply 11 | inline-flex 12 | justify-center 13 | w-full 14 | border-2 15 | border-zinc-900/10 16 | shadow-zinc-900/10 17 | rounded-md 18 | shadow-sm 19 | px-4 20 | py-2 21 | bg-transparent 22 | text-sm 23 | font-medium 24 | text-zinc-900/80 25 | hover:bg-zinc-400/10 26 | } 27 | 28 | .userCircleIcon { 29 | @apply 30 | mr-2 31 | my-auto 32 | h-10 33 | w-10 34 | } 35 | 36 | .chevronDownIcon { 37 | @apply 38 | -mr-1 39 | ml-2 40 | my-auto 41 | h-8 42 | w-8 43 | } 44 | 45 | .menuItems { 46 | @apply 47 | origin-top-right 48 | absolute 49 | right-0 50 | mt-2 51 | w-full 52 | rounded-md 53 | shadow-md 54 | shadow-zinc-900/10 55 | bg-zinc-50 56 | ring-2 57 | ring-zinc-900/10 58 | divide-y-2 59 | divide-zinc-900/10 60 | focus:outline-none 61 | } -------------------------------------------------------------------------------- /src/Components/Navbar/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | import MenuButton from './MenuButton' 4 | import CartButton from './CartButton' 5 | import styles from './styles.module.css' 6 | import { useProduct } from '../../Context/ProductContext' 7 | import { useAuth } from '../../Context/AuthContext' 8 | import { Disclosure, } from '@headlessui/react' 9 | import { MenuIcon, XIcon, LogoutIcon } from '@heroicons/react/outline' 10 | import NAVIGATION from '../../Config/navbarItemList' 11 | 12 | const Navbar = () => { 13 | const { categories, setCategory } = useProduct() 14 | const { loggedIn, currentUser, setIsSubmitting, logout } = useAuth() 15 | 16 | const handleLogout = async () => { 17 | setIsSubmitting(true) 18 | try { 19 | await logout() 20 | } catch { 21 | alert("Error") 22 | } 23 | setIsSubmitting(false) 24 | } 25 | 26 | return ( 27 | <> 28 | 29 | {({ open }) => ( 30 | <> 31 |
32 |
33 |
34 | {/* Mobile menu button*/} 35 | 36 | Open main menu 37 | {open ? ( 38 | 43 |
44 |
45 |
46 | 47 |
48 |

LOGO

49 |
50 | 51 |
52 |
53 |
54 |
55 |
56 | 57 |
58 |
59 | 60 |
61 | {/* Profile dropdown */} 62 |
63 |
64 |
65 | 66 | 67 |
68 | {!loggedIn && NAVIGATION.map(({ 69 | id, 70 | name, 71 | link, 72 | icon, 73 | underlined, 74 | loggedIn, 75 | onclick, 76 | }) => ( 77 | 85 | 86 | {icon} 87 | {name} 88 | 89 | 90 | ))} 91 | {loggedIn && NAVIGATION.map(({ 92 | id, 93 | name, 94 | link, 95 | icon, 96 | underlined, 97 | loggedIn, 98 | onclick, 99 | }) => ( 100 | 108 | 109 | {icon} 110 | {name} 111 | 112 | 113 | ))} 114 | {loggedIn && ( 115 | 119 | 120 | 126 | 127 | )} 128 | 129 |
130 |
131 | 132 | )} 133 |
134 |
135 | 162 |
163 | 164 | ); 165 | }; 166 | 167 | export default Navbar; 168 | -------------------------------------------------------------------------------- /src/Components/Navbar/styles.module.css: -------------------------------------------------------------------------------- 1 | .nav { 2 | @apply 3 | flex 4 | justify-between 5 | bg-transparent 6 | p-6 7 | z-10 8 | } 9 | 10 | .logo { 11 | @apply 12 | flex 13 | items-center 14 | flex-shrink-0 15 | } 16 | 17 | .logo .link { 18 | @apply 19 | font-semibold 20 | text-xl 21 | tracking-tight 22 | flex 23 | flex-row 24 | } 25 | 26 | .categoryNav { 27 | @apply 28 | flex 29 | py-2 30 | max-w-7xl 31 | mx-auto 32 | bg-transparent 33 | rounded-lg 34 | overflow-x-auto 35 | sm:justify-start 36 | md:justify-center 37 | } 38 | 39 | .categoryLink { 40 | @apply 41 | tracking-widest 42 | text-black 43 | md:hover:border-x-4 44 | md:hover:border-yellow-300 45 | decoration-dashed 46 | px-6 47 | py-2 48 | hover:underline-offset-[5px] 49 | mx-0 50 | flex 51 | } 52 | 53 | .categoryLink h1 { 54 | @apply mx-4 55 | } 56 | 57 | .logoText { 58 | font-family: 'Oswald', sans-serif; 59 | @apply 60 | text-3xl 61 | text-yellow-300 62 | ml-2 63 | my-auto 64 | tracking-widest 65 | 66 | } 67 | 68 | .disclosureButton { 69 | @apply 70 | bg-zinc-50 71 | hover:bg-zinc-400/10 72 | text-zinc-900/80 73 | items-center 74 | w-full 75 | py-2 76 | px-2 77 | text-sm 78 | font-medium 79 | flex 80 | } 81 | 82 | .logoBox { 83 | @apply 84 | bg-gradient-to-b 85 | from-blue-600 86 | via-blue-700 87 | to-blue-600 88 | w-[5.6rem] 89 | h-10 90 | rounded-md 91 | } 92 | 93 | .disclosurePanel { 94 | @apply 95 | sm:hidden 96 | flex 97 | flex-col 98 | border-2 99 | rounded-md 100 | border-zinc-900/10 101 | shadow-md 102 | shadow-zinc-900/10 103 | mb-4 104 | mx-2 105 | } -------------------------------------------------------------------------------- /src/Components/Spinner/index.js: -------------------------------------------------------------------------------- 1 | import Styles from './styles.module.css' 2 | import React from 'react' 3 | 4 | const Spinner = () => { 5 | return ( 6 | <> 7 |
8 |
9 |
10 |
11 |

Loading...

12 |

This may take a few seconds, please don't close this page.

13 |
14 | 15 | 16 | ) 17 | } 18 | 19 | export default Spinner -------------------------------------------------------------------------------- /src/Components/Spinner/styles.module.css: -------------------------------------------------------------------------------- 1 | .spinner { 2 | @apply 3 | flex 4 | flex-col 5 | justify-between 6 | items-center 7 | mx-auto 8 | mt-44 9 | } 10 | 11 | .firstCircle { 12 | @apply 13 | relative 14 | w-12 15 | h-12 16 | animate-spin 17 | rounded-full 18 | bg-gradient-to-l 19 | from-blue-400 20 | via-blue-600 21 | to-blue-500 22 | } 23 | 24 | .secondCircle { 25 | @apply 26 | absolute 27 | top-1/2 28 | left-1/2 29 | transform 30 | -translate-x-1/2 31 | -translate-y-1/2 32 | w-9 33 | h-9 34 | bg-neutral-50 35 | rounded-full 36 | border-2 37 | border-dashed 38 | border-white 39 | } 40 | 41 | .status { 42 | @apply 43 | mt-5 44 | text-lg 45 | font-semibold 46 | text-center 47 | mx-auto 48 | } 49 | 50 | .statusText { 51 | @apply 52 | font-light 53 | } -------------------------------------------------------------------------------- /src/Config/navbarItemList.js: -------------------------------------------------------------------------------- 1 | import { 2 | LoginIcon, 3 | IdentificationIcon, 4 | UserIcon, 5 | ClipboardListIcon, 6 | HeartIcon, 7 | ShoppingCartIcon, 8 | } from '@heroicons/react/outline' 9 | 10 | const NAVIGATION = [ 11 | { 12 | id: 1, 13 | name: "Login", 14 | link: "/signin", 15 | icon: