├── public ├── p1.png ├── p2.png ├── p3.png ├── p4.png ├── p5.png ├── p6.png ├── p7.png ├── favicon.ico ├── slide-1.png ├── slide-2.png ├── slide-3.png ├── empty-cart.jpg ├── product-1.webp ├── start-black.svg ├── start-black2.svg ├── start-gold.svg ├── start-gray.svg ├── logo.svg └── spinner.svg ├── jsconfig.json ├── postcss.config.js ├── utils ├── urls.js ├── helper.js └── api.js ├── .eslintrc.json ├── pages ├── api │ └── hello.js ├── _document.js ├── failed.js ├── success.js ├── _app.js ├── index.js ├── category │ └── [slug].js ├── cart.js └── product │ └── [slug].js ├── store ├── store.js └── cartSlice.js ├── next.config.js ├── components ├── Wrapper.jsx ├── RelatedProducts.jsx ├── ProductDetailsCarousel.jsx ├── ProductCard.jsx ├── HeroBanner.jsx ├── Menu.jsx ├── MenuMobile.jsx ├── Header.jsx ├── CartItem.jsx └── Footer.jsx ├── .gitignore ├── tailwind.config.js ├── package.json ├── README.md └── styles └── globals.css /public/p1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShariqAnsari88/shoe-store-frontend/HEAD/public/p1.png -------------------------------------------------------------------------------- /public/p2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShariqAnsari88/shoe-store-frontend/HEAD/public/p2.png -------------------------------------------------------------------------------- /public/p3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShariqAnsari88/shoe-store-frontend/HEAD/public/p3.png -------------------------------------------------------------------------------- /public/p4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShariqAnsari88/shoe-store-frontend/HEAD/public/p4.png -------------------------------------------------------------------------------- /public/p5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShariqAnsari88/shoe-store-frontend/HEAD/public/p5.png -------------------------------------------------------------------------------- /public/p6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShariqAnsari88/shoe-store-frontend/HEAD/public/p6.png -------------------------------------------------------------------------------- /public/p7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShariqAnsari88/shoe-store-frontend/HEAD/public/p7.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShariqAnsari88/shoe-store-frontend/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/slide-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShariqAnsari88/shoe-store-frontend/HEAD/public/slide-1.png -------------------------------------------------------------------------------- /public/slide-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShariqAnsari88/shoe-store-frontend/HEAD/public/slide-2.png -------------------------------------------------------------------------------- /public/slide-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShariqAnsari88/shoe-store-frontend/HEAD/public/slide-3.png -------------------------------------------------------------------------------- /public/empty-cart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShariqAnsari88/shoe-store-frontend/HEAD/public/empty-cart.jpg -------------------------------------------------------------------------------- /public/product-1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShariqAnsari88/shoe-store-frontend/HEAD/public/product-1.webp -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /utils/urls.js: -------------------------------------------------------------------------------- 1 | export const STRAPI_API_TOKEN = process.env.NEXT_PUBLIC_STRAPI_API_TOKEN; 2 | 3 | export const API_URL = 4 | process.env.NEXT_PUBLIC_API_URL || "http://127.0.0.1:1337"; 5 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals", 3 | "rules": { 4 | "react/no-unescaped-entities": "off", 5 | "@next/next/no-page-custom-font": "off" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /pages/api/hello.js: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | 3 | export default function handler(req, res) { 4 | res.status(200).json({ name: 'John Doe' }) 5 | } 6 | -------------------------------------------------------------------------------- /store/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | import cartSlice from "./cartSlice"; 3 | 4 | export default configureStore({ 5 | reducer: { 6 | cart: cartSlice, 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /public/start-black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/start-black2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/start-gold.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/start-gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | images: { 8 | domains: ["res.cloudinary.com"], 9 | }, 10 | }; 11 | 12 | module.exports = nextConfig; 13 | -------------------------------------------------------------------------------- /pages/_document.js: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from 'next/document' 2 | 3 | export default function Document() { 4 | return ( 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /utils/helper.js: -------------------------------------------------------------------------------- 1 | export const getDiscountedPricePercentage = ( 2 | originalPrice, 3 | discountedPrice 4 | ) => { 5 | const discount = originalPrice - discountedPrice; 6 | 7 | const discountPercentage = (discount / originalPrice) * 100; 8 | 9 | return discountPercentage.toFixed(2); 10 | }; 11 | -------------------------------------------------------------------------------- /components/Wrapper.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Wrapper = ({ children, className }) => { 4 | return ( 5 |
10 | {children} 11 |
12 | ); 13 | }; 14 | 15 | export default Wrapper; 16 | -------------------------------------------------------------------------------- /.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 | 32 | # vercel 33 | .vercel 34 | -------------------------------------------------------------------------------- /public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./app/**/*.{js,ts,jsx,tsx}", 5 | "./pages/**/*.{js,ts,jsx,tsx}", 6 | "./components/**/*.{js,ts,jsx,tsx}", 7 | 8 | // Or if using `src` directory: 9 | "./src/**/*.{js,ts,jsx,tsx}", 10 | ], 11 | theme: { 12 | fontFamily: { 13 | oswald: "Oswald, sans-serif", 14 | urbanist: "Urbanist, sans-serif", 15 | }, 16 | extend: {}, 17 | }, 18 | plugins: [], 19 | }; 20 | -------------------------------------------------------------------------------- /utils/api.js: -------------------------------------------------------------------------------- 1 | import { API_URL, STRAPI_API_TOKEN } from "./urls"; 2 | 3 | export const fetchDataFromApi = async (endpoint) => { 4 | const options = { 5 | method: "GET", 6 | headers: { 7 | Authorization: "Bearer " + STRAPI_API_TOKEN, 8 | }, 9 | }; 10 | 11 | const res = await fetch(`${API_URL}${endpoint}`, options); 12 | const data = await res.json(); 13 | 14 | return data; 15 | }; 16 | 17 | export const makePaymentRequest = async (endpoint, payload) => { 18 | const res = await fetch(`${API_URL}${endpoint}`, { 19 | method: "POST", 20 | headers: { 21 | Authorization: "Bearer " + STRAPI_API_TOKEN, 22 | "Content-Type": "application/json", 23 | }, 24 | body: JSON.stringify(payload), 25 | }); 26 | const data = await res.json(); 27 | return data; 28 | }; 29 | -------------------------------------------------------------------------------- /public/spinner.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pages/failed.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Wrapper from "@/components/Wrapper"; 3 | import Link from "next/link"; 4 | 5 | const Failed = () => { 6 | return ( 7 |
8 | 9 |
10 |
Payment failed!
11 |
12 | For any product related query, drop an email to 13 |
14 |
shoeshopcontact@shop.com
15 | 16 | 17 | Continue Shopping 18 | 19 |
20 |
21 |
22 | ); 23 | }; 24 | 25 | export default Failed; 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 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 | "@next/font": "13.1.6", 13 | "@reduxjs/toolkit": "^1.9.3", 14 | "@stripe/react-stripe-js": "^1.16.5", 15 | "@stripe/stripe-js": "^1.48.0", 16 | "eslint": "8.34.0", 17 | "eslint-config-next": "13.1.6", 18 | "next": "13.1.6", 19 | "react": "18.2.0", 20 | "react-dom": "18.2.0", 21 | "react-icons": "^4.7.1", 22 | "react-markdown": "^8.0.5", 23 | "react-multi-carousel": "^2.8.2", 24 | "react-redux": "^8.0.5", 25 | "react-responsive-carousel": "^3.2.23", 26 | "react-toastify": "^9.1.1", 27 | "swr": "^2.1.0" 28 | }, 29 | "devDependencies": { 30 | "autoprefixer": "^10.4.14", 31 | "postcss": "^8.4.21", 32 | "tailwindcss": "^3.2.7" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /pages/success.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Wrapper from "@/components/Wrapper"; 3 | import Link from "next/link"; 4 | 5 | const Success = () => { 6 | return ( 7 |
8 | 9 |
10 |
11 | Thanks for shopping with us! 12 |
13 |
14 | Your order has been placed successfully. 15 |
16 |
17 | For any product related query, drop an email to 18 |
19 |
shoeshopcontact@shop.com
20 | 21 | 22 | Continue Shopping 23 | 24 |
25 |
26 |
27 | ); 28 | }; 29 | 30 | export default Success; 31 | -------------------------------------------------------------------------------- /components/RelatedProducts.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import Carousel from "react-multi-carousel"; 4 | import "react-multi-carousel/lib/styles.css"; 5 | import ProductCard from "./ProductCard"; 6 | 7 | const RelatedProducts = ({ products }) => { 8 | const responsive = { 9 | desktop: { 10 | breakpoint: { max: 3000, min: 1024 }, 11 | items: 3, 12 | }, 13 | tablet: { 14 | breakpoint: { max: 1023, min: 464 }, 15 | items: 2, 16 | }, 17 | mobile: { 18 | breakpoint: { max: 767, min: 0 }, 19 | items: 1, 20 | }, 21 | }; 22 | 23 | return ( 24 |
25 |
You Might Also Like
26 | 31 | {products?.data?.map((product) => ( 32 | 33 | ))} 34 | 35 |
36 | ); 37 | }; 38 | 39 | export default RelatedProducts; 40 | -------------------------------------------------------------------------------- /components/ProductDetailsCarousel.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "react-responsive-carousel/lib/styles/carousel.min.css"; // requires a loader 3 | import { Carousel } from "react-responsive-carousel"; 4 | 5 | const ProductDetailsCarousel = ({ images }) => { 6 | return ( 7 |
8 | 15 | {images?.map((img) => ( 16 | {img.attributes.name} 21 | ))} 22 | {/* 23 | 24 | 25 | 26 | 27 | */} 28 | 29 |
30 | ); 31 | }; 32 | 33 | export default ProductDetailsCarousel; 34 | -------------------------------------------------------------------------------- /store/cartSlice.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | export const cartSlice = createSlice({ 4 | name: "cart", 5 | initialState: { 6 | cartItems: [], 7 | }, 8 | reducers: { 9 | addToCart: (state, action) => { 10 | const item = state.cartItems.find( 11 | (p) => p.id === action.payload.id 12 | ); 13 | if (item) { 14 | item.quantity++; 15 | item.attributes.price = item.oneQuantityPrice * item.quantity; 16 | } else { 17 | state.cartItems.push({ ...action.payload, quantity: 1 }); 18 | } 19 | }, 20 | updateCart: (state, action) => { 21 | state.cartItems = state.cartItems.map((p) => { 22 | if (p.id === action.payload.id) { 23 | if (action.payload.key === "quantity") { 24 | p.attributes.price = 25 | p.oneQuantityPrice * action.payload.val; 26 | } 27 | return { ...p, [action.payload.key]: action.payload.val }; 28 | } 29 | return p; 30 | }); 31 | }, 32 | removeFromCart: (state, action) => { 33 | state.cartItems = state.cartItems.filter( 34 | (p) => p.id !== action.payload.id 35 | ); 36 | }, 37 | }, 38 | }); 39 | 40 | // Action creators are generated for each case reducer function 41 | export const { addToCart, updateCart, removeFromCart } = cartSlice.actions; 42 | 43 | export default cartSlice.reducer; 44 | -------------------------------------------------------------------------------- /pages/_app.js: -------------------------------------------------------------------------------- 1 | import "@/styles/globals.css"; 2 | import Head from "next/head"; 3 | 4 | import Header from "@/components/Header"; 5 | import Footer from "@/components/Footer"; 6 | 7 | import { Provider } from "react-redux"; 8 | import store from "@/store/store"; 9 | 10 | export default function App({ Component, pageProps }) { 11 | return ( 12 | <> 13 | 14 | Online Shoe Store | JS Dev Hindi 15 | 19 | 23 | 24 | 25 | 30 | 34 | 35 | 36 |
37 | 38 |