├── public ├── robots.txt ├── favicon.ico ├── favicon-16x16.png ├── favicon-32x32.png ├── maskable_icon.png ├── apple-touch-icon.png ├── android-chrome-192x192.png └── android-chrome-512x512.png ├── src ├── assets │ ├── Blog1.webp │ ├── Blog2.webp │ ├── Blog3.webp │ ├── light1.webp │ ├── light2.webp │ ├── instaGram1.webp │ ├── instaGram2.webp │ ├── instaGram3.webp │ ├── instaGram4.webp │ ├── basketChair.webp │ ├── undraw_search_engine.svg │ └── undraw_empty_cart.svg ├── components │ ├── Error.jsx │ ├── Loading.jsx │ ├── ProductsHome.jsx │ ├── Logo.jsx │ ├── View_button.jsx │ ├── Breadcrumb.jsx │ ├── Product_title.jsx │ ├── ProductImage.jsx │ ├── AllProducts.jsx │ ├── Grid_view_products.jsx │ ├── ProductGrid.jsx │ ├── CollectionProducts.jsx │ ├── Empty_cart.jsx │ ├── List_view_products.jsx │ ├── NotFound.jsx │ ├── ProductCategory.jsx │ ├── Stars.jsx │ ├── Basket.jsx │ ├── Header.jsx │ ├── Stripe_Checkout.jsx │ ├── Instagram.jsx │ ├── ProductImages.jsx │ ├── Cart_Button.jsx │ ├── CategoryProducts.jsx │ ├── Navbar.jsx │ ├── Sidebar.jsx │ ├── index.jsx │ ├── Sort.jsx │ ├── Order_summary.jsx │ ├── CheckoutForm.jsx │ ├── HomeProduct.jsx │ ├── AddToCart.jsx │ ├── Footer.jsx │ ├── Filters.jsx │ ├── CartItems.jsx │ └── Sidebar_Filter.jsx ├── pages │ ├── Checkout.jsx │ ├── News.jsx │ ├── Features.jsx │ ├── Services.jsx │ ├── ProtectedRoute.jsx │ ├── Cart.jsx │ ├── index.jsx │ ├── Error.jsx │ ├── Home.jsx │ ├── Products.jsx │ ├── Completion.jsx │ ├── SingleProduct.jsx │ └── ui-script.js ├── utils │ ├── helper.jsx │ └── constants.jsx ├── index.css ├── main.jsx ├── actions │ └── actions.jsx ├── App.jsx ├── context │ ├── cart │ │ └── cart_context.jsx │ ├── product │ │ └── products_context.jsx │ └── filter │ │ └── filter_context.jsx ├── reducers │ ├── product │ │ └── products_reducer.jsx │ ├── cart │ │ └── cart_reducer.jsx │ └── filter │ │ └── filter_reducer.jsx └── app.css ├── postcss.config.cjs ├── dev-dist ├── registerSW.js ├── sw.js ├── workbox-7369c0e1.js ├── workbox-3625d7b0.js ├── workbox-519d0965.js └── workbox-68741b2f.js ├── netlify.toml ├── .gitignore ├── tailwind.config.cjs ├── functions ├── single-product.js ├── stripe-payment-intent.js └── products.js ├── LICENSE ├── package.json ├── vite.config.js ├── index.html └── README.MD /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/Blog1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/src/assets/Blog1.webp -------------------------------------------------------------------------------- /src/assets/Blog2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/src/assets/Blog2.webp -------------------------------------------------------------------------------- /src/assets/Blog3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/src/assets/Blog3.webp -------------------------------------------------------------------------------- /src/assets/light1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/src/assets/light1.webp -------------------------------------------------------------------------------- /src/assets/light2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/src/assets/light2.webp -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/maskable_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/public/maskable_icon.png -------------------------------------------------------------------------------- /src/assets/instaGram1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/src/assets/instaGram1.webp -------------------------------------------------------------------------------- /src/assets/instaGram2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/src/assets/instaGram2.webp -------------------------------------------------------------------------------- /src/assets/instaGram3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/src/assets/instaGram3.webp -------------------------------------------------------------------------------- /src/assets/instaGram4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/src/assets/instaGram4.webp -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/public/apple-touch-icon.png -------------------------------------------------------------------------------- /src/assets/basketChair.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/src/assets/basketChair.webp -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/galaxyxyz5/E-Commerce-Web/HEAD/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /dev-dist/registerSW.js: -------------------------------------------------------------------------------- 1 | if('serviceWorker' in navigator) navigator.serviceWorker.register('/dev-sw.js?dev-sw', { scope: '/', type: 'classic' }) -------------------------------------------------------------------------------- /src/components/Error.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | const Error = () => { 4 | return
There was an error... Please try again!
5 | } 6 | 7 | export default Error 8 | -------------------------------------------------------------------------------- /src/pages/Checkout.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Stripe_Checkout } from "../components" 3 | 4 | const Checkout = () => { 5 | return ( 6 | <> 7 |
8 | 9 |
10 | 11 | ) 12 | } 13 | 14 | export default Checkout 15 | -------------------------------------------------------------------------------- /src/components/Loading.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { CgSpinner } from "react-icons/cg" 3 | const Loading = () => { 4 | return ( 5 |
6 | {" "} 7 | {" "} 8 |
9 | ) 10 | } 11 | 12 | export default Loading 13 | -------------------------------------------------------------------------------- /src/pages/News.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Breadcrumb } from "../components" 3 | 4 | const News = () => { 5 | return ( 6 |
7 | 8 |

9 | Coming Soon... 10 |

11 |
12 | ) 13 | } 14 | 15 | export default News 16 | -------------------------------------------------------------------------------- /src/pages/Features.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Breadcrumb } from "../components" 3 | 4 | const Features = () => { 5 | return ( 6 |
7 | 8 |

9 | Coming Soon... 10 |

11 |
12 | ) 13 | } 14 | 15 | export default Features 16 | -------------------------------------------------------------------------------- /src/pages/Services.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Breadcrumb } from "../components" 3 | 4 | const Services = () => { 5 | return ( 6 |
7 | 8 |

9 | Coming Soon... 10 |

11 |
12 | ) 13 | } 14 | 15 | export default Services 16 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | functions = "./functions" 3 | 4 | [[redirects]] 5 | from = "/*" 6 | to = "/index.html" 7 | status = 200 8 | 9 | [[headers]] 10 | for = "/manifest.webmanifest" 11 | [headers.values] 12 | Content-Type = "application/manifest+json" 13 | 14 | [[headers]] 15 | for = "/assets/*" 16 | [headers.values] 17 | cache-control = ''' 18 | max-age=31536000, 19 | immutable 20 | ''' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | .env 11 | node_modules 12 | dist 13 | dist-ssr 14 | *.local 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | 27 | # Local Netlify folder 28 | .netlify 29 | -------------------------------------------------------------------------------- /src/pages/ProtectedRoute.jsx: -------------------------------------------------------------------------------- 1 | import { useAuth0 } from "@auth0/auth0-react" 2 | import React from "react" 3 | import { Navigate } from "react-router-dom" 4 | 5 | const ProtectedRoute = ({ children }) => { 6 | const { user, isLoading } = useAuth0() 7 | if (isLoading) return
Loading...
8 | if (!user) { 9 | return 10 | } 11 | return children 12 | } 13 | 14 | export default ProtectedRoute 15 | -------------------------------------------------------------------------------- /src/components/ProductsHome.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import FiltersComponent from './Filters' 3 | import AllProducts from './AllProducts' 4 | 5 | const ProductsHome = () => { 6 | return ( 7 | <> 8 |
9 | 10 | 11 |
12 | 13 | ) 14 | } 15 | 16 | export default ProductsHome -------------------------------------------------------------------------------- /src/utils/helper.jsx: -------------------------------------------------------------------------------- 1 | export const formatPrice = (number) => { 2 | const newNumber = Intl.NumberFormat("en-US", { 3 | style: "currency", 4 | currency: "INR", 5 | }).format(number) 6 | return newNumber 7 | } 8 | 9 | export const getUniqueValues = (data, type) => { 10 | let dataMap = data.map((item) => item[type]) 11 | if (type === "colors") { 12 | dataMap = dataMap.flat() 13 | } 14 | return ["all", ...new Set(dataMap)] 15 | } -------------------------------------------------------------------------------- /tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"], 4 | theme: { 5 | screens: { 6 | sm: "480px", 7 | md: "768px", 8 | lg: "976px", 9 | xl: "1440px", 10 | }, 11 | extend: { 12 | colors: { 13 | primary: "#48c4a0", 14 | }, 15 | }, 16 | }, 17 | plugins: [require("@tailwindcss/forms")], 18 | } -------------------------------------------------------------------------------- /src/pages/Cart.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Breadcrumb, CartItems } from "../components" 3 | import { useCartContext } from "../context/cart/cart_context" 4 | import { Empty_cart } from "../components" 5 | 6 | const Cart = () => { 7 | const { cart } = useCartContext() 8 | if (cart.length === 0) return 9 | return ( 10 | <> 11 | 12 | 13 | 14 | ) 15 | } 16 | 17 | export default Cart 18 | -------------------------------------------------------------------------------- /src/components/Logo.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link } from "react-router-dom" 3 | 4 | const Logo = ({ className }) => { 5 | return ( 6 | 7 |

10 | Shoptik 11 | 12 |

13 | 14 | ) 15 | } 16 | 17 | export default Logo 18 | -------------------------------------------------------------------------------- /src/components/View_button.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link } from "react-router-dom" 3 | 4 | const View_button = ({ title, className }) => { 5 | return ( 6 | <> 7 |
8 | 11 | {title} 12 | 13 |
14 | 15 | ) 16 | } 17 | 18 | export default View_button 19 | -------------------------------------------------------------------------------- /src/components/Breadcrumb.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link } from "react-router-dom" 3 | 4 | const Breadcrumb = ({ title, product }) => { 5 | return ( 6 | <> 7 |
8 |

9 | Home 10 | {product && / Products } / {title} 11 |

12 |
13 | 14 | ) 15 | } 16 | 17 | export default Breadcrumb 18 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400;500;700;900&display=swap'); 2 | 3 | @layer base { 4 | body { 5 | font-family: 'Roboto', sans-serif; 6 | letter-spacing: .05em 7 | } 8 | input[type="number"]::-webkit-inner-spin-button, 9 | input[type="number"]::-webkit-outer-spin-button { 10 | -webkit-appearance: none; 11 | margin: 0; 12 | } 13 | .scrollbar-hide::-webkit-scrollbar { 14 | display: none; 15 | } 16 | } 17 | 18 | 19 | @tailwind base; 20 | @tailwind components; 21 | @tailwind utilities; -------------------------------------------------------------------------------- /src/utils/constants.jsx: -------------------------------------------------------------------------------- 1 | export const navLinks = [ 2 | { 3 | id: 1, 4 | title: "home", 5 | url: "/", 6 | }, 7 | { 8 | id: 2, 9 | title: "shop", 10 | url: "/shop", 11 | }, 12 | { 13 | id: 3, 14 | title: "features", 15 | url: "/features", 16 | }, 17 | { 18 | id: 4, 19 | title: "services", 20 | url: "/services", 21 | }, 22 | { 23 | id: 5, 24 | title: "news", 25 | url: "/news", 26 | }, 27 | ] 28 | 29 | export const products_url = ".netlify/functions/products" 30 | export const single_product_url = `/.netlify/functions/single-product?id=` 31 | -------------------------------------------------------------------------------- /src/pages/index.jsx: -------------------------------------------------------------------------------- 1 | import Cart from "./Cart" 2 | import Checkout from "./Checkout" 3 | import Completion from "./Completion" 4 | import Error from "./Error" 5 | import Features from "./Features" 6 | import Home from "./Home" 7 | import News from "./News" 8 | import Products from "./Products" 9 | import ProtectedRoute from "./ProtectedRoute" 10 | import Services from "./Services" 11 | import SingleProduct from "./SingleProduct" 12 | 13 | export { 14 | Features, 15 | Services, 16 | News, 17 | Completion, 18 | Cart, 19 | Checkout, 20 | Error, 21 | Home, 22 | Products, 23 | SingleProduct, 24 | ProtectedRoute, 25 | } 26 | -------------------------------------------------------------------------------- /src/components/Product_title.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link } from "react-router-dom" 3 | import { formatPrice } from "../utils/helper" 4 | 5 | const Product_title = ({ product, className }) => { 6 | const { name, price, id } = product 7 | return ( 8 | <> 9 |
10 | 14 | {" "} 15 | {name} 16 | 17 |

{formatPrice(price)}

18 |
19 | 20 | ) 21 | } 22 | 23 | export default Product_title 24 | -------------------------------------------------------------------------------- /src/components/ProductImage.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link } from "react-router-dom" 3 | 4 | const ProductImage = ({ product, className }) => { 5 | const { image, name, id } = product 6 | return ( 7 | <> 8 | 9 |
10 | {name} 17 |
18 | 19 | 20 | ) 21 | } 22 | 23 | export default ProductImage 24 | -------------------------------------------------------------------------------- /src/components/AllProducts.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { useProductsContext } from "../context/product/products_context" 3 | import { 4 | Loading, 5 | Error, 6 | Grid_view_products, 7 | List_view_products, 8 | } from "../components" 9 | import { useFilterContext } from "../context/filter/filter_context" 10 | 11 | const AllProducts = () => { 12 | const { products_loading, products_error } = useProductsContext() 13 | const { filtered_products: products, grid_view } = useFilterContext() 14 | 15 | if (products_loading) return 16 | if (products_error) return 17 | if (grid_view === false) return 18 | 19 | return ( 20 | <> 21 | 22 | 23 | ) 24 | } 25 | 26 | export default AllProducts 27 | -------------------------------------------------------------------------------- /src/components/Grid_view_products.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { ProductImage, Product_title } from "../components" 3 | const Grid_view_products = ({ products }) => { 4 | return ( 5 | <> 6 |
7 | {products.map((product) => { 8 | const { id } = product 9 | return ( 10 |
11 | 15 | 19 |
20 | ) 21 | })} 22 |
23 | 24 | ) 25 | } 26 | 27 | export default Grid_view_products 28 | -------------------------------------------------------------------------------- /src/components/ProductGrid.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { CollectionProducts } from "../components" 3 | import { useProductsContext } from "../context/product/products_context" 4 | 5 | const ProductGrid = () => { 6 | const { featured_products, newArrival_products, bestSeller_products } = 7 | useProductsContext() 8 | 9 | return ( 10 |
11 | {/* Bestseller */} 12 | 13 | 14 | {/* New Arrival */} 15 | 16 | 17 | {/* Featured Products */} 18 | 19 |
20 | ) 21 | } 22 | 23 | export default ProductGrid 24 | -------------------------------------------------------------------------------- /src/pages/Error.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link } from "react-router-dom" 3 | import PageNotFound from "../assets/undraw_page_not_found.svg" 4 | 5 | const Error = () => { 6 | return ( 7 | <> 8 |
9 | Page not found 10 |
11 |

Page Not Found

12 |

13 | The page you're looking for does not seem to exist. 14 |

15 | 19 | {" "} 20 | Go to home{" "} 21 | 22 |
23 |
24 | 25 | ) 26 | } 27 | 28 | export default Error 29 | -------------------------------------------------------------------------------- /src/components/CollectionProducts.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { ProductImage, Product_title } from "../components" 3 | 4 | const CollectionProducts = ({ products, title }) => { 5 | return ( 6 | <> 7 |
8 |

9 | {" "} 10 | {title}{" "} 11 |

12 |
13 | {products.slice(0, 3).map((product) => { 14 | const { id } = product 15 | return ( 16 |
20 | 21 | 22 |
23 | ) 24 | })} 25 |
26 | 27 | ) 28 | } 29 | 30 | export default CollectionProducts 31 | -------------------------------------------------------------------------------- /src/components/Empty_cart.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Empty_Cart_Image from "../assets/undraw_empty_cart.svg" 3 | import { Link } from "react-router-dom" 4 | 5 | const Empty_cart = () => { 6 | return ( 7 |
8 | 9 |
10 |

Your cart is empty.

11 |

12 | Looks like you have not added anything to your cart. 13 |

14 | 18 | {" "} 19 | Add items{" "} 20 | 21 |
22 |
23 | ) 24 | } 25 | 26 | export default Empty_cart 27 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import { Auth0Provider } from "@auth0/auth0-react" 2 | import React from "react" 3 | import ReactDOM from "react-dom/client" 4 | import App from "./App" 5 | import { CartProvider } from "./context/cart/cart_context" 6 | import { FiltersProvider } from "./context/filter/filter_context" 7 | import { ProductsProvider } from "./context/product/products_context" 8 | import "./index.css" 9 | ReactDOM.createRoot(document.getElementById("root")).render( 10 | 11 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | ) 29 | -------------------------------------------------------------------------------- /functions/single-product.js: -------------------------------------------------------------------------------- 1 | import dotenv from "dotenv" 2 | dotenv.config() 3 | 4 | import Airtable from "airtable-node" 5 | 6 | 7 | const airtable = new Airtable({ apiKey: process.env.AIRTABLE_API_KEY }) 8 | .base(process.env.AIRTABLE_BASE) 9 | .table(process.env.AIRTABLE_TABLE) 10 | 11 | exports.handler = async (event, context, cb) => { 12 | const { id } = event.queryStringParameters 13 | if (id) { 14 | try { 15 | let product = await airtable.retrieve(id) 16 | if (product.error) { 17 | return { 18 | statusCode: 404, 19 | body: `No product with id: ${id}`, 20 | } 21 | } 22 | product = { id: product.id, ...product.fields } 23 | return { 24 | statusCode: 200, 25 | body: JSON.stringify(product), 26 | } 27 | } catch (error) { 28 | return { 29 | statusCode: 500, 30 | body: `Server Error`, 31 | } 32 | } 33 | } 34 | return { 35 | statusCode: 400, 36 | body: "Please provide product id", 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/components/List_view_products.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { ProductImage, Product_title } from "../components" 3 | 4 | const List_view_products = ({ products }) => { 5 | return ( 6 | <> 7 |
8 | {products.map((product) => { 9 | const { id } = product 10 | return ( 11 |
15 | 19 |
20 | 21 |
22 |
23 | ) 24 | })} 25 |
26 | 27 | ) 28 | } 29 | 30 | export default List_view_products 31 | -------------------------------------------------------------------------------- /src/components/NotFound.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import NotFoundProduct from "../assets/undraw_search_engine.svg" 3 | import { useFilterContext } from "../context/filter/filter_context" 4 | const NotFound = () => { 5 | const { 6 | filters: { text }, 7 | } = useFilterContext() 8 | return ( 9 |
10 |

11 | {" "} 12 | You searched for 13 | {text} {" "} 14 |

15 | 16 |
17 |

18 | {" "} 19 | We could't find any matches!{" "} 20 |

21 |

22 | Please check the spelling or try searching something else 23 |

24 |
25 |
26 | ) 27 | } 28 | 29 | export default NotFound 30 | -------------------------------------------------------------------------------- /src/components/ProductCategory.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { useProductsContext } from "../context/product/products_context" 3 | import { CategoryProducts } from "../components" 4 | const ProductCategory = () => { 5 | const { products } = useProductsContext() 6 | 7 | const all_Decoration_products = products.filter( 8 | (product) => product.category === "decoration" 9 | ) 10 | const all_Architect_products = products.filter( 11 | (product) => product.category === "architect" 12 | ) 13 | 14 | return ( 15 | <> 16 |
17 |
18 | 22 | 26 |
27 |
28 | 29 | ) 30 | } 31 | 32 | export default ProductCategory 33 | -------------------------------------------------------------------------------- /src/pages/Home.jsx: -------------------------------------------------------------------------------- 1 | import React, { Suspense, lazy } from "react" 2 | 3 | import { useProductsContext } from "../context/product/products_context" 4 | import { Loading } from "../components" 5 | 6 | const HomeProduct = lazy(() => import("../components/HomeProduct")) 7 | const BasketProduct = lazy(() => import("../components/Basket")) 8 | const Header = lazy(() => import("../components/Header")) 9 | const Instagram = lazy(() => import("../components/Instagram")) 10 | const ProductCategory = lazy(() => import("../components/ProductCategory")) 11 | const ProductGrid = lazy(() => import("../components/ProductGrid")) 12 | 13 | const Home = () => { 14 | const { products_loading: loading } = useProductsContext() 15 | if (loading) return 16 | return ( 17 | <> 18 | }> 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ) 28 | } 29 | 30 | export default Home 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Kumar Avishek (Saurav) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/components/Stars.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { BsStarFill, BsStarHalf, BsStar } from "react-icons/bs" 3 | 4 | const Stars = ({ stars, reviews }) => { 5 | const tempStars = Array.from({ length: 5 }, (_, index) => { 6 | const number = index + 0.5 7 | return ( 8 | 9 | {stars > number ? ( 10 | 11 | ) : stars > index ? ( 12 | 13 | ) : ( 14 | 15 | )} 16 | 17 | ) 18 | }) 19 | 20 | return ( 21 |
22 |

23 | 24 | {" "} 25 | {tempStars} 26 | {" "} 27 | {stars} 28 |

29 |

{reviews} Reviews

30 |
31 | ) 32 | } 33 | 34 | export default Stars 35 | -------------------------------------------------------------------------------- /src/components/Basket.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import BasketImage from "../assets/basketChair.webp" 3 | import { View_button } from "../components" 4 | 5 | const Basket = () => { 6 | return ( 7 |
8 |
9 | {/* Mobile image */} 10 | Basket chair 17 |

18 | {" "} 19 | Stylish minimal chair 20 |

21 | 22 |
23 | {/* XL Image */} 24 | 29 |
30 | ) 31 | } 32 | 33 | export default Basket -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Shoptik-ecommerce-web-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite ", 8 | "start": "netlify dev --targetPort 5173 ", 9 | "netlify": "netlify dev", 10 | "build": "vite build", 11 | "preview": "vite preview" 12 | }, 13 | "dependencies": { 14 | "@auth0/auth0-react": "^2.0.0", 15 | "@stripe/react-stripe-js": "^1.16.4", 16 | "@stripe/stripe-js": "^1.46.0", 17 | "airtable-node": "^0.1.20", 18 | "axios": "^1.2.5", 19 | "dotenv": "^16.0.3", 20 | "react": "^18.2.0", 21 | "react-dom": "^18.2.0", 22 | "react-ga4": "^2.1.0", 23 | "react-icons": "^4.4.0", 24 | "react-router-dom": "^6.4.2", 25 | "stripe": "^11.11.0" 26 | }, 27 | "devDependencies": { 28 | "@tailwindcss/forms": "^0.5.3", 29 | "@types/react": "^18.0.17", 30 | "@types/react-dom": "^18.0.6", 31 | "@vitejs/plugin-react": "^2.1.0", 32 | "autoprefixer": "^10.4.12", 33 | "netlify-cli": "^12.9.2", 34 | "postcss": "^8.4.17", 35 | "prettier": "^2.8.4", 36 | "prettier-plugin-tailwindcss": "^0.2.4", 37 | "tailwindcss": "^3.1.8", 38 | "vite": "^3.1.0", 39 | "vite-plugin-pwa": "^0.15.0", 40 | "workbox-build": "^6.5.4", 41 | "workbox-window": "^6.5.4" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/pages/Products.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react" 2 | import { 3 | Breadcrumb, 4 | Filters, 5 | AllProducts, 6 | Sort, 7 | NotFound, 8 | Sidebar_Filter, 9 | Loading, 10 | } from "../components" 11 | import { useFilterContext } from "../context/filter/filter_context" 12 | import { useProductsContext } from "../context/product/products_context" 13 | import ReactGA from "react-ga4" 14 | const Products = () => { 15 | const { filtered_products: products } = useFilterContext() 16 | const { products_loading } = useProductsContext() 17 | if (products_loading) return 18 | 19 | useEffect(() => { 20 | ReactGA.send({ 21 | hitType: "pageView", 22 | page: window.location.pathname, 23 | title: "Shop page", 24 | }) 25 | }) 26 | return ( 27 | <> 28 | 29 |
30 | 31 |
32 | {products.length < 1 && } 33 | {products.length >= 1 && } 34 | 35 |
36 | {/* Sidebar filter */} 37 | 38 |
39 | 40 | ) 41 | } 42 | 43 | export default Products 44 | -------------------------------------------------------------------------------- /src/actions/actions.jsx: -------------------------------------------------------------------------------- 1 | // Sidebar actions 2 | export const SIDEBAR_OPEN = "SIDEBAR_OPEN" 3 | export const SIDEBAR_CLOSE = "SIDEBAR_CLOSE" 4 | 5 | // All products actions 6 | export const GET_PRODUCTS_BEGIN = "GET_PRODUCTS_BEGIN" 7 | export const GET_PRODUCTS_SUCCESS = "GET_PRODUCTS_SUCCESS" 8 | export const GET_PRODUCTS_ERROR = "GET_PRODUCTS_ERROR" 9 | 10 | // Single products actions 11 | export const GET_SINGLE_PRODUCT_BEGIN = "GET_SINGLE_PRODUCT_BEGIN" 12 | export const GET_SINGLE_PRODUCT_SUCCESS = "GET_SINGLE_PRODUCT_SUCCESS" 13 | export const GET_SINGLE_PRODUCT_ERROR = "GET_SINGLE_PRODUCT_ERROR" 14 | 15 | export const LOAD_PRODUCTS = "LOAD_PRODUCTS" 16 | 17 | // View actions 18 | export const SET_GRID_VIEW = "SET_GRID_VIEW" 19 | export const SET_LIST_VIEW = "SET_LIST_VIEW" 20 | 21 | // Filter actions 22 | export const UPDATE_SORT = "UPDATE_SORT" 23 | export const SORT_PRODUCTS = "SORT_PRODUCTS" 24 | export const UPDATE_FILTERS = "UPDATE_FILTERS" 25 | export const FILTER_PRODUCTS = "FILTER_PRODUCTS" 26 | export const CLEAR_FILTERS = "CLEAR_FILTERS" 27 | 28 | // Cart actions 29 | export const ADD_TO_CART = "ADD_TO_CART" 30 | export const REMOVE_CART_ITEM = "REMOVE_CART_ITEM" 31 | export const TOGGLE_CART_ITEM_AMOUNT = "TOGGLE_CART_ITEM_AMOUNT" 32 | export const CLEAR_CART = "CLEAR_CART" 33 | export const COUNT_CART_TOTALS = "COUNT_CART_TOTALS" 34 | -------------------------------------------------------------------------------- /functions/stripe-payment-intent.js: -------------------------------------------------------------------------------- 1 | import dotenv from "dotenv" 2 | dotenv.config() 3 | // Connect to the Stripe payment system 4 | import Stripe from "stripe" 5 | const stripe = new Stripe(process.env.VITE_STRIPE_SECRET_KEY) 6 | 7 | exports.handler = async (event, context) => { 8 | const { shipping_fee, total_amount } = JSON.parse(event.body) 9 | const calculateOrderAmount = () => { 10 | // Calculate the order total on the server to prevent 11 | // people from directly manipulating the amount on the client 12 | return (shipping_fee + total_amount) * 100 13 | } 14 | try { 15 | // Create a PaymentIntent with the order amount and currency 16 | const paymentIntent = await stripe.paymentIntents.create({ 17 | amount: calculateOrderAmount(), 18 | currency: "INR", 19 | description: "product name", 20 | shipping: { 21 | name: "user name", 22 | address: { 23 | line1: "510 Townsend St", 24 | postal_code: "98140", 25 | city: "San Francisco", 26 | state: "CA", 27 | country: "US", 28 | }, 29 | }, 30 | }) 31 | 32 | return { 33 | statusCode: 200, 34 | body: JSON.stringify({ clientSecret: paymentIntent.client_secret }), 35 | } 36 | } catch (error) { 37 | return { 38 | statusCode: 500, 39 | body: JSON.stringify({ error: error.message }), 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/components/Header.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Light1 from "../assets/light1.webp" 3 | import Light2 from "../assets/light2.webp" 4 | import { View_button } from "../components" 5 | const Header = () => { 6 | return ( 7 |
8 |
9 |
10 |

11 | {" "} 12 | Shoptik Number #1Trusted 13 | furniture website.{" "} 14 |

15 |

16 | coming soon in your door with a huge discount. 17 |

18 |
19 | 20 |
21 | 26 | 31 |
32 | ) 33 | } 34 | 35 | export default Header -------------------------------------------------------------------------------- /src/components/Stripe_Checkout.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react" 2 | import { loadStripe } from "@stripe/stripe-js" 3 | import { useCartContext } from "../context/cart/cart_context" 4 | import CardStyle from "../app.css" 5 | import axios from "axios" 6 | import { Elements } from "@stripe/react-stripe-js" 7 | import CheckoutForm from "./CheckoutForm" 8 | 9 | const stripePromise = loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY) 10 | 11 | const Stripe_Checkout = () => { 12 | const { cart, total_amount, shipping_fee } = useCartContext() 13 | // Stripe Stuff 14 | const [clientSecret, setClientSecret] = useState("") 15 | 16 | const createPaymentIntent = async () => { 17 | try { 18 | const { data } = await axios.post( 19 | "/.netlify/functions/stripe-payment-intent", 20 | JSON.stringify({ cart, shipping_fee, total_amount }) 21 | ) 22 | setClientSecret(data.clientSecret) 23 | } catch (error) { 24 | // console.log(error.response) 25 | } 26 | } 27 | 28 | const appearance = { 29 | theme: "stripe", 30 | } 31 | const options = { 32 | clientSecret, 33 | appearance, 34 | } 35 | 36 | useEffect(() => { 37 | createPaymentIntent() 38 | }, []) 39 | 40 | return ( 41 |
42 | {clientSecret && ( 43 | 44 | 45 | 46 | )} 47 |
48 | ) 49 | } 50 | 51 | export default Stripe_Checkout 52 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import { Navbar, Footer } from "./components" 2 | import { BrowserRouter, Route, Routes } from "react-router-dom" 3 | import { 4 | Home, 5 | Cart, 6 | Products, 7 | SingleProduct, 8 | Error, 9 | Checkout, 10 | ProtectedRoute, 11 | Completion, 12 | Features, 13 | Services, 14 | News, 15 | } from "./pages" 16 | import ReactGA from "react-ga4" 17 | const measurementID = "G-Y1EV1Q38PH" 18 | ReactGA.initialize(measurementID) 19 | function App() { 20 | return ( 21 | 22 | 23 | 24 | } /> 25 | } /> 26 | } /> 27 | } /> 28 | 32 | {" "} 33 | {" "} 34 | 35 | } 36 | /> 37 | 41 | {" "} 42 | {" "} 43 | 44 | } 45 | /> 46 | 47 | } /> 48 | } /> 49 | } /> 50 | } /> 51 | 52 |