diff --git a/src/hooks/Mutations/shop/useCartSwagg.jsx b/src/hooks/Mutations/shop/useCartSwagg.jsx
index 8896841a..90be5009 100644
--- a/src/hooks/Mutations/shop/useCartSwagg.jsx
+++ b/src/hooks/Mutations/shop/useCartSwagg.jsx
@@ -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}`,
@@ -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}`,
@@ -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 };
diff --git a/src/hooks/Mutations/shop/useMakeOrder.jsx b/src/hooks/Mutations/shop/useMakeOrder.jsx
index 08d91dfc..df6b2e68 100644
--- a/src/hooks/Mutations/shop/useMakeOrder.jsx
+++ b/src/hooks/Mutations/shop/useMakeOrder.jsx
@@ -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;
@@ -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();
}
},
});
diff --git a/src/hooks/Queries/shop/useCartProducts.jsx b/src/hooks/Queries/shop/useCartProducts.jsx
index e834e4b1..d3f9ee24 100644
--- a/src/hooks/Queries/shop/useCartProducts.jsx
+++ b/src/hooks/Queries/shop/useCartProducts.jsx
@@ -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}`,
diff --git a/src/hooks/Queries/shop/useSwagList.jsx b/src/hooks/Queries/shop/useSwagList.jsx
index b14035f1..2201942f 100644
--- a/src/hooks/Queries/shop/useSwagList.jsx
+++ b/src/hooks/Queries/shop/useSwagList.jsx
@@ -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");
diff --git a/src/pages/shop/Homepage.jsx b/src/pages/shop/Homepage.jsx
index 3ed1e2b1..adaa2637 100644
--- a/src/pages/shop/Homepage.jsx
+++ b/src/pages/shop/Homepage.jsx
@@ -1,4 +1,6 @@
+import { useState } from "react";
import SeoMetadata from "../../components/SeoMetadata";
+import CartDrawer from "../../components/shop/CartDrawer";
import CartIcon from "../../components/shop/CartIcon";
import Banner from "./sections/Banner/index";
import BrowseProducts from "./sections/BrowseProducts";
@@ -7,6 +9,8 @@ import FilterSection from "./sections/FilterSection";
import NewProducts from "./sections/NewArrivals";
function Homepage() {
+ const [open, setOpen] = useState(false);
+
return (
<>
-
+
@@ -28,6 +38,7 @@ function Homepage() {
+
>
);
}
diff --git a/src/pages/shop/OrderSummaryPage.jsx b/src/pages/shop/OrderSummaryPage.jsx
index 8ee4cf39..cea35de5 100644
--- a/src/pages/shop/OrderSummaryPage.jsx
+++ b/src/pages/shop/OrderSummaryPage.jsx
@@ -5,7 +5,10 @@ import { FaTrash } from "react-icons/fa";
import { LazyLoadImage } from "react-lazy-load-image-component";
import { Link } from "react-router-dom";
-import { useDeleteSwag } from "../../hooks/Mutations/shop/useCartSwagg";
+import {
+ useDeleteSwag,
+ useDeleteAllSwag,
+} from "../../hooks/Mutations/shop/useCartSwagg";
import useMakeOrder from "../../hooks/Mutations/shop/useMakeOrder";
import useProductsInCart from "../../hooks/Queries/shop/useCartProducts";
import PaymentMethd from "./PaymentMethd";
@@ -20,15 +23,30 @@ function Checkout() {
} = useMakeOrder();
const { mutate: deleteSwag } = useDeleteSwag(); // Use deleteSwag
+ const { mutate: clearCart } = useDeleteAllSwag();
+
const [isOpen, setIsOpen] = useState(false);
+ const clearLocalStorageCart = () => {
+ localStorage.setItem("swagList", []);
+ };
+
const handleSubmit = (data) => {
const payload = {
- country: data.address.country,
+ city: `${data.address.city}, ${data.address.country}`,
phone: data.phoneNumber,
- address: `${data.address.postalAddress}, ${data.address.city}`,
+ address: data.address.postalAddress,
+ postal_code: data.address.postalCode,
};
makeOrder(payload);
+
+ if (successfulOrder) {
+ // clear session cart
+ clearCart();
+
+ // delete local storage cart
+ clearLocalStorageCart();
+ }
};
const closeModal = () => {
diff --git a/src/pages/shop/SingleItemPage.jsx b/src/pages/shop/SingleItemPage.jsx
index 4e0a8481..ecb54c52 100644
--- a/src/pages/shop/SingleItemPage.jsx
+++ b/src/pages/shop/SingleItemPage.jsx
@@ -9,13 +9,21 @@ import SmallSample1 from "../../assets/images/shop-page/small-sample-colored.png
import SmallSample2 from "../../assets/images/shop-page/small-sample-greyscale.png";
import SeoMetadata from "../../components/SeoMetadata";
import CartDrawer from "../../components/shop/CartDrawer";
-import Counter from "../../components/shop/Counter";
+// import Counter from "../../components/shop/Counter";
import { useAddSwagToCart } from "../../hooks/Mutations/shop/useCartSwagg";
import { useSingleSwag } from "../../hooks/Queries/shop/useSwagList";
import formatPrice from "../../utilities/formatPrice";
import ItemHeader from "./sections/ItemHeader";
-const VariationData = [SmallSample1, SmallSample2, SmallSample1, SmallSample2];
+const VariationData = [
+ SmallSample1,
+ SmallSample2,
+ SmallSample1,
+ SmallSample2,
+ SmallSample2,
+ SmallSample1,
+ SmallSample2,
+];
export default function SingleItemPage() {
const params = useParams();
@@ -23,36 +31,74 @@ export default function SingleItemPage() {
const [count, setCount] = useState(1);
const [open, setOpen] = useState(false);
const [selectedSize, setSelectedSize] = useState(null);
- const [selectedColor, setSelectedColor] = useState(null);
- const [Payload, setPayload] = useState({});
+ const [selectedColor, setSelectedColor] = useState("");
+
+ const [selectedVariant, setSelectedVariant] = useState(null);
+ const [variants, setVariants] = useState(null);
+ const [selectedImage, setSelectedImage] = useState(1);
+ const [error, setError] = useState("");
// const { data: singleOrder } = useSingleOrder(params.id);
- const { data: singleSwag, isSuccess, refetch } = useSingleSwag(params.id);
+ const {
+ data: singleSwag,
+ isSuccess,
+ isPending,
+ isError,
+ refetch,
+ } = useSingleSwag(params.id);
+
const { mutate: addItemsToCart } = useAddSwagToCart();
- const sizes = ["XS", "S", "M", "L", "XL", "XXL"];
- const colors = ["BBD278", "BBC1F8", "FFD3F8", "AF674F"];
+ const sizes = {
+ XS: "Extra Small",
+ S: "Small",
+ M: "Medium",
+ L: "Large",
+ XL: "Extra Large",
+ };
useEffect(() => {
- localStorage.setItem("swagList", []);
if (isSuccess) {
- setPayload({
- swagg_id: singleSwag.id,
- product: {
- name: singleSwag.name,
- description: singleSwag.description,
- price: singleSwag.price,
- size: selectedSize,
- image: singleSwag.image,
- },
- quantity: count,
- });
+ const initialVariant = singleSwag.attributes[0];
+ setSelectedVariant(initialVariant);
+ setSelectedColor(initialVariant.color);
+ setVariants(singleSwag.attributes);
}
+ }, [isSuccess, singleSwag]);
+
+ useEffect(() => {
refetch();
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [params.id]);
+ }, [params.id, refetch]);
+
+ useEffect(() => {
+ // Update selected variant when selected color changes
+ if (selectedColor && variants) {
+ const variant = variants.find((v) => v.color === selectedColor);
+ setSelectedVariant(variant);
+ }
+ }, [selectedColor, variants]);
const addToLocalStorage = () => {
+ // find an attribute with an image URL
+ const attributeWithImages = singleSwag.attributes.find(
+ (attribute) => attribute.images.length > 0
+ );
+
+ const newData = {
+ id: crypto.randomUUID(),
+ name: singleSwag.name,
+ category: singleSwag.category,
+ size: selectedSize.name,
+ color: selectedColor,
+ price: singleSwag.price * count,
+ orderUnits: count,
+ slug: singleSwag.slug,
+ image:
+ selectedVariant.images.length > 0
+ ? selectedVariant.images[0].image
+ : attributeWithImages.images.map((img) => img.image)[0],
+ };
+
let swagList = [];
let swagListJSON;
if (localStorage.getItem("swagList")) {
@@ -60,11 +106,11 @@ export default function SingleItemPage() {
swagList = JSON.parse(localStorage.getItem("swagList"));
// Also check for matching swagg_id that already exist in local storage
- swagList.push(Payload);
+ swagList.push(newData);
swagListJSON = JSON.stringify(swagList);
localStorage.setItem("swagList", swagListJSON);
} else {
- swagList.push(Payload);
+ swagList.push(newData);
swagListJSON = JSON.stringify(swagList);
localStorage.setItem("swagList", swagListJSON);
@@ -72,18 +118,25 @@ export default function SingleItemPage() {
};
const handleAddToCart = () => {
- // Send to backend not giving a usable response
- addItemsToCart(Payload);
-
- // Add to local storage
- addToLocalStorage();
+ if (!selectedSize) {
+ setError("Please select a size");
+ } else {
+ // Add a new item to the cart in the backend
+ addItemsToCart({
+ product_attribute: selectedVariant.id,
+ quantity: count,
+ });
+ // Add to local storage
+ addToLocalStorage();
- setOpen(true);
+ // open cart
+ setOpen(true);
+ }
};
// const handleBuyNow = () => {
// // Send to backend not giving a usable response
- // addItemsToCart(Payload);
+ // addItemsToCart(payload);
// // Add to local storage
// addToLocalStorage();
@@ -91,6 +144,17 @@ export default function SingleItemPage() {
// navigate("/shop/checkout");
// };
+ const increment = () => {
+ setCount((prevCount) => prevCount + 1);
+ };
+
+ const decrement = () => {
+ setCount((prevCount) => (prevCount > 1 ? prevCount - 1 : prevCount));
+ };
+
+ const getSizeKeyByValue = (value) =>
+ Object.keys(sizes).find((key) => sizes[key] === value);
+
return (
<>
setOpen((prev) => !prev)} />
- {isSuccess ? (
+ {isSuccess && (
-
-
- {VariationData.map((pic) => (
-
-
-
+
+ {VariationData.map((image, index) => (
+
+ ))}
+
+
+ {VariationData.map((pic, index) => (
+
))}
- {singleSwag.name}
+ {singleSwag?.name}
- KES {formatPrice(singleSwag.price)}
+ KES {formatPrice(singleSwag?.price)}
4.5
@@ -139,68 +219,104 @@ export default function SingleItemPage() {
- {colors.map((color) => (
-
- ))}
+ ) : (
+
+ )}
+
+ ))}
Choose a size
- {sizes.map((size) => (
- setSelectedSize(size)}
- >
- {selectedSize === size ? (
-
- ) : (
-
- )}{" "}
- {size}
-
- ))}
+ {selectedVariant &&
+ selectedVariant?.size.map((size) => (
+ setSelectedSize(size)}
+ >
+ {selectedSize === size ? (
+
+ ) : (
+
+ )}{" "}
+ {getSizeKeyByValue(size.name)}
+
+ ))}
+ {error && (
+
{error}
+ )}
-
+ maxStock={selectedVariant?.stock}
+ /> */}
+
+
+ −
+
+
+ {count}
+
+
selectedVariant?.stock
+ }
+ 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={increment}
+ >
+ +
+
+
- {singleSwag.description}
+ {singleSwag?.description}
+
+
+
+ )}
+ {isPending && (
+
+ )}
+ {isError && (
+
+
+
+ Error fetching product. Try again later
- ) : (
-
Error Fetching Item
)}
{/* Cart Drawer */}
diff --git a/src/pages/shop/sections/Banner/Carousal.jsx b/src/pages/shop/sections/Banner/Carousal.jsx
index 275dc828..d010902e 100644
--- a/src/pages/shop/sections/Banner/Carousal.jsx
+++ b/src/pages/shop/sections/Banner/Carousal.jsx
@@ -2,6 +2,7 @@ import { useEffect, useRef, useState } from "react";
import { LazyLoadImage } from "react-lazy-load-image-component";
import { Link } from "react-router-dom";
import { useSwagList } from "../../../../hooks/Queries/shop/useSwagList";
+import formatPrice from "../../../../utilities/formatPrice";
function Carousel() {
const [width, setWidth] = useState(0);
@@ -80,9 +81,11 @@ function Carousel() {
Buy out most stylish tech themed items
-
From KES 2,600
+
+ From KES {formatPrice(swagList[selectedIndex]?.price)}
+
Shop Now
diff --git a/src/pages/shop/sections/BrowseProducts.jsx b/src/pages/shop/sections/BrowseProducts.jsx
index d01d5d26..d1f11205 100644
--- a/src/pages/shop/sections/BrowseProducts.jsx
+++ b/src/pages/shop/sections/BrowseProducts.jsx
@@ -4,7 +4,7 @@ import SectionWrapper from "../../../components/shop/SectionWrapper";
import { useSwagList } from "../../../hooks/Queries/shop/useSwagList";
function BrowseProducts() {
- const { data: swagList } = useSwagList();
+ const { data: swagList, isSuccess, isError, isPending } = useSwagList();
return (
@@ -15,11 +15,41 @@ function BrowseProducts() {
- {Array.isArray(swagList) &&
+ {isSuccess &&
+ swagList?.length > 0 &&
swagList.map((product) => (
))}
+ {isSuccess && swagList?.length === 0 && (
+
+
+
No products available
+
+
+ )}
+ {isPending && (
+
+
+
Loading products...
+
+
+
+ )}
+ {isError && (
+
+
+
+ Error fetching products. Try again later
+
+
+
+ )}
);
diff --git a/src/pages/shop/sections/ItemHeader.jsx b/src/pages/shop/sections/ItemHeader.jsx
index 155ff9a9..23091ebe 100644
--- a/src/pages/shop/sections/ItemHeader.jsx
+++ b/src/pages/shop/sections/ItemHeader.jsx
@@ -5,7 +5,9 @@
// import { Fragment, useState } from "react";
// import { useSwagList } from "../../../hooks/Queries/shop/useSwagList";
import PropTypes from "prop-types";
+import { useState } from "react";
import { useLocation, useParams } from "react-router-dom";
+import CartDrawer from "../../../components/shop/CartDrawer";
import CartIcon from "../../../components/shop/CartIcon";
import SectionWrapper from "../../../components/shop/SectionWrapper";
@@ -13,6 +15,7 @@ import SectionWrapper from "../../../components/shop/SectionWrapper";
function ItemHeader({ show }) {
const { pathname } = useLocation();
const { id } = useParams();
+ const [open, setOpen] = useState(false);
const pathnames = pathname
.split("/")
@@ -66,7 +69,14 @@ function ItemHeader({ show }) {
-
+
setOpen(true)}
+ >
+
+
+
{/* Search box */}
{/*
diff --git a/src/pages/shop/sections/NewArrivals.jsx b/src/pages/shop/sections/NewArrivals.jsx
index 8fb5c56a..b2c1d9f7 100644
--- a/src/pages/shop/sections/NewArrivals.jsx
+++ b/src/pages/shop/sections/NewArrivals.jsx
@@ -4,7 +4,7 @@ import SectionWrapper from "../../../components/shop/SectionWrapper";
import { useSwagList } from "../../../hooks/Queries/shop/useSwagList";
function NewProducts() {
- const { data: swagList } = useSwagList();
+ const { data: swagList, isSuccess, isError, isPending } = useSwagList();
return (
@@ -15,7 +15,8 @@ function NewProducts() {
- {Array.isArray(swagList) &&
+ {isSuccess &&
+ swagList?.length > 0 &&
swagList.slice(0, 10).map((product) => (
))}
+ {isSuccess && swagList?.length === 0 && (
+
+
+
+ No new products available
+
+
+
+ )}
+ {isPending && (
+
+
+
Loading products...
+
+
+
+ )}
+ {isError && (
+
+
+
+ Error fetching products. Try again later
+
+
+
+ )}
);
diff --git a/src/pages/shop/sections/PopularItemsSection.jsx b/src/pages/shop/sections/PopularItemsSection.jsx
index 50a6d03b..f750cc7b 100644
--- a/src/pages/shop/sections/PopularItemsSection.jsx
+++ b/src/pages/shop/sections/PopularItemsSection.jsx
@@ -1,13 +1,8 @@
-import { CiShoppingTag } from "react-icons/ci";
-import { LazyLoadImage } from "react-lazy-load-image-component";
-import { useNavigate } from "react-router-dom";
+import ProductCard from "../../../components/shop/ProductCard";
import { useSwagList } from "../../../hooks/Queries/shop/useSwagList";
-import formatPrice from "../../../utilities/formatPrice";
function PopularItemsSection() {
- const navigate = useNavigate();
-
- const { data: products } = useSwagList();
+ const { data: products, isSuccess, isError, isPending } = useSwagList();
return (
@@ -21,61 +16,47 @@ function PopularItemsSection() {
Products similar to the one above
-
- {products
- ?.slice(0, 8)
- .map(({ stock, category, id, name, image, price }) => (
+ {isSuccess && products?.length > 0 && (
+
+ {products?.slice(0, 8).map((product) => (
navigate(`/shop/item/${id}`)}
- role="button"
- tabIndex={0}
- onKeyPress={(event) => {
- if (event.key === "Enter" || event.key === " ") {
- navigate(`/shop/item/${id}`);
- }
- }}
+ className="min-w-[100%] sm:min-w-[50%] lg:min-w-[33%] h-full"
+ key={product.id}
>
-
-
-
-
-
-
-
- {name}
-
-
- {stock ? (
-
- {stock} {stock === 1 ? "item" : "items"} left
-
- ) : (
-
- Out of stock
-
- )}
-
-
-
-
- KES {formatPrice(price)}
-
-
-
+
))}
-
+
+ )}
+ {isSuccess && products?.length === 0 && (
+
+
+
No products available
+
+
+ )}
+ {isPending && (
+
+
+
Loading products...
+
+
+
+ )}
+ {isError && (
+
+
+
+ Error fetching products. Try again later
+
+
+
+ )}
);
}