116 lines
3.1 KiB
TypeScript
116 lines
3.1 KiB
TypeScript
'use client';
|
|
|
|
import { Button } from '@/components/ui/Button';
|
|
import { addItem } from 'components/cart/actions';
|
|
import { useProduct } from 'components/product/product-context';
|
|
import { Product, ProductVariant } from 'lib/shopify/types';
|
|
import { useState, useTransition } from 'react';
|
|
import { useCart } from './cart-context';
|
|
|
|
function SubmitButton({
|
|
availableForSale,
|
|
selectedVariantId,
|
|
isLoading
|
|
}: {
|
|
availableForSale: boolean;
|
|
selectedVariantId: string | undefined;
|
|
isLoading: boolean;
|
|
}) {
|
|
|
|
if (!availableForSale) {
|
|
return (
|
|
<Button
|
|
disabled
|
|
variant="primary"
|
|
size="lg"
|
|
fullWidth
|
|
>
|
|
Out Of Stock
|
|
</Button>
|
|
);
|
|
}
|
|
|
|
if (!selectedVariantId) {
|
|
return (
|
|
<Button
|
|
aria-label="Please select an option"
|
|
disabled
|
|
variant="primary"
|
|
size="lg"
|
|
fullWidth
|
|
>
|
|
Please Select Options
|
|
</Button>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Button
|
|
aria-label="Add to cart"
|
|
disabled={isLoading}
|
|
variant="primary"
|
|
size="lg"
|
|
fullWidth
|
|
>
|
|
{isLoading ? 'Adding...' : 'Add to Cart'}
|
|
</Button>
|
|
);
|
|
}
|
|
|
|
export function AddToCart({ product, quantity = 1 }: { product: Product; quantity?: number }) {
|
|
const { variants, availableForSale } = product;
|
|
const { addCartItem } = useCart();
|
|
const { state } = useProduct();
|
|
const [isPending, startTransition] = useTransition();
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
const variant = variants.find((variant: ProductVariant) =>
|
|
variant.selectedOptions.every((option) => option.value === state[option.name.toLowerCase()])
|
|
);
|
|
const defaultVariantId = variants.length === 1 ? variants[0]?.id : undefined;
|
|
const selectedVariantId = variant?.id || defaultVariantId;
|
|
const finalVariant = variants.find((variant) => variant.id === selectedVariantId)!;
|
|
|
|
const handleSubmit = (event: React.FormEvent) => {
|
|
event.preventDefault();
|
|
|
|
// Don't proceed if the form is already being processed
|
|
if (isLoading) return;
|
|
|
|
// Don't proceed if there's no variant ID
|
|
if (!selectedVariantId) return;
|
|
|
|
// Set loading state
|
|
setIsLoading(true);
|
|
|
|
// Use the quantity prop passed to the component
|
|
// No need to get it from formData since there's no quantity input in the form
|
|
|
|
const finalVariant = variants.find((v) => v.id === selectedVariantId);
|
|
if (!finalVariant) return;
|
|
|
|
// Call the server action to add the item to the cart
|
|
// @ts-ignore - We know our server action accepts quantity
|
|
addItem(null, selectedVariantId, quantity)
|
|
.then(() => {
|
|
// Add to context cart for immediate UI feedback
|
|
addCartItem(finalVariant, product, quantity);
|
|
});
|
|
|
|
// Add a small delay before removing loading state for better UX
|
|
setTimeout(() => {
|
|
setIsLoading(false);
|
|
}, 500);
|
|
};
|
|
|
|
return (
|
|
<form onSubmit={handleSubmit} className="w-full">
|
|
<SubmitButton
|
|
availableForSale={availableForSale}
|
|
selectedVariantId={selectedVariantId}
|
|
isLoading={isLoading}
|
|
/>
|
|
</form>
|
|
);
|
|
}
|