Skip to content

Commit

Permalink
Cart product
Browse files Browse the repository at this point in the history
  • Loading branch information
hozayves committed Jul 13, 2024
1 parent f38f190 commit 325d395
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 12 deletions.
5 changes: 5 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import CategoriesPage from './pages/CategoriesPage';
import ResetPassword from './pages/ResetPassword';
import NewPassword from './pages/NewPassword';
import { ProductDetail } from './pages/product/ProductDetail';
import Cart from './components/cart/Cart';

const App = () => {
const { data, error, isLoading } = useGetProductsQuery();
Expand Down Expand Up @@ -70,6 +71,10 @@ const App = () => {
path: 'auth/success/:token',
element: <GoogleAuthSuccess />,
},
{
path: 'shoppingcart',
element: <Cart />
},
{
path: 'categories/:categoryId',
element: <CategoriesPage />,
Expand Down
63 changes: 63 additions & 0 deletions src/components/cart/Cart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, { useEffect, useState } from "react"
import Navbar from "../navbar/Navbar"
import CartItem from "./CartItem"
import { useGetCartsQuery } from "../../services/cartApi"

const Cart: React.FC = () => {
const { data: carts, isLoading, isSuccess, isError, error } = useGetCartsQuery()
const [totalPrice, setTotalPrice] = useState(0)
const [items, setItems] = useState(0)

useEffect(() => {
if (isSuccess && carts) {
// Calculate total price
const calculatedTotalPrice = carts.cartProducts.reduce((total, cart) => {

Check failure on line 14 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Property 'cartProducts' does not exist on type 'Cart[]'.

Check failure on line 14 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Parameter 'total' implicitly has an 'any' type.

Check failure on line 14 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Parameter 'cart' implicitly has an 'any' type.

Check failure on line 14 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Property 'cartProducts' does not exist on type 'Cart[]'.

Check failure on line 14 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Parameter 'total' implicitly has an 'any' type.

Check failure on line 14 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Parameter 'cart' implicitly has an 'any' type.
const pricePerItem = cart.sizes[0]?.price || 0;
const itemTotalPrice = pricePerItem * cart.quantity;
return total + itemTotalPrice;
}, 0);

// Update total price state
setTotalPrice(calculatedTotalPrice);

// Optionally calculate the number of items if needed
const totalItems = carts.cartProducts.length;

Check failure on line 24 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Property 'cartProducts' does not exist on type 'Cart[]'.

Check failure on line 24 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Property 'cartProducts' does not exist on type 'Cart[]'.
setItems(totalItems);
}
}, [isSuccess, carts]);

let content;
if (isLoading) {
content = <div>Loading</div>
} else if (isSuccess) {
console.log(carts)
const renderedCart = carts.cartProducts.map((cart, index) => (

Check failure on line 34 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Property 'cartProducts' does not exist on type 'Cart[]'.

Check failure on line 34 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Parameter 'cart' implicitly has an 'any' type.

Check failure on line 34 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Parameter 'index' implicitly has an 'any' type.

Check failure on line 34 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Property 'cartProducts' does not exist on type 'Cart[]'.

Check failure on line 34 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Parameter 'cart' implicitly has an 'any' type.

Check failure on line 34 in src/components/cart/Cart.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Parameter 'index' implicitly has an 'any' type.
< CartItem key={index} {...cart} />
))
content = renderedCart
} else if (isError) {
content = <div>{error.toString()}</div>
}
return (
<div className="w-full min-h-screen overflow-x-hidden font-roboto flex flex-col 2xl:items-center">
<Navbar />
<div className="w-full px-3 pt-5 flex flex-col gap-2 md:p-4 xl:px-10 2xl:w-[1440px]">
<h1 className="leading-none font-semibold text-lg subpixel-antialiased tracking-wide">Shopping Cart ({items})</h1>
<p className="leading-none subpixel-antialiased text-xs tracking-wide font-light hidden md:block">Your cart contains {items} items and comes to a total of $210</p>
<div className="flex flex-col md:flex-row-reverse lg:gap-10 xl:gap-12">
<div className="flex flex-col gap-4 px-3 py-2 pt-4 md:flex-grow lg:w-72 lg:flex-grow-0 xl:flex-grow-0 xl:w-80">
<div className="flex justify-between text-sm font-medium">
<span className="md:font-semibold md:text-lg">Total:</span>
<span className="md:font-semibold md:text-lg">${totalPrice}</span>
</div>
<button className="leading-none bg-greenColor hover:bg-[#1a6461] rounded-full px-5 py-3 text-whiteColor font-medium text-xs transition-all delay-75 ease-in cursor-pointer">Checkout</button>
</div>
<div className="bg-[#f7f7f7] flex flex-col py-3 mt-2 md:flex-grow">
{content}
</div>
</div>
</div>
</div>
)
}
export default Cart
75 changes: 75 additions & 0 deletions src/components/cart/CartItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React, { useEffect, useState } from 'react'
import { useUpdateCartMutation } from '../../services/cartApi'
interface CartItem {
id: string,
name: string,
image: string,
price: number,
sizes: [],
quantity: number
}
const CartItem: React.FC<CartItem> = ({ id, name, image, sizes, quantity }) => {
const [itemTotalPrice, setItemTotalPrice] = useState(sizes[0].price * quantity)

Check failure on line 12 in src/components/cart/CartItem.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Object is possibly 'undefined'.

Check failure on line 12 in src/components/cart/CartItem.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Tuple type '[]' of length '0' has no element at index '0'.

Check failure on line 12 in src/components/cart/CartItem.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Object is possibly 'undefined'.

Check failure on line 12 in src/components/cart/CartItem.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Tuple type '[]' of length '0' has no element at index '0'.
const [updateCart] = useUpdateCartMutation()
const currentPrice = sizes[0].price;

Check failure on line 14 in src/components/cart/CartItem.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Object is possibly 'undefined'.

Check failure on line 14 in src/components/cart/CartItem.tsx

View workflow job for this annotation

GitHub Actions / Build (20)

Object is possibly 'undefined'.

useEffect(() => {
setItemTotalPrice(currentPrice * quantity);
}, [quantity, currentPrice]);

const addQty = (quantity, productId, sizeId) => {
const newQuantity = quantity + 1;
updateCart({ id, updatedCart: { productId, quantity: newQuantity, sizeId } })
}
const removeQty = (quantity, productId, sizeId) => {
const newQuantity = quantity - 1;
if (newQuantity > 0) {
updateCart({ id, updatedCart: { productId, quantity: newQuantity, sizeId } })
}
}
return (
<>
<div className="flex gap-1 border-b border-b-grayColor py-2 px-3">
<div className="h-36 max-w-[98px] min-w-[100px]">
<img src={image} alt="" className="w-full h-36" />
</div>
<div className="flex flex-col gap-2 ml-3 w-full">
<div className="flex justify-between font-semibold">
<h3 className="leading-5 w-2/3 text-wrap capitalize text-sm break-words font-medium tracking-normal outline-none
md:text-lg">{name}</h3>
<span className="text-xs md:text-base">${itemTotalPrice}</span>
</div>
<div className="">
<div className="flex flex-col gap-2 md:gap-1">
<div className="flex flex-col gap-1 font-light mt-1 md:gap-1">
<label htmlFor="size" className="leading-none text-xs opacity-70">Size</label>
<div id="size" className="border border-greenColor rounded-full h-9 p-[6px] text-sm bg-whiteColor w-4/5 font-medium outline-none md:w-1/2 justify-start flex items-center leading-none px-3">
{sizes[0].size !== null ? sizes[0].size : 'One'}
</div>
</div>
<div className="flex flex-col font-light gap-1 mt-2">
<label htmlFor="quantity" className="leading-none text-xs opacity-70">Quantity</label>
<div>
<button
onClick={() => removeQty(quantity, id, sizes[0].id)}
className="border w-10 h-9 text-greenColor rounded-l-full bg-whiteColor cursor-pointer text-center"
>-</button>
<input type="text" value={quantity} className="h-9 w-9 border-t border-t-greenColor border-b text-center outline-none" />
<button
onClick={() => addQty(quantity, id, sizes[0].id)}
className="border w-10 h-9 text-greenColor rounded-r-full bg-whiteColor cursor-pointer text-center"
>+</button>
</div>
</div>
<div className="flex justify-end gap-2 mt-2 flex-col sm:flex-row">
<button className="border border-greenColor rounded-full px-3 py-1 text-xs font-medium cursor-pointer">Save For Later</button>
<button className="border border-greenColor rounded-full px-3 py-1 text-xs font-medium cursor-pointer">Remove</button>
</div>
</div>
</div>
</div>
</div>
</>
)
}
export default CartItem
55 changes: 43 additions & 12 deletions src/services/cartApi.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,48 @@
import { mavericksApi } from '.';
import { ICart } from '../utils/schemas';
import { mavericksApi } from ".";
import { Cart } from "../types/Types";

export const cartApi = mavericksApi.injectEndpoints({
const cartsApi = mavericksApi.injectEndpoints({
endpoints: builder => ({
addProductToCart: builder.mutation({
query: (cart: ICart) => ({
url: 'cart',
method: 'POST',
body: cart,
getCarts: builder.query<Cart[], void>({
query: () => '/cart',
providesTags: ["Carts"]
}),
updateCart: builder.mutation({
query: ({ id, updatedCart }) => ({
url: `/cart/${id}`,
method: 'PATCH',
body: updatedCart
}),
invalidatesTags: ["Carts"],
// async onQueryStarted({ id, updatedCart }, { dispatch, queryFulfilled }) {
// const patchResult = dispatch(
// mavericksApi.util.updateQueryData('getCarts', undefined, draft => {
// console.log(draft)
// const cart = draft.find(cart => cart.id === id)
// if (cart) {
// const size = cart.sizes.find(size => size.id === updatedCart.sizeId)
// if (size) {
// cart.quantity = updatedCart.quantity;
// size.price = updatedCart.price
// }
// }
// })
// );
// try {
// await queryFulfilled
// } catch (error) {
// patchResult.undo()
// }
// }
}),
}),
overrideExisting: false,
});
deleteCart: builder.mutation({
query: (cartId) => ({
url: `/cart/${cartId}`,
method: 'DELETE'
}),
invalidatesTags: ["Carts"]
})
})
})

export const { useAddProductToCartMutation } = cartApi;
export const { useGetCartsQuery, useDeleteCartMutation, useUpdateCartMutation } = cartsApi

0 comments on commit 325d395

Please sign in to comment.