├── .babelrc
├── .eslintrc.json
├── sanity_ecommerce
├── plugins
│ └── .gitkeep
├── .eslintrc
├── config
│ ├── @sanity
│ │ ├── data-aspects.json
│ │ ├── vision.json
│ │ ├── form-builder.json
│ │ ├── default-layout.json
│ │ └── default-login.json
│ └── .checksums
├── static
│ ├── .gitkeep
│ └── favicon.ico
├── .npmignore
├── tsconfig.json
├── schemas
│ ├── schema.js
│ ├── product.js
│ └── banner.js
├── README.md
├── sanity.json
└── package.json
├── public
├── logo.png
├── favicon.ico
├── favicon-16x16.png
├── favicon-32x32.png
├── assets
│ ├── homepage.png
│ └── Lighthouse scores.png
└── vercel.svg
├── assets
├── Mouse
│ ├── Logitech
│ │ ├── G705
│ │ │ ├── g705-gallery-1.png
│ │ │ ├── g705-gallery-2.png
│ │ │ ├── g705-gallery-3.png
│ │ │ └── G705.txt
│ │ ├── G303
│ │ │ ├── shroud-g303-gallery-1.png
│ │ │ ├── shroud-g303-gallery-2.png
│ │ │ ├── shroud-g303-gallery-3.png
│ │ │ ├── shroud-g303-gallery-5.png
│ │ │ └── LOGITECH G303 SHROUD EDITION.txt
│ │ ├── G502 PLUS
│ │ │ ├── g502x-plus-gallery-3-white.png
│ │ │ ├── g502x-plus-gallery-5-white.png
│ │ │ ├── g502x-plus-gallery-6-white.png
│ │ │ ├── g502x-plus-gallery-white-01.png
│ │ │ ├── g502x-plus-gallery-white-02.png
│ │ │ └── G502 X PLUS GAMING MOUSE.txt
│ │ ├── G502 X GAMING MOUSE
│ │ │ ├── g502x-corded-gallery-1-white.png
│ │ │ ├── g502x-corded-gallery-2-white.png
│ │ │ ├── g502x-corded-gallery-3-white.png
│ │ │ ├── g502x-corded-gallery-4-white.png
│ │ │ ├── g502x-corded-gallery-5-white.png
│ │ │ └── G502.txt
│ │ └── PRO wirwless LoL
│ │ │ ├── league-of-legends-pro-wireless-gaming-mouse-gallery-1.png
│ │ │ ├── league-of-legends-pro-wireless-gaming-mouse-gallery-2.png
│ │ │ ├── league-of-legends-pro-wireless-gaming-mouse-gallery-3.png
│ │ │ ├── league-of-legends-pro-wireless-gaming-mouse-gallery-4.png
│ │ │ └── PRO WIRELESS MOUSE.txt
│ └── Corsair
│ │ ├── Dark Core
│ │ ├── -CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-01.png
│ │ ├── -CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-21.png
│ │ ├── -CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-25.png
│ │ ├── -CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-26.png
│ │ ├── -CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-32.png
│ │ └── DARK CORE RGB PRO SE.txt
│ │ ├── Scimitar pro
│ │ ├── -CH-9304111-NA-Gallery-Scimitar-PRO-BLK-01.png
│ │ ├── -CH-9304111-NA-Gallery-Scimitar-PRO-BLK-04.png
│ │ ├── -CH-9304111-NA-Gallery-Scimitar-PRO-BLK-05.png
│ │ ├── -CH-9304111-NA-Gallery-Scimitar-PRO-BLK-08.png
│ │ ├── -CH-9304111-NA-Gallery-Scimitar-PRO-BLK-22.png
│ │ └── SCIMITAR PRO RGB Optical.txt
│ │ ├── ironclaw
│ │ ├── -CH-9317011-NA-Gallery-IRONCLAW-RGB-WIRELESS-01.png
│ │ ├── -CH-9317011-NA-Gallery-IRONCLAW-RGB-WIRELESS-02.png
│ │ ├── -CH-9317011-NA-Gallery-IRONCLAW-RGB-WIRELESS-03.png
│ │ ├── -CH-9317011-NA-Gallery-IRONCLAW-RGB-WIRELESS-04.png
│ │ └── IRONCLAW RGB WIRELESS Gaming Mouse.txt
│ │ ├── katar
│ │ ├── -base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-01.png
│ │ ├── -base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-23.png
│ │ ├── -base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-24.png
│ │ ├── -base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-26.png
│ │ ├── -base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-27.png
│ │ └── KATAR PRO WIRELESS Gaming Mouse.txt
│ │ └── m65
│ │ ├── -base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-01.png
│ │ ├── -base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-08.png
│ │ ├── -base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-11.png
│ │ ├── -base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-13.png
│ │ ├── -base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-16.png
│ │ └── M65 RGB ULTRA WIRELESS.txt
├── Mousepads
│ ├── ASUS Rog
│ │ ├── ROG Sheath
│ │ │ ├── h525.png
│ │ │ ├── h732.png
│ │ │ ├── h732 (1).png
│ │ │ └── ROG Sheath.txt
│ │ └── ROG Sheath Electro Punk
│ │ │ ├── h732.png
│ │ │ ├── h732 (1).png
│ │ │ ├── h732 (2).png
│ │ │ └── ROG Sheath Electro Punk.txt
│ └── Corsair
│ │ ├── MM350
│ │ ├── -CH-9413561-WW-Gallery-MM350-XL-01.png
│ │ ├── -CH-9413561-WW-Gallery-MM350-XL-03.png
│ │ ├── -CH-9413561-WW-Gallery-MM350-XL-04.png
│ │ └── MM350 Premium Anti-Fray Cloth Gaming Mouse Pad – X-Large.txt
│ │ └── MM700
│ │ ├── -base-mm700-rgb-config-Gallery-MM700-RGB-01.png
│ │ ├── -base-mm700-rgb-config-Gallery-MM700-RGB-08.png
│ │ ├── -base-mm700-rgb-config-Gallery-MM700-RGB-17.png
│ │ └── MM700 RGB Extended Mouse Pad.txt
├── Headsets
│ ├── Logitech
│ │ ├── g733-kda-gallery-1.png
│ │ ├── g733-kda-gallery-2.png
│ │ ├── g733-kda-gallery-3.png
│ │ └── description.txt
│ └── Corsair
│ │ ├── HS70
│ │ ├── -CA-9011227-NA-Gallery-HS70-Bluetooth-01.png
│ │ ├── -CA-9011227-NA-Gallery-HS70-Bluetooth-11.png
│ │ ├── -CA-9011227-NA-Gallery-HS70-Bluetooth-12.png
│ │ └── asdas.txt
│ │ ├── HS80
│ │ ├── -CA-901123B-NA-Gallery-CA-901123B-NA-01.png
│ │ ├── -CA-901123B-NA-Gallery-CA-901123B-NA-02.png
│ │ └── qwedasento de texto.txt
│ │ ├── virt wireless
│ │ ├── -CA-9011188-NA-Gallery-VIRTUOSO-XT-01.png
│ │ ├── -CA-9011188-NA-Gallery-VIRTUOSO-XT-06.png
│ │ ├── -CA-9011188-NA-Gallery-VIRTUOSO-XT-12.png
│ │ ├── -CA-9011188-NA-Gallery-VIRTUOSO-XT-14.png
│ │ └── asdasdq.txt
│ │ ├── Virtuoso
│ │ ├── -CA-9011181-NA-Gallery-VIRTUOSO-SE-BROWN-01.png
│ │ ├── -CA-9011181-NA-Gallery-VIRTUOSO-SE-BROWN-20.png
│ │ ├── -CA-9011181-NA-Gallery-VIRTUOSO-SE-BROWN-21.png
│ │ ├── -CA-9011181-NA-Gallery-VIRTUOSO-SE-BROWN-22.png
│ │ └── qwasd.txt
│ │ └── hs55
│ │ ├── -base-hs55-wireless-config-Gallery-HS55-WIRELESS-CORE-BLACK-10.png
│ │ ├── -base-hs55-wireless-config-Gallery-HS55-WIRELESS-CORE-BLACK-11.png
│ │ ├── -base-hs55-wireless-config-Gallery-HS55-WIRELESS-CORE-BLACK-12.png
│ │ └── asd.txt
└── Keyboards
│ ├── Logitech
│ ├── G915 TKL
│ │ ├── g915-tkl-gallery-1-carbon.png
│ │ ├── g915-tkl-gallery-3-carbon.png
│ │ ├── g915-tkl-gallery-4-carbon.png
│ │ ├── us-g915-tkl-carbon-gallery-topdown.png
│ │ └── G915 TKL.txt
│ ├── PRO KEYBOARD
│ │ ├── pro-clicky-gallery-2.png
│ │ ├── pro-clicky-gallery-3.png
│ │ ├── navigation-products-keyboard.jpg
│ │ └── PRO KEYBOARD.txt
│ └── PRO KEYBOARD League of Legends
│ │ ├── league-of-legends-pro-x-gaming-keyboard-gallery-1.png
│ │ ├── league-of-legends-pro-x-gaming-keyboard-gallery-2.png
│ │ ├── league-of-legends-pro-x-gaming-keyboard-gallery-3.png
│ │ ├── league-of-legends-pro-x-gaming-keyboard-gallery-4.png
│ │ ├── league-of-legends-pro-x-gaming-keyboard-gallery-5.png
│ │ └── PRO KEYBOARD League of Legends.txt
│ └── Corsair
│ ├── k100 optical
│ ├── -CH-912A01A-NA-Gallery-K100-RGB-01.png
│ ├── -CH-912A01A-NA-Gallery-K100-RGB-12.png
│ ├── -CH-912A01A-NA-Gallery-K100-RGB-13.png
│ ├── -CH-912A01A-NA-Gallery-K100-RGB-14.png
│ └── K100 RGB Optical-Mechanical.txt
│ ├── k70
│ ├── -CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-01.png
│ ├── -CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-02.png
│ ├── -CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-03.png
│ ├── -CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-05.png
│ ├── -CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-09.png
│ └── K70 PRO MINI WIRELESS.txt
│ └── k100
│ ├── -base-k100-air-wireless-config-Gallery-K100-RGB-AIR-WIRELESS-01.png
│ ├── -base-k100-air-wireless-config-Gallery-K100-RGB-AIR-WIRELESS-11.png
│ ├── -base-k100-air-wireless-config-Gallery-K100-RGB-AIR-WIRELESS-14.png
│ └── K100 AIR WIRELESS RGB.txt
├── lib
├── error.js
├── getStripe.js
├── client.js
├── data.js
├── db.js
└── utils.js
├── next.config.js
├── pages
├── api
│ ├── seed2.js
│ ├── seed.js
│ ├── orders
│ │ ├── history.js
│ │ ├── [id]
│ │ │ ├── index.js
│ │ │ ├── delete.js
│ │ │ └── pay.js
│ │ └── index.js
│ ├── auth
│ │ ├── update.js
│ │ ├── signup.js
│ │ └── [...nextauth].js
│ └── stripe.js
├── unauthorized.js
├── _app.js
├── success.js
├── login.js
├── index.js
├── product
│ └── [slug].js
├── order
│ └── [id].js
├── profile.js
├── register.js
├── shop.js
└── checkout.js
├── cambios.txt
├── models
├── User.js
└── Order.js
├── .gitignore
├── components
├── index.js
├── Footer.jsx
├── Product.jsx
├── Layout.jsx
├── FooterBanner.jsx
├── Loader.jsx
├── HamburgerMenu.jsx
├── FeaturedItems.jsx
├── CategoryMenu.jsx
├── HeroBanner.jsx
├── Cart.jsx
└── Navbar.jsx
├── package.json
├── context
└── StateContext.js
├── README.md
└── styles
└── globals.css
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["next/babel"]
3 | }
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["next/babel","next/core-web-vitals"]
3 | }
4 |
--------------------------------------------------------------------------------
/sanity_ecommerce/plugins/.gitkeep:
--------------------------------------------------------------------------------
1 | User-specific packages can be placed here
2 |
--------------------------------------------------------------------------------
/sanity_ecommerce/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@sanity/eslint-config-studio"
3 | }
4 |
--------------------------------------------------------------------------------
/sanity_ecommerce/config/@sanity/data-aspects.json:
--------------------------------------------------------------------------------
1 | {
2 | "listOptions": {}
3 | }
4 |
--------------------------------------------------------------------------------
/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/public/logo.png
--------------------------------------------------------------------------------
/sanity_ecommerce/config/@sanity/vision.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultApiVersion": "2021-10-21"
3 | }
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/public/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/public/favicon-32x32.png
--------------------------------------------------------------------------------
/public/assets/homepage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/public/assets/homepage.png
--------------------------------------------------------------------------------
/sanity_ecommerce/config/@sanity/form-builder.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": {
3 | "directUploads": true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/sanity_ecommerce/static/.gitkeep:
--------------------------------------------------------------------------------
1 | Files placed here will be served by the Sanity server under the `/static`-prefix
2 |
--------------------------------------------------------------------------------
/public/assets/Lighthouse scores.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/public/assets/Lighthouse scores.png
--------------------------------------------------------------------------------
/sanity_ecommerce/config/@sanity/default-layout.json:
--------------------------------------------------------------------------------
1 | {
2 | "toolSwitcher": {
3 | "order": [],
4 | "hidden": []
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/sanity_ecommerce/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/sanity_ecommerce/static/favicon.ico
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G705/g705-gallery-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G705/g705-gallery-1.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G705/g705-gallery-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G705/g705-gallery-2.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G705/g705-gallery-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G705/g705-gallery-3.png
--------------------------------------------------------------------------------
/assets/Mousepads/ASUS Rog/ROG Sheath/h525.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mousepads/ASUS Rog/ROG Sheath/h525.png
--------------------------------------------------------------------------------
/assets/Mousepads/ASUS Rog/ROG Sheath/h732.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mousepads/ASUS Rog/ROG Sheath/h732.png
--------------------------------------------------------------------------------
/assets/Headsets/Logitech/g733-kda-gallery-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Logitech/g733-kda-gallery-1.png
--------------------------------------------------------------------------------
/assets/Headsets/Logitech/g733-kda-gallery-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Logitech/g733-kda-gallery-2.png
--------------------------------------------------------------------------------
/assets/Headsets/Logitech/g733-kda-gallery-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Logitech/g733-kda-gallery-3.png
--------------------------------------------------------------------------------
/assets/Mousepads/ASUS Rog/ROG Sheath/h732 (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mousepads/ASUS Rog/ROG Sheath/h732 (1).png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G303/shroud-g303-gallery-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G303/shroud-g303-gallery-1.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G303/shroud-g303-gallery-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G303/shroud-g303-gallery-2.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G303/shroud-g303-gallery-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G303/shroud-g303-gallery-3.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G303/shroud-g303-gallery-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G303/shroud-g303-gallery-5.png
--------------------------------------------------------------------------------
/assets/Mousepads/ASUS Rog/ROG Sheath Electro Punk/h732.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mousepads/ASUS Rog/ROG Sheath Electro Punk/h732.png
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/G915 TKL/g915-tkl-gallery-1-carbon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Logitech/G915 TKL/g915-tkl-gallery-1-carbon.png
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/G915 TKL/g915-tkl-gallery-3-carbon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Logitech/G915 TKL/g915-tkl-gallery-3-carbon.png
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/G915 TKL/g915-tkl-gallery-4-carbon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Logitech/G915 TKL/g915-tkl-gallery-4-carbon.png
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/PRO KEYBOARD/pro-clicky-gallery-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Logitech/PRO KEYBOARD/pro-clicky-gallery-2.png
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/PRO KEYBOARD/pro-clicky-gallery-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Logitech/PRO KEYBOARD/pro-clicky-gallery-3.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G502 PLUS/g502x-plus-gallery-3-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G502 PLUS/g502x-plus-gallery-3-white.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G502 PLUS/g502x-plus-gallery-5-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G502 PLUS/g502x-plus-gallery-5-white.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G502 PLUS/g502x-plus-gallery-6-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G502 PLUS/g502x-plus-gallery-6-white.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G502 PLUS/g502x-plus-gallery-white-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G502 PLUS/g502x-plus-gallery-white-01.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G502 PLUS/g502x-plus-gallery-white-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G502 PLUS/g502x-plus-gallery-white-02.png
--------------------------------------------------------------------------------
/assets/Mousepads/ASUS Rog/ROG Sheath Electro Punk/h732 (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mousepads/ASUS Rog/ROG Sheath Electro Punk/h732 (1).png
--------------------------------------------------------------------------------
/assets/Mousepads/ASUS Rog/ROG Sheath Electro Punk/h732 (2).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mousepads/ASUS Rog/ROG Sheath Electro Punk/h732 (2).png
--------------------------------------------------------------------------------
/assets/Mousepads/Corsair/MM350/-CH-9413561-WW-Gallery-MM350-XL-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mousepads/Corsair/MM350/-CH-9413561-WW-Gallery-MM350-XL-01.png
--------------------------------------------------------------------------------
/assets/Mousepads/Corsair/MM350/-CH-9413561-WW-Gallery-MM350-XL-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mousepads/Corsair/MM350/-CH-9413561-WW-Gallery-MM350-XL-03.png
--------------------------------------------------------------------------------
/assets/Mousepads/Corsair/MM350/-CH-9413561-WW-Gallery-MM350-XL-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mousepads/Corsair/MM350/-CH-9413561-WW-Gallery-MM350-XL-04.png
--------------------------------------------------------------------------------
/lib/error.js:
--------------------------------------------------------------------------------
1 | const getError = (err) => {
2 | err.response && err.response.data && err.response.data.message
3 | ? err.response.data.message
4 | : err.message;
5 | };
6 |
7 | export default getError;
--------------------------------------------------------------------------------
/sanity_ecommerce/config/@sanity/default-login.json:
--------------------------------------------------------------------------------
1 | {
2 | "providers": {
3 | "mode": "append",
4 | "redirectOnSingle": false,
5 | "entries": []
6 | },
7 | "loginMethod": "dual"
8 | }
9 |
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/PRO KEYBOARD/navigation-products-keyboard.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Logitech/PRO KEYBOARD/navigation-products-keyboard.jpg
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/HS70/-CA-9011227-NA-Gallery-HS70-Bluetooth-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/HS70/-CA-9011227-NA-Gallery-HS70-Bluetooth-01.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/HS70/-CA-9011227-NA-Gallery-HS70-Bluetooth-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/HS70/-CA-9011227-NA-Gallery-HS70-Bluetooth-11.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/HS70/-CA-9011227-NA-Gallery-HS70-Bluetooth-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/HS70/-CA-9011227-NA-Gallery-HS70-Bluetooth-12.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/HS80/-CA-901123B-NA-Gallery-CA-901123B-NA-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/HS80/-CA-901123B-NA-Gallery-CA-901123B-NA-01.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/HS80/-CA-901123B-NA-Gallery-CA-901123B-NA-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/HS80/-CA-901123B-NA-Gallery-CA-901123B-NA-02.png
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/G915 TKL/us-g915-tkl-carbon-gallery-topdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Logitech/G915 TKL/us-g915-tkl-carbon-gallery-topdown.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G502 X GAMING MOUSE/g502x-corded-gallery-1-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G502 X GAMING MOUSE/g502x-corded-gallery-1-white.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G502 X GAMING MOUSE/g502x-corded-gallery-2-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G502 X GAMING MOUSE/g502x-corded-gallery-2-white.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G502 X GAMING MOUSE/g502x-corded-gallery-3-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G502 X GAMING MOUSE/g502x-corded-gallery-3-white.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G502 X GAMING MOUSE/g502x-corded-gallery-4-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G502 X GAMING MOUSE/g502x-corded-gallery-4-white.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G502 X GAMING MOUSE/g502x-corded-gallery-5-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/G502 X GAMING MOUSE/g502x-corded-gallery-5-white.png
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k100 optical/-CH-912A01A-NA-Gallery-K100-RGB-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Corsair/k100 optical/-CH-912A01A-NA-Gallery-K100-RGB-01.png
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k100 optical/-CH-912A01A-NA-Gallery-K100-RGB-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Corsair/k100 optical/-CH-912A01A-NA-Gallery-K100-RGB-12.png
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k100 optical/-CH-912A01A-NA-Gallery-K100-RGB-13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Corsair/k100 optical/-CH-912A01A-NA-Gallery-K100-RGB-13.png
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k100 optical/-CH-912A01A-NA-Gallery-K100-RGB-14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Corsair/k100 optical/-CH-912A01A-NA-Gallery-K100-RGB-14.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/virt wireless/-CA-9011188-NA-Gallery-VIRTUOSO-XT-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/virt wireless/-CA-9011188-NA-Gallery-VIRTUOSO-XT-01.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/virt wireless/-CA-9011188-NA-Gallery-VIRTUOSO-XT-06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/virt wireless/-CA-9011188-NA-Gallery-VIRTUOSO-XT-06.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/virt wireless/-CA-9011188-NA-Gallery-VIRTUOSO-XT-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/virt wireless/-CA-9011188-NA-Gallery-VIRTUOSO-XT-12.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/virt wireless/-CA-9011188-NA-Gallery-VIRTUOSO-XT-14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/virt wireless/-CA-9011188-NA-Gallery-VIRTUOSO-XT-14.png
--------------------------------------------------------------------------------
/assets/Mousepads/Corsair/MM700/-base-mm700-rgb-config-Gallery-MM700-RGB-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mousepads/Corsair/MM700/-base-mm700-rgb-config-Gallery-MM700-RGB-01.png
--------------------------------------------------------------------------------
/assets/Mousepads/Corsair/MM700/-base-mm700-rgb-config-Gallery-MM700-RGB-08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mousepads/Corsair/MM700/-base-mm700-rgb-config-Gallery-MM700-RGB-08.png
--------------------------------------------------------------------------------
/assets/Mousepads/Corsair/MM700/-base-mm700-rgb-config-Gallery-MM700-RGB-17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mousepads/Corsair/MM700/-base-mm700-rgb-config-Gallery-MM700-RGB-17.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/Virtuoso/-CA-9011181-NA-Gallery-VIRTUOSO-SE-BROWN-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/Virtuoso/-CA-9011181-NA-Gallery-VIRTUOSO-SE-BROWN-01.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/Virtuoso/-CA-9011181-NA-Gallery-VIRTUOSO-SE-BROWN-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/Virtuoso/-CA-9011181-NA-Gallery-VIRTUOSO-SE-BROWN-20.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/Virtuoso/-CA-9011181-NA-Gallery-VIRTUOSO-SE-BROWN-21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/Virtuoso/-CA-9011181-NA-Gallery-VIRTUOSO-SE-BROWN-21.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/Virtuoso/-CA-9011181-NA-Gallery-VIRTUOSO-SE-BROWN-22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/Virtuoso/-CA-9011181-NA-Gallery-VIRTUOSO-SE-BROWN-22.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/Dark Core/-CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/Dark Core/-CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-01.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/Dark Core/-CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/Dark Core/-CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-21.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/Dark Core/-CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-25.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/Dark Core/-CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-25.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/Dark Core/-CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-26.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/Dark Core/-CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-26.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/Dark Core/-CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/Dark Core/-CH-9315511-NA-Gallery-DARK-CORE-RGB-PRO-SE-32.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/Scimitar pro/-CH-9304111-NA-Gallery-Scimitar-PRO-BLK-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/Scimitar pro/-CH-9304111-NA-Gallery-Scimitar-PRO-BLK-01.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/Scimitar pro/-CH-9304111-NA-Gallery-Scimitar-PRO-BLK-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/Scimitar pro/-CH-9304111-NA-Gallery-Scimitar-PRO-BLK-04.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/Scimitar pro/-CH-9304111-NA-Gallery-Scimitar-PRO-BLK-05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/Scimitar pro/-CH-9304111-NA-Gallery-Scimitar-PRO-BLK-05.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/Scimitar pro/-CH-9304111-NA-Gallery-Scimitar-PRO-BLK-08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/Scimitar pro/-CH-9304111-NA-Gallery-Scimitar-PRO-BLK-08.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/Scimitar pro/-CH-9304111-NA-Gallery-Scimitar-PRO-BLK-22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/Scimitar pro/-CH-9304111-NA-Gallery-Scimitar-PRO-BLK-22.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/ironclaw/-CH-9317011-NA-Gallery-IRONCLAW-RGB-WIRELESS-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/ironclaw/-CH-9317011-NA-Gallery-IRONCLAW-RGB-WIRELESS-01.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/ironclaw/-CH-9317011-NA-Gallery-IRONCLAW-RGB-WIRELESS-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/ironclaw/-CH-9317011-NA-Gallery-IRONCLAW-RGB-WIRELESS-02.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/ironclaw/-CH-9317011-NA-Gallery-IRONCLAW-RGB-WIRELESS-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/ironclaw/-CH-9317011-NA-Gallery-IRONCLAW-RGB-WIRELESS-03.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/ironclaw/-CH-9317011-NA-Gallery-IRONCLAW-RGB-WIRELESS-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/ironclaw/-CH-9317011-NA-Gallery-IRONCLAW-RGB-WIRELESS-04.png
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k70/-CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Corsair/k70/-CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-01.png
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k70/-CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Corsair/k70/-CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-02.png
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k70/-CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Corsair/k70/-CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-03.png
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k70/-CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Corsair/k70/-CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-05.png
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k70/-CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Corsair/k70/-CH-9189014-NA-Gallery-K70-PRO-MINI-WIRELESS-PBT-09.png
--------------------------------------------------------------------------------
/sanity_ecommerce/.npmignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | /logs
3 | *.log
4 |
5 | # Coverage directory used by tools like istanbul
6 | /coverage
7 |
8 | # Dependency directories
9 | node_modules
10 |
11 | # Compiled sanity studio
12 | /dist
13 |
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/katar/-base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/katar/-base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-01.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/katar/-base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/katar/-base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-23.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/katar/-base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/katar/-base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-24.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/katar/-base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-26.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/katar/-base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-26.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/katar/-base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-27.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/katar/-base-katar-pro-wireless-config-Gallery-KATAR-PRO-WIRELESS-27.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/hs55/-base-hs55-wireless-config-Gallery-HS55-WIRELESS-CORE-BLACK-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/hs55/-base-hs55-wireless-config-Gallery-HS55-WIRELESS-CORE-BLACK-10.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/hs55/-base-hs55-wireless-config-Gallery-HS55-WIRELESS-CORE-BLACK-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/hs55/-base-hs55-wireless-config-Gallery-HS55-WIRELESS-CORE-BLACK-11.png
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/hs55/-base-hs55-wireless-config-Gallery-HS55-WIRELESS-CORE-BLACK-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Headsets/Corsair/hs55/-base-hs55-wireless-config-Gallery-HS55-WIRELESS-CORE-BLACK-12.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/PRO wirwless LoL/league-of-legends-pro-wireless-gaming-mouse-gallery-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/PRO wirwless LoL/league-of-legends-pro-wireless-gaming-mouse-gallery-1.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/PRO wirwless LoL/league-of-legends-pro-wireless-gaming-mouse-gallery-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/PRO wirwless LoL/league-of-legends-pro-wireless-gaming-mouse-gallery-2.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/PRO wirwless LoL/league-of-legends-pro-wireless-gaming-mouse-gallery-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/PRO wirwless LoL/league-of-legends-pro-wireless-gaming-mouse-gallery-3.png
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/PRO wirwless LoL/league-of-legends-pro-wireless-gaming-mouse-gallery-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Logitech/PRO wirwless LoL/league-of-legends-pro-wireless-gaming-mouse-gallery-4.png
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k100/-base-k100-air-wireless-config-Gallery-K100-RGB-AIR-WIRELESS-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Corsair/k100/-base-k100-air-wireless-config-Gallery-K100-RGB-AIR-WIRELESS-01.png
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k100/-base-k100-air-wireless-config-Gallery-K100-RGB-AIR-WIRELESS-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Corsair/k100/-base-k100-air-wireless-config-Gallery-K100-RGB-AIR-WIRELESS-11.png
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k100/-base-k100-air-wireless-config-Gallery-K100-RGB-AIR-WIRELESS-14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Corsair/k100/-base-k100-air-wireless-config-Gallery-K100-RGB-AIR-WIRELESS-14.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/m65/-base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/m65/-base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-01.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/m65/-base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/m65/-base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-08.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/m65/-base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/m65/-base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-11.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/m65/-base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/m65/-base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-13.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/m65/-base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Mouse/Corsair/m65/-base-m65-rgb-ultra-wireless-config-Gallery-M65-RGB-ULTRA-WIRELESS-16.png
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | swcMinify: true,
5 | i18n: {
6 | locales: ['en'],
7 | defaultLocale: 'en',
8 | },
9 | }
10 |
11 | module.exports = nextConfig
12 |
--------------------------------------------------------------------------------
/assets/Mousepads/ASUS Rog/ROG Sheath/ROG Sheath.txt:
--------------------------------------------------------------------------------
1 | ROG Sheath
2 |
3 | $29.99
4 |
5 | The stage for the ultimate battle, optimized for smooth mouse gliding. Massive dimensions for all your gaming gear
6 | Non-slip ROG red rubber base
7 | Durable anti-fray stitching
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/PRO KEYBOARD League of Legends/league-of-legends-pro-x-gaming-keyboard-gallery-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Logitech/PRO KEYBOARD League of Legends/league-of-legends-pro-x-gaming-keyboard-gallery-1.png
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/PRO KEYBOARD League of Legends/league-of-legends-pro-x-gaming-keyboard-gallery-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Logitech/PRO KEYBOARD League of Legends/league-of-legends-pro-x-gaming-keyboard-gallery-2.png
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/PRO KEYBOARD League of Legends/league-of-legends-pro-x-gaming-keyboard-gallery-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Logitech/PRO KEYBOARD League of Legends/league-of-legends-pro-x-gaming-keyboard-gallery-3.png
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/PRO KEYBOARD League of Legends/league-of-legends-pro-x-gaming-keyboard-gallery-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Logitech/PRO KEYBOARD League of Legends/league-of-legends-pro-x-gaming-keyboard-gallery-4.png
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/PRO KEYBOARD League of Legends/league-of-legends-pro-x-gaming-keyboard-gallery-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InfVlad/Ecommerce-AwesomeGear/HEAD/assets/Keyboards/Logitech/PRO KEYBOARD League of Legends/league-of-legends-pro-x-gaming-keyboard-gallery-5.png
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/Scimitar pro/SCIMITAR PRO RGB Optical.txt:
--------------------------------------------------------------------------------
1 | SCIMITAR PRO RGB Optical MOBA/MMO Gaming Mouse — Black
2 |
3 | $79.99USD
4 |
5 | The SCIMITAR PRO RGB gaming mouse advances your game with the customizable Key Slider™ macro button control system, a native 16000 DPI.
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/Dark Core/DARK CORE RGB PRO SE.txt:
--------------------------------------------------------------------------------
1 | DARK CORE RGB PRO SE Wireless Gaming Mouse
2 | SPECIAL PRICE
3 | $89.99USD
4 |
5 | The CORSAIR DARK CORE RGB SE gaming mouse uses an ultra-fast 1ms 2.4GHz wireless connection, Qi® wireless charging and a 18,000 DPI optical sensor for true wireless gaming.
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G502 X GAMING MOUSE/G502.txt:
--------------------------------------------------------------------------------
1 | G502 X GAMING MOUSE
2 | $79.99
3 |
4 | G502 X is the latest addition to the legendary G502 lineage. Redesigned to achieve an impressive weight reduction down to 89 grams. Featuring our first-ever LIGHTFORCE hybrid optical-mechanical switches and HERO 25K sub-micron sensor.
--------------------------------------------------------------------------------
/lib/getStripe.js:
--------------------------------------------------------------------------------
1 | import { loadStripe } from "@stripe/stripe-js";
2 |
3 | let stripePromise;
4 |
5 | const getStripe = () => {
6 | if(!stripePromise){
7 | stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY);
8 | }
9 |
10 | return stripePromise;
11 | }
12 |
13 | export default getStripe;
--------------------------------------------------------------------------------
/sanity_ecommerce/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // Note: This config is only used to help editors like VS Code understand/resolve
3 | // parts, the actual transpilation is done by babel. Any compiler configuration in
4 | // here will be ignored.
5 | "include": ["./node_modules/@sanity/base/types/**/*.ts", "./**/*.ts", "./**/*.tsx"]
6 | }
7 |
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/m65/M65 RGB ULTRA WIRELESS.txt:
--------------------------------------------------------------------------------
1 | M65 RGB ULTRA WIRELESS Tunable FPS Gaming Mouse
2 |
3 | SPECIAL PRICE
4 | $109.99USD
5 |
6 | Make all your clicks count with the CORSAIR M65 RGB ULTRA WIRELESS Tunable Gaming Mouse, boasting a durable aluminum frame, hyper-fast SLIPSTREAM WIRELESS, and a 26,000 DPI MARKSMAN optical sensor.
--------------------------------------------------------------------------------
/pages/api/seed2.js:
--------------------------------------------------------------------------------
1 | import Order from '../../models/Order';
2 | import data from '../../lib/data';
3 | import db from '../../lib/db';
4 |
5 | const handler = async (req, res) => {
6 | await db.connect();
7 | await Order.deleteMany();
8 | await db.disconnect();
9 | res.send({ message: 'seeded successfully' });
10 | };
11 | export default handler;
--------------------------------------------------------------------------------
/sanity_ecommerce/schemas/schema.js:
--------------------------------------------------------------------------------
1 | import createSchema from 'part:@sanity/base/schema-creator'
2 | import schemaTypes from 'all:part:@sanity/base/schema-type'
3 | import product from "./product"
4 | import banner from "./banner"
5 |
6 |
7 | export default createSchema({
8 | name: 'default',
9 | types: schemaTypes.concat([ product, banner, ]),
10 | })
11 |
--------------------------------------------------------------------------------
/cambios.txt:
--------------------------------------------------------------------------------
1 | creates file
2 | .babelrc on root with:
3 | {
4 | "presets": ["next/babel"]
5 | }
6 |
7 | cambia .eslintrc.json
8 | de:
9 | {
10 | "extends": "next/core-web-vitals"
11 | }
12 | a:
13 | {
14 | "extends": ["next/babel","next/core-web-vitals"]
15 | }
16 |
17 | en babelrc cambio:
18 |
19 | {
20 | "presets": ["next/babel". "@babel/preset-react"]
21 | }
22 |
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/ironclaw/IRONCLAW RGB WIRELESS Gaming Mouse.txt:
--------------------------------------------------------------------------------
1 | IRONCLAW RGB WIRELESS Gaming Mouse
2 |
3 | SPECIAL PRICE
4 | $69.99USD
5 |
6 | The CORSAIR IRONCLAW RGB WIRELESS Gaming Mouse combines a native 18,000 DPI optical sensor with a comfortable palm grip, connecting to your PC via hyper-fast, sub-1ms SLIPSTREAM CORSAIR WIRELESS TECHNOLOGY, Bluetooth or USB wired connection.
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G303/LOGITECH G303 SHROUD EDITION.txt:
--------------------------------------------------------------------------------
1 | LOGITECH G303 SHROUD EDITION
2 | Wireless Gaming Mouse
3 | $129.99
4 | In stock. Ready to ship
5 | ADD TO CART
6 | Free shipping and returns
7 | Aim higher with a remastered iconic mouse. Designed in collaboration with Shroud and matched to his specs. LIGHTSPEED wireless, HERO 25K Sensor, and an incredible 145 gaming-hour battery life.
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G705/G705.txt:
--------------------------------------------------------------------------------
1 | G705
2 | Wireless Gaming Mouse
3 | $99.99
4 | In stock. Ready to ship
5 | ADD TO CART
6 | Free shipping and returns
7 | From the Aurora Collection, G705 Wireless Gaming Mouse is contoured for comfort and control with an intentional design to be inclusive of smaller hands. Features gaming-grade LIGHTSPEED wireless, LIGHTSYNC RGB, and advanced gaming technology.
--------------------------------------------------------------------------------
/pages/api/seed.js:
--------------------------------------------------------------------------------
1 | import User from '../../models/User';
2 | import data from '../../lib/data';
3 | import db from '../../lib/db';
4 |
5 | const handler = async (req, res) => {
6 | await db.connect();
7 | await User.deleteMany();
8 | await User.insertMany(data.users);
9 | await db.disconnect();
10 | res.send({ message: 'seeded successfully' });
11 | };
12 | export default handler;
--------------------------------------------------------------------------------
/assets/Mouse/Corsair/katar/KATAR PRO WIRELESS Gaming Mouse.txt:
--------------------------------------------------------------------------------
1 | KATAR PRO WIRELESS Gaming Mouse
2 | $49.99USD
3 |
4 | Experience lightweight design and heavyweight performance with the CORSAIR KATAR PRO WIRELESS Gaming Mouse, connecting via hyper-fast SLIPSTREAM WIRELESS or low-latency Bluetooth®. Weighing in at just 96g, its compact symmetric shape is suitable for both claw and fingertip grip styles.
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/G502 PLUS/G502 X PLUS GAMING MOUSE.txt:
--------------------------------------------------------------------------------
1 | G502 X PLUS GAMING MOUSE
2 | $159.99
3 | 4 interest-free payments of $39.99 with Klarna. Learn More
4 |
5 |
6 | White
7 | Sold Out Temporarily
8 | Free shipping and returns
9 | G502 X PLUS is the latest addition to legendary G502 lineage. Reinvented with our first-ever LIGHTFORCE hybrid switches, LIGHTSPEED pro-grade wireless, LIGHTSYNC RGB, HERO 25K sensor, and more.
--------------------------------------------------------------------------------
/assets/Mouse/Logitech/PRO wirwless LoL/PRO WIRELESS MOUSE.txt:
--------------------------------------------------------------------------------
1 | PRO WIRELESS MOUSE
2 | League of Legends Edition
3 | $129.99
4 | 4 interest-free payments of $32.49 with Klarna. Learn More
5 |
6 | In stock. Ready to ship
7 | ADD TO CART
8 | Free shipping and returns
9 | Our hit PRO mouse with iconic League of Legends design. Hextech Magic blue and Hextech Metal gold adorn the unrivaled performance and precision you need to succeed in the Summoner’s Rift.
--------------------------------------------------------------------------------
/lib/client.js:
--------------------------------------------------------------------------------
1 | import sanityClient from "@sanity/client";
2 | import imageUrlBuilder from "@sanity/image-url"
3 |
4 | export const client = sanityClient({
5 | projectId: "y64aoq1q",
6 | dataset: "production",
7 | apiVersion: "2022-10-17",
8 | useCdn: true,
9 | token: process.env.NEXT_PUBLIC_SANITY_TOKEN
10 | })
11 |
12 | const builder = imageUrlBuilder(client)
13 |
14 | export const urlFor = (source) => builder.image(source);
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/PRO KEYBOARD/PRO KEYBOARD.txt:
--------------------------------------------------------------------------------
1 | PRO KEYBOARD
2 | KEYBOARD
3 | $129.99
4 | 4 interest-free payments of $32.49 with Klarna. Learn More
5 |
6 |
7 | Black
8 |
9 | CHOOSE A STYLE
10 | In stock. Ready to ship
11 | ADD TO CART
12 | Free shipping and returns
13 | The tournament-proven PRO gaming keyboard, now with advanced GX Blue Clicky mechanical switches. Built to win in collaboration with the world’s top esports athletes.
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/hs55/asd.txt:
--------------------------------------------------------------------------------
1 | HS55 WIRELESS CORE Gaming Headset
2 | $99.99USD
3 | shipping Icon
4 | SHIPS WITHIN ONE BUSINESS DAY. FREE SHIPPING ON ORDERS OVER $79. EXCLUSIONS APPLY.
5 |
6 | 4 interest-free payments of $24.99 with Klarna. Learn More
7 |
8 | The CORSAIR HS55 WIRELESS CORE Gaming Headset matches low-latency 2.4GHz wireless audio or Bluetooth®connections with lightweight construction, for essential all-day wireless comfort and great sound.
--------------------------------------------------------------------------------
/assets/Mousepads/ASUS Rog/ROG Sheath Electro Punk/ROG Sheath Electro Punk.txt:
--------------------------------------------------------------------------------
1 | ROG Sheath Electro Punk
2 |
3 | $29.99
4 |
5 | The extra-large ROG Sheath Electro Punk mouse pad is optimized for all gaming mouse types, with a smooth surface that perfectly ensures pixel-precise tracking for unmatched command and control. ROG Sheath Electro Punk is designed for your comfort and features a non-slip rubber base that keeps it in place and stitched edges that resist fraying.
--------------------------------------------------------------------------------
/assets/Mousepads/Corsair/MM700/MM700 RGB Extended Mouse Pad.txt:
--------------------------------------------------------------------------------
1 | MM700 RGB Extended Mouse Pad
2 | $59.99USD
3 | shipping Icon
4 | SHIPS WITHIN ONE BUSINESS DAY. FREE SHIPPING ON ORDERS OVER $79. EXCLUSIONS APPLY.
5 |
6 | 4 interest-free payments of $14.99 with Klarna. Learn More
7 |
8 | The CORSAIR MM700 RGB Extended Cloth Gaming Mouse Pad provides an expansive 930mm x 400mm surface with ample room for your peripherals, surrounded by 360° of three-zone dynamic RGB lighting.
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/HS70/asdas.txt:
--------------------------------------------------------------------------------
1 | HS70 Wired Gaming Headset with Bluetooth
2 | $99.99USD
3 | shipping Icon
4 | SHIPS WITHIN ONE BUSINESS DAY. FREE SHIPPING ON ORDERS OVER $79. EXCLUSIONS APPLY.
5 |
6 | 4 interest-free payments of $24.99 with Klarna. Learn More
7 |
8 | The CORSAIR HS70 BLUETOOTH Gaming Headset delivers both comfort and quality with memory foam ear pads, custom-tuned 50mm neodymium audio drivers, and simultaneous wired connection for game audio with Bluetooth® for chat.
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/PRO KEYBOARD League of Legends/PRO KEYBOARD League of Legends.txt:
--------------------------------------------------------------------------------
1 | PRO KEYBOARD
2 | League of Legends Edition
3 | $129.99
4 | 4 interest-free payments of $32.49 with Klarna. Learn More
5 |
6 | In stock. Ready to ship
7 | ADD TO CART
8 | Free shipping and returns
9 | We clad our tournament-tested PRO Keyboard in the iconic League of Legends colors. Compact, tenkeyless design and pro-grade tactile switches make it a powerful weapon for League of Legends and beyond.
--------------------------------------------------------------------------------
/lib/data.js:
--------------------------------------------------------------------------------
1 | import bcrypt from "bcryptjs";
2 |
3 | const data = {
4 | users: [
5 | {
6 | name: 'John',
7 | email: 'admin1@example.com',
8 | password: bcrypt.hashSync('123456'),
9 | isAdmin: true,
10 | },
11 | {
12 | name: 'Jane',
13 | email: 'user@example.com',
14 | password: bcrypt.hashSync('123456'),
15 | isAdmin: false,
16 | },
17 | ]
18 | }
19 |
20 | export default data;
--------------------------------------------------------------------------------
/models/User.js:
--------------------------------------------------------------------------------
1 | import mongoose from "mongoose";
2 |
3 | const userSchema = new mongoose.Schema(
4 | {
5 | name: { type: String, required: true },
6 | email: { type: String, required: true, unique: true },
7 | password: { type: String, required: true },
8 | isAdmin: { type: Boolean, required: true, default: false },
9 | },
10 | {
11 | timestamps: true,
12 | }
13 | );
14 |
15 | const User = mongoose.models.User || mongoose.model('User', userSchema);
16 | export default User;
17 |
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k100/K100 AIR WIRELESS RGB.txt:
--------------------------------------------------------------------------------
1 | K100 AIR WIRELESS RGB Ultra-Thin Mechanical Gaming Keyboard - CHERRY MX Ultra Low Profile Tactile (NA)
2 | $279.99USD
3 | shipping Icon
4 | SHIPS WITHIN ONE BUSINESS DAY. FREE SHIPPING ON ORDERS OVER $79. EXCLUSIONS APPLY.
5 |
6 | 4 interest-free payments of $69.99 with Klarna. Learn More
7 |
8 | The CORSAIR K100 AIR Wireless Mechanical Gaming Keyboard delivers outstanding performance with an unbelievably thin design, with CHERRY MX Ultra Low Profile keyswitches and hyper-fast wireless connectivity.
--------------------------------------------------------------------------------
/pages/unauthorized.js:
--------------------------------------------------------------------------------
1 | import { useRouter } from 'next/router'
2 | import React from 'react'
3 |
4 | const Unauthorized = () => {
5 | const router = useRouter();
6 | const { message } = router.query;
7 | return (
8 |
9 |
10 |
11 |
Access Denied
12 | {message &&
{message}
}
13 |
14 |
15 | )
16 | }
17 |
18 | export default Unauthorized
--------------------------------------------------------------------------------
/.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 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 | .env
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/sanity_ecommerce/README.md:
--------------------------------------------------------------------------------
1 | # Sanity Clean Content Studio
2 |
3 | Congratulations, you have now installed the Sanity Content Studio, an open source real-time content editing environment connected to the Sanity backend.
4 |
5 | Now you can do the following things:
6 |
7 | - [Read “getting started” in the docs](https://www.sanity.io/docs/introduction/getting-started?utm_source=readme)
8 | - [Join the community Slack](https://slack.sanity.io/?utm_source=readme)
9 | - [Extend and build plugins](https://www.sanity.io/docs/content-studio/extending?utm_source=readme)
10 |
--------------------------------------------------------------------------------
/assets/Keyboards/Logitech/G915 TKL/G915 TKL.txt:
--------------------------------------------------------------------------------
1 | G915 TKL
2 | Logitech G915 TKL Tenkeyless LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard
3 | $229.99
4 |
5 |
6 | A breakthrough in design and engineering, now in black and white colorways. G915 TKL features LIGHTSPEED pro-grade wireless, advanced LIGHTSYNC RGB, and high-performance low-profile mechanical switches. Meticulously crafted from premium materials, the G915 TKL is a sophisticated design of unparalleled beauty, strength, and performance, now in an even more compact form factor. G915 TKL. Play the next dimension.
7 |
8 |
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/Virtuoso/qwasd.txt:
--------------------------------------------------------------------------------
1 | VIRTUOSO RGB WIRELESS SE High-Fidelity Gaming Headset — Espresso
2 | $229.99USD
3 | shipping Icon
4 | SHIPS WITHIN ONE BUSINESS DAY. FREE SHIPPING ON ORDERS OVER $79. EXCLUSIONS APPLY.
5 |
6 | promo Icon
7 | BUY SELECT HEADSETS AND GET A ST100 HEADSET STAND AT 20% OFF
8 | 4 interest-free payments of $57.49 with Klarna. Learn More
9 |
10 | The CORSAIR VIRTUOSO RGB Wireless SE delivers a high-fidelity audio experience, all-day comfort from its premium memory foam earpads, and hyper-fast connectivity with SLIPSTREAM WIRELESS technology.
--------------------------------------------------------------------------------
/assets/Headsets/Logitech/description.txt:
--------------------------------------------------------------------------------
1 | G733
2 |
3 | LIGHTSPEED Wireless RGB Gaming Headset
4 |
5 | $139.99
6 |
7 | Wireless gaming headset designed for performance and comfort. Outfitted with all the surround sound, voice filters, and advanced lighting you need to look, sound, and play with more style than ever.
8 |
9 | Finally, a headset that can be as expressive as you. G733 is wireless and designed for comfort. And it’s outfitted with all the surround sound, voice filters, and advanced lighting you need to look, sound, and play with more style than ever.
10 |
11 |
--------------------------------------------------------------------------------
/assets/Mousepads/Corsair/MM350/MM350 Premium Anti-Fray Cloth Gaming Mouse Pad – X-Large.txt:
--------------------------------------------------------------------------------
1 | MM350 Premium Anti-Fray Cloth Gaming Mouse Pad – X-Large
2 | $24.99USD
3 | shipping Icon
4 | SHIPS WITHIN ONE BUSINESS DAY. FREE SHIPPING ON ORDERS OVER $79. EXCLUSIONS APPLY.
5 |
6 | 4 interest-free payments. Available for orders above $35. Klarna. Learn More
7 |
8 | Enjoy hours of plush gaming comfort on the CORSAIR MM350 Anti-Fray Cloth Gaming Mousepad – X-Large, boasting a roomy 450mm x 400mm surface with ample room for high-performance optical and laser sensor gaming mice.
9 |
10 |
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/virt wireless/asdasdq.txt:
--------------------------------------------------------------------------------
1 | VIRTUOSO RGB WIRELESS XT High-Fidelity Gaming Headset — Slate
2 | $269.99USD
3 | shipping Icon
4 | SHIPS WITHIN ONE BUSINESS DAY. FREE SHIPPING ON ORDERS OVER $79. EXCLUSIONS APPLY.
5 |
6 | promo Icon
7 | BUY SELECT HEADSETS AND GET A ST100 HEADSET STAND AT 20% OFF
8 | 4 interest-free payments of $67.49 with Klarna. Learn More
9 |
10 | The CORSAIR VIRTUOSO RGB Wireless XT delivers a high-fidelity audio experience, all-day comfort from its premium memory foam earpads, and simultaneous connectivity with hyper-fast SLIPSTREAM WIRELESS and Bluetooth®.
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k100 optical/K100 RGB Optical-Mechanical.txt:
--------------------------------------------------------------------------------
1 | K100 RGB Optical-Mechanical Gaming Keyboard — CORSAIR OPX Switch — Black
2 | SPECIAL PRICE
3 | $229.99USD
4 | Was $249.99 USD
5 | shipping Icon
6 | SHIPS WITHIN ONE BUSINESS DAY. FREE SHIPPING ON ORDERS OVER $79. EXCLUSIONS APPLY.
7 |
8 | 4 interest-free payments of $57.49 with Klarna. Learn More
9 |
10 | The incomparable CORSAIR K100 RGB Optical-Mechanical Gaming Keyboard combines stunning aluminum design, per-key RGB lighting with powerful CORSAIR AXON Hyper-Processing Technology and CORSAIR OPX RGB keyswitches.
11 |
12 |
--------------------------------------------------------------------------------
/assets/Headsets/Corsair/HS80/qwedasento de texto.txt:
--------------------------------------------------------------------------------
1 | HS80 RGB WIRELESS Premium Gaming Headset with Spatial Audio – Ethereal Blue
2 | $159.99USD
3 | shipping Icon
4 | SHIPS WITHIN ONE BUSINESS DAY. FREE SHIPPING ON ORDERS OVER $79. EXCLUSIONS APPLY.
5 |
6 | promo Icon
7 | BUY K65 ETHEREAL SKIES AND GET HS80 ETHEREAL SKIES AT 10% OFF
8 | 4 interest-free payments of $39.99 with Klarna. Learn More
9 |
10 | The CORSAIR HS80 RGB WIRELESS Gaming Headset connects with hyper-fast SLIPSTREAM WIRELESS, delivering incredibly detailed sound through custom-tuned 50mm neodymium audio drivers with immersive Dolby Atmos®.
--------------------------------------------------------------------------------
/sanity_ecommerce/config/.checksums:
--------------------------------------------------------------------------------
1 | {
2 | "#": "Used by Sanity to keep track of configuration file checksums, do not delete or modify!",
3 | "@sanity/default-layout": "bb034f391ba508a6ca8cd971967cbedeb131c4d19b17b28a0895f32db5d568ea",
4 | "@sanity/default-login": "e2ed4e51e97331c0699ba7cf9f67cbf76f1c6a5f806d6eabf8259b2bcb5f1002",
5 | "@sanity/form-builder": "b38478227ba5e22c91981da4b53436df22e48ff25238a55a973ed620be5068aa",
6 | "@sanity/data-aspects": "d199e2c199b3e26cd28b68dc84d7fc01c9186bf5089580f2e2446994d36b3cb6",
7 | "@sanity/vision": "da5b6ed712703ecd04bf4df560570c668aa95252c6bc1c41d6df1bda9b8b8f60"
8 | }
9 |
--------------------------------------------------------------------------------
/sanity_ecommerce/sanity.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "project": {
4 | "name": "ecommerce"
5 | },
6 | "api": {
7 | "projectId": "y64aoq1q",
8 | "dataset": "production"
9 | },
10 | "plugins": [
11 | "@sanity/base",
12 | "@sanity/default-layout",
13 | "@sanity/default-login",
14 | "@sanity/desk-tool"
15 | ],
16 | "env": {
17 | "development": {
18 | "plugins": [
19 | "@sanity/vision"
20 | ]
21 | }
22 | },
23 | "parts": [
24 | {
25 | "name": "part:@sanity/base/schema",
26 | "path": "./schemas/schema"
27 | }
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/assets/Keyboards/Corsair/k70/K70 PRO MINI WIRELESS.txt:
--------------------------------------------------------------------------------
1 | K70 PRO MINI WIRELESS 60% Mechanical CHERRY MX Speed Switch Keyboard with RGB Backlighting - Black
2 | SPECIAL PRICE
3 | $159.99USD
4 | Was $179.99 USD
5 | shipping Icon
6 | SHIPS WITHIN ONE BUSINESS DAY. FREE SHIPPING ON ORDERS OVER $79. EXCLUSIONS APPLY.
7 |
8 | 4 interest-free payments of $39.99 with Klarna. Learn More
9 |
10 | The CORSAIR K70 PRO MINI WIRELESS RGB 60% Mechanical Gaming Keyboard is big on both performance and customization, equipped with hyper-fast, sub-1ms SLIPSTREAM WIRELESS and swappable CHERRY MX keyswitches in a portable profile.
--------------------------------------------------------------------------------
/components/index.js:
--------------------------------------------------------------------------------
1 | export { default as Footer } from "./Footer";
2 | export { default as Layout } from "./Layout";
3 | export { default as Navbar } from "./Navbar";
4 | export { default as Product } from "./Product";
5 | export { default as HeroBanner } from "./HeroBanner";
6 | export { default as FooterBanner } from "./FooterBanner";
7 | export { default as Cart } from "./Cart";
8 | export { default as CategoryMenu } from "./CategoryMenu";
9 | export { default as FeaturedItems } from "./FeaturedItems";
10 | export { default as Loader } from "./Loader";
11 | export { default as HamburgerMenu } from "./HamburgerMenu";
12 |
--------------------------------------------------------------------------------
/pages/api/orders/history.js:
--------------------------------------------------------------------------------
1 | import { getSession } from "next-auth/react";
2 | import Order from "../../../models/Order";
3 | import db from "../../../lib/db";
4 |
5 | const handler = async (req, res) => {
6 | const session = await getSession({ req });
7 | if (!session) {
8 | return res.status(401).send({ message: "Signin required" });
9 | }
10 | const { user } = session;
11 | try {
12 | await db.connect();
13 | const orders = await Order.find({ user: user._id });
14 | res.send(orders);
15 | } catch (error) {
16 |
17 | return res.status(422).json({ error });
18 | }
19 | };
20 |
21 | export default handler;
--------------------------------------------------------------------------------
/components/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { AiFillGithub } from "react-icons/ai";
3 |
4 | const Footer = () => {
5 | return (
6 |
7 |
Site made by Vladimir Infante
8 |
Copyright © 2023 Awesome Gear. All rights reserved
9 |
10 |
16 |
17 |
18 |
19 |
20 | );
21 | };
22 |
23 | export default Footer;
24 |
--------------------------------------------------------------------------------
/pages/api/orders/[id]/index.js:
--------------------------------------------------------------------------------
1 | import { getSession } from "next-auth/react";
2 | import Order from "../../../../models/Order";
3 | import db from "../../../../lib/db";
4 |
5 | const handler = async (req, res) => {
6 | const session = await getSession({ req });
7 | if (!session) {
8 | return res.status(401).json({error:"Signin required"});
9 | }
10 | try{
11 | await db.connect();
12 |
13 | const order = await Order.findById(req.query.id);
14 | await db.disconnect();
15 | res.status(200).send(order);
16 | } catch (error){
17 | console.log(error)
18 | res.status(404).json({error})
19 | }
20 | };
21 |
22 |
23 | export default handler;
24 |
--------------------------------------------------------------------------------
/pages/api/orders/[id]/delete.js:
--------------------------------------------------------------------------------
1 | import { getSession } from "next-auth/react";
2 | import Order from "../../../../models/Order";
3 | import db from "../../../../lib/db";
4 |
5 | const deleteHandler = async (req, res) => {
6 | const session = await getSession({ req });
7 | if (!session) {
8 | return res.status(401).json({ error: "Error: Signin required" });
9 | }
10 |
11 | await db.connect();
12 | const order = await Order.findById(req.body.orderId);
13 | if (order) {
14 | await order.remove();
15 | await db.disconnect();
16 | res.send({ message: "Order Deleted" });
17 | } else {
18 | await db.disconnect();
19 | res.status(404).send({ message: "Order Not Found" });
20 | }
21 | };
22 |
23 | export default deleteHandler;
--------------------------------------------------------------------------------
/pages/api/orders/index.js:
--------------------------------------------------------------------------------
1 | import { getSession } from "next-auth/react";
2 | import Order from "../../../models/Order";
3 | import db from "../../../lib/db";
4 |
5 | const handler = async (req, res) => {
6 | const session = await getSession({ req });
7 | if (!session) {
8 | return res.status(401).json({
9 | error: "Signin required",
10 | });
11 | }
12 |
13 | const { user } = session;
14 | try {
15 | await db.connect();
16 | const newOrder = new Order({
17 | ...req.body,
18 | user: user._id,
19 | });
20 |
21 | const order = await newOrder.save();
22 | return res.status(201).json({ msg: "Order created successfully", order });
23 | } catch (error) {
24 | console.log(error);
25 | return res.status(422).json({ error });
26 | }
27 | };
28 | export default handler;
29 |
--------------------------------------------------------------------------------
/sanity_ecommerce/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ecommerce",
3 | "private": true,
4 | "version": "1.0.0",
5 | "description": "",
6 | "main": "package.json",
7 | "author": "Vladimir Infante ",
8 | "license": "UNLICENSED",
9 | "scripts": {
10 | "start": "sanity start",
11 | "build": "sanity build"
12 | },
13 | "keywords": [
14 | "sanity"
15 | ],
16 | "dependencies": {
17 | "@sanity/base": "^2.34.0",
18 | "@sanity/core": "^2.34.0",
19 | "@sanity/default-layout": "^2.34.0",
20 | "@sanity/default-login": "^2.34.0",
21 | "@sanity/desk-tool": "^2.34.1",
22 | "@sanity/eslint-config-studio": "^2.0.0",
23 | "@sanity/vision": "^2.34.0",
24 | "eslint": "^8.6.0",
25 | "prop-types": "^15.7",
26 | "react": "^17.0",
27 | "react-dom": "^17.0",
28 | "styled-components": "^5.2.0"
29 | },
30 | "devDependencies": {}
31 | }
32 |
--------------------------------------------------------------------------------
/pages/api/auth/update.js:
--------------------------------------------------------------------------------
1 | import { getSession } from "next-auth/react";
2 | import User from "../../../models/User";
3 | import db from "../../../lib/db";
4 |
5 | async function handler(req, res) {
6 | if (req.method !== "PUT") {
7 | return res.status(400).send({ message: `${req.method} not supported` });
8 | }
9 |
10 | const session = await getSession({ req });
11 | if (!session) {
12 | return res.status(401).send({ message: "Signin required" });
13 | }
14 |
15 | const { user } = session;
16 | const { name } = req.body;
17 |
18 | if (!name) {
19 | res.status(422).json({
20 | message: "Validation error",
21 | });
22 | return;
23 | }
24 |
25 | await db.connect();
26 | const toUpdateUser = await User.findById(user._id);
27 | toUpdateUser.name = name;
28 |
29 | await toUpdateUser.save();
30 | await db.disconnect();
31 | res.send({
32 | message: "User updated",
33 | });
34 |
35 | }
36 |
37 | export default handler;
38 |
--------------------------------------------------------------------------------
/lib/db.js:
--------------------------------------------------------------------------------
1 | import mongoose from "mongoose";
2 |
3 | const connection = {};
4 |
5 | async function connect() {
6 | if (connection.isConnected) {
7 | console.log("already connected");
8 | return;
9 | }
10 | if (mongoose.connections.length > 0) {
11 | connection.isConnected = mongoose.connections[0].readyState;
12 | if (connection.isConnected === 1) {
13 | console.log("use previous connection");
14 | return;
15 | }
16 | await mongoose.disconnect();
17 | }
18 | const db = await mongoose.connect(process.env.MONGODB_URI);
19 | console.log("new connection");
20 | connection.isConnected = db.connections[0].readyState;
21 | }
22 |
23 | async function disconnect() {
24 | if (connection.isConnected) {
25 | if (process.env.NODE_ENV === "production") {
26 | await mongoose.disconnect();
27 | connection.isConnected = false;
28 | } else {
29 | console.log("not disconnected");
30 | }
31 | }
32 | }
33 |
34 | const db = { connect, disconnect };
35 |
36 | export default db;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ecommerce",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@babel/core": "^7.17.9",
13 | "@headlessui/react": "^1.7.7",
14 | "@sanity/client": "^3.4.1",
15 | "@sanity/image-url": "^1.0.1",
16 | "@stripe/stripe-js": "^1.25.0",
17 | "bcryptjs": "^2.4.3",
18 | "canvas-confetti": "^1.5.1",
19 | "framer-motion": "^8.5.4",
20 | "mongoose": "^6.8.4",
21 | "next": "12.3.1",
22 | "next-auth": "^4.18.8",
23 | "next-sanity-image": "^5.0.0",
24 | "react": "18.2.0",
25 | "react-dom": "18.2.0",
26 | "react-hook-form": "^7.42.1",
27 | "react-hot-toast": "^2.2.0",
28 | "react-icons": "^4.3.1",
29 | "stripe": "^8.209.0"
30 | },
31 | "devDependencies": {
32 | "@babel/preset-react": "^7.16.7",
33 | "eslint": "8.25.0",
34 | "eslint-config-next": "12.3.1"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/components/Product.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Link from "next/link";
3 | import { urlFor } from "../lib/client";
4 | import { motion } from "framer-motion";
5 |
6 | const Product = ({
7 | product: { image, name, slug, price, manufacturer, _id },
8 | }) => {
9 | return (
10 |
21 |
22 |
23 |
30 |
{name}
31 |
{manufacturer}
32 |
${price}
33 |
34 |
35 |
36 | );
37 | };
38 |
39 | export default Product;
40 |
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/components/Layout.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Head from "next/head";
3 | import Navbar from "./Navbar";
4 | import Footer from "./Footer";
5 | import { useStateContext } from "../context/StateContext";
6 |
7 |
8 | const Layout = ({ children }) => {
9 |
10 | const {lightTheme} = useStateContext();
11 |
12 |
13 | return (
14 |
15 |
16 |
22 |
28 |
Awesome Gear - Gaming Store
29 |
33 |
34 |
37 | {children}
38 |
41 |
42 | );
43 | };
44 |
45 | export default Layout;
46 |
--------------------------------------------------------------------------------
/components/FooterBanner.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Link from "next/link";
3 | import { urlFor } from "../lib/client";
4 | import { motion } from "framer-motion";
5 |
6 | const FooterBanner = ({
7 | footerBanner: {
8 | largeText1,
9 | largeText2,
10 | smallText,
11 | midText,
12 | buttonText,
13 | image,
14 | desc,
15 | slug,
16 | },
17 | }) => {
18 | return (
19 |
23 |
24 |
25 |
{largeText1}
26 | {largeText2}
27 |
28 |
29 |
{smallText}
30 |
{midText}
31 |
{desc}
32 |
33 |
{buttonText}
34 |
35 |
36 |
37 |
38 |
39 | );
40 | };
41 |
42 | export default FooterBanner;
43 |
--------------------------------------------------------------------------------
/pages/api/orders/[id]/pay.js:
--------------------------------------------------------------------------------
1 | import { getSession } from 'next-auth/react';
2 | import Order from '../../../../models/Order';
3 | import db from '../../../../lib/db';
4 |
5 |
6 | const handler = async (req, res) => {
7 | const session = await getSession({ req });
8 | if (!session) {
9 | return res.status(401).json({error:'Error: Signin required'});
10 | }
11 |
12 | await db.connect();
13 | try{
14 | const order = await Order.findById(req.body.orderId);
15 | console.log("stripe made the Call! trying to update order");
16 | if (order) {
17 | if (order.isPaid) {
18 | return res.status(400).json({ message: 'Error: order is already paid' });
19 | }
20 | order.isPaid = true;
21 | order.paidAt = Date.now();
22 | const paidOrder = await order.save();
23 | await db.disconnect();
24 | return res.json({ message: 'Order paid successfully', order: paidOrder });
25 | } else {
26 | await db.disconnect();
27 | return res.status(404).json({ message: 'Error: order not found' });
28 | }
29 | }catch(error){
30 | return res.status(500).json({error})
31 | }
32 |
33 | };
34 |
35 | export default handler;
36 |
--------------------------------------------------------------------------------
/components/Loader.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Loader = () => {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | );
30 | };
31 |
32 | export default Loader;
33 |
--------------------------------------------------------------------------------
/models/Order.js:
--------------------------------------------------------------------------------
1 | import mongoose from 'mongoose';
2 |
3 | const orderSchema = new mongoose.Schema(
4 | {
5 | user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
6 | orderItems: [
7 | {
8 | name: { type: String, required: true },
9 | quantity: { type: Number, required: true },
10 | image: { type: String, required: true },
11 | price: { type: Number, required: true },
12 | },
13 | ],
14 | shippingAddress: {
15 | fullName: { type: String, required: true },
16 | address: { type: String, required: true },
17 | city: { type: String, required: true },
18 | postalCode: { type: String, required: true },
19 | country: { type: String, required: true },
20 | },
21 | itemsPrice: { type: Number, required: true },
22 | shippingPrice: { type: Number, required: true },
23 | totalPrice: { type: Number, required: true },
24 | isPaid: { type: Boolean, required: true, default: false },
25 | paidAt: { type: Date },
26 | },
27 | {
28 | timestamps: true,
29 | }
30 | );
31 |
32 | const Order = mongoose.models.Order || mongoose.model('Order', orderSchema);
33 | export default Order;
--------------------------------------------------------------------------------
/pages/_app.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "../styles/globals.css";
3 | import { Layout, Loader } from "../components";
4 | import { StateContext } from "../context/StateContext";
5 | import { Toaster } from "react-hot-toast";
6 | import { SessionProvider, useSession } from "next-auth/react";
7 | import { useRouter } from "next/router";
8 |
9 | function MyApp({ Component, pageProps: { session, ...pageProps } }) {
10 | const Auth = ({ children }) => {
11 | const router = useRouter();
12 | const { status } = useSession({
13 | required: true,
14 | onUnauthenticated() {
15 | router.push("/unauthorized?message=login required");
16 | },
17 | });
18 | if (status === "loading") {
19 | //TO-DO: add loader
20 | return ;
21 | }
22 | return children;
23 | };
24 |
25 | return (
26 |
27 |
28 |
29 |
30 | {Component.auth ? (
31 |
32 |
33 |
34 | ) : (
35 |
36 | )}
37 |
38 |
39 |
40 | );
41 |
42 |
43 | }
44 |
45 | export default MyApp;
46 |
--------------------------------------------------------------------------------
/pages/api/auth/signup.js:
--------------------------------------------------------------------------------
1 | import bcryptjs from "bcryptjs";
2 | import User from "../../../models/User";
3 | import db from "../../../lib/db";
4 |
5 | const handler = async (req, res) => {
6 | if (req.method !== "POST") {
7 | return res.status(405).send({ message: `${req.method} not supported` });
8 | }
9 | const { name, email, password } = req.body;
10 | if (
11 | !name ||
12 | !email ||
13 | !email.includes("@") ||
14 | !password ||
15 | password.trim().length < 5
16 | ) {
17 | return res.status(422).json({
18 | error: "Validation error",
19 | });
20 |
21 | }
22 |
23 | await db.connect();
24 |
25 | const existingUser = await User.findOne({ email: email });
26 | if (existingUser) {
27 | await db.disconnect();
28 | res.status(422).json({ error: "User already exists!" });
29 | return;
30 | }
31 | try{
32 |
33 | const newUser = new User({
34 | name,
35 | email,
36 | password: bcryptjs.hashSync(password),
37 | isAdmin: false,
38 | });
39 |
40 | await newUser.save();
41 | await db.disconnect();
42 | } catch(error){
43 | res.status(422).json({error})
44 | return
45 | }
46 | res.status(201).json({
47 | msg: "Created user!",
48 | });
49 | return;
50 | };
51 |
52 | export default handler;
53 |
--------------------------------------------------------------------------------
/sanity_ecommerce/schemas/product.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: "product",
3 | title: "Product",
4 | type: "document",
5 | fields: [
6 | {
7 | name: "image",
8 | title: "Image",
9 | type: "array",
10 | of: [{type: "image"}],
11 | options: {
12 | hotspot: true,
13 | }
14 | },
15 | {
16 | name: "name",
17 | title: "Name",
18 | type: "string"
19 | },
20 | {
21 | name: "slug",
22 | title: "Slug",
23 | type: "slug",
24 | options: {
25 | source: "name",
26 | maxLength: 90,
27 | }
28 | },
29 | {
30 | name: "manufacturer",
31 | title: "Manufacturer",
32 | type: "string",
33 | },
34 | {
35 | name: "price",
36 | title: "Price",
37 | type: "number",
38 | },
39 | {
40 | name: "details",
41 | title: "Details",
42 | type: "string",
43 | },
44 | {
45 | name: "category",
46 | title: "Category",
47 | type: "string",
48 | }
49 | ]
50 | }
--------------------------------------------------------------------------------
/pages/api/auth/[...nextauth].js:
--------------------------------------------------------------------------------
1 | import nextAuth from "next-auth";
2 | import db from "../../../lib/db";
3 | import User from "../../../models/User";
4 | import bcryptjs from "bcryptjs";
5 | import CredentialsProvider from "next-auth/providers/credentials";
6 |
7 |
8 | export default nextAuth({
9 | session: {
10 | strategy: "jwt",
11 | },
12 | callbacks: {
13 | async jwt({ token, user }) {
14 | if (user?._id) token._id = user._id;
15 | if (user?.isAdmin) token.isAdmin = user.isAdmin;
16 | return token;
17 | },
18 | async session({ session, token }) {
19 | if (token?._id) session.user._id = token._id;
20 | if (token?.isAdmin) session.user.isAdmin = token.isAdmin;
21 | return session;
22 | },
23 | },
24 | providers: [
25 | CredentialsProvider({
26 | async authorize(credentials) {
27 | await db.connect();
28 | const user = await User.findOne({
29 | email: credentials.email,
30 | });
31 | await db.disconnect();
32 | if (user && bcryptjs.compareSync(credentials.password, user.password)) {
33 | return {
34 | _id: user._id,
35 | name: user.name,
36 | email: user.email,
37 | isAdmin: user.isAdmin,
38 | };
39 | }
40 | throw new Error("Invalid email or password");
41 | },
42 | }),
43 | ],
44 | secret: process.env.NEXTAUTH_SECRET,
45 | });
46 |
--------------------------------------------------------------------------------
/pages/success.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import Link from "next/link";
3 | import { BsBagCheckFill } from "react-icons/bs";
4 | import { useStateContext } from "../context/StateContext";
5 | import { runFireworks, putData } from "../lib/utils";
6 | import { useRouter } from "next/router";
7 |
8 | const Success = () => {
9 | const { setCartItems, setTotalPrice, setTotalQuantities } = useStateContext();
10 | // const router = useRouter();
11 | // const { status, order } = router.query;
12 |
13 | // const updateOrderPayment = async () => {
14 | // if (status && order && status === "success") {
15 | // const res = await putData(`/api/orders/${order}/pay`,);
16 | // }
17 | // };
18 |
19 | useEffect(() => {
20 | setCartItems([]);
21 | setTotalPrice(0);
22 | setTotalQuantities(0);
23 | runFireworks();
24 | return () => {};
25 | }, []);
26 |
27 | return (
28 |
29 |
30 |
31 |
32 |
33 |
Thank you for your order!
34 |
35 | If you have any questions, please email
36 |
37 | order@example.com
38 |
39 |
40 |
41 |
42 | Continue Shopping
43 |
44 |
45 |
46 |
47 | );
48 | };
49 | Success.auth = true;
50 | export default Success;
51 |
--------------------------------------------------------------------------------
/components/HamburgerMenu.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Link from "next/link";
3 | import { useSession } from "next-auth/react";
4 | import { FaUser } from "react-icons/fa";
5 |
6 | const HamburgerMenu = ({ logoutClickHandler }) => {
7 | const { status, data: session } = useSession();
8 |
9 | return (
10 |
11 |
12 | {session?.user ? (
13 | <>
14 |
15 |
16 |
17 |
18 |
19 | {session.user.name}
20 |
21 |
22 |
23 |
Profile
24 |
25 | >
26 | ) : (
27 |
28 |
Login
29 |
30 | )}
31 |
32 |
33 |
34 |
Mice
35 |
36 |
37 |
Keyboards
38 |
39 |
40 |
Headsets
41 |
42 |
43 |
Mouse pads
44 |
45 | {session?.user ? (
46 | <>
47 |
48 |
49 | Logout
50 |
51 | >
52 | ) : null}
53 |
54 |
55 | );
56 | };
57 |
58 | export default HamburgerMenu;
59 |
--------------------------------------------------------------------------------
/components/FeaturedItems.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Link from "next/link";
3 | import { urlFor } from "../lib/client";
4 | import { BsArrowRightCircle } from "react-icons/bs";
5 | import { motion } from "framer-motion";
6 |
7 | const Item = ({
8 | product: { image, name, slug, price, manufacturer },
9 | rotate = false,
10 | }) => {
11 | return (
12 |
13 |
14 |
15 |
26 |
{name}
27 |
{manufacturer}
28 |
${price}
29 |
33 |
34 |
35 |
36 | );
37 | };
38 |
39 | const FeaturedItems = ({ featuredItems }) => {
40 | return (
41 |
47 | Featured Gears:
48 | FEATURED
49 |
50 |
51 |
52 |
53 |
54 | );
55 | };
56 |
57 | export default FeaturedItems;
58 |
--------------------------------------------------------------------------------
/components/CategoryMenu.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { urlFor } from "../lib/client";
3 | import Link from "next/link";
4 | import { BsArrowRightCircle } from "react-icons/bs";
5 | import { motion } from "framer-motion";
6 |
7 | const MenuItem = ({ category, product: { image, price }, top, right }) => {
8 | return (
9 | <>
10 |
11 |
Starting from:
12 |
$ {price}
13 |
{category}
14 |
{category}
15 |
16 |
20 |
21 |
22 |
28 |
29 | >
30 | );
31 | };
32 |
33 | const CategoryMenu = ({ categoryMenuItems }) => {
34 | return (
35 | <>
36 |
45 |
51 |
57 |
63 |
69 |
70 | >
71 | );
72 | };
73 |
74 | export default CategoryMenu;
75 |
--------------------------------------------------------------------------------
/pages/api/stripe.js:
--------------------------------------------------------------------------------
1 | import Stripe from "stripe";
2 | import { putData } from "../../lib/utils";
3 |
4 | const stripe = new Stripe(process.env.NEXT_PUBLIC_STRIPE_SECRET_KEY);
5 |
6 | export default async function handler(req, res) {
7 | if (req.method === 'POST') {
8 |
9 | try {
10 | const params = {
11 | submit_type: 'pay',
12 | mode: 'payment',
13 | payment_method_types: ['card'],
14 | billing_address_collection: 'auto',
15 | shipping_options: [
16 | { shipping_rate: 'shr_1Lv1wQFzRgi0pLUVRjlviJbV'},
17 | ],
18 | line_items: req.body.cartItems.map(item => {
19 | const img = item.image[0].asset._ref;
20 | const newImage = img.replace("image-","https://cdn.sanity.io/images/y64aoq1q/production/").replace("-webp",".webp")
21 | const newItem = {
22 | price_data: {
23 | currency: "usd",
24 | product_data: {
25 | name: item.name,
26 | images: [newImage],
27 | },
28 | unit_amount: Math.floor(item.price * 100),
29 | },
30 | adjustable_quantity: {
31 | enabled: true,
32 | minimum: 1,
33 | },
34 | quantity: item.quantity,
35 | };
36 | return newItem;
37 | }),
38 | success_url: `${req.headers.origin}/success?status=success&orderid=${req.body.orderId}`,
39 | cancel_url: `${req.headers.origin}/?status=canceled&orderid=${req.body.orderId}`,
40 | }
41 |
42 | // Create Checkout Sessions from body params.
43 | const session = await stripe.checkout.sessions.create(params);
44 | res.status(200).json(session);
45 | } catch (error) {
46 | res.status(error.statusCode || 500).json(error.message);
47 | }
48 | } else {
49 | res.setHeader('Allow', 'POST');
50 | res.status(405).end('Method Not Allowed');
51 | }
52 | }
--------------------------------------------------------------------------------
/sanity_ecommerce/schemas/banner.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'banner',
3 | title: 'Banner',
4 | type: 'document',
5 | fields: [
6 | {
7 | name: 'image',
8 | title: 'Image',
9 | type: 'image',
10 | options: {
11 | hotspot: true,
12 | },
13 | },
14 | {
15 | name: 'buttonText',
16 | title: 'ButtonText',
17 | type: 'string',
18 | },
19 | {
20 | name: 'product',
21 | title: 'Product',
22 | type: 'string',
23 | },
24 | {
25 | name: "slug",
26 | title: "Slug",
27 | type: "slug",
28 | options: {
29 | source: "product",
30 | maxLength: 90,
31 | }
32 | },
33 | {
34 | name: 'manufacturer',
35 | title: 'Manufacturer',
36 | type: 'string',
37 | },
38 | {
39 | name: 'desc',
40 | title: 'Desc',
41 | type: 'string',
42 | },
43 | {
44 | name: 'smallText',
45 | title: 'SmallText',
46 | type: 'string',
47 | },
48 | {
49 | name: 'midText',
50 | title: 'MidText',
51 | type: 'string',
52 | },
53 | {
54 | name: 'largeText1',
55 | title: 'LargeText1',
56 | type: 'string',
57 | },
58 | {
59 | name: 'largeText2',
60 | title: 'LargeText2',
61 | type: 'string',
62 | },
63 | {
64 | name: 'discount',
65 | title: 'Discount',
66 | type: 'string',
67 | },
68 | {
69 | name: 'price',
70 | title: 'Price',
71 | type: 'number',
72 | },
73 | {
74 | name: 'oldPrice',
75 | title: 'OldPrice',
76 | type: 'number',
77 | },
78 | {
79 | name: 'saleTime',
80 | title: 'SaleTime',
81 | type: 'string',
82 | },
83 | ],
84 | };
--------------------------------------------------------------------------------
/lib/utils.js:
--------------------------------------------------------------------------------
1 | import confetti from "canvas-confetti";
2 | import toast from "react-hot-toast";
3 |
4 | export const getImage = (item) => {
5 | return item.image[0].asset._ref
6 | .replace("image-", "https://cdn.sanity.io/images/y64aoq1q/production/")
7 | .replace("-webp", ".webp");
8 | };
9 |
10 | export const getData = async (endpoint) => {
11 | const res = await fetch(endpoint);
12 | return res;
13 | };
14 |
15 | export const postData = async (endpoint, post) => {
16 | const res = await fetch(endpoint, {
17 | method: "POST",
18 | body: JSON.stringify(post),
19 | headers: {
20 | "Content-Type": "application/json",
21 | },
22 | });
23 | return res;
24 | };
25 |
26 |
27 |
28 | export const putData = async (endpoint, post) => {
29 | const res = await fetch(endpoint, {
30 | method: "PUT",
31 | body: JSON.stringify(post),
32 | headers: {
33 | "Content-Type": "application/json",
34 | },
35 | });
36 | return res;
37 | }
38 | export const deleteData = async (endpoint, post) => {
39 | const res = await fetch(endpoint, {
40 | method: "DELETE",
41 | body: JSON.stringify(post),
42 | headers: {
43 | "Content-Type": "application/json",
44 | },
45 | });
46 | return res;
47 | }
48 |
49 | export const paymentNotification = (paymentStatus, orderid) => {
50 | if (paymentStatus === "cancel") {
51 | toast.error("Payment Canceled!");
52 | toast(orderid);
53 | }
54 | if (paymentStatus === "success") {
55 | toast.success("Payment Successful!");
56 | }
57 | };
58 |
59 | export const runFireworks = () => {
60 | var duration = 5 * 1000;
61 | var animationEnd = Date.now() + duration;
62 | var defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 };
63 |
64 | function randomInRange(min, max) {
65 | return Math.random() * (max - min) + min;
66 | }
67 |
68 | var interval = setInterval(function () {
69 | var timeLeft = animationEnd - Date.now();
70 |
71 | if (timeLeft <= 0) {
72 | return clearInterval(interval);
73 | }
74 |
75 | var particleCount = 50 * (timeLeft / duration);
76 | // since particles fall down, start a bit higher than random
77 | confetti(
78 | Object.assign({}, defaults, {
79 | particleCount,
80 | origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 },
81 | })
82 | );
83 | confetti(
84 | Object.assign({}, defaults, {
85 | particleCount,
86 | origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 },
87 | })
88 | );
89 | }, 250);
90 | };
91 |
--------------------------------------------------------------------------------
/pages/login.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import Link from "next/link";
3 | import { signIn, useSession } from "next-auth/react";
4 | import { useForm } from "react-hook-form";
5 | import toast from "react-hot-toast";
6 | import { useRouter } from "next/router";
7 | import getError from "../lib/error";
8 | import { useStateContext } from "../context/StateContext";
9 |
10 | const Login = () => {
11 | const { data: session } = useSession();
12 |
13 | const router = useRouter();
14 | const { redirect } = router.query;
15 | const { inCheckoutProcess, setInCheckoutProcess } = useStateContext();
16 |
17 | useEffect(() => {
18 | if (session?.user) {
19 | if (!inCheckoutProcess) {
20 | router.push(redirect || "/");
21 | } else {
22 | setInCheckoutProcess(false);
23 | router.push(redirect || "/checkout");
24 | }
25 | }
26 | }, [router, session, redirect]);
27 | const {
28 | handleSubmit,
29 | register,
30 | formState: { errors },
31 | } = useForm();
32 |
33 | const submitHandler = async ({ email, password }) => {
34 | try {
35 | const result = await signIn("credentials", {
36 | redirect: false,
37 | email,
38 | password,
39 | });
40 | if (result.error) {
41 | toast.error(result.error);
42 | }
43 | } catch (err) {
44 | toast.error(getError(err));
45 | }
46 | };
47 | return (
48 | <>
49 |
103 | >
104 | );
105 | };
106 |
107 | export default Login;
108 |
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { client } from "../lib/client";
3 | import Link from "next/link";
4 | import dynamic from "next/dynamic"
5 | import {
6 | HeroBanner,
7 | FooterBanner,
8 | CategoryMenu,
9 | } from "../components";
10 | import { BsArrowRightCircle } from "react-icons/bs";
11 | import { motion } from "framer-motion";
12 |
13 | const LazyFeaturedItems = dynamic(()=> import("../components/FeaturedItems"),{
14 | loading: () => "Loading..."
15 | })
16 |
17 | const Home = ({ bannerData, featuredItems, categoryMenuItems }) => {
18 | return (
19 | <>
20 |
21 |
22 |
31 | Checkout our products!
32 |
33 |
34 |
35 |
36 |
37 |
38 | >
39 | );
40 | };
41 |
42 | export const getServerSideProps = async () => {
43 | const bannerQuery = '*[_type == "banner"]';
44 | const bannerData = await client.fetch(bannerQuery);
45 |
46 | // Gonna use the cheapest item of each category for the menu category
47 | const keyboardPriceQuery =
48 | '*[_type == "product" && category == "keyboard"] | order(price asc) [0]';
49 | const keyboardLowestPrice = await client.fetch(keyboardPriceQuery);
50 |
51 | const mousePriceQuery =
52 | '*[_type == "product" && category == "mouse"] | order(price asc) [0]';
53 | const mouseLowestPrice = await client.fetch(mousePriceQuery);
54 |
55 | const headsetPriceQuery =
56 | '*[_type == "product" && category == "headset"] | order(price asc) [0]';
57 | const headsetLowestPrice = await client.fetch(headsetPriceQuery);
58 |
59 | const mousePadPriceQuery =
60 | '*[_type == "product" && category == "mouse pad"] | order(price asc) [0]';
61 | const mousePadLowestPrice = await client.fetch(mousePadPriceQuery);
62 |
63 | const categoryMenuItems = [
64 | mouseLowestPrice,
65 | keyboardLowestPrice,
66 | headsetLowestPrice,
67 | mousePadLowestPrice,
68 | ];
69 |
70 | // setting arbitrary items as featured
71 | const keyboardQuery = '*[_type == "product" && category == "keyboard"][2]';
72 | const keyboard = await client.fetch(keyboardQuery);
73 |
74 | const mouseQuery = '*[_type == "product" && category == "mouse"][2]';
75 | const mouse = await client.fetch(mouseQuery);
76 |
77 | const headsetQuery = '*[_type == "product" && category == "headset"][2]';
78 | const headset = await client.fetch(headsetQuery);
79 |
80 | const mousePadQuery = '*[_type == "product" && category == "mouse pad"][2]';
81 | const mousePad = await client.fetch(mousePadQuery);
82 |
83 | const featuredItems = [mouse, keyboard, headset, mousePad];
84 | return {
85 | props: { bannerData, featuredItems, categoryMenuItems },
86 | };
87 | };
88 | export default Home;
89 |
--------------------------------------------------------------------------------
/pages/product/[slug].js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { client, urlFor } from "../../lib/client";
3 | import {
4 | AiOutlineMinus,
5 | AiOutlinePlus,
6 | AiFillStar,
7 | AiOutlineStar,
8 | } from "react-icons/ai";
9 | import { Product } from "../../components";
10 | import { useStateContext } from "../../context/StateContext";
11 |
12 | const ProductDetails = ({ product, products }) => {
13 | const { image, name, details, price } = product;
14 | const [index, setIndex] = useState(0);
15 | const { decQty, incQty, qty, onAdd, setQty, setShowCart } = useStateContext();
16 |
17 | const handleBuyNow = () => {
18 | onAdd(product, qty);
19 | setShowCart(true);
20 | };
21 |
22 | useEffect(() => {
23 | setQty(1);
24 | }, [product]);
25 |
26 | return (
27 |
28 |
29 |
30 |
31 |
36 |
37 |
38 | {image?.map((item, i) => (
39 |
setIndex(i)}
46 | />
47 | ))}
48 |
49 |
50 |
51 |
52 |
{name}
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
(20)
62 |
63 |
Details:
64 |
{details}
65 |
${price}
66 |
67 |
Quantity
68 |
69 |
70 |
71 |
72 | {qty}
73 |
74 |
75 |
76 |
77 |
78 |
79 | onAdd(product, qty)}
83 | >
84 | Add to Cart
85 |
86 |
87 | Buy Now
88 |
89 |
90 |
91 |
92 |
93 |
You may also like
94 |
95 |
96 | {products.map((item) => (
97 |
98 | ))}
99 |
100 |
101 |
102 |
103 | );
104 | };
105 |
106 | export const getStaticPaths = async () => {
107 | const query = `*[_type =="product"] {
108 | slug {
109 | current
110 | }
111 | }`;
112 |
113 | const products = await client.fetch(query);
114 |
115 | const paths = products.map((product) => ({
116 | params: {
117 | slug: product.slug.current,
118 | },
119 | }));
120 | return {
121 | paths,
122 | fallback: "blocking",
123 | };
124 | };
125 |
126 | export const getStaticProps = async ({ params: { slug } }) => {
127 | const query = `*[_type == "product" && slug.current == "${slug}"][0]`;
128 | const productsQuery = "*[_type == 'product']";
129 |
130 | const product = await client.fetch(query);
131 | const products = await client.fetch(productsQuery);
132 |
133 | return {
134 | props: { product, products },
135 | };
136 | };
137 |
138 | export default ProductDetails;
139 |
--------------------------------------------------------------------------------
/context/StateContext.js:
--------------------------------------------------------------------------------
1 | import React, { createContext, useContext, useState } from "react";
2 | import { toast } from "react-hot-toast";
3 |
4 | const Context = createContext();
5 |
6 | export const StateContext = ({ children }) => {
7 | const [showCart, setShowCart] = useState(false);
8 | const [cartItems, setCartItems] = useState([]);
9 | const [totalPrice, setTotalPrice] = useState(0);
10 | const [totalQuantities, setTotalQuantities] = useState(0);
11 | const [qty, setQty] = useState(1);
12 | const [inCheckoutProcess, setInCheckoutProcess] = useState(false);
13 | const [lightTheme, setLightTheme] = useState(false);
14 |
15 | let foundProduct;
16 | let index;
17 |
18 | const round = (number) => {
19 | return Math.round((number + Number.EPSILON) * 100) / 100;
20 | };
21 |
22 | const onAdd = (product, quantity) => {
23 | const checkProductInCart = cartItems.find(
24 | (item) => item._id === product._id
25 | );
26 |
27 | setTotalPrice((prevTotalPrice) =>
28 | round(prevTotalPrice + product.price * quantity)
29 | );
30 | setTotalQuantities((prevTotalQuantities) => prevTotalQuantities + quantity);
31 | if (checkProductInCart) {
32 | const updatedCardItems = cartItems.map((cartProduct) => {
33 | if (cartProduct._id === product._id)
34 | return {
35 | ...cartProduct,
36 | quantity: cartProduct.quantity + quantity,
37 | };
38 | });
39 | setCartItems(updatedCardItems);
40 | } else {
41 | product.quantity = quantity;
42 |
43 | setCartItems([...cartItems, { ...product }]);
44 | }
45 | toast.success(`${qty} ${product.name} added to the cart.`);
46 | };
47 |
48 | const onRemove = (product) => {
49 | foundProduct = cartItems.find((item) => item._id === product._id);
50 | const newCartItems = cartItems.filter((item) => item._id !== product._id);
51 | setCartItems(newCartItems);
52 | setTotalPrice((prev) => round(prev - foundProduct.price * foundProduct.quantity));
53 | setTotalQuantities((prev) => prev - foundProduct.quantity);
54 | };
55 |
56 | const toggleCartItemQuantity = (id, value) => {
57 | foundProduct = cartItems.find((item) => item._id === id);
58 | index = cartItems.findIndex((product) => product._id === id);
59 | let newCartItems = cartItems.filter((item) => item._id !== id);
60 |
61 | if (value === "inc") {
62 | newCartItems.splice(index, 0, {
63 | ...foundProduct,
64 | quantity: foundProduct.quantity + 1,
65 | });
66 |
67 | setCartItems(newCartItems);
68 | setTotalPrice((prev) => round(prev + foundProduct.price));
69 | setTotalQuantities((prev) => prev + 1);
70 | } else if (value === "dec") {
71 | if (foundProduct.quantity > 1) {
72 | newCartItems.splice(index, 0, {
73 | ...foundProduct,
74 | quantity: foundProduct.quantity - 1,
75 | });
76 |
77 | setCartItems(newCartItems);
78 | setTotalPrice((prev) => round(prev - foundProduct.price));
79 | setTotalQuantities((prev) => prev - 1);
80 | }
81 | }
82 | };
83 |
84 | const incQty = () => {
85 | setQty((prev) => prev + 1);
86 | };
87 | const decQty = () => {
88 | setQty((prevQty) => {
89 | if (prevQty > 1) return prevQty - 1;
90 | else return 1;
91 | });
92 | };
93 |
94 | // useEffect(()=>{
95 | // setTotalPrice(prev=>(Math.round((prev + Number.EPSILON) * 100) / 100))
96 | // },[totalPrice])
97 |
98 | return (
99 |
122 | {children}
123 |
124 | );
125 | };
126 |
127 | export const useStateContext = () => useContext(Context);
128 |
--------------------------------------------------------------------------------
/pages/order/[id].js:
--------------------------------------------------------------------------------
1 | import { useRouter } from "next/router";
2 | import { useState, useEffect } from "react";
3 | import { Loader } from "../../components";
4 | import { getData } from "../../lib/utils";
5 |
6 | const OrderScreen = () => {
7 | // order/:id
8 | const [isLoading, setIsLoading] = useState(true);
9 | const [order, setOrder] = useState({});
10 | const { query } = useRouter();
11 | const orderId = query.id;
12 | const regex = /T.*/i
13 |
14 | useEffect(() => {
15 | const fetchOrder = async () => {
16 | try {
17 | const res = await getData(`/api/orders/${orderId}`);
18 | if (res.error) {
19 | console.log(res.error);
20 | return;
21 | } else {
22 | const data = await res.json();
23 | console.log(data);
24 | setIsLoading(false);
25 | setOrder(data);
26 | }
27 | } catch (err) {
28 | console.log(err);
29 | }
30 | };
31 | if (!order._id || (order._id && order._id !== orderId)) {
32 | fetchOrder();
33 | }
34 | }, [order, orderId]);
35 | const {
36 | shippingAddress,
37 | orderItems,
38 | itemsPrice,
39 | shippingPrice,
40 | totalPrice,
41 | paidAt,
42 | } = order;
43 |
44 | return (
45 |
46 |
{`Order Details`}
47 |
{`ID: ${orderId}`}
48 | {isLoading ? (
49 |
50 | ) : (
51 | <>
52 |
Shipping Address
53 |
54 | {shippingAddress.fullName}, {shippingAddress.address}, {shippingAddress.city}, {shippingAddress.postalCode}, {shippingAddress.country}
55 |
56 |
57 |
58 |
Payment
59 |
Paid with Stripe at {paidAt.replace(regex,"")}
60 |
61 |
62 |
Order Items
63 |
64 |
65 |
66 |
67 | Item
68 | Quantity
69 | Price
70 | Subtotal
71 |
72 |
73 |
74 | {orderItems.map((item) => (
75 |
76 |
77 |
78 |
84 |
85 | {item.name}
86 |
87 |
88 |
89 | {item.quantity}
90 |
91 |
92 | ${item.price}
93 |
94 |
95 | ${item.quantity * item.price}
96 |
97 |
98 | ))}
99 |
100 |
101 |
102 |
103 |
104 |
Order Summary
105 |
106 |
107 |
108 |
Items
109 |
${itemsPrice}
110 |
111 |
112 |
113 |
114 |
Shipping
115 |
${shippingPrice}
116 |
117 |
118 |
119 |
120 |
Total
121 |
${totalPrice}
122 |
123 |
124 |
125 |
126 | >
127 | )}
128 |
129 | );
130 | };
131 |
132 | OrderScreen.auth = true;
133 | export default OrderScreen;
134 |
--------------------------------------------------------------------------------
/pages/profile.js:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 | import React, { useEffect, useState } from "react";
3 | import { getData, putData } from "../lib/utils";
4 | import { useForm } from "react-hook-form";
5 | import { toast } from "react-hot-toast";
6 | import { Loader } from "../components";
7 |
8 | const Profile = () => {
9 | const [isLoading, setIsLoading] = useState(true);
10 | const [orders, setOrders] = useState([]);
11 |
12 | const {
13 | handleSubmit,
14 | register,
15 | formState: { errors },
16 | } = useForm();
17 |
18 |
19 | //this is needed to show the new name after an update but to make it work
20 | //the SessionProvider property "refetchOnWindowFocus" need to be true,
21 | //but that makes it auto-update the session when a user switches windows and i don't want that
22 | // const reloadSession = () => {
23 | // const event = new Event("visibilitychange");
24 | // document.dispatchEvent(event);
25 | // };
26 |
27 | const handleUpdate = async ({ name }) => {
28 | try {
29 | const updateRes = await putData("/api/auth/update", { name });
30 | const updateData = await updateRes.json();
31 | console.log(updateData);
32 | toast.success("Name updated successfully!");
33 | toast("SignIn again to see the changes");
34 | //reloadSession();
35 | if (updateData.error) {
36 | toast.error(updateData.error);
37 | }
38 | } catch (error) {
39 | toast.error(error);
40 | }
41 | };
42 |
43 | useEffect(() => {
44 | const fetchOrders = async () => {
45 | try {
46 | const res = await getData(`/api/orders/history`);
47 | const data = await res.json();
48 | if (data.error) {
49 | console.log(data.error);
50 | } else {
51 | setIsLoading(false);
52 | }
53 | setOrders(data);
54 | } catch (error) {
55 | console.log(error);
56 | }
57 | };
58 | fetchOrders();
59 | }, []);
60 | return (
61 | <>
62 |
63 |
84 |
85 |
Order History
86 | {isLoading ? (
87 |
88 | ) : orders.length < 1 ? (
89 |
90 | You don't have orders yet
91 |
92 | ) : (
93 |
94 |
95 |
96 |
97 | ID
98 | DATE
99 | TOTAL
100 | PAID
101 | ACTION
102 |
103 |
104 |
105 | {orders?.map((order) => (
106 |
107 |
108 | {order._id.substring(20, 24)}
109 |
110 |
111 | {order.createdAt.substring(0, 10)}
112 |
113 | ${order.totalPrice}
114 |
115 | {order.isPaid
116 | ? `${order.paidAt.substring(0, 10)}`
117 | : "not paid"}
118 |
119 |
120 |
121 | Details
122 |
123 |
124 |
125 | ))}
126 |
127 |
128 |
129 | )}
130 |
131 | >
132 | );
133 | };
134 |
135 | Profile.auth = true;
136 | export default Profile;
137 |
--------------------------------------------------------------------------------
/components/HeroBanner.jsx:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 | import React, { useState, useEffect } from "react";
3 | import { urlFor } from "../lib/client";
4 | import { FaChevronLeft, FaChevronRight } from "react-icons/fa";
5 | import { motion, AnimatePresence } from "framer-motion";
6 |
7 | const HeroBanner = ({ heroBannerData }) => {
8 | const [heroItem, setHeroItem] = useState(0);
9 | const [direction, setDirection] = useState(1);
10 |
11 | const heroBannerUpdate = (action) => {
12 | if (action === "right") {
13 | if (direction !== 1) {
14 | setDirection((prev) => prev * -1);
15 | }
16 | if (heroItem === 2) {
17 | setHeroItem(0);
18 | } else {
19 | setHeroItem((prev) => prev + 1);
20 | }
21 | }
22 | if (action === "left") {
23 | if (direction === 1) {
24 | setDirection((prev) => prev * -1);
25 | }
26 | if (heroItem === 0) {
27 | setHeroItem(2);
28 | } else {
29 | setHeroItem((prev) => prev - 1);
30 | }
31 | }
32 | };
33 | //i being the order of animation
34 | const imageAnimation = (i) => {
35 | return {
36 | initial: { translateX: -50 * direction, opacity: 0 },
37 | animate: { translateX: 0, opacity: 1 },
38 | transition: { duration: 0.6, delay: 1+ 0.55 * i },
39 | exit: {
40 | translateX: 50 * direction,
41 | opacity: 0,
42 | transition: { duration: 0.1, delay: 0.3},
43 | },
44 | };
45 | };
46 | const leftSidAnimation = (initialMovement, i) => {
47 |
48 | return {
49 | initial: { translateX: -50 * initialMovement, opacity: 0 },
50 | animate: { translateX: 0, opacity: 1 },
51 | transition: { duration: 0.45, delay: 1.1 + 0.25* i },
52 | exit: {
53 | translateX: 50,
54 | opacity: 0,
55 | transition: { duration: 0.1, delay: 0.2 },
56 | },
57 | };
58 | };
59 | //im actually using this one for the image, the product name and description
60 | const rightSideAnimation = (i) => {
61 | return {
62 | initial: { opacity: 0 },
63 | animate: { opacity: 1 },
64 | transition: { duration: 0.55, delay: 1.5 + 0.2* i },
65 | };
66 | };
67 |
68 | const heroBanner = heroBannerData[heroItem];
69 | return (
70 |
71 |
72 |
73 |
78 | {heroBanner.smallText}
79 |
80 |
84 | {heroBanner.midText}
85 |
86 |
90 | {heroBanner.largeText1}
91 |
92 |
97 | ${heroBanner.oldPrice}
98 |
99 |
104 | ${heroBanner.price}
105 |
106 |
107 |
114 |
115 |
116 |
117 |
118 |
119 |
124 | {heroBanner.buttonText}
125 |
126 |
127 |
132 | {heroBanner.product}
133 |
134 |
135 |
136 |
137 | heroBannerUpdate("right")}
140 | />
141 | heroBannerUpdate("left")}
144 | />
145 |
146 |
147 |
152 | Description
153 | {heroBanner.desc}
154 |
155 |
156 |
157 |
158 |
159 | );
160 | };
161 |
162 | export default HeroBanner;
163 |
--------------------------------------------------------------------------------
/components/Cart.jsx:
--------------------------------------------------------------------------------
1 | import React, { useRef } from "react";
2 | import Link from "next/link";
3 | import {
4 | AiOutlineMinus,
5 | AiOutlinePlus,
6 | AiOutlineLeft,
7 | AiOutlineShopping,
8 | } from "react-icons/ai";
9 | import { TiDeleteOutline } from "react-icons/ti";
10 | import toast from "react-hot-toast";
11 | import { useStateContext } from "../context/StateContext";
12 | import { urlFor } from "../lib/client";
13 | import { useSession, signIn } from "next-auth/react";
14 | import { useRouter } from "next/router";
15 | import getError from "../lib/error";
16 | import { motion } from "framer-motion";
17 |
18 | const Cart = () => {
19 | const cartRef = useRef();
20 | const {
21 | totalPrice,
22 | totalQuantities,
23 | cartItems,
24 | setShowCart,
25 | toggleCartItemQuantity,
26 | onRemove,
27 | setInCheckoutProcess,
28 | } = useStateContext();
29 |
30 | const { data: session } = useSession();
31 | const router = useRouter();
32 | const { redirect } = router.query;
33 | const loginDemo = async (email, password) => {
34 | try {
35 | const result = await signIn("credentials", {
36 | redirect: false,
37 | email,
38 | password,
39 | });
40 | if (result.error) {
41 | toast.error(result.error);
42 | }
43 | } catch (err) {
44 | toast.error(getError(err));
45 | }
46 | };
47 |
48 | const handlePlaceOrder = async () => {
49 | setShowCart(false);
50 |
51 | if (!session?.user) {
52 | const asDemo = confirm("Do you want to login with a Demo Account?");
53 | if (asDemo) {
54 | await loginDemo("user1@example.com", "123456");
55 | router.push(redirect || "/checkout");
56 | } else {
57 | toast("Please login before placing an order");
58 | setInCheckoutProcess(true);
59 | setTimeout(() => router.push("/login"), 600);
60 | }
61 | } else {
62 | router.push("/checkout");
63 | }
64 | };
65 |
66 | const variants = {
67 | initial: { opacity: 0, x: "100%" },
68 | animate: { opacity: 1, x: 0 },
69 | transition: { duration: 0.5 },
70 | };
71 |
72 | return (
73 |
74 |
75 | setShowCart(false)}
79 | >
80 |
81 | Your Cart
82 | ({totalQuantities} items)
83 |
84 | {cartItems.length < 1 && (
85 |
86 |
87 |
Your shopping bag is empty
88 |
89 |
setShowCart(false)}
92 | className="btn"
93 | >
94 | Continue Shopping
95 |
96 |
97 |
98 | )}
99 |
100 |
101 | {cartItems.length >= 1 &&
102 | cartItems.map((item, index) => (
103 |
104 |
109 |
110 |
111 |
{item.name}
112 | ${item.price}
113 |
114 |
115 |
116 |
117 |
120 | toggleCartItemQuantity(item._id, "dec")
121 | }
122 | >
123 |
124 |
125 | {item.quantity}
126 |
129 | toggleCartItemQuantity(item._id, "inc")
130 | }
131 | >
132 |
133 |
134 |
135 |
136 |
onRemove(item)}
140 | >
141 |
142 |
143 |
144 |
145 |
146 | ))}
147 |
148 | {cartItems.length >= 1 && (
149 |
150 |
151 |
Subtotal:
152 | ${totalPrice}
153 |
154 |
155 |
156 | Proceed to Checkout
157 |
158 |
159 |
160 | )}
161 |
162 |
163 | );
164 | };
165 |
166 | export default Cart;
167 |
--------------------------------------------------------------------------------
/pages/register.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import Link from "next/link";
3 | import { signIn, useSession } from "next-auth/react";
4 | import { useForm } from "react-hook-form";
5 | import toast from "react-hot-toast";
6 | import { useRouter } from "next/router";
7 | import getError from "../lib/error";
8 | import { useStateContext } from "../context/StateContext";
9 | import { postData } from "../lib/utils";
10 |
11 | const Register = () => {
12 | const { data: session } = useSession();
13 |
14 | const router = useRouter();
15 | const { redirect } = router.query;
16 | const { inCheckoutProcess, setInCheckoutProcess } = useStateContext();
17 |
18 | useEffect(() => {
19 | if (session?.user) {
20 | if (!inCheckoutProcess) {
21 | router.push(redirect || "/");
22 | } else {
23 | setInCheckoutProcess(false);
24 | router.push(redirect || "/checkout");
25 | }
26 | }
27 | }, [router, session, redirect]);
28 | const {
29 | handleSubmit,
30 | register,
31 | getValues,
32 | formState: { errors },
33 | } = useForm();
34 |
35 | const submitHandler = async ({ name, email, password }) => {
36 | const userData = {
37 | name,
38 | email,
39 | password,
40 | };
41 | try {
42 | const res = await postData("/api/auth/signup",userData);
43 | const data = await res.json();
44 | if(res.error){
45 | toast.error(res.error)
46 | return;
47 | } else {
48 | toast.success(data.msg)
49 | }
50 | } catch (error) {
51 | toast.error(getError(error));
52 | return;
53 | }
54 | try {
55 | const result = await signIn("credentials", {
56 | redirect: false,
57 | email,
58 | password,
59 | });
60 | if (result.error) {
61 | toast.error(result.error);
62 | }
63 | } catch (error) {
64 | toast.error(getError(error));
65 | }
66 | };
67 | return (
68 | <>
69 |
164 | >
165 | );
166 | };
167 |
168 | export default Register;
169 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ecommerce - Awesome Gear
2 |
3 | 
4 |
5 | Ecommerce website built with NextJs.
6 |
7 | - Demo live: https://awesome-gear-shop.vercel.app/
8 |
9 | ## Features
10 |
11 | - Registration
12 | - Input validation on forms
13 | - Authentication
14 | - Protected routes
15 | - Smooth animations
16 | - Product data managed by Sanity (headless CMS)
17 | - User and order data managed with MongoDB
18 | - Checkout with Stripe
19 | - User profile with order history
20 | - Server Side Rendered homepage for better SEO
21 | - Static Site Generated individual product pages for the fastest response
22 | - Product filtering on shop page
23 | - Light/Dark theme
24 | - Responsive design
25 |
26 | ## Chrome lighthouse scores:
27 |
28 | ---
29 |
30 | These are the scores of the test while using incognito mode:
31 |
32 | 
33 |
34 | ## Environment Variables
35 |
36 | ---
37 |
38 | To run this project, you will need these environment variables on your .env:
39 |
40 | `NEXT_PUBLIC_SANITY_TOKEN`
41 |
42 | `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY`
43 |
44 | `NEXT_PUBLIC_STRIPE_SECRET_KEY`
45 |
46 | `NEXTAUTH_SECRET`
47 |
48 | `MONGODB_URI`
49 |
50 | First, run the development server:
51 |
52 | ```bash
53 | npm install --legacy-peer-deps
54 | # to avoid deps bugs
55 |
56 | ```
57 |
58 | Next:
59 |
60 | ```bash
61 | npm install -g @sanity/cli
62 | cd sanity_ecommerce
63 | npm install --legacy-peer-deps
64 | sanity start
65 | ```
66 |
67 | Open [http://localhost:3333](http://localhost:3333) with your browser to see the sanity studio where you can add the products.
68 | You can find the images and data of the products i used in the assets folder
69 |
70 | Then:
71 |
72 | ```bash
73 | npm run dev
74 | ```
75 |
76 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
77 |
78 | ## Technologies used for this project:
79 |
80 | ---
81 |
82 | - Next.js
83 | - NextAuth.js
84 | - Sanity
85 | - MongoDB
86 | - Framer Motion
87 |
88 | ## Deployment:
89 |
90 | ---
91 |
92 | This project is deployed in Vercel, the DB is hosted using MongoDB Atlas
93 |
94 | ## Decisions:
95 |
96 | ---
97 |
98 | - ### Why did you build this project?
99 |
100 | I wanted to try Next Js and check why is it so popular and what a better way to learn how to use a tool than building something with it. I gave it some thought and decided between 3 options:
101 |
102 | 1. An app that helps to manage inventories, profits, clients, and tracks issues for any shop dedicated to fix electronics, I've worked in this field in the past and i really wanted one app like that with a modern UI.
103 | 2. An online Shop where i can sell anything i want, AKA, an Ecommerce.
104 | 3. An app dedicated to solve a problem i have with a video game i like.
105 |
106 | At the end i went with the 2nd option, because is more general and more people might need something like that, that been said i plan to build the other apps anyways because those a problems that need a solution and programming is fun.
107 |
108 | - ### TypeScript vs JavaScript
109 |
110 | When i started this project Next.Js 12 had a warning in their documentation about that using TypeScript with ServerSideProps could bring some issues, as a new dev diving into Next.Js i wasn't going to take the risk of adding bugs to my code for free. So for this project i decided to go with JavaScript.
111 |
112 | - ### Design
113 |
114 | I took inspiration from some designs i saw on dribbble and added my own personal style. I know it has room for improvement (Im not a designer) but im still proud of the visuals.
115 |
116 | - ### Styling
117 |
118 | For this project i could have used Tailwind Css but i stayed with vanilla CSS just to not throw some old code i had. For anything i build with vanilla CSS i always use BEM convention, too good not to use it.
119 |
120 | - ### Why MongoDB with Sanity?
121 |
122 | At the beginning of this project i didn't want to build a full backend so i went with Sanity but after some time i decided to take this project to the next level, many features i wanted required a database, for me that don't know SQL, MongoDB was an easy pick.
123 |
124 | - ### Are you going to add different authentication methods?
125 |
126 | Yes, Im gonna add authentication with Google and Facebook but not now because Next Auth requires an "adapter" to save the users data in the database and for MongoDB it uses the "mongodb" module as adapter and currently Im using Mongoose as a driver to connect with MongoDB Atlas, which creates a conflict with the models if i try to install both, there's actually an issue about this topic in Next Auth's repository in github.
127 |
128 | - ### Testing
129 |
130 | For this project i didn't use any testing strategy, that said as soon as I finish building my personal portfolio, i plan to refactor some code,add new features and expand this project even more. That's why i believe adding unit and E2E testing to some specific parts that i plan to refactor will help deliver more reliable code.
131 |
132 | ## Next Steps
133 |
134 | ---
135 |
136 | For now Im gonna leave this project as it is, because I need to focus in another projects, but as soon Im done with those I plan to go work on these:
137 |
138 | - Migrate this project to TypeScript and NextJs 13.
139 | - Take Sanity out of the project and use MongoDB to manage the product's data.
140 | - Refactor some CSS code, maybe split it into modules.
141 | - Improve the design and animations.
142 | - Add an Admin panel, for products, users and orders management.
143 | - Create a webhook to monitor stripe payment confirmation.
144 | - Separate shipping address, payment and checkout in to different pages.
145 |
--------------------------------------------------------------------------------
/pages/shop.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { client } from "../lib/client";
3 | import { Product } from "../components";
4 | import { useRouter } from "next/router";
5 | import { motion, AnimatePresence } from "framer-motion";
6 | // import { useForm } from "react-hook-form";
7 |
8 | const Shop = ({ products }) => {
9 | const router = useRouter();
10 | const [category, setCategory] = useState("All");
11 | const [manufacturer, setManufacturer] = useState("All");
12 | const [productsList, setProductsList] = useState(products);
13 | const [query, setQuery] = useState("");
14 | const [isOpen, setIsOpen] = useState(false);
15 | const [sort, setSort] = useState("featured");
16 |
17 | const manufacturersList = ["All", "ASUS", "Logitech G", "Corsair"];
18 | const categoriesList = ["All", "Mouse pad", "Mouse", "Keyboard", "Headset"];
19 |
20 | useEffect(() => {
21 | if (!router.query.category) return;
22 | if (router.query.category === "Mousepad") {
23 | setCategory("Mouse pad");
24 | } else {
25 | setCategory(router.query.category);
26 | }
27 | }, [router.query.category]);
28 |
29 | const handleCategory = (e) => {
30 | setCategory(e.target.value);
31 | };
32 | const handleManufacturer = (e) => {
33 | setManufacturer(e.target.value);
34 | };
35 | const handleSort = (e) => {
36 | setSort(e.target.value);
37 | };
38 | const showFilterHandler = () => {
39 | setIsOpen((prev) => !prev);
40 | console.log(isOpen);
41 | };
42 | const sortProducts = (products, filter) => {
43 | //lets just say the original order is by "featured"
44 | //sort array method doesn't make a copy, it changes the array in place
45 | //normally i would make a deepcopy with JSON stringify and parse but in this case isn't needed
46 | if (filter === "featured") return products;
47 | if (filter === "low to high") {
48 | return products.sort((a, b) => a.price - b.price);
49 | }
50 | if (filter === "high to low") {
51 | return products.sort((a, b) => b.price - a.price);
52 | }
53 | };
54 | const filterProducts = (products) => {
55 | let updatedList = [...products];
56 | if (query.length > 0) {
57 | updatedList = updatedList.filter((product) =>
58 | product.name.toLowerCase().includes(query.toLowerCase())
59 | );
60 | }
61 | if (category !== "All") {
62 | updatedList = updatedList.filter(
63 | (product) => product.category === category.toLowerCase()
64 | );
65 | }
66 | if (manufacturer !== "All") {
67 | updatedList = updatedList.filter(
68 | (product) => product.manufacturer === manufacturer
69 | );
70 | }
71 | return updatedList;
72 | };
73 | useEffect(() => {
74 | let updatedList = filterProducts(products);
75 | updatedList = sortProducts(updatedList, sort);
76 | setProductsList(updatedList);
77 | }, [category, manufacturer, query, sort]);
78 |
79 | return (
80 |
81 |
82 |
High Quality Products
83 |
84 |
85 | Search products
86 |
87 |
{
91 | setQuery(e.target.value);
92 | }}
93 | autoFocus
94 | />
95 |
96 | Show Filters
97 |
98 |
99 |
102 | {
103 |
104 |
105 | Category
106 |
107 |
108 | {categoriesList.map((category, i) => {
109 | return (
110 |
111 | {category}
112 |
113 | );
114 | })}
115 |
116 |
117 | Manufacturer
118 |
119 |
120 | {manufacturersList.map((manufacturer, i) => {
121 | return (
122 |
127 | {manufacturer}
128 |
129 | );
130 | })}
131 |
132 |
133 | Sort by
134 |
135 |
136 |
137 | Featured
138 |
139 |
140 | Price: Low to High
141 |
142 |
143 | Price: High to Low
144 |
145 |
146 |
147 | }
148 |
149 |
150 |
155 |
156 | {productsList?.map((product) => (
157 |
158 | ))}
159 |
160 |
161 |
162 |
163 | );
164 | };
165 |
166 | export const getServerSideProps = async () => {
167 | const query = '*[_type == "product"]';
168 | const products = await client.fetch(query);
169 |
170 | return {
171 | props: { products },
172 | };
173 | };
174 | export default Shop;
175 |
--------------------------------------------------------------------------------
/components/Navbar.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import Link from "next/link";
3 | import { useSession, signOut } from "next-auth/react";
4 | import { FaShoppingCart, FaUser, FaMoon, FaSun } from "react-icons/fa";
5 | import { GiHamburgerMenu } from "react-icons/gi";
6 | import Cart from "./Cart";
7 | import { useStateContext } from "../context/StateContext";
8 | import { Menu } from "@headlessui/react";
9 | import { deleteData, paymentNotification } from "../lib/utils";
10 | import { useRouter } from "next/router";
11 | import { motion } from "framer-motion";
12 | import HamburgerMenu from "./HamburgerMenu";
13 | // import { HamburgerMenu } from ""
14 |
15 | const Navbar = () => {
16 | const [showHamMenu, setShowHamMenu] = useState(false);
17 | const {
18 | showCart,
19 | setShowCart,
20 | totalQuantities,
21 | setCartItems,
22 | setTotalPrice,
23 | setTotalQuantities,
24 | lightTheme,
25 | setLightTheme,
26 | } = useStateContext();
27 | const router = useRouter();
28 | const { status, data: session } = useSession();
29 | const { status: queryStatus, orderid: orderId } = router.query;
30 |
31 | const logoutClickHandler = () => {
32 | setCartItems([]);
33 | setTotalPrice(0);
34 | setTotalQuantities(0);
35 | signOut({ callbackUrl: "/login" });
36 | };
37 | useEffect(() => {
38 | if (
39 | (queryStatus && queryStatus === "canceled") ||
40 | queryStatus === "success"
41 | ) {
42 | paymentNotification(queryStatus, orderId);
43 | }
44 | const deleteCanceledOrder = async () => {
45 | if (queryStatus && orderId && queryStatus === "canceled") {
46 | try {
47 | const res = await deleteData(`/api/orders/${orderId}/delete`, {
48 | orderId,
49 | });
50 | const data = await res.json();
51 | console.log(data);
52 | } catch (error) {
53 | console.log(error);
54 | }
55 | }
56 | };
57 | deleteCanceledOrder();
58 | }, [queryStatus]);
59 |
60 | return (
61 |
62 |
63 |
69 |
70 | AwesomeGear
71 |
72 |
73 |
74 |
75 |
81 | Mice
82 |
83 |
84 |
85 |
86 |
92 | Keyboards
93 |
94 |
95 |
96 |
102 | Headsets
103 |
104 |
105 |
106 |
112 | Mouse pads
113 |
114 |
115 |
116 |
117 |
setLightTheme((prev) => !prev)}
125 | >
126 | {lightTheme ? (
127 |
128 | ) : (
129 |
130 | )}
131 |
132 |
133 |
{
141 | setShowCart(true);
142 | if (showHamMenu) setShowHamMenu(false);
143 | }}
144 | >
145 |
146 | {totalQuantities}
147 |
148 |
154 |
155 |
156 |
setShowHamMenu((prev) => !prev)}
159 | >
160 |
161 |
162 |
163 |
164 | {showHamMenu && (
165 |
166 | )}
167 |
168 | {status === "loading" ? (
169 |
Loading
170 | ) : session?.user ? (
171 |
172 |
173 |
174 |
175 |
176 |
177 | {session.user.name}
178 |
179 |
180 |
181 |
182 |
183 | Profile
184 |
185 |
186 |
187 |
192 | Logout
193 |
194 |
195 |
196 |
197 | ) : (
198 |
199 |
Login
200 |
201 | )}
202 |
203 |
204 |
205 | {showCart &&
}
206 |
207 | );
208 | };
209 |
210 | export default Navbar;
211 |
--------------------------------------------------------------------------------
/pages/checkout.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useForm } from "react-hook-form";
3 | import getStripe from "../lib/getStripe";
4 | import { useStateContext } from "../context/StateContext";
5 | import toast from "react-hot-toast";
6 | import { urlFor } from "../lib/client";
7 | import {
8 | AiOutlineMinus,
9 | AiOutlinePlus,
10 | AiOutlineShopping,
11 | } from "react-icons/ai";
12 | import { TiDeleteOutline } from "react-icons/ti";
13 | import Link from "next/link";
14 | import { getImage, postData, putData } from "../lib/utils";
15 | import getError from "../lib/error";
16 |
17 | const Checkout = () => {
18 | const {
19 | totalPrice,
20 | cartItems,
21 | setShowCart,
22 | toggleCartItemQuantity,
23 | onRemove,
24 | } = useStateContext();
25 | const {
26 | handleSubmit,
27 | register,
28 | formState: { errors },
29 | } = useForm();
30 |
31 | const handleCheckout = async (data) => {
32 | const orderItems = cartItems.map((item) => ({
33 | name: item.name,
34 | quantity: item.quantity,
35 | image: getImage(item),
36 | price: item.price,
37 | }));
38 | const shippingAddress = { ...data };
39 | const order = {
40 | orderItems,
41 | shippingAddress,
42 | itemsPrice: totalPrice,
43 | shippingPrice: 0,
44 | totalPrice,
45 | isPaid: false,
46 | paidAt: undefined,
47 | };
48 | try {
49 |
50 | // TO-DO: isPaid should be changed to true After the payment is successful
51 |
52 | const orderResponse = await postData("/api/orders", order);
53 | const orderData = await orderResponse.json();
54 | console.log("orderResponse", orderResponse, "orderData", orderData)
55 | const orderId = orderData.order._id;
56 | if (orderResponse.error) {
57 | toast.error(orderResponse.error);
58 | return;
59 | } else {
60 | toast.success(orderData.msg);
61 | }
62 |
63 | const stripe = await getStripe();
64 | const res = await postData("/api/stripe", {cartItems, orderId});
65 | const data = await res.json();
66 | console.log("stripe res",res);
67 | console.log("stripe data", data);
68 |
69 |
70 | if (res.statusCode === 500) return;
71 |
72 | toast.loading("Redirecting to Stripe...");
73 | //yes, im updating the isPaid status and its not even successful yet,
74 | //TO-DO: create a webhook with stripe api and wait for success
75 | //but for now i made the api for update and im gonna use it,
76 | //either way if its canceled the order its gonna be deleted
77 | const updateResult = await putData(`/api/orders/${orderId}/pay`,{orderId})
78 | const dataPaymentUpdate = await updateResult.json();
79 |
80 | console.log(dataPaymentUpdate.message);
81 | stripe.redirectToCheckout({ sessionId: data.id });
82 | } catch (error) {
83 | toast.error(getError(error));
84 | }
85 | };
86 |
87 | return (
88 |
240 | );
241 | };
242 | Checkout.auth = true;
243 | export default Checkout;
244 |
--------------------------------------------------------------------------------
/styles/globals.css:
--------------------------------------------------------------------------------
1 | /*========== GOOGLE FONTS ================*/
2 | @import url("https://fonts.googleapis.com/css2?family=Cabin:wght@400;700&display=swap");
3 |
4 | /*=====================CSS VARIABLES =======================*/
5 | :root {
6 | --header-height: 3rem;
7 |
8 | /*================= Colors ============*/
9 | /* Main color*/
10 | --hue-color: 237;
11 |
12 | /* Colors in HSL*/
13 | --first-color: hsl(237, 77%, 65%);
14 | --first-color-second: hsl(237, 69%, 67%);
15 | --first-color-alt: hsl(237, 57%, 53%);
16 | --first-color-lighter: hsl(237, 83%, 70%);
17 | --text-color: hsl(237, 77%, 97%);
18 | --text-color-darker: hsl(237, 8%, 75%);
19 | --bg-color-light: hsl(237, 45%, 79%);
20 | --secondary-color: hsl(237, 26%, 64%);
21 | --secondary-color-light: hsl(237, 65%, 84%);
22 | --secondary-color-darker: hsl(237, 12%, 44%);
23 | --third-color: hsl(237, 4%, 5%);
24 | --bg-color: hsl(237, 9%, 19%);
25 | --scroll-bar-color: hsl(237, 12%, 90%);
26 | --scroll-thumb-color: hsl(237, 12%, 80%);
27 |
28 | /*=============== Font and typography==========*/
29 | --body-font: "Cabin", sans-serif;
30 |
31 | /* .5rem = 8px, 1rem = 16px....*/
32 | --big-font-size-XL: 2rem;
33 | --big-font-size: 1.4rem;
34 | --h1-font-size: 1.5rem;
35 | --h2-font-size: 1.25rem;
36 | --h3-font-size: 1.125rem;
37 | --normal-font-size: 0.938rem;
38 | --small-font-size: 0.813rem;
39 | --smaller-font-size: 0.75rem;
40 |
41 | /*================= Font Weight================*/
42 | --font-medium: 500;
43 | --font-semi-bold: 600;
44 | --font-bold: 700;
45 |
46 | /*================ Margins Bottom =============*/
47 | --mb-0-25: 0.25rem;
48 | --mb-0-5: 0.5rem;
49 | --mb-0-75: 0.75rem;
50 | --mb-1: 1rem;
51 | --mb-1-5: 1.5rem;
52 | --mb-2: 2rem;
53 | --mb-2-5: 2.5rem;
54 | --mb-3: 3rem;
55 | }
56 |
57 | /*================ Variables light theme ====================*/
58 | .light-theme {
59 | /* Colors in HSL*/
60 | /* --first-color-second: hsl(237, 30%, 8%);
61 | --title-color: hsl(237, 8%, 95%); */
62 | --bg-color: hsl(237, 70%, 96%);
63 | --text-color: hsl(237, 13%, 24%);
64 | /* --input-color: hsl(237, 29%, 16%);
65 | --body-color: hsl(237, 28%, 12%);
66 | --container-color: hsl(237, 29%, 16%);
67 | --scroll-bar-color: hsl(237, 12%, 48%);
68 | --scroll-thumb-color: hsl(237, 12%, 36%); */
69 | }
70 |
71 | html,
72 | body,
73 | * {
74 | padding: 0;
75 | margin: 0;
76 | font-family: var(--body-font);
77 | box-sizing: border-box;
78 | }
79 | /* ::-webkit-scrollbar {
80 | width: 0px;
81 | } */
82 |
83 | a {
84 | color: inherit;
85 | text-decoration: none;
86 | }
87 |
88 | .main-container {
89 | margin: auto;
90 | width: 100%;
91 | background-color: var(--bg-color);
92 | }
93 |
94 | ul {
95 | list-style: none;
96 | }
97 |
98 | a {
99 | text-decoration: none;
100 | }
101 |
102 | .body {
103 | background-color: var(--bg-color);
104 | min-height: 100vh;
105 | /* width: 100vw; */
106 | transition: background 0.6s ease;
107 | }
108 |
109 | /*======================== Navbar =======================*/
110 | .navbar-container {
111 | display: flex;
112 | justify-content: space-between;
113 | padding: 8px 19px;
114 | position: relative;
115 | /* background-color: var(--bg-color); */
116 | padding-top: 13px;
117 | max-width: 1400px;
118 | margin-left: auto;
119 | margin-right: auto;
120 | z-index: 2;
121 | }
122 |
123 | .logo-container {
124 | color: var(--text-color);
125 | padding: 5px;
126 | font-size: var(--big-font-size);
127 | cursor: pointer;
128 | display: flex;
129 | justify-content: center;
130 | align-items: center;
131 | }
132 | .logo {
133 | height: 45px;
134 | width: 45px;
135 | object-fit: contain;
136 | }
137 |
138 | .navbar-buttons-container {
139 | display: flex;
140 | flex-direction: row;
141 | align-items: center;
142 | color: var(--text-color);
143 | font-size: var(--h3-font-size);
144 | }
145 |
146 | .navbar-button {
147 | padding: 8px 20px;
148 | /* background-color: var(--first-color-lighter); */
149 | cursor: pointer;
150 | transition: transform 0.5s ease;
151 | z-index: 2;
152 | }
153 |
154 | .navbar-button:hover {
155 | text-shadow: 1px 2px 10px var(--first-color);
156 | transform: scale(1.05, 1.05);
157 | }
158 |
159 | .navbar-user-container {
160 | display: flex;
161 | flex-direction: row;
162 | justify-content: space-between;
163 | position: relative;
164 | }
165 |
166 | .navbar-hamburger-container {
167 | display: flex;
168 | justify-content: space-between;
169 | align-items: center;
170 | height: 40px;
171 | }
172 | /* ------------------------- */
173 | .navbar-hamburger-menu-wrapper {
174 | width: 20vw;
175 | min-width: 180px;
176 | /* background: rgba(0, 0, 0, 0.5); */
177 | background-color: var(--bg-color);
178 | border: 3px solid var(--first-color);
179 | border-radius: 15px;
180 | position: fixed;
181 | right: 0;
182 | top: 92px;
183 | z-index: 100;
184 | will-change: transform;
185 | transition: all 1s ease-in-out;
186 | max-height: 60vh;
187 | cursor: auto;
188 | }
189 |
190 | /* .navbar-hamburger-menu-items-container {
191 | height: 600px;
192 | width: 300px;
193 | background-color: var(--bg-color);
194 | float: right;
195 | padding: 40px 10px;
196 | position: relative;
197 | } */
198 |
199 | .hamburger-menu-item {
200 | display: block;
201 | min-width: 150px;
202 | text-align: left;
203 | padding-top: 0.5rem;
204 | padding-left: 0.9rem;
205 | clear: both;
206 | width: 100%;
207 | margin-bottom: 0.5rem;
208 | transition: all 0.3s ease;
209 | cursor: pointer;
210 | }
211 | .hamburger-menu-item:hover {
212 | padding-left: 1.3rem;
213 | color: var(--first-color);
214 | }
215 | .hamburger-separator {
216 | width: 100%;
217 | height: 2px;
218 | margin: 8px 0;
219 | background-color: var(--first-color);
220 | }
221 | .hamburger-menu-user {
222 | display: flex;
223 | justify-content: center;
224 | align-items: center;
225 | margin-top: 10px;
226 | padding-left: 0.9rem;
227 | gap: 0.4rem;
228 | }
229 | .hamburger-menu-user-name {
230 | color: var(--first-color);
231 | }
232 |
233 | /* --------------------- */
234 | .navbar-hamburger-container {
235 | display: none;
236 | position: relative;
237 | height: 60px;
238 | }
239 |
240 | .navbar-hamburger-container .hamburger-lines {
241 | display: block;
242 | height: 20px;
243 | width: 26px;
244 | position: absolute;
245 | top: 21px;
246 | left: -5px;
247 | z-index: 2;
248 | display: flex;
249 | flex-direction: column;
250 | justify-content: space-between;
251 | }
252 |
253 | .navbar-hamburger-container .hamburger-lines .line {
254 | display: block;
255 | height: 4px;
256 | width: 100%;
257 | border-radius: 10px;
258 | background: var(--secondary-color);
259 | }
260 |
261 | .navbar-hamburger-container .hamburger-lines .line1 {
262 | transform-origin: 0% 0%;
263 | transition: transform 0.4s ease-in-out;
264 | }
265 |
266 | .navbar-hamburger-container .hamburger-lines .line2 {
267 | transition: transform 0.2s ease-in-out;
268 | }
269 |
270 | .navbar-hamburger-container .hamburger-lines .line3 {
271 | transform-origin: 0% 100%;
272 | transition: transform 0.4s ease-in-out;
273 | }
274 |
275 | .navbar-hamburger-container .hamburger-lines.active .line1 {
276 | transform: rotate(45deg);
277 | }
278 |
279 | .navbar-hamburger-container .hamburger-lines.active .line2 {
280 | transform: scaleY(0);
281 | }
282 |
283 | .navbar-hamburger-container .hamburger-lines.active .line3 {
284 | transform: rotate(-45deg);
285 | }
286 |
287 | .cart-icon-btn {
288 | font-size: 25px;
289 | color: var(--secondary-color);
290 | margin-right: 12px;
291 | cursor: pointer;
292 | position: relative;
293 | transition: transform 0.4s ease;
294 | border: none;
295 | background-color: transparent;
296 | width: 24px;
297 | }
298 | .cart-icon {
299 | position: absolute;
300 | top: 16px;
301 | right: -10px;
302 | }
303 | .cart-icon:hover {
304 | transform: scale(1.1, 1.1);
305 | }
306 | .cart-item-qty {
307 | position: absolute;
308 | right: -19px;
309 | top: 13px;
310 | font-size: 12px;
311 | color: #eee;
312 | background-color: var(--first-color);
313 | width: 18px;
314 | height: 18px;
315 | border-radius: 50%;
316 | text-align: center;
317 | font-weight: 600;
318 | }
319 |
320 | .user-container {
321 | display: flex;
322 | flex-direction: row;
323 | align-items: center;
324 | padding-left: 10px;
325 | height: 40px;
326 | margin: 5px 12px;
327 | border-left: 2px solid var(--first-color);
328 | cursor: pointer;
329 | }
330 |
331 | .user-icon {
332 | border: 3px solid var(--first-color);
333 | font-size: var(--h2-font-size);
334 | border-radius: 50%;
335 | margin: 0 2px;
336 | width: fit-content;
337 | padding: 0 3px;
338 | }
339 | .burger-icon {
340 | margin-top: 8px;
341 | font-size: 1.9rem;
342 | display: none;
343 | }
344 |
345 | .fa-icon {
346 | color: var(--secondary-color);
347 | }
348 |
349 | .user-name {
350 | margin-left: 5px;
351 | color: var(--text-color);
352 | font-size: var(--h3-font-size);
353 | }
354 |
355 | /*=========================== Home Page ===============================*/
356 | /*=====================Hero Banner ==================*/
357 | /*
358 | .logo{
359 | color: gray;
360 | font-size: 18px;
361 |
362 | }*/
363 |
364 | .hero-banner-container {
365 | padding: 100px 40px;
366 | border-radius: 15px;
367 | position: relative;
368 | max-width: 1400px;
369 | height: 500px;
370 | line-height: 0.9;
371 | width: 100%;
372 | margin: auto;
373 | color: var(--first-color);
374 | z-index: 0;
375 | overflow: hidden;
376 | }
377 | .hero-banner-container .top-small-text {
378 | font-size: 25px;
379 | }
380 |
381 | .hero-banner-container h3 {
382 | font-size: 4rem;
383 | margin-top: 4px;
384 | }
385 | .hero-banner-container h1 {
386 | color: var(--text-color);
387 | font-size: 7em;
388 | /* margin-left: -20px; */
389 | text-transform: uppercase;
390 | }
391 |
392 | .hero-banner-container .old-price {
393 | font-size: 25px;
394 | color: var(--secondary-color-light);
395 | text-decoration: line-through;
396 | }
397 | .light-theme .hero-banner-container .old-price {
398 | font-size: 25px;
399 | color: var(--secondary-color);
400 | text-decoration: line-through;
401 | }
402 |
403 | .hero-banner-container .new-price {
404 | margin-top: 10px;
405 | font-size: 25px;
406 | color: var(--text-color);
407 | }
408 |
409 | .hero-banner-container button {
410 | border-radius: 15px;
411 | padding: 10px 16px;
412 | background-color: var(--first-color);
413 | color: var(--text-color);
414 | border: none;
415 | margin-top: 25px;
416 | font-size: 28px;
417 | font-weight: var(--font-semi-bold);
418 | cursor: pointer;
419 | transition: transform 0.4s ease;
420 | /* z-index:10000 !important; */
421 | }
422 | .hero-banner-container button:hover {
423 | transform: scale(1.1, 1.1);
424 | }
425 |
426 | .hero-banner-image {
427 | position: absolute;
428 | top: -15%;
429 | right: 20%;
430 | width: 650px;
431 | height: 650px;
432 | object-fit: contain;
433 | pointer-events: none;
434 | z-index: -1;
435 | }
436 | .smallerImage {
437 | width: 450px;
438 | height: 450px;
439 | right: 32%;
440 | top: 0;
441 | }
442 |
443 | .hero-product-name {
444 | position: absolute;
445 | right: 5%;
446 | top: 17%;
447 | width: 300px;
448 | line-height: 1.3;
449 | display: flex;
450 | flex-direction: column;
451 | color: var(--text-color);
452 | font-size: var(--big-font-size-XL);
453 | }
454 |
455 | .right-icon,
456 | .left-icon {
457 | position: absolute;
458 | right: 12%;
459 | font-size: 3rem;
460 | color: var(--first-color);
461 | cursor: pointer;
462 | transition: transform 0.4s ease;
463 | }
464 |
465 | .right-icon {
466 | top: 35%;
467 | }
468 |
469 | .left-icon {
470 | top: 48%;
471 | }
472 |
473 | .right-icon:hover,
474 | .left-icon:hover {
475 | transform: scale(1.1, 1.1);
476 | }
477 |
478 | .desc {
479 | position: absolute;
480 | right: 10%;
481 | bottom: 5%;
482 | width: 300px;
483 | line-height: 1.3;
484 | display: flex;
485 | flex-direction: column;
486 | color: var(--first-color);
487 | }
488 | .desc p {
489 | color: var(--text-color-darker);
490 | font-weight: 100;
491 | text-align: end;
492 | display: -webkit-box;
493 | overflow: hidden;
494 | -webkit-line-clamp: 5;
495 | line-clamp: 5;
496 | -webkit-box-orient: vertical;
497 | }
498 | .desc h5 {
499 | margin-bottom: 12px;
500 | font-weight: 700;
501 | font-size: 16px;
502 | align-self: flex-end;
503 | }
504 |
505 | /*==================== Marquee (Slug / Product details) ===================*/
506 | .marquee-text {
507 | font-size: 29px;
508 | font-weight: 600;
509 | margin: 60px 0px;
510 | color: var(--first-color);
511 | }
512 | .marquee {
513 | position: relative;
514 | height: 400px;
515 | width: 100%;
516 | overflow-x: hidden;
517 | }
518 |
519 | .track {
520 | position: absolute;
521 | white-space: nowrap;
522 | will-change: transform;
523 | animation: marquee 15s linear infinite;
524 | width: 180%;
525 | }
526 | .track:hover {
527 | animation-play-state: paused;
528 | }
529 | @keyframes marquee {
530 | from {
531 | transform: translateX(0);
532 | }
533 | to {
534 | transform: translateX(-50%);
535 | }
536 | }
537 |
538 | span.text-red {
539 | -webkit-text-stroke: 1px var(--first-color);
540 | margin-left: 6px;
541 | }
542 |
543 | .shop-products {
544 | display: flex;
545 | max-height: 80vh;
546 | overflow: hidden;
547 | width: 100%;
548 | }
549 | .products-filters {
550 | border: 3px solid var(--first-color);
551 | border-left: 0px;
552 | border-top-right-radius: 15px;
553 | width: 280px;
554 | height: 75vh;
555 | margin-top: 20px;
556 | display: flex;
557 | flex-direction: column;
558 | padding: 2rem 20px;
559 | color: var(--text-color);
560 | transition: 1s;
561 | overflow: hidden;
562 | }
563 |
564 | .filter-label {
565 | font-size: 1.2rem;
566 | margin: 20px 0;
567 | }
568 | .products-filters select {
569 | font-size: 1rem;
570 | /* transition: 0.3s all ease; */
571 | }
572 |
573 |
574 | .products-container {
575 | display: flex;
576 | flex-wrap: wrap;
577 | justify-content: flex-start;
578 | gap: 15px;
579 | margin-top: 20px;
580 | width: 100%;
581 | max-height: 75vh;
582 | overflow: auto;
583 | padding: 0 1.5rem;
584 | }
585 | .product-card {
586 | cursor: pointer;
587 | transform: scale(1, 1);
588 | transition: transform 0.5s ease;
589 | color: var(--first-color);
590 | width: 250px;
591 | overflow: hidden;
592 | }
593 | .product-card:hover {
594 | transform: scale(1.1, 1.1);
595 | }
596 | .product-image {
597 | border-radius: 15px;
598 | background-color: var(--bg-color-light);
599 | transform: scale(1, 1);
600 | transition: transform 0.5s ease;
601 | object-fit: contain;
602 | }
603 |
604 | .product-name {
605 | font-weight: 500;
606 | }
607 | .product-manufacturer {
608 | color: var(--first-color-lighter);
609 | }
610 | .product-price {
611 | font-weight: 800;
612 | margin-top: 6px;
613 | color: var(--text-color);
614 | }
615 |
616 | .products-heading {
617 | text-align: center;
618 | margin: 40px 0px;
619 | color: var(--first-color);
620 | }
621 | .products-heading h2 {
622 | font-size: 40px;
623 | font-weight: 800;
624 | }
625 | .products-heading p {
626 | font-size: 16px;
627 | font-weight: 200;
628 | }
629 | .footer-banner-container {
630 | padding: 100px 40px;
631 | background-color: var(--first-color);
632 | border-radius: 15px;
633 | position: relative;
634 | height: 450px;
635 | max-width: 1300px;
636 | margin-left: auto;
637 | margin-right: auto;
638 | line-height: 1;
639 | color: var(--text-color);
640 | width: 95%;
641 | margin-top: 80px;
642 | overflow: hidden;
643 | z-index: 4;
644 | }
645 | .banner-desc {
646 | display: flex;
647 | justify-content: flex-start;
648 | max-width: 100%;
649 | }
650 | .banner-desc button {
651 | border-radius: 15px;
652 | padding: 10px 16px;
653 | background-color: var(--text-color);
654 | color: var(--first-color);
655 | border: none;
656 | margin-top: 40px;
657 | font-size: 20px;
658 | font-weight: var(--font-bold);
659 | cursor: pointer;
660 | }
661 | .banner-desc .left {
662 | max-width: 340px;
663 | }
664 | .banner-desc .left h3 {
665 | font-weight: 900;
666 | font-size: 70px;
667 | margin-left: 25px;
668 | }
669 | .banner-desc .left p {
670 | margin: 18px;
671 | }
672 | .footer-banner-image {
673 | position: absolute;
674 | /* top: -35%;
675 | left: 8%; */
676 | top: -15%;
677 | right: 0;
678 | width: 550px;
679 | height: 550px;
680 | object-fit: contain;
681 | pointer-events: none;
682 | z-index: -1;
683 | }
684 | .banner-desc .right {
685 | line-height: 1.4;
686 | max-width: 100%;
687 | }
688 | .banner-desc .right h3 {
689 | font-weight: 800;
690 | font-size: 60px;
691 | }
692 | .banner-desc .right p {
693 | font-size: 23px;
694 | max-width: 750px;
695 | }
696 | /* .banner-desc .right .company-desc{
697 | font-size: 14px;
698 | font-weight: 300;
699 | } */
700 | .light-theme .light-theme .banner-desc button {
701 | color: var(--first-color);
702 | }
703 | .light-theme .hero-banner-container button,
704 | .light-theme .footer-banner-container {
705 | color: var(--bg-color);
706 | }
707 | .light-theme .link-search-products-container .checkout-products,
708 | .light-theme .link-search-products-container svg {
709 | color: var(--bg-color);
710 | }
711 | .light-theme .footer-banner-container button {
712 | background-color: var(--bg-color);
713 | }
714 | .light-theme .hero-banner-container .desc p {
715 | color: var(--secondary-color-darker);
716 | }
717 |
718 | .cart-wrapper {
719 | width: 100vw;
720 | background: rgba(0, 0, 0, 0.5);
721 | position: fixed;
722 | right: 0;
723 | top: 0;
724 | z-index: 100;
725 | /* will-change: transform; */
726 | transition: all 1s ease-in-out;
727 | }
728 | .cart-container {
729 | height: 100vh;
730 | width: 600px;
731 | background-color: var(--bg-color);
732 | float: right;
733 | padding: 40px 10px;
734 | position: relative;
735 | }
736 |
737 | .footer-container {
738 | color: var(--text-color);
739 | background-color: var(--bg-color);
740 | text-align: center;
741 | padding: 30px 10px;
742 | font-weight: 700;
743 | display: flex;
744 | flex-direction: column;
745 | align-items: center;
746 | gap: 10px;
747 | justify-content: center;
748 | min-height: 156px;
749 | }
750 | .footer-container .icons {
751 | font-size: 30px;
752 | display: flex;
753 | gap: 10px;
754 | }
755 | .cart-heading {
756 | display: flex;
757 | align-items: center;
758 | font-size: 18px;
759 | font-weight: 500;
760 | cursor: pointer;
761 | gap: 2px;
762 | margin-left: 10px;
763 | border: none;
764 | background-color: transparent;
765 | color: var(--text-color);
766 | }
767 |
768 | .cart-heading .heading {
769 | margin-left: 10px;
770 | color: var(--text-color);
771 | }
772 | .cart-num-items {
773 | margin-left: 10px;
774 | color: var(--first-color);
775 | }
776 | .empty-cart {
777 | margin: 40px;
778 | text-align: center;
779 | color: var(--text-color);
780 | }
781 | .empty-cart h3 {
782 | font-weight: 600;
783 | font-size: 20px;
784 | }
785 | .cancel {
786 | cursor: pointer;
787 | }
788 | .shop-container {
789 | display: flex;
790 | flex-direction: column;
791 | justify-content: center;
792 | align-items: center;
793 | }
794 | .product-container {
795 | margin-top: 15px;
796 | overflow: auto;
797 | max-height: 70vh;
798 | padding: 20px 10px;
799 | }
800 | .search-label {
801 | margin-bottom: 1rem;
802 | font-size: var(--h1-font-size);
803 | font-weight: var(--font-bold);
804 | line-height: 1.75rem;
805 | text-align: center;
806 | color: var(--text-color);
807 | }
808 | .products-search {
809 | margin-top: 0.6rem;
810 | height: 2rem;
811 | width: 90%;
812 | max-width: 800px;
813 | border-radius: 8px;
814 | font-size: 1.2rem;
815 | transition: all 0.4s ease;
816 | }
817 |
818 | .products-search:focus {
819 | outline: none;
820 | border: 3px solid var(--first-color);
821 | box-shadow: 0 0 10px var(--first-color);
822 | }
823 |
824 | .product {
825 | display: flex;
826 | gap: 30px;
827 | padding: 20px;
828 | }
829 | .product .cart-product-image {
830 | width: 150px;
831 | height: 150px;
832 | border-radius: 15px;
833 | background-color: #ebebeb;
834 | object-fit: contain;
835 | }
836 | .item-desc .flex {
837 | display: flex;
838 | justify-content: space-between;
839 | width: 350px;
840 | color: var(--text-color);
841 | }
842 | .item-desc .bottom {
843 | margin-top: 60px;
844 | }
845 | .flex h5 {
846 | font-size: 24px;
847 | }
848 | .flex h4 {
849 | font-size: 20px;
850 | }
851 | .total {
852 | display: flex;
853 | justify-content: space-between;
854 | color: var(--text-color);
855 | }
856 | .total h3 {
857 | font-size: 22px;
858 | }
859 | .remove-item {
860 | font-size: 24px;
861 | color: #f02d34;
862 | cursor: pointer;
863 | background: transparent;
864 | border: none;
865 | }
866 | .cart-bottom {
867 | position: absolute;
868 | bottom: 12px;
869 | right: 5px;
870 | width: 100%;
871 | padding: 30px 65px;
872 | }
873 |
874 | .btn-container {
875 | width: 400px;
876 | margin: auto;
877 | }
878 | .btn {
879 | width: 100%;
880 | max-width: 400px;
881 | padding: 10px 12px;
882 | border-radius: 15px;
883 | border: none;
884 | font-size: 20px;
885 | margin-top: 40px;
886 | text-transform: uppercase;
887 | background-color: var(--first-color);
888 | color: var(--text-color);
889 | cursor: pointer;
890 | transform: scale(1, 1);
891 | transition: transform 0.5s ease;
892 | }
893 | .btn:hover {
894 | transform: scale(1.1, 1.1);
895 | }
896 |
897 | .product-detail-container {
898 | display: flex;
899 | max-width: 1400px;
900 | gap: 40px;
901 | margin: auto;
902 | margin-top: 60px;
903 | color: var(--text-color);
904 | /* overflow: hidden; */
905 | }
906 |
907 | .product-detail-image {
908 | border-radius: 15px;
909 | background-color: #ebebeb;
910 |
911 | width: 400px;
912 | height: 400px;
913 | cursor: pointer;
914 | transition: 0.3s ease-in-out;
915 | object-fit: contain;
916 | }
917 | .product-detail-image:hover {
918 | background-color: var(--first-color);
919 | }
920 | .small-images-container {
921 | display: flex;
922 | gap: 10px;
923 | margin-top: 20px;
924 | }
925 | .small-image {
926 | border-radius: 8px;
927 | background-color: #ebebeb;
928 | width: 70px;
929 | height: 70px;
930 | cursor: pointer;
931 | }
932 |
933 | .selected-image {
934 | background-color: var(--first-color);
935 | }
936 | .reviews {
937 | color: var(--first-color);
938 | margin-top: 10px;
939 | display: flex;
940 | gap: 5px;
941 | align-items: center;
942 | }
943 |
944 | .product-detail-desc h4 {
945 | margin-top: 10px;
946 | }
947 | .product-detail-desc p {
948 | margin-top: 10px;
949 | }
950 | .reviews p {
951 | color: var(--text-color);
952 | margin-top: 0px;
953 | }
954 | .product-detail-desc .price {
955 | font-weight: 700;
956 | font-size: 26px;
957 | margin-top: 30px;
958 | color: var(--first-color);
959 | }
960 | .price .old-price,
961 | .product-price .old-price,
962 | .price .old-price {
963 | color: gray;
964 | text-decoration: line-through;
965 | }
966 | .product-detail-desc .quantity {
967 | display: flex;
968 | gap: 20px;
969 | margin-top: 10px;
970 | align-items: center;
971 | }
972 | .product-detail-desc .buttons {
973 | display: flex;
974 | gap: 30px;
975 | }
976 | .buttons .add-to-cart {
977 | padding: 10px 20px;
978 | border: 1px solid var(--first-color);
979 | margin-top: 40px;
980 | font-size: 18px;
981 | font-weight: 500;
982 | background-color: white;
983 | color: var(--first-color-alt);
984 | cursor: pointer;
985 | width: 200px;
986 | transform: scale(1, 1);
987 | transition: transform 0.5s ease;
988 | border-radius: 0.5rem;
989 | }
990 | .buttons .add-to-cart:hover {
991 | transform: scale(1.1, 1.1);
992 | }
993 | .buttons .buy-now {
994 | width: 200px;
995 |
996 | padding: 10px 20px;
997 | background-color: var(--first-color-alt);
998 | color: white;
999 | border: none;
1000 | margin-top: 40px;
1001 | font-size: 18px;
1002 | font-weight: 500;
1003 | cursor: pointer;
1004 | transform: scale(1, 1);
1005 | transition: transform 0.5s ease;
1006 | border-radius: 0.5rem;
1007 | }
1008 | .buttons .buy-now:hover {
1009 | transform: scale(1.1, 1.1);
1010 | }
1011 | .quantity-desc {
1012 | border: 1px solid gray;
1013 | padding: 6px;
1014 | }
1015 | .quantity-desc span {
1016 | font-size: 16px;
1017 | padding: 6px 12px;
1018 | cursor: pointer;
1019 | }
1020 | .quantity-desc .minus {
1021 | border-right: 1px solid gray;
1022 | color: var(--first-color);
1023 | }
1024 | .quantity-desc .num {
1025 | border-right: 1px solid gray;
1026 | font-size: 20px;
1027 | }
1028 | .quantity-desc .plus {
1029 | color: var(--first-color);
1030 | }
1031 |
1032 | .maylike-products-wrapper {
1033 | margin-top: 120px;
1034 | }
1035 | .maylike-products-wrapper h2 {
1036 | text-align: center;
1037 | margin: 50px;
1038 | color: var(--text-color);
1039 |
1040 | font-size: 28px;
1041 | }
1042 | .maylike-products-container {
1043 | display: flex;
1044 | justify-content: center;
1045 | gap: 15px;
1046 | margin-top: 20px;
1047 | }
1048 | .max-qty {
1049 | font-weight: 500;
1050 | color: var(--first-color);
1051 | }
1052 | .success-wrapper,
1053 | .cancel-wrapper {
1054 | background-color: var(--bg-color);
1055 | min-height: 60vh;
1056 | /* height: 40rem; */
1057 | /* max-height: 90vh; */
1058 |
1059 | /* height: 800px; */
1060 | color: var(--text-color);
1061 | margin-top: 20vh;
1062 | }
1063 | .success,
1064 | .cancel {
1065 | width: 1000px;
1066 | max-width: 95%;
1067 | margin: auto;
1068 | margin-top: 160px;
1069 | background-color: var(--secondary-color-darker);
1070 | padding: 50px;
1071 | border-radius: 15px;
1072 | display: flex;
1073 | justify-content: center;
1074 | align-items: center;
1075 | flex-direction: column;
1076 | }
1077 |
1078 | .success .icon {
1079 | color: green;
1080 | font-size: 40px;
1081 | }
1082 | .success h2 {
1083 | text-transform: capitalize;
1084 | margin-top: 15px 0px;
1085 | font-weight: 900;
1086 | font-size: 40px;
1087 | color: var(--text-color);
1088 | }
1089 | .success .email-msg {
1090 | font-size: var(--h3-font-size);
1091 | font-weight: 600;
1092 | text-align: center;
1093 | }
1094 | .cancel p {
1095 | font-size: 20px;
1096 | font-weight: 600;
1097 | }
1098 | .success .description {
1099 | font-size: var(--h3-font-size);
1100 | font-weight: 600;
1101 | text-align: center;
1102 | margin: 10px;
1103 | margin-top: 30px;
1104 | }
1105 | .success .description .email {
1106 | margin-left: 5px;
1107 | color: var(--first-color-lighter);
1108 | }
1109 | .product-max-qty {
1110 | margin-top: 10px;
1111 | }
1112 |
1113 | .category-menu-container {
1114 | min-width: 700px;
1115 | max-width: 1100px;
1116 | display: flex;
1117 | flex-wrap: wrap;
1118 | color: var(--text-color);
1119 | margin: auto;
1120 | justify-content: center;
1121 | align-items: center;
1122 | }
1123 | .category-menu-item {
1124 | height: 400px;
1125 | min-width: 550px;
1126 | /* width: 550px; */
1127 | /* max-width: 550px; */
1128 | border-style: solid;
1129 | border-width: 0.05rem;
1130 | border-color: var(--secondary-color);
1131 | overflow: hidden;
1132 | position: relative;
1133 | z-index: 2;
1134 | }
1135 | .category-menu-text {
1136 | position: absolute;
1137 | top: 8%;
1138 | left: 8%;
1139 | font-size: 1.2rem;
1140 | }
1141 |
1142 | .category-menu-lowest-price {
1143 | position: absolute;
1144 | top: 15%;
1145 | left: 8%;
1146 | color: var(--first-color);
1147 | font-weight: var(--font-bold);
1148 | font-size: 1.8rem;
1149 | }
1150 | .category-menu-bg-text {
1151 | position: absolute;
1152 | color: var(--secondary-color-darker);
1153 | top: 40%;
1154 | left: -7%;
1155 | font-size: 9rem;
1156 | font-weight: bolder;
1157 | opacity: 0.45;
1158 | z-index: -3;
1159 | }
1160 | .category-menu-item h1 {
1161 | position: absolute;
1162 | bottom: 30%;
1163 | left: 5%;
1164 | font-size: 2.5rem;
1165 | }
1166 | .category-item-image {
1167 | position: absolute;
1168 | height: 500px;
1169 | width: 500px;
1170 | object-fit: contain;
1171 | z-index: -1;
1172 | }
1173 | .category-menu-button-container {
1174 | position: absolute;
1175 | bottom: 5%;
1176 | left: 8%;
1177 | display: flex;
1178 | justify-content: center;
1179 | align-items: center;
1180 | gap: 0.5rem;
1181 | cursor: pointer;
1182 | transition: 0.2s ease-in-out;
1183 | }
1184 | .category-menu-button-container:hover {
1185 | left: 10%;
1186 | }
1187 |
1188 | .category-arrow-icon {
1189 | color: var(--first-color);
1190 | font-size: 2.5rem;
1191 | }
1192 | .featured-items-container {
1193 | position: relative;
1194 | display: flex;
1195 | align-items: center;
1196 | justify-content: center;
1197 | flex-wrap: wrap;
1198 | min-height: 550px;
1199 | max-width: 1100px;
1200 | overflow: hidden;
1201 | z-index: 4;
1202 | margin: auto;
1203 | }
1204 |
1205 | .featured-product-card {
1206 | cursor: pointer;
1207 | transform: scale(1, 1);
1208 | transition: transform 0.5s ease;
1209 | color: var(--first-color);
1210 | width: 250px;
1211 | display: flex;
1212 | flex-direction: column;
1213 | align-items: center;
1214 | font-size: var(--h2-font-size);
1215 | margin: 0.5rem 0.5rem;
1216 | }
1217 | .featured-product-card:hover {
1218 | transform: scale(1.1, 1.1);
1219 | }
1220 | .featured-product-image {
1221 | transform: scale(1, 1);
1222 | transition: transform 0.5s ease;
1223 | object-fit: contain;
1224 | }
1225 |
1226 | .featured-product-name {
1227 | font-weight: 500;
1228 | white-space: nowrap;
1229 | overflow: hidden;
1230 | text-overflow: ellipsis;
1231 | }
1232 | .featured-product-manufacturer {
1233 | color: var(--first-color-lighter);
1234 | }
1235 | .featured-product-price {
1236 | font-weight: 800;
1237 | margin-top: 6px;
1238 | color: var(--text-color);
1239 | }
1240 |
1241 | .rotate {
1242 | transform: rotate(90deg);
1243 | }
1244 | .featured-product-button-container {
1245 | display: flex;
1246 | justify-content: center;
1247 | align-items: center;
1248 | column-gap: 0.5rem;
1249 | margin-top: 0.45rem;
1250 | }
1251 | .featured-product-button-text {
1252 | color: var(--text-color);
1253 | }
1254 | .featured-arrow-icon {
1255 | font-size: 2rem;
1256 | }
1257 | .featured-top-text {
1258 | position: absolute;
1259 | top: 7%;
1260 | left: 4%;
1261 | color: var(--text-color);
1262 | font-size: 2.5rem;
1263 | margin-bottom: 1rem;
1264 | }
1265 | .featured-bg-text {
1266 | position: absolute;
1267 | color: var(--secondary-color-darker);
1268 | font-size: 16rem;
1269 | font-weight: bolder;
1270 | left: 0;
1271 | right: 0;
1272 | margin-left: auto;
1273 | margin-right: auto;
1274 | /* overflow: hidden; */
1275 | width: 1100px;
1276 | opacity: 0.45;
1277 | z-index: -3;
1278 | }
1279 |
1280 | .link-search-products-container {
1281 | display: flex;
1282 | align-items: center;
1283 | justify-content: center;
1284 | margin: 3rem auto;
1285 | column-gap: 1rem;
1286 | cursor: pointer;
1287 | max-width: max-content;
1288 | padding: 0.85rem;
1289 | border-radius: 15px;
1290 | background-color: var(--first-color);
1291 | }
1292 | .checkout-products {
1293 | font-size: 2.5rem;
1294 | color: var(--text-color);
1295 | }
1296 | .checkout-arrow-icon {
1297 | color: var(--text-color);
1298 | font-size: 2.8rem;
1299 | transition: 0.2s ease-in-out;
1300 | }
1301 | .link-search-products-container:hover .checkout-arrow-icon {
1302 | transform: translateX(0.5rem);
1303 | }
1304 |
1305 | .login-form-container,
1306 | .register-form-container {
1307 | margin: 24vh auto;
1308 | max-width: 400px;
1309 | color: var(--text-color);
1310 | font-size: var(--h2-font-size);
1311 | /* height: 65vh; */
1312 | }
1313 | .login-form-top-text,
1314 | .register-form-top-text {
1315 | margin-bottom: 1rem;
1316 | font-size: var(--h1-font-size);
1317 | font-weight: var(--font-bold);
1318 | line-height: 1.75rem;
1319 | text-align: center;
1320 | }
1321 | .login-email,
1322 | .login-password,
1323 | .login-button {
1324 | margin-bottom: 1rem;
1325 | }
1326 | .email-input,
1327 | .password-input {
1328 | margin-top: 0.6rem;
1329 | height: 2rem;
1330 | width: 100%;
1331 | border-radius: 8px;
1332 | font-size: 1.2rem;
1333 | transition: all 0.4s ease;
1334 | }
1335 |
1336 | .email-input:focus,
1337 | .password-input:focus {
1338 | outline: none;
1339 | border: 3px solid var(--first-color);
1340 | box-shadow: 0 0 10px var(--first-color);
1341 | }
1342 |
1343 | .login-btn {
1344 | border-radius: 15px;
1345 | background-color: var(--first-color);
1346 | font-size: 1.5rem;
1347 | border-style: none;
1348 | color: var(--text-color);
1349 | padding: 0.4rem;
1350 | width: 7rem;
1351 | cursor: pointer;
1352 | }
1353 | .login-botton-text .link,
1354 | .dropdown-button {
1355 | color: var(--first-color);
1356 | }
1357 | .register-input-item {
1358 | margin-bottom: 1rem;
1359 | }
1360 | .register-input {
1361 | margin-top: 0.6rem;
1362 | height: 2rem;
1363 | width: 100%;
1364 | border-radius: 8px;
1365 | font-size: 1.2rem;
1366 | transition: all 0.4s ease;
1367 | }
1368 | .register-input:focus {
1369 | outline: none;
1370 | border: 3px solid var(--first-color);
1371 | box-shadow: 0 0 10px var(--first-color);
1372 | }
1373 | .dropdown-button {
1374 | display: flex;
1375 | background-color: var(--bg-color);
1376 | border-style: none;
1377 | font-size: 1.2rem;
1378 | justify-content: center;
1379 | align-items: center;
1380 | cursor: pointer;
1381 | }
1382 | .dropdown-menu-container {
1383 | position: relative;
1384 | display: inline-block;
1385 | background-color: var(--bg-color);
1386 | }
1387 | .dropdown-menu-items {
1388 | position: absolute;
1389 | padding-right: 0;
1390 | right: 0;
1391 | top: 2rem;
1392 | z-index: 3;
1393 | background-color: var(--bg-color);
1394 | border-style: solid;
1395 | border-color: var(--first-color);
1396 | border-radius: 10px;
1397 | }
1398 | .dropdown-menu-item {
1399 | display: block;
1400 | min-width: 150px;
1401 | text-align: left;
1402 | padding-top: 0.5rem;
1403 | padding-left: 0.4rem;
1404 | clear: both;
1405 | width: 100%;
1406 | margin-bottom: 0.5rem;
1407 | transition: all 0.3s ease;
1408 | }
1409 | .dropdown-menu-item:hover {
1410 | padding-left: 0.8rem;
1411 | color: var(--first-color);
1412 | }
1413 | .dropdown-button-text {
1414 | margin-left: 4px;
1415 | }
1416 | .checkout-container {
1417 | padding-top: 12vh;
1418 | padding-bottom: 12vh;
1419 | }
1420 | .shipping-form-container {
1421 | margin: auto auto;
1422 | max-width: 600px;
1423 | color: var(--text-color);
1424 | font-size: var(--h2-font-size);
1425 | /* height: 65vh; */
1426 | }
1427 | .checkout-title-text {
1428 | margin-top: 1rem;
1429 | margin-bottom: 1rem;
1430 | padding-top: 2rem;
1431 | padding-bottom: 0.8rem;
1432 | /* padding-bottom: 2rem; */
1433 | font-size: 2rem;
1434 | font-weight: var(--font-bold);
1435 | /* line-height: 1.75rem; */
1436 | text-align: center;
1437 | border-bottom: 4px solid var(--first-color);
1438 | }
1439 | .shipping-form-item {
1440 | margin-bottom: 1rem;
1441 | display: flex;
1442 | flex-direction: column;
1443 | justify-content: flex-start;
1444 | }
1445 | .shipping-form-item label {
1446 | margin-bottom: 0.8rem;
1447 | }
1448 |
1449 | .shipping-form-item input {
1450 | margin-top: 0.6rem;
1451 | height: 2rem;
1452 | width: 100%;
1453 | border-radius: 8px;
1454 | font-size: 1.2rem;
1455 | transition: all 0.4s ease;
1456 | }
1457 | .shipping-form-item input:focus {
1458 | outline: none;
1459 | border: 3px solid var(--first-color);
1460 | box-shadow: 0 0 10px var(--first-color);
1461 | }
1462 | .input-error-message {
1463 | color: #e44e53;
1464 | }
1465 | .checkout-cart-bottom {
1466 | /* position: absolute; */
1467 | bottom: 12px;
1468 | right: 5px;
1469 | width: 100%;
1470 | padding: 30px 65px;
1471 | }
1472 | .place-order-button {
1473 | display: flex;
1474 | justify-content: center;
1475 | }
1476 | .order-history-title {
1477 | color: var(--text-color);
1478 | }
1479 | .table-container {
1480 | color: var(--text-color);
1481 | overflow: auto;
1482 | }
1483 | .column-title {
1484 | text-align: left;
1485 | padding: 1.3rem;
1486 | }
1487 | .table {
1488 | font-size: 1.4rem;
1489 | margin-bottom: 2rem;
1490 | border-collapse: collapse;
1491 | border-radius: 15px;
1492 | /* box-shadow: 0 0 12px 5px var(--first-color); */
1493 | border: 0.2rem solid var(--first-color);
1494 | }
1495 | .table-head {
1496 | background-color: var(--first-color);
1497 | /* ba */
1498 | /* border-color: var(--first-color); */
1499 | }
1500 | .table-item {
1501 | padding: 1.4rem;
1502 | }
1503 | .table-row {
1504 | border: 0.1px solid var(--first-color);
1505 | /* color: var(--first-color); */
1506 | }
1507 | .table-row .details {
1508 | color: var(--first-color);
1509 | }
1510 | .order-history-empty {
1511 | font-size: 1.2rem;
1512 | }
1513 | .order-history {
1514 | min-height: 30vh;
1515 | overflow: auto;
1516 | }
1517 |
1518 | .profile-container {
1519 | max-width: 1100px;
1520 | margin: 0.5rem auto;
1521 | color: var(--text-color);
1522 | margin-left: 15vw;
1523 | }
1524 | .profile-title {
1525 | margin-top: 10vh;
1526 | margin-bottom: 0.7rem;
1527 | font-size: 2rem;
1528 | }
1529 | .update-input {
1530 | margin-bottom: 1.5rem;
1531 | max-width: 350px;
1532 | font-size: 1.2rem;
1533 | }
1534 | .update-button {
1535 | max-width: 400px;
1536 | }
1537 |
1538 | .update-btn {
1539 | width: 90%;
1540 | max-width: 220px;
1541 | padding: 10px 12px;
1542 | border-radius: 15px;
1543 | border: none;
1544 | font-size: 1.2rem;
1545 | margin-top: 16px;
1546 | /* text-transform: uppercase; */
1547 | background-color: var(--first-color);
1548 | color: var(--text-color);
1549 | cursor: pointer;
1550 | transform: scale(1, 1);
1551 | transition: transform 0.5s ease;
1552 | }
1553 | .update-btn:hover {
1554 | transform: scale(1.1, 1.1);
1555 | }
1556 | .order-details-container {
1557 | margin-top: 10vh;
1558 | margin-left: 5vw;
1559 | color: var(--text-color);
1560 | max-width: 740px;
1561 | width: 80vw;
1562 | margin-right: auto;
1563 | margin-left: auto;
1564 | }
1565 | .order-details-title {
1566 | margin-bottom: 1rem;
1567 | font-size: 2rem;
1568 | }
1569 | .order-details-address {
1570 | font-size: 1.2rem;
1571 | margin-bottom: 0.9rem;
1572 | }
1573 | .order-details-id {
1574 | font-size: 1.2rem;
1575 | margin-bottom: 1rem;
1576 | }
1577 | .order-details-subtitle {
1578 | font-size: 1.6rem;
1579 | margin: 1.5rem 0;
1580 | border-bottom: 3px solid var(--first-color);
1581 | padding-bottom: 0.3rem;
1582 | }
1583 | .order-details-image-container {
1584 | display: flex;
1585 | justify-content: center;
1586 | align-items: center;
1587 | }
1588 | .order-details-card {
1589 | margin-top: 1.5rem;
1590 | border: 3px solid var(--first-color);
1591 | padding: 0.3rem;
1592 | width: max-content;
1593 | border-radius: 15px;
1594 | }
1595 | .order-details-table-container {
1596 | width: 100%;
1597 | overflow: scroll;
1598 | }
1599 | .order-details-table-head {
1600 | font-size: 1.3rem;
1601 | }
1602 | .order-details-table-body {
1603 | font-size: 1.1rem;
1604 | }
1605 |
1606 | .order-details-table-column-item,
1607 | .order-details-table-column-title {
1608 | text-align: center;
1609 | padding: 0.8rem;
1610 | }
1611 | .order-details-summary {
1612 | width: 180px;
1613 | }
1614 | .order-details-summary-item {
1615 | display: flex;
1616 | justify-content: space-between;
1617 | margin-bottom: 0.8rem;
1618 | }
1619 | .order-details-summary-item.bold {
1620 | font-size: 1.2rem;
1621 | font-weight: var(--font-bold);
1622 | }
1623 | .order-details-payment {
1624 | font-size: 1.2rem;
1625 | }
1626 | .unauthorized-page-container{
1627 | min-height: 70vh;
1628 | margin: auto;
1629 | color: var(--text-color);
1630 | display: flex;
1631 | align-items: center;
1632 | justify-content: center;
1633 | }
1634 | .unauthorized-title{
1635 | font-size: 2.5rem;
1636 | text-align: center;
1637 | }
1638 | .unauthorized-message{
1639 | font-size: 1.4rem;
1640 | text-align: center;
1641 | }
1642 | /* ==============Loader Component=========== */
1643 | .loader-container {
1644 | margin: 0;
1645 | padding: 0;
1646 | box-sizing: border-box;
1647 | display: flex;
1648 | justify-content: center;
1649 | align-items: center;
1650 | min-height: 50vh;
1651 | background-color: var(--bg-color);
1652 | /* animation: animateBg 10s linear infinite; */
1653 | }
1654 | /* @keyframes animateBg {
1655 | 0%
1656 | {
1657 | filter: hue-rotate(0deg);
1658 | }
1659 |
1660 | } */
1661 |
1662 | .loader-container .loader {
1663 | position: relative;
1664 | width: 120px;
1665 | height: 120px;
1666 | }
1667 | .loader-container .loader span {
1668 | position: absolute;
1669 | top: 0;
1670 | left: 0;
1671 | width: 100%;
1672 | height: 100%;
1673 | }
1674 | /* if there is a better way to do this without SASS let know */
1675 | .loader-container .loader :nth-child(1) {
1676 | transform: rotate(calc(18deg * 1));
1677 | }
1678 | .loader-container .loader :nth-child(2) {
1679 | transform: rotate(calc(18deg * 2));
1680 | }
1681 | .loader-container .loader :nth-child(3) {
1682 | transform: rotate(calc(18deg * 3));
1683 | }
1684 | .loader-container .loader :nth-child(4) {
1685 | transform: rotate(calc(18deg * 4));
1686 | }
1687 | .loader-container .loader :nth-child(5) {
1688 | transform: rotate(calc(18deg * 5));
1689 | }
1690 | .loader-container .loader :nth-child(6) {
1691 | transform: rotate(calc(18deg * 6));
1692 | }
1693 | .loader-container .loader :nth-child(7) {
1694 | transform: rotate(calc(18deg * 7));
1695 | }
1696 | .loader-container .loader :nth-child(8) {
1697 | transform: rotate(calc(18deg * 8));
1698 | }
1699 | .loader-container .loader :nth-child(9) {
1700 | transform: rotate(calc(18deg * 9));
1701 | }
1702 | .loader-container .loader :nth-child(10) {
1703 | transform: rotate(calc(18deg * 10));
1704 | }
1705 | .loader-container .loader :nth-child(11) {
1706 | transform: rotate(calc(18deg * 11));
1707 | }
1708 | .loader-container .loader :nth-child(12) {
1709 | transform: rotate(calc(18deg * 12));
1710 | }
1711 | .loader-container .loader :nth-child(13) {
1712 | transform: rotate(calc(18deg * 13));
1713 | }
1714 | .loader-container .loader :nth-child(14) {
1715 | transform: rotate(calc(18deg * 14));
1716 | }
1717 | .loader-container .loader :nth-child(15) {
1718 | transform: rotate(calc(18deg * 15));
1719 | }
1720 | .loader-container .loader :nth-child(16) {
1721 | transform: rotate(calc(18deg * 16));
1722 | }
1723 | .loader-container .loader :nth-child(17) {
1724 | transform: rotate(calc(18deg * 17));
1725 | }
1726 | .loader-container .loader :nth-child(18) {
1727 | transform: rotate(calc(18deg * 18));
1728 | }
1729 | .loader-container .loader :nth-child(19) {
1730 | transform: rotate(calc(18deg * 19));
1731 | }
1732 | .loader-container .loader :nth-child(20) {
1733 | transform: rotate(calc(18deg * 20));
1734 | }
1735 | .loader-container .loader :nth-child(1)::before {
1736 | animation-delay: calc(0.1s * 1);
1737 | }
1738 | .loader-container .loader :nth-child(2)::before {
1739 | animation-delay: calc(0.1s * 2);
1740 | }
1741 | .loader-container .loader :nth-child(3)::before {
1742 | animation-delay: calc(0.1s * 3);
1743 | }
1744 | .loader-container .loader :nth-child(4)::before {
1745 | animation-delay: calc(0.1s * 4);
1746 | }
1747 | .loader-container .loader :nth-child(5)::before {
1748 | animation-delay: calc(0.1s * 5);
1749 | }
1750 | .loader-container .loader :nth-child(6)::before {
1751 | animation-delay: calc(0.1s * 6);
1752 | }
1753 | .loader-container .loader :nth-child(7)::before {
1754 | animation-delay: calc(0.1s * 7);
1755 | }
1756 | .loader-container .loader :nth-child(8)::before {
1757 | animation-delay: calc(0.1s * 8);
1758 | }
1759 | .loader-container .loader :nth-child(9)::before {
1760 | animation-delay: calc(0.1s * 9);
1761 | }
1762 | .loader-container .loader :nth-child(10)::before {
1763 | animation-delay: calc(0.1s * 10);
1764 | }
1765 | .loader-container .loader :nth-child(11)::before {
1766 | animation-delay: calc(0.1s * 11);
1767 | }
1768 | .loader-container .loader :nth-child(12)::before {
1769 | animation-delay: calc(0.1s * 12);
1770 | }
1771 | .loader-container .loader :nth-child(13)::before {
1772 | animation-delay: calc(0.1s * 13);
1773 | }
1774 | .loader-container .loader :nth-child(14)::before {
1775 | animation-delay: calc(0.1s * 14);
1776 | }
1777 | .loader-container .loader :nth-child(15)::before {
1778 | animation-delay: calc(0.1s * 15);
1779 | }
1780 | .loader-container .loader :nth-child(16)::before {
1781 | animation-delay: calc(0.1s * 16);
1782 | }
1783 | .loader-container .loader :nth-child(17)::before {
1784 | animation-delay: calc(0.1s * 17);
1785 | }
1786 | .loader-container .loader :nth-child(18)::before {
1787 | animation-delay: calc(0.1s * 18);
1788 | }
1789 | .loader-container .loader :nth-child(19)::before {
1790 | animation-delay: calc(0.1s * 19);
1791 | }
1792 | .loader-container .loader :nth-child(20)::before {
1793 | animation-delay: calc(0.1s * 20);
1794 | }
1795 | .loader-container .loader span::before {
1796 | content: "";
1797 | position: absolute;
1798 | top: 0;
1799 | left: 0;
1800 | width: 15px;
1801 | height: 15px;
1802 | border-radius: 50%;
1803 | background-color: var(--first-color);
1804 | box-shadow: 0 0 10px var(--first-color), 0 0 20px var(--first-color),
1805 | 0 0 40px var(--first-color), 0 0 60px var(--first-color),
1806 | 0 0 80px var(--first-color), 0 0 100px var(--first-color);
1807 | animation: animate 2s linear infinite;
1808 | animation-delay: calc();
1809 | }
1810 | .btn.show-filters-btn {
1811 | display: none;
1812 | }
1813 | @keyframes animate {
1814 | 0% {
1815 | transform: scale(1);
1816 | }
1817 | 80%,
1818 | 100% {
1819 | transform: scale(0);
1820 | }
1821 | }
1822 | @media screen and (max-width: 1066px) {
1823 | .footer-banner-container {
1824 | height: 500px;
1825 | }
1826 | .btn.show-filters-btn{
1827 | width: 180px;
1828 | font-size: 1rem;
1829 | display: inline;
1830 | }
1831 |
1832 | .banner-desc h3 {
1833 | font-size: 20px;
1834 | }
1835 | .banner-desc .right p {
1836 | display: -webkit-box;
1837 | overflow: hidden;
1838 | -webkit-line-clamp: 4;
1839 | line-clamp: 4;
1840 | -webkit-box-orient: vertical;
1841 | }
1842 |
1843 | .featured-items-container {
1844 | padding-top: 4rem;
1845 | max-width: 760px;
1846 | }
1847 | .featured-bg-text {
1848 | font-size: 10rem;
1849 | }
1850 | .featured-top-text {
1851 | /* position: absolute; */
1852 | top: 3%;
1853 | left: 4%;
1854 | font-size: 2rem;
1855 | }
1856 | .closed .products-filters {
1857 | display: none;
1858 | }
1859 | .show-filter-btn {
1860 | display: inline-block;
1861 | }
1862 | .products-container.closed {
1863 | justify-content: center;
1864 | }
1865 | /* .closed .products-filters{
1866 | display: none;
1867 | } */
1868 | }
1869 | @media screen and (max-width: 880px) {
1870 | .buttons .add-to-cart {
1871 | width: 150px;
1872 | }
1873 | .buttons .buy-now {
1874 | width: 150px;
1875 | }
1876 | .navbar-buttons-container,
1877 | .dropdown-button-text,
1878 | .dropdown-menu-container,
1879 | .login {
1880 | display: none;
1881 | }
1882 | .navbar-hamburger-container {
1883 | display: block;
1884 | }
1885 | }
1886 |
1887 | @media screen and (max-width: 768px) {
1888 | .hero-banner-container {
1889 | height: 560px;
1890 | overflow: hidden;
1891 | }
1892 | .hero-banner-image {
1893 | width: 80%;
1894 | height: 73%;
1895 | top: 12%;
1896 | right: 15%;
1897 | }
1898 |
1899 | .hero-banner-container {
1900 | line-height: 1.3;
1901 | }
1902 | .hero-banner-container h1 {
1903 | font-size: 60px;
1904 | }
1905 | .hero-banner-container h3 {
1906 | font-size: 40px;
1907 | }
1908 | .hero-banner-container button {
1909 | margin-top: 90px;
1910 | z-index: 10000;
1911 | }
1912 | .desc {
1913 | bottom: 60px;
1914 | }
1915 | .product-detail-container {
1916 | flex-wrap: wrap;
1917 | }
1918 | .product-detail-container .product-detail-image {
1919 | width: 350px;
1920 | height: 350px;
1921 | }
1922 | .image-container {
1923 | display: flex;
1924 | align-items: center;
1925 | justify-content: center;
1926 | }
1927 | .cart-container {
1928 | width: 415px;
1929 | padding: 4px;
1930 | }
1931 | .cart-heading {
1932 | margin-top: 35px;
1933 | }
1934 | .product-container {
1935 | margin-top: 10px;
1936 | }
1937 | .product {
1938 | padding: 20px 5px;
1939 | }
1940 | .checkout-product {
1941 | justify-content: space-around;
1942 | gap: 10px;
1943 | }
1944 | .product .cart-product-image {
1945 | width: 25%;
1946 | height: 25%;
1947 | }
1948 | .product-detail-container {
1949 | margin: 20px;
1950 | }
1951 |
1952 | .item-desc .flex {
1953 | width: 200px;
1954 | }
1955 | .top {
1956 | flex-wrap: wrap;
1957 | gap: 10px;
1958 | }
1959 | .item-desc .bottom {
1960 | margin-top: 30px;
1961 | }
1962 | .flex h5 {
1963 | font-size: 16px;
1964 | color: var(--text-color);
1965 | }
1966 | .flex h4 {
1967 | font-size: 16px;
1968 | }
1969 | .cart-bottom {
1970 | padding: 30px;
1971 | }
1972 |
1973 | .total h3 {
1974 | font-size: 20px;
1975 | }
1976 | .track {
1977 | animation: marquee 10s linear infinite;
1978 | width: 550%;
1979 | }
1980 | .success-wrapper,
1981 | .cancel-wrapper {
1982 | min-height: 69vh;
1983 | }
1984 | .success,
1985 | .cancel {
1986 | width: 370px;
1987 | margin-top: 100px;
1988 | padding: 20px;
1989 | }
1990 | .success {
1991 | height: 350px;
1992 | }
1993 | .success h2 {
1994 | font-size: 17px;
1995 | }
1996 | .btn-container {
1997 | width: 300px;
1998 | margin: auto;
1999 | }
2000 | .link-search-products-container {
2001 | margin: 3rem auto;
2002 | column-gap: 0.3rem;
2003 | width: fit-content;
2004 | max-width: 90%;
2005 | padding: 0.85rem;
2006 | border-radius: 15px;
2007 | flex-wrap: wrap;
2008 | }
2009 | .checkout-products {
2010 | font-size: 1.7rem;
2011 | }
2012 | .checkout-arrow-icon {
2013 | font-size: 2.8rem;
2014 | }
2015 |
2016 | .category-menu-container {
2017 | min-width: 230px;
2018 | max-width: 550px;
2019 | }
2020 |
2021 | .category-menu-item {
2022 | width: 95%;
2023 | min-width: 250px;
2024 | max-width: 550px;
2025 | }
2026 |
2027 | .category-item-image {
2028 | height: 400px;
2029 | width: 400px;
2030 | }
2031 | /* .featured-items-container{
2032 | padding-top: 4rem;
2033 | } */
2034 |
2035 | .featured-bg-text {
2036 | font-size: 10rem;
2037 | }
2038 |
2039 | .footer-banner-container {
2040 | height: 480px;
2041 | margin-top: 80px;
2042 | overflow: hidden;
2043 | }
2044 | .footer-banner-image {
2045 | width: 80%;
2046 | left: 30%;
2047 | top: 6%;
2048 | height: 59%;
2049 | }
2050 | .banner-desc .left h3 {
2051 | font-weight: 900;
2052 | font-size: 50px;
2053 | margin-left: 5px;
2054 | }
2055 | .banner-desc .left p {
2056 | margin: 18px;
2057 | }
2058 | .banner-desc .right h3 {
2059 | font-size: 35px;
2060 | }
2061 | .banner-desc .right p {
2062 | font-size: 18px;
2063 | }
2064 | .banner-desc .right .company-desc {
2065 | font-size: 14px;
2066 | }
2067 | .banner-desc {
2068 | flex-wrap: wrap;
2069 | gap: 20px;
2070 | }
2071 | .banner-desc .right p {
2072 | display: -webkit-box;
2073 | overflow: hidden;
2074 | -webkit-line-clamp: 3;
2075 | line-clamp: 3;
2076 | -webkit-box-orient: vertical;
2077 | }
2078 | .profile-container {
2079 | margin: 0.5rem auto;
2080 | margin-left: 5vw;
2081 | margin-right: 5vw;
2082 | overflow-x: scroll;
2083 | }
2084 |
2085 | .table {
2086 | width: 500px;
2087 | }
2088 | }
2089 |
2090 | /* 320-480 mobile , 481-768 tablet, 769-1024 small scr
2091 | , 1025- 1200 big stuff*/
2092 | @media screen and (max-width: 480px) {
2093 | /* .link-search-products-container{
2094 | flex-direction: column;
2095 | } */
2096 | .navbar-shop-name {
2097 | display: none;
2098 | }
2099 | .hero-banner-container {
2100 | height: 500px;
2101 | margin-bottom: 0;
2102 | }
2103 | .hero-banner-image {
2104 | width: 80%;
2105 | height: 73%;
2106 | top: 12%;
2107 | right: 5%;
2108 | }
2109 | .hero-product-name {
2110 | height: 100px;
2111 | top: 72%;
2112 | left: 10%;
2113 | font-size: 1.4rem;
2114 | /* bottom: 25%; */
2115 | }
2116 | .desc {
2117 | display: none;
2118 | }
2119 | .hero-banner-container h1 {
2120 | font-size: 50px;
2121 | }
2122 | .checkout-arrow-icon {
2123 | font-size: 2.5rem;
2124 | }
2125 |
2126 | .category-item-image {
2127 | height: 350px;
2128 | width: 350px;
2129 | }
2130 | .featured-top-text {
2131 | top: 2%;
2132 | }
2133 | .footer-banner-container {
2134 | height: 550px;
2135 | }
2136 | .banner-desc .left {
2137 | max-width: 300px;
2138 | }
2139 | .product-detail-container .product-detail-image {
2140 | width: 260px;
2141 | height: 260px;
2142 | }
2143 | .small-images-container {
2144 | gap: 7px;
2145 | margin-top: 20px;
2146 | }
2147 | .small-image {
2148 | border-radius: 8px;
2149 | width: 53px;
2150 | height: 53px;
2151 | }
2152 | .product-detail-desc h1 {
2153 | font-size: 1.4rem;
2154 | }
2155 | .product-detail-desc .buttons {
2156 | gap: 9px;
2157 | }
2158 | .buttons .add-to-cart,
2159 | .buttons .buy-now {
2160 | padding: 10px 13px;
2161 | }
2162 |
2163 | .cart-container {
2164 | width: 325px;
2165 | }
2166 |
2167 | .product-container {
2168 | max-height: 70vh;
2169 | padding: 10px 5px;
2170 | max-width: 95vw;
2171 | margin-left: auto;
2172 | }
2173 | .product {
2174 | gap: 10px;
2175 | padding: 10px;
2176 | }
2177 |
2178 | .btn-container {
2179 | width: 210px;
2180 | }
2181 | .cart-bottom {
2182 | padding: 65px;
2183 | }
2184 | .quantity-desc span {
2185 | padding: 6px 6px;
2186 | }
2187 | .item-desc .flex {
2188 | width: 160px;
2189 | }
2190 | .products-container {
2191 | justify-content: center;
2192 | }
2193 | }
2194 | @media screen and (max-width: 327px) {
2195 | .hero-product-name {
2196 | left: 15%;
2197 | font-size: 1.2rem;
2198 | }
2199 |
2200 | .right-icon,
2201 | .left-icon {
2202 | font-size: 2.5rem;
2203 | }
2204 | .right-icon {
2205 | top: 45%;
2206 | }
2207 |
2208 | .left-icon {
2209 | top: 55%;
2210 | }
2211 |
2212 | .link-search-products-container {
2213 | width: 190px;
2214 | }
2215 | .checkout-arrow-icon {
2216 | font-size: 2.6rem;
2217 | }
2218 | }
2219 |
--------------------------------------------------------------------------------