Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 89 additions & 101 deletions src/components/Cart/CartContents.component.tsx
Original file line number Diff line number Diff line change
@@ -1,65 +1,43 @@
/*eslint complexity: ["error", 20]*/
// Imports
import { useContext, useEffect } from 'react';
import { useMutation, useQuery } from '@apollo/client';
import Link from 'next/link';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { v4 as uuidv4 } from 'uuid';

// State
import { CartContext } from '@/stores/CartProvider';

// Components
import Button from '@/components/UI/Button.component';
import LoadingSpinner from '../LoadingSpinner/LoadingSpinner.component';

// Utils
import {
getFormattedCart,
getUpdatedItems,
handleQuantityChange,
IProductRootObject,
} from '@/utils/functions/functions';

// GraphQL
import { GET_CART } from '@/utils/gql/GQL_QUERIES';
import { UPDATE_CART } from '@/utils/gql/GQL_MUTATIONS';

/**
* Renders cart contents.
* @function CartContents
* @returns {JSX.Element} - Rendered component
*/
const CartContents = () => {
const router = useRouter();

const { setCart } = useContext(CartContext);

const isCheckoutPage = router.pathname === '/kasse';

// Get cart data query
const { data, refetch } = useQuery(GET_CART, {
notifyOnNetworkStatusChange: true,
onCompleted: () => {
// Update cart in the localStorage.
const updatedCart = getFormattedCart(data);

if (!updatedCart && !data.cart.contents.nodes.length) {
// Clear the localStorage if we have no remote cart

localStorage.removeItem('woocommerce-cart');
setCart(null);
return;
}

localStorage.setItem('woocommerce-cart', JSON.stringify(updatedCart));

// Update cart data in React Context.
setCart(updatedCart);
},
});

// Update Cart Mutation.
const [updateCart, { loading: updateCartProcessing }] = useMutation(
UPDATE_CART,
{
Expand All @@ -76,11 +54,8 @@ const CartContents = () => {
cartKey: string,
products: IProductRootObject[],
) => {
if (products.length) {
// By passing the newQty to 0 in updateCart Mutation, it will remove the item.
const newQty = 0;
const updatedItems = getUpdatedItems(products, newQty, cartKey);

if (products?.length) {
const updatedItems = getUpdatedItems(products, 0, cartKey);
updateCart({
variables: {
input: {
Expand All @@ -90,9 +65,7 @@ const CartContents = () => {
},
});
}

refetch();

setTimeout(() => {
refetch();
}, 3000);
Expand All @@ -102,50 +75,46 @@ const CartContents = () => {
refetch();
}, [refetch]);

const cartTotal = data?.cart?.total || '0';

const getUnitPrice = (subtotal: string, quantity: number) => {
const numericSubtotal = parseFloat(subtotal.replace(/[^0-9.-]+/g, ''));
return isNaN(numericSubtotal)
? 'N/A'
: (numericSubtotal / quantity).toFixed(2);
};

return (
<section className="py-8 mt-10">
<div className="container flex flex-wrap items-center mx-auto">
{data?.cart?.contents?.nodes.length ? (
data.cart.contents.nodes.map((item: IProductRootObject) => (
<div
className="container mx-auto mt-4 flex flex-wrap flex-row justify-around items-center content-center m-w-[1380px] border border-gray-300 rounded-lg shadow
"
key={item.key}
>
<div className="lg:m-2 xl:m-4 xl:w-1/6 lg:w-1/6 sm:m-2 w-auto">
<span className="block mt-2 font-extrabold">
Slett: <br />
</span>
<span className="inline-block mt-4 w-20 h-12 md:w-full lg:w-full xl:w-full">
<Button
color="red"
buttonDisabled={updateCartProcessing}
handleButtonClick={() =>
handleRemoveProductClick(
item.key,
data.cart.contents.nodes,
)
<div className="container mx-auto px-4 py-8">
{data?.cart?.contents?.nodes?.length ? (
<>
<div className="bg-white rounded-lg shadow-md p-6 mb-8 md:w-full">
{data.cart.contents.nodes.map((item: IProductRootObject) => (
<div
key={item.key}
className="flex items-center border-b border-gray-200 py-4"
>
<div className="flex-shrink-0 w-24 h-24 relative">
<Image
src={
item.product.node.image?.sourceUrl || '/placeholder.png'
}
>
Slett
</Button>
</span>
</div>
<div className="lg:m-2 xl:m-4 xl:w-1/6 lg:w-1/6 sm:m-2 w-auto">
<span className="block mt-2 font-extrabold">
Navn: <br />
</span>
<span className="inline-block mt-4 w-20 h-12 md:w-full lg:w-full xl:w-full">
{item.product.node.name}
</span>
</div>
<div className="lg:m-2 xl:m-4 xl:w-1/6 lg:w-1/6 sm:m-2 w-auto">
<span className="block mt-2 font-extrabold">
Antall: <br />
</span>
<span className="inline-block mt-4 w-20 h-12 md:w-full lg:w-full xl:w-full">
alt={item.product.node.name}
layout="fill"
objectFit="cover"
className="rounded"
/>
</div>
<div className="flex-grow ml-4">
<h2 className="text-lg font-semibold">
{item.product.node.name}
</h2>
<p className="text-gray-600">
kr {getUnitPrice(item.subtotal, item.quantity)}
</p>
</div>
<div className="flex items-center">
<input
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
type="number"
min="1"
value={item.quantity}
Expand All @@ -158,41 +127,60 @@ const CartContents = () => {
updateCartProcessing,
);
}}
className="w-16 px-2 py-1 text-center border border-gray-300 rounded mr-2"
/>
</span>
</div>
<div className="lg:m-2 xl:m-4 xl:w-1/6 lg:w-1/6 sm:m-2 w-auto">
<span className="block mt-2 font-extrabold">
Total: <br />
</span>
<span className="inline-block mt-4 w-20 h-12 md:w-full lg:w-full xl:w-full">
{item.subtotal}
</span>
<Button
handleButtonClick={() =>
handleRemoveProductClick(
item.key,
data.cart.contents.nodes,
)
}
color="red"
buttonDisabled={updateCartProcessing}
>
Fjern
</Button>
</div>
<div className="ml-4">
<p className="text-lg font-semibold">{item.subtotal}</p>
</div>
</div>
))}
</div>
<div className="bg-white rounded-lg shadow-md p-6 md:w-full">
<div className="flex justify-end mb-4">
<span className="font-semibold pr-2">Subtotal:</span>
<span>{cartTotal}</span>
</div>
))
) : (
<h1 className="text-2xl font-bold mx-auto">
Ingen produkter i handlekurven
</h1>
)}
{updateCartProcessing && (
<div className="mt-4 w-full">
<div className="text-xl mx-auto text-center">
Oppdaterer antall, vennligst vent ...
<LoadingSpinner />
</div>
{!isCheckoutPage && (
<div className="flex justify-center mb-4">
<Link href="/kasse" passHref>
<Button fullWidth>GÅ TIL KASSE</Button>
</Link>
</div>
)}
</div>
)}
{!isCheckoutPage && data?.cart?.contents?.nodes.length ? (
<div className="mt-4 mx-auto">
<Link href="/kasse" passHref>
<Button>GÅ TIL KASSE</Button>
</Link>
</>
) : (
<div className="text-center">
<h2 className="text-2xl font-bold mb-4">
Ingen produkter i handlekurven
</h2>
<Link href="/produkter" passHref>
<Button>Fortsett å handle</Button>
</Link>
</div>
)}
{updateCartProcessing && (
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50">
<div className="bg-white p-4 rounded-lg">
<p className="text-lg mb-2">Oppdaterer handlekurv...</p>
<LoadingSpinner />
</div>
) : null}
</div>
</section>
</div>
)}
</div>
);
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/Layout/Layout.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const Layout = ({ children, title }: ILayoutProps) => {
}, [refetch]);

return (
<div className="flex flex-col min-h-screen">
<div className="flex flex-col min-h-screen container min-w-[140vw] md:min-w-[700px]">
<Header title={title} />
<PageTitle title={title} />
<main className="flex-grow">
Expand Down
2 changes: 1 addition & 1 deletion src/components/Product/SingleProduct.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ const SingleProduct = ({ product }: IProductRootObject) => {
<select
id="variant"
name="variant"
className="block w-full px-4 py-2 bg-white border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className="max-w-[14.375rem] block w-full px-4 py-2 bg-white border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
onChange={(e) => {
setSelectedVariation(Number(e.target.value));
}}
Expand Down
Loading