Skip to content

Commit

Permalink
Merge branch 'Dev' into feature/admin-shop-orders
Browse files Browse the repository at this point in the history
  • Loading branch information
sonylomo committed Sep 17, 2024
2 parents d6b1972 + c28a4bb commit 98601ff
Show file tree
Hide file tree
Showing 16 changed files with 477 additions and 263 deletions.
11 changes: 10 additions & 1 deletion src/components/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { LazyLoadImage } from "react-lazy-load-image-component";
import { Link, useLocation } from "react-router-dom";

import logo from "../assets/images/sytLogo.png";
import CartDrawer from "./shop/CartDrawer";
import CartIcon from "./shop/CartIcon";

const navLinks = [
Expand Down Expand Up @@ -52,6 +53,7 @@ const navLinks = [

function Header() {
const [showNavlinks, setShowNavlinks] = useState(false);
const [open, setOpen] = useState(false);

const { pathname } = useLocation();

Expand All @@ -66,7 +68,13 @@ function Header() {
{/* mobile menu */}
<div className="flex gap-4 items-center">
<div className="flex md:hidden">
<CartIcon />
<button
type="button"
aria-label="open cart"
onClick={() => setOpen(true)}
>
<CartIcon />
</button>
</div>
{showNavlinks ? (
<button
Expand Down Expand Up @@ -139,6 +147,7 @@ function Header() {
})}
</nav>
</header>
<CartDrawer open={open} setOpen={setOpen} />
</div>
);
}
Expand Down
114 changes: 31 additions & 83 deletions src/components/shop/CartDrawer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,59 +6,27 @@ import { IoIosCloseCircleOutline } from "react-icons/io";
import { RiDeleteBin6Line } from "react-icons/ri";
import { LazyLoadImage } from "react-lazy-load-image-component";
import { Link, useNavigate } from "react-router-dom";
import { useDeleteSwag } from "../../hooks/Mutations/shop/useCartSwagg";
import formatPrice from "../../utilities/formatPrice";

function CartDrawer({ open, setOpen }) {
const navigate = useNavigate();

// Get the JSON string from localStorage
const [cartProducts, setCartProducts] = useState([]);

const dummyCartData = [
{
id: "271fcc1c-0337-44f4-9449-2bc35b6ffd01",
name: "Cityscape Jacket",
description:
"Introducing our Cityscape Jacket: a blend of urban flair and unbeatable comfort. Crafted with premium materials, it offers sleek design and weather resistance for city adventures. Stay stylish and protected with adjustable features and convenient pockets. Upgrade your urban wardrobe today!",
category: "Jackets",
image:
"https://apis.spaceyatech.com/media/product_images/main-sample_copy_Fud5OzF.png",
price: "3000.00",
stock: 10,
color: "brown",
},
{
id: "232437b9-3e64-4cad-a6c3-08158e118207",
name: "Cityscape Jacket - Mid",
description:
"Introducing our Cityscape Jacket: a blend of urban flair and unbeatable comfort. Crafted with premium materials, it offers sleek design and weather resistance for city adventures. Stay stylish and protected with adjustable features and convenient pockets. Upgrade your urban wardrobe today!",
category: "Jackets",
image:
"https://apis.spaceyatech.com/media/product_images/main-sample_copy_BRv17MK.png",
price: "1800.00",
stock: 11,
color: "brown",
},
{
id: "9cd9a601-0ed9-4685-8633-4b04e0811fc7",
name: "SYT Hoodie",
description:
"Unleash your tech-savvy style with our Tech-Fit Hoodie. Designed for the modern individual, it seamlessly integrates functionality and fashion. Crafted with cutting-edge materials, it offers unrivaled comfort and durability. Elevate your wardrobe with this essential piece that effortlessly combines innovation and style.",
category: "Hoodies",
image:
"https://apis.spaceyatech.com/media/product_images/sample1_copy_PXgn3MX.png",
price: "2000.00",
stock: 10,
color: "white",
},
];
const [cartProducts, setCartProducts] = useState(() => {
// Initialize state with the value from localStorage if it exists
const storedProducts = localStorage.getItem("swagList");
return storedProducts ? JSON.parse(storedProducts) : [];
});

useEffect(() => {
const storage = localStorage.getItem("swagList")
? JSON.parse(localStorage.getItem("swagList"))
: null;
setCartProducts(storage);
}, [cartProducts]);
if (open) {
const storedProducts = localStorage.getItem("swagList");
if (storedProducts) {
setCartProducts(JSON.parse(storedProducts));
}
}
}, [open]);

// const { data: cartProducts, isSuccess } = useProductsInCart();
useEffect(() => {
Expand All @@ -78,31 +46,23 @@ function CartDrawer({ open, setOpen }) {
};
}, []);

// const { mutate: deleteSwag } = useDeleteSwag();
const { mutate: removeSwagFromCart } = useDeleteSwag();

const deleteFromLocalStorage = (cartItemId) => {
// Parse it back to an array of objects
const swagList = cartProducts;

const idxToDelete = swagList.findIndex(
(swag) => swag.swagg_id === cartItemId
// Create a new array by filtering out the item to delete
const updatedSwagList = cartProducts.filter(
(swag) => swag.id !== cartItemId
);

// Check if the object was found
if (idxToDelete !== -1) {
// Remove the object from the swagList
swagList.splice(idxToDelete, 1);

// Convert the updated list to a JSON string
setCartProducts(JSON.stringify(swagList));
// Update the state with the new array
setCartProducts(updatedSwagList);

// Store the updated list back to localStorage
localStorage.setItem("swagList", cartProducts);
}
// Convert the updated list to a JSON string and store it in localStorage
localStorage.setItem("swagList", JSON.stringify(updatedSwagList));
};

const handleDeleteSwag = (cartItemId) => {
// deleteSwag(cartItemId);
removeSwagFromCart(cartItemId);
deleteFromLocalStorage(cartItemId);
};

Expand Down Expand Up @@ -167,25 +127,18 @@ function CartDrawer({ open, setOpen }) {
<div className="flow-root">
<ul className="-my-6 divide-y divide-gray-200 border-b">
{/* {isSuccess && */}
{dummyCartData?.length > 0 &&
(dummyCartData?.cart_items
? dummyCartData.cart_items
: dummyCartData
)?.map((cartProduct) => (
{cartProducts?.length > 0 &&
cartProducts?.map((cartProduct) => (
<li
key={crypto.randomUUID()}
className="flex py-6 space-x-4 sm:space-x-16"
>
<div className="h-32 w-28 flex-shrink-0 overflow-hidden rounded-2xl">
<LazyLoadImage
src={`${
cartProduct.image ||
cartProduct.product?.image
cartProduct.image || cartProduct?.image
}`}
alt={
cartProduct.name ||
cartProduct.product?.name
}
alt={cartProduct.name}
className="h-full w-full object-cover object-center"
/>
</div>
Expand All @@ -197,20 +150,18 @@ function CartDrawer({ open, setOpen }) {
<div className="flex justify-between">
<p className="flex justify-between items-center gap-1 font-medium bg-[#FEF3F2] text-[#B42318] text-sm rounded-full px-2 py-1">
<CiShoppingTag />
Hoodies
{cartProduct.category}
</p>
</div>
<h3>
<p className="text-base md:text-xl text-[#656767]">
{" "}
<Link
to={`/shop/item/${
cartProduct.productId ||
cartProduct.swagg_id
cartProduct.slug
}`}
>
{cartProduct.name ||
cartProduct.product?.name}
{cartProduct.name}
</Link>
</p>
</h3>
Expand All @@ -219,18 +170,15 @@ function CartDrawer({ open, setOpen }) {
type="button"
className="flex justify-end"
onClick={() => {
handleDeleteSwag(
cartProduct.id ||
cartProduct.swagg_id
);
handleDeleteSwag(cartProduct.id);
}}
>
{/* Delete icon */}
<RiDeleteBin6Line className="h-6 w-6 text-[#FC5555]" />
</button>
</div>
<div className="flex flex-row justify-between text-[#656767] text-sm sm:text-base font-medium">
<p>Qty: 1</p>
<p>Qty: {cartProduct.orderUnits}</p>
<p>
KES {formatPrice(cartProduct.price)}
</p>
Expand Down
12 changes: 9 additions & 3 deletions src/components/shop/Counter.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import PropTypes from "prop-types";

function Counter({ className, setCount, count }) {
function Counter({ className, setCount, count, maxStock }) {
const increment = () => setCount((prevCount) => prevCount + 1);
const decrement = () =>
setCount((prevCount) => (prevCount > 1 ? prevCount - 1 : prevCount));
// console.log(count)
return (
<div className={`flex rounded-lg ${className}`}>
<button
type="button"
data-action="decrement"
className="cursor-pointer outline-none w-20 border-y border-l border-l-[#EAECF0] border-y-[#EAECF0] rounded-l-md border-r"
onClick={() => setCount(count > 1 ? count - 1 : 1)}
onClick={decrement}
>
<span className=" text-base"></span>
</button>
Expand All @@ -18,10 +22,11 @@ function Counter({ className, setCount, count }) {
{count}
</p>
<button
disabled={maxStock === count || count > maxStock}
type="button"
data-action="increment"
className="cursor-pointer outline-none w-20 border-y border-r border-r-[#EAECF0] border-y-[#EAECF0] rounded-r-md border-l"
onClick={() => setCount(count + 1)}
onClick={increment}
>
<span className="text-base">+</span>
</button>
Expand All @@ -39,4 +44,5 @@ Counter.propTypes = {
className: PropTypes.string,
setCount: PropTypes.func.isRequired,
count: PropTypes.number.isRequired,
maxStock: PropTypes.number.isRequired,
};
8 changes: 5 additions & 3 deletions src/components/shop/ProductCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function ProductCard({ product }) {
return (
<div className="border rounded-lg p-2.5 pr-1.5 shadow-sm group hover:bg-green-dark/10 bg-white flex flex-col gap-4 ">
<Link
to={`/shop/item/${product.id}`}
to={`/shop/item/${product.slug}`}
className="aspect-h-1 aspect-w-1 w-full bg-gray-200 lg:aspect-none group-hover:opacity-75 lg:h-96"
>
<LazyLoadImage
Expand All @@ -31,7 +31,7 @@ function ProductCard({ product }) {
/>
</Link>
<Link
to={`/shop/item/${product.id}`}
to={`/shop/item/${product.slug}`}
className="flex justify-between pr-1"
>
<h3 className="text-md uppercase font-medium text-gray-600">
Expand All @@ -41,7 +41,9 @@ function ProductCard({ product }) {
{totalStock > 0 ? (
<p className="text-green-dark font-medium text-sm px-1">
<span> {totalStock}</span>
<span className="ml-2">items left</span>
<span className="ml-2">
{totalStock === 1 ? "item" : "items"} left
</span>
</p>
) : (
<div className=" text-red-800 p-1 rounded-lg bg-red-800/20 font-bold text-sm">
Expand Down
34 changes: 31 additions & 3 deletions src/hooks/Mutations/shop/useCartSwagg.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const useAddSwagToCart = () => {

return useMutation({
mutationFn: async (cartItems) => {
const response = await publicAxios.post("/cart/swaggs/", cartItems, {
const response = await publicAxios.post("/cart-items/", cartItems, {
headers: {
"Content-Type": "application/json",
// Authorization: `Bearer ${auth?.access}`,
Expand All @@ -36,7 +36,7 @@ const useDeleteSwag = () => {

return useMutation({
mutationFn: async (id) => {
const response = await publicAxios.delete(`/cart/swaggs/${id}/`, {
const response = await publicAxios.delete(`/cart-items/${id}/`, {
headers: {
"Content-Type": "application/json",
// Authorization: `Bearer ${auth?.access}`,
Expand All @@ -58,4 +58,32 @@ const useDeleteSwag = () => {
});
};

export { useAddSwagToCart, useDeleteSwag };
const useDeleteAllSwag = () => {
const { logout } = useAuth();
const queryClient = useQueryClient();

return useMutation({
mutationFn: async () => {
const response = await publicAxios.delete("/cart-items/clear_cart/", {
headers: {
"Content-Type": "application/json",
// Authorization: `Bearer ${auth?.access}`,
},
});

return response.data;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["productsInCart"] });
},
onError: (error) => {
// eslint-disable-next-line no-console
console.error("Unable to delete all cart items");
if (error.response.status === 401) {
logout();
}
},
});
};

export { useAddSwagToCart, useDeleteSwag, useDeleteAllSwag };
12 changes: 6 additions & 6 deletions src/hooks/Mutations/shop/useMakeOrder.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import privateAxios from "../../../api/privateAxios";
import useAuth from "../../useAuth";
// import useAuth from "../../useAuth";

// POST: https://apis.spaceyatech.com/api/orders/
// POST: https://apis.spaceyatech.com/api/checkout/
const useMakeOrder = () => {
const { auth, logout } = useAuth();
// const { auth, logout } = useAuth();
const queryClient = useQueryClient();

return useMutation({
mutationFn: async (customerInfo) => {
const response = await privateAxios.post("/orders/", customerInfo, {
const response = await privateAxios.post("/checkout/", customerInfo, {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${auth?.access}`,
// Authorization: `Bearer ${auth?.access}`,
},
});
return response.data;
Expand All @@ -25,7 +25,7 @@ const useMakeOrder = () => {
// eslint-disable-next-line no-console
console.error("Unable to add availability");
if (error.response.status === 401) {
logout();
// logout();
}
},
});
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/Queries/shop/useCartProducts.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const fetchProductsInCart = async () => {
// const { access } = authObject;

try {
const response = await publicAxios.get("/cart/swaggs/", {
const response = await publicAxios.get("/cart-items/", {
headers: {
"Content-Type": "application/json",
// Authorization: `Bearer ${access}`,
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/Queries/shop/useSwagList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const useSwagList = () =>

const fetchSingleSwag = async (id) => {
try {
const response = await publicAxios.get(`/swaggs/${id}`);
const response = await publicAxios.get(`/swaggsnew/${id}`);
return response.data;
} catch (error) {
toast.error("Error fetching swag list");
Expand Down
Loading

0 comments on commit 98601ff

Please sign in to comment.