Skip to content

Commit

Permalink
added cart functionallity
Browse files Browse the repository at this point in the history
  • Loading branch information
gateniomer committed Nov 7, 2022
1 parent 6dd898b commit 53b299b
Show file tree
Hide file tree
Showing 13 changed files with 82 additions and 24 deletions.
10 changes: 9 additions & 1 deletion components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@ import Link from "next/link";
import Image from "next/image";
import styles from '../styles/Card.module.css';
import { ProductType } from "../utils/types";
import {useState} from 'react';

const Card = ({product}:{product:ProductType}) => {
const handleImage = ()=>{
if(!product.images[0].includes('http')){
return <Image src={'/product_placeholder.jpg'} layout={'fill'} objectFit={'cover'} placeholder={'blur'} blurDataURL={'/product_placeholder.jpg'}/>
}
return <Image src={product.images[0]} layout={'fill'} objectFit={'cover'} placeholder={'blur'} blurDataURL={'/product_placeholder.jpg'}/>
}

return (
<Link key={product.id} href={'/products/'+product.id}>
<div className={styles.card}>
<div className={styles.imageContainer}>
<Image src={product.images[0]} layout={'fill'} objectFit={'cover'}/>
{handleImage()}
</div>
<span className={styles.category}>{product.category.name}</span>
<div className={styles.bottomContainer}>
Expand Down
37 changes: 29 additions & 8 deletions components/Cart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import styles from '../styles/Cart.module.css';
import { useAppSelector } from "../utils/hooks";
import Link from 'next/link';
import useOutsideAlerter from '../hooks/useOutsideAlerter';
import { useRouter } from 'next/router';
import { useAppDispatch } from '../utils/hooks';
import { ProductType } from '../utils/types';
import { updateCartThunk } from '../utils/thunk';

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faCartShopping } from "@fortawesome/free-solid-svg-icons"
Expand All @@ -13,30 +17,47 @@ export const Cart = () => {
const numOfItems = cartProducts?.reduce((prev,current)=>prev+current.quantity,0);
const totalPrice = cartProducts?.reduce((prev,current)=>prev+(Math.floor(current.price*current.quantity)),0);

const router = useRouter();
const dispatch = useAppDispatch();

const ref = useRef(null);
const [clickedOutside] = useOutsideAlerter(ref);
useEffect(()=>{setOpened(false)},[clickedOutside]);

const addProductQuantity = (product:ProductType)=>{
dispatch(updateCartThunk({item:product}));
}
const subtractProductQuantity = (product:ProductType)=>{
dispatch(updateCartThunk({item:product,subtruct:true}));
}

const navigateToProduct = (id:number)=>{
router.push('/products/'+id);
setOpened(false);
}
return (
<div className={styles.cart} ref={ref}>
<div ref={ref}>
<div onClick={()=>setOpened(prev=>!prev)}>
<FontAwesomeIcon icon={faCartShopping}/>
<span>{numOfItems}</span>
</div>
{/* <button onClick={()=>setOpened(prev=>!prev)}>Cart ({numOfItems})</button> */}
{opened &&
<div className={styles.container} onClick={()=>setOpened(false)}>
<div className={styles.container}>
<h2>Products:</h2>
{cartProducts && cartProducts.map(product =>
<Link key={product.id} href={'/products/'+product.id}>
<div className={styles.cartItem}>
<img src={product.image} alt={product.title} />
<span className={styles.cartItemTitle}>{product.title}: {Math.floor(product.price * product.quantity)}$</span>
<div key={product.id} className={styles.cartItem}>
<img src={product.image} alt={product.title} onClick={()=>navigateToProduct(product.id)}/>
<div>
<span className={styles.cartItemTitle} onClick={()=>navigateToProduct(product.id)}>{product.title}</span>
<span className={styles.cartItemTotal}>Total: {Math.floor(product.price * product.quantity)}$</span>
</div>
<button onClick={()=>addProductQuantity(product)}>+</button>
<span className={styles.cartItemQuantity}>{product.quantity}</span>
<button onClick={()=>subtractProductQuantity(product)}>-</button>
</div>
</Link>
)}
<Link href={'/checkout'}>Checkout</Link>
<button className={styles.checkoutButton} onClick={()=>router.push('/checkout')}>Checkout</button>
</div>}
</div>)
}
Expand Down
2 changes: 1 addition & 1 deletion next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const nextConfig = {
reactStrictMode: false,
swcMinify: true,
images: {
domains: ['fakestoreapi.com','api.escuelajs.co','api.lorem.space','placeimg.com'],
domains: ['ih1.redbubble.net','api.escuelajs.co','api.lorem.space','placeimg.com'],
},
}

Expand Down
2 changes: 1 addition & 1 deletion pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { updateProducts } from '../utils/products.slice'
import Card from '../components/Card'

export const getServerSideProps:GetServerSideProps = async () => {
const products = await (await fetch('https://api.escuelajs.co/api/v1/products?offset=1&limit=9')).json();
const products = await (await fetch('https://api.escuelajs.co/api/v1/products?offset=1&limit=30')).json();
const categories = await (await fetch('https://api.escuelajs.co/api/v1/categories')).json();
return {
props:{products,categories}
Expand Down
2 changes: 1 addition & 1 deletion pages/products/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const Product:NextPage<{product?:ProductType}> = ({product}) => {
const dispatch = useAppDispatch();
const user = useAppSelector(state=>state.userDetails.user);
const onAddToCartHandler = (product:ProductType) => {
dispatch(updateCartThunk(product));
dispatch(updateCartThunk({item:product}));
}

return(
Expand Down
1 change: 0 additions & 1 deletion public/blob-haikei (1).svg

This file was deleted.

1 change: 0 additions & 1 deletion public/blob-haikei.svg

This file was deleted.

1 change: 0 additions & 1 deletion public/circle-scatter-haikei.svg

This file was deleted.

Binary file removed public/leone-venter-mTkXSSScrzw-unsplash.jpg
Binary file not shown.
Binary file removed public/paul-earle-wVjd0eWNqI8-unsplash.jpg
Binary file not shown.
Binary file added public/product_placeholder.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 22 additions & 5 deletions styles/Cart.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
/* background-color: #555; */
padding: 5px;
/* border: 5px solid #333; */
margin-bottom: 10px;
}

.cartItem img {
Expand All @@ -29,16 +30,32 @@

.cartItemTitle {
font-weight: bold;
display: block;
}
.cartItemTotal {
font-size: 0.9rem;
}

.cartItemQuantity {
display: inline-block;
display: flex;
align-items: center;
justify-content: center;
background-color: #333;
border-radius: 50%;
border-radius: 10px;
font-size: 1rem;
width: 3rem;
height: 2rem;
color: #fff;
}

.checkoutButton {
background: #333;
color: #fff;
padding: 0.5rem 1rem;
border-radius: 30px;
border: none;
font-size: 1rem;
width: 30px;
height: 30px;
line-height: 30px;
cursor: pointer;
}

@keyframes enter {
Expand Down
23 changes: 19 additions & 4 deletions utils/thunk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,33 @@ import { ProductType } from "./types";
import {createAsyncThunk} from '@reduxjs/toolkit';
import { RootState } from "./store";

export const updateCartThunk = createAsyncThunk<any,ProductType,{state:RootState}>('updateCartThunk',async (item:ProductType,{getState})=>{
const state = getState();
type Props = {
item:ProductType,
subtruct?:boolean
}
type ThunkApi = {
state:RootState
}
export const updateCartThunk = createAsyncThunk
<any,Props,ThunkApi>
('updateCartThunk',async (props,thunkApi)=>{
const {item,subtruct} = props;
const state = thunkApi.getState();
let isExist = -1;
const oldCart = state.userDetails.cart ? [...state.userDetails.cart]: [];
let newCart;
oldCart.forEach((product,index)=>{
if(product.id===item.id) isExist = index;
})
if(isExist != -1){
const updatedProduct = {...item,quantity:oldCart[isExist].quantity+1};
const quantity = subtruct ? oldCart[isExist].quantity-1:oldCart[isExist].quantity+1;
const updatedProduct:ProductType = {...item,quantity};
oldCart.splice(isExist,1);
newCart = [updatedProduct,...oldCart];
if(quantity>0){
newCart = [updatedProduct,...oldCart];
}else{
newCart = [...oldCart];
}
}else{
newCart = [{...item,quantity:1},...oldCart];
}
Expand Down

1 comment on commit 53b299b

@vercel
Copy link

@vercel vercel bot commented on 53b299b Nov 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nextapp – ./

nextapp-gateniomer.vercel.app
nextapp-gilt.vercel.app
nextapp-git-main-gateniomer.vercel.app

Please sign in to comment.