├── .env ├── .gitattributes ├── public ├── favicon.ico ├── images │ ├── slide-1.jpg │ ├── slide-2.jpg │ ├── featured-1.jpg │ ├── featured-2.jpg │ ├── featured-3.jpg │ ├── logos │ │ ├── visa.png │ │ ├── maestro.png │ │ ├── paypal.png │ │ ├── discover.png │ │ ├── mastercard.png │ │ ├── dhl.svg │ │ └── dpd.svg │ ├── subscribe.jpg │ ├── products │ │ ├── product-1.jpg │ │ ├── product-2.jpg │ │ ├── product-3.jpg │ │ ├── product-4.jpg │ │ ├── product-5.jpg │ │ ├── product-6.jpg │ │ └── product-7.jpg │ ├── logo.svg │ └── icons │ │ └── gmail.svg └── vercel.svg ├── utils ├── markup.ts ├── server.ts ├── data │ ├── products-types.ts │ ├── products-sizes.ts │ ├── products-colors.ts │ └── products.ts ├── services.ts ├── localstorage.ts └── gtag.ts ├── assets ├── css │ ├── fonts │ │ └── icons │ │ │ ├── icons.eot │ │ │ ├── icons.ttf │ │ │ ├── icons.woff │ │ │ ├── icons.woff2 │ │ │ ├── icons.css │ │ │ └── icons.svg │ ├── styles.scss │ └── partials │ │ ├── breakpoints.scss │ │ ├── variables.scss │ │ └── reset.css └── icons │ └── logo │ └── index.js ├── next.config.js ├── next-env.d.ts ├── pages ├── cart.tsx ├── api │ ├── products.ts │ ├── product │ │ └── [pid].ts │ └── login.ts ├── 404.tsx ├── products.tsx ├── _app.tsx ├── _document.tsx ├── product │ └── [pid].tsx ├── register.tsx ├── forgot-password.tsx ├── index.tsx ├── login.tsx └── cart │ └── checkout.tsx ├── components ├── context │ ├── theme-context.tsx │ ├── local-storage.tsx │ └── theme-provider.tsx ├── breadcrumb │ └── index.tsx ├── product-item │ ├── loading │ │ └── index.tsx │ └── index.tsx ├── products-content │ ├── list │ │ ├── loading │ │ │ └── index.js │ │ └── index.tsx │ └── index.tsx ├── checkout-status │ └── index.tsx ├── products-filter │ ├── form-builder │ │ ├── checkbox │ │ │ └── index.tsx │ │ └── checkbox-color │ │ │ └── index.tsx │ └── index.tsx ├── subscribe │ └── index.tsx ├── product-single │ ├── gallery │ │ └── index.tsx │ ├── reviews │ │ ├── index.tsx │ │ ├── reviews-list │ │ │ └── index.tsx │ │ └── punctuation │ │ │ └── index.tsx │ ├── description │ │ └── index.tsx │ └── content │ │ └── index.tsx ├── products-featured │ ├── index.tsx │ └── carousel │ │ └── index.tsx ├── checkout │ └── items │ │ └── index.jsx ├── shopping-cart │ ├── item │ │ └── index.tsx │ └── index.tsx ├── page-intro │ └── index.tsx ├── footer │ └── index.tsx └── header │ └── index.tsx ├── .gitignore ├── README.md ├── layouts ├── 404.tsx └── Main.tsx ├── LICENSE ├── types └── index.ts ├── package.json ├── store ├── reducers │ ├── user.ts │ └── cart.ts └── index.ts └── tsconfig.json /.env: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_ANALYTICS_ID=UA-114361661-6 -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.css linguist-detectable=false 2 | *.js linguist-detectable=true -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/images/slide-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/slide-1.jpg -------------------------------------------------------------------------------- /public/images/slide-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/slide-2.jpg -------------------------------------------------------------------------------- /public/images/featured-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/featured-1.jpg -------------------------------------------------------------------------------- /public/images/featured-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/featured-2.jpg -------------------------------------------------------------------------------- /public/images/featured-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/featured-3.jpg -------------------------------------------------------------------------------- /public/images/logos/visa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/logos/visa.png -------------------------------------------------------------------------------- /public/images/subscribe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/subscribe.jpg -------------------------------------------------------------------------------- /public/images/logos/maestro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/logos/maestro.png -------------------------------------------------------------------------------- /public/images/logos/paypal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/logos/paypal.png -------------------------------------------------------------------------------- /utils/markup.ts: -------------------------------------------------------------------------------- 1 | const createMarkup = (content: string) => { 2 | return {__html: content}; 3 | } 4 | 5 | export default createMarkup; -------------------------------------------------------------------------------- /assets/css/fonts/icons/icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/assets/css/fonts/icons/icons.eot -------------------------------------------------------------------------------- /assets/css/fonts/icons/icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/assets/css/fonts/icons/icons.ttf -------------------------------------------------------------------------------- /assets/css/fonts/icons/icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/assets/css/fonts/icons/icons.woff -------------------------------------------------------------------------------- /assets/css/fonts/icons/icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/assets/css/fonts/icons/icons.woff2 -------------------------------------------------------------------------------- /public/images/logos/discover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/logos/discover.png -------------------------------------------------------------------------------- /public/images/logos/mastercard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/logos/mastercard.png -------------------------------------------------------------------------------- /public/images/products/product-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/products/product-1.jpg -------------------------------------------------------------------------------- /public/images/products/product-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/products/product-2.jpg -------------------------------------------------------------------------------- /public/images/products/product-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/products/product-3.jpg -------------------------------------------------------------------------------- /public/images/products/product-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/products/product-4.jpg -------------------------------------------------------------------------------- /public/images/products/product-5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/products/product-5.jpg -------------------------------------------------------------------------------- /public/images/products/product-6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/products/product-6.jpg -------------------------------------------------------------------------------- /public/images/products/product-7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitehorse21/next.js-ecommerce-template/HEAD/public/images/products/product-7.jpg -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | sassOptions: { 5 | includePaths: [path.join(__dirname, 'styles')], 6 | }, 7 | } -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /utils/server.ts: -------------------------------------------------------------------------------- 1 | //const dev = process.env.NODE_ENV !== "production"; 2 | 3 | //export const server = dev ? "http://localhost:3000" : "http://localhost:3000"; 4 | export const server = "https://next-js-ecommerce-template-ten.vercel.app"; 5 | -------------------------------------------------------------------------------- /assets/css/styles.scss: -------------------------------------------------------------------------------- 1 | // import font 2 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap'); 3 | 4 | // import icons 5 | @import './fonts/icons/icons.css'; 6 | 7 | // import main 8 | @import './main.scss'; -------------------------------------------------------------------------------- /pages/cart.tsx: -------------------------------------------------------------------------------- 1 | import Layout from "../layouts/Main"; 2 | import ShoppingCart from "../components/shopping-cart"; 3 | 4 | const Products = () => ( 5 | 6 | 7 | 8 | ); 9 | 10 | export default Products; 11 | -------------------------------------------------------------------------------- /components/context/theme-context.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | type ContextType = { 4 | theme: string; 5 | toggleTheme: () => void; 6 | }; 7 | 8 | export const ThemeContext = React.createContext({ 9 | theme: "light", 10 | toggleTheme: () => {}, 11 | }); 12 | -------------------------------------------------------------------------------- /components/breadcrumb/index.tsx: -------------------------------------------------------------------------------- 1 | const Breadcrumb = () => ( 2 |
3 |
4 |
    5 |
  • 6 |
  • All Products
  • 7 |
8 |
9 |
10 | ); 11 | 12 | 13 | export default Breadcrumb -------------------------------------------------------------------------------- /pages/api/products.ts: -------------------------------------------------------------------------------- 1 | import type { NextApiRequest, NextApiResponse } from 'next'; 2 | 3 | // fake data 4 | import products from '../../utils/data/products'; 5 | 6 | export default (req: NextApiRequest, res: NextApiResponse) => { 7 | console.log(req); 8 | 9 | // fake loading time 10 | setTimeout(() => { 11 | res.status(200).json(products); 12 | }, 800); 13 | } 14 | -------------------------------------------------------------------------------- /pages/api/product/[pid].ts: -------------------------------------------------------------------------------- 1 | import type { NextApiRequest, NextApiResponse } from 'next'; 2 | 3 | // fake data 4 | import products from '../../../utils/data/products'; 5 | 6 | export default (req: NextApiRequest, res: NextApiResponse) => { 7 | const { 8 | query: { pid }, 9 | } = req 10 | 11 | const product = products.find(x => x.id === pid); 12 | res.status(200).json(product); 13 | } 14 | -------------------------------------------------------------------------------- /components/product-item/loading/index.tsx: -------------------------------------------------------------------------------- 1 | const ProductItemLoading = () => ( 2 | 3 |
4 | 5 |
6 | 7 |
8 |

9 |
10 |

11 |
12 |
13 |
14 | ); 15 | 16 | 17 | export default ProductItemLoading -------------------------------------------------------------------------------- /utils/data/products-types.ts: -------------------------------------------------------------------------------- 1 | export const productsTypes = [ 2 | { 3 | id: '1', 4 | name: 'T-Shirts', 5 | count: '172', 6 | }, 7 | { 8 | id: '2', 9 | name: 'Sweatshirts', 10 | count: '131', 11 | }, 12 | { 13 | id: '3', 14 | name: 'Tank Tops', 15 | count: '56', 16 | }, 17 | { 18 | id: '4', 19 | name: 'Dress shirts', 20 | count: '8', 21 | }, 22 | ]; 23 | 24 | export default productsTypes; -------------------------------------------------------------------------------- /utils/services.ts: -------------------------------------------------------------------------------- 1 | // function to post data 2 | export async function postData(url = '', data = {}) { 3 | const response = await fetch(url, { 4 | method: 'POST', 5 | mode: 'cors', 6 | cache: 'no-cache', 7 | credentials: 'same-origin', 8 | headers: { 9 | 'Content-Type': 'application/json' 10 | }, 11 | redirect: 'follow', 12 | referrerPolicy: 'no-referrer', 13 | body: JSON.stringify(data) 14 | }); 15 | return response.json(); 16 | } -------------------------------------------------------------------------------- /components/products-content/list/loading/index.js: -------------------------------------------------------------------------------- 1 | import ProductItemLoading from './../../../product-item/loading'; 2 | 3 | const ProductsLoading = () => { 4 | return ( 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | ); 14 | }; 15 | 16 | export default ProductsLoading -------------------------------------------------------------------------------- /pages/api/login.ts: -------------------------------------------------------------------------------- 1 | import type { NextApiRequest, NextApiResponse } from 'next'; 2 | 3 | // fake login 4 | export default (req: NextApiRequest, res: NextApiResponse) => { 5 | const request = req.body; 6 | const email = request.email; 7 | const password = request.password; 8 | 9 | if(email === 'dragonfly4141@outlook.com' && password === 'dragonfly') { 10 | res.status(200).json({ status: true }); 11 | } else { 12 | res.status(401).json({ status: false }); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /pages/404.tsx: -------------------------------------------------------------------------------- 1 | import LayoutError from "../layouts/404"; 2 | 3 | const ErrorPage = () => ( 4 | 5 |
6 |
7 |

Error 404

8 |

Woops. Looks like this page doesn't exist

9 | 10 | Go to home 11 | 12 |
13 |
14 |
15 | ); 16 | 17 | export default ErrorPage; 18 | -------------------------------------------------------------------------------- /utils/localstorage.ts: -------------------------------------------------------------------------------- 1 | export const loadState = (key) => { 2 | try { 3 | const serializedState = localStorage.getItem(key); 4 | if(serializedState === null) { 5 | return undefined; 6 | } 7 | return JSON.parse(serializedState); 8 | } 9 | catch (err) { 10 | return undefined; 11 | } 12 | }; 13 | 14 | export const saveState = (key, value) => { 15 | try { 16 | localStorage.setItem(key, JSON.stringify(value)); 17 | } 18 | catch (err) { 19 | 20 | } 21 | }; -------------------------------------------------------------------------------- /utils/data/products-sizes.ts: -------------------------------------------------------------------------------- 1 | export const productsSizes = [ 2 | { 3 | id: '1', 4 | label: 'XS', 5 | }, 6 | { 7 | id: '2', 8 | label: 'S', 9 | }, 10 | { 11 | id: '3', 12 | label: 'M', 13 | }, 14 | { 15 | id: '4', 16 | label: 'L', 17 | }, 18 | { 19 | id: '5', 20 | label: 'XL', 21 | }, 22 | { 23 | id: '6', 24 | label: 'XXL', 25 | }, 26 | ]; 27 | 28 | export default productsSizes; -------------------------------------------------------------------------------- /.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 | 21 | # debug 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # local env files 27 | .env.local 28 | .env.development.local 29 | .env.test.local 30 | .env.production.local 31 | .vercel 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚙️ Project 2 | 3 | Ecommerce Template using Next.js, Typescript, Redux Toolkit, SCSS, with the implementation of a responsive design and CSS interactions with the fields. 4 | 5 | # ✈️ Technologies 6 | 7 | - Next.js 8 | - TypeScript 9 | - Redux Toolkit 10 | - React Hook Form 11 | -------------------------------------------------------------------------------- /components/context/local-storage.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | export function useLocalStorage(key: string, fallbackValue: T) { 4 | const [value, setValue] = useState(fallbackValue); 5 | useEffect(() => { 6 | const stored = localStorage.getItem(key); 7 | setValue(stored ? JSON.parse(stored) : fallbackValue); 8 | }, [fallbackValue, key]); 9 | 10 | useEffect(() => { 11 | localStorage.setItem(key, JSON.stringify(value)); 12 | }, [key, value]); 13 | 14 | return [value, setValue] as const; 15 | } 16 | -------------------------------------------------------------------------------- /components/checkout-status/index.tsx: -------------------------------------------------------------------------------- 1 | type CheckoutStatusProps = { 2 | step: string; 3 | } 4 | 5 | const CheckoutStatus = ({ step }: CheckoutStatusProps) => { 6 | return ( 7 |
8 |
    9 |
  • 10 |
  • 11 |
12 |
13 | ) 14 | }; 15 | 16 | 17 | export default CheckoutStatus -------------------------------------------------------------------------------- /components/products-filter/form-builder/checkbox/index.tsx: -------------------------------------------------------------------------------- 1 | type CheckboxType = { 2 | type?: string; 3 | label: string; 4 | name: string; 5 | onChange?: () => void; 6 | } 7 | 8 | const Checkbox = ({ type = '', label, name, onChange }: CheckboxType) => ( 9 | 14 | ); 15 | 16 | export default Checkbox; -------------------------------------------------------------------------------- /public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pages/products.tsx: -------------------------------------------------------------------------------- 1 | import Layout from "../layouts/Main"; 2 | import Footer from "../components/footer"; 3 | import Breadcrumb from "../components/breadcrumb"; 4 | import ProductsFilter from "../components/products-filter"; 5 | import ProductsContent from "../components/products-content"; 6 | 7 | const Products = () => ( 8 | 9 | 10 |
11 |
12 | 13 | 14 |
15 |
16 |