'use server'; import { TAGS } from 'lib/constants'; import { addToCart, createCart, getCart, removeFromCart, updateCart } from 'lib/shopify'; import { revalidateTag } from 'next/cache'; import { cookies } from 'next/headers'; import { redirect } from 'next/navigation'; export async function addItem( prevState: any, selectedVariantId: string | undefined, quantity: number = 1, attributes?: { key: string; value: string }[] ) { const cookieStore = await cookies(); let cartId = cookieStore.get('cartId')?.value; if (!selectedVariantId) { return 'Error adding item to cart'; } try { if (!cartId) { const cart = await createCart(); cartId = cart.id!; cookieStore.set('cartId', cartId); } await addToCart(cartId, [{ merchandiseId: selectedVariantId, quantity, attributes }]); revalidateTag(TAGS.cart); } catch (e) { return 'Error adding item to cart'; } } export async function removeItem(prevState: any, merchandiseId: string, itemId?: string) { const cookieStore = await cookies(); let cartId = cookieStore.get('cartId')?.value; if (!cartId) { return 'Missing cart ID'; } try { const cart = await getCart(cartId); if (!cart) { return 'Error fetching cart'; } // Find specific line item - first by itemId if provided, otherwise by merchandiseId let lineItem; if (itemId) { // If we have a specific item ID (e.g., for box items), use that first lineItem = cart.lines.find((line) => line.id === itemId); } // If no item ID was provided or no match was found, fall back to merchandise ID if (!lineItem) { lineItem = cart.lines.find((line) => line.merchandise.id === merchandiseId); } if (lineItem && lineItem.id) { // Check if this is a box item being removed const lineAttributes = lineItem.attributes || []; const boxType = lineAttributes.find(attr => attr.key === '_box_type')?.value; const boxGroupId = lineAttributes.find(attr => attr.key === '_box_group_id')?.value; // If this is a box item (not container), check if it's the last one before removing if (boxType === 'item' && boxGroupId) { // Find all items in this box (excluding the current one we're removing) const remainingBoxItems = cart.lines.filter(line => { const attrs = line.attributes || []; const itemBoxGroupId = attrs.find(attr => attr.key === '_box_group_id')?.value; const itemBoxType = attrs.find(attr => attr.key === '_box_type')?.value; return itemBoxGroupId === boxGroupId && line.id !== lineItem.id && itemBoxType === 'item'; }); // If this is the last item, find the box container and remove both together if (remainingBoxItems.length === 0) { const boxContainer = cart.lines.find(line => { const attrs = line.attributes || []; const containerBoxGroupId = attrs.find(attr => attr.key === '_box_group_id')?.value; const containerBoxType = attrs.find(attr => attr.key === '_box_type')?.value; return containerBoxGroupId === boxGroupId && containerBoxType === 'container'; }); // If box container exists, remove both item and container in a single operation if (boxContainer && boxContainer.id) { // Batched removal of both the item and box container await removeFromCart(cartId, [lineItem.id, boxContainer.id]); } else { // Just remove the item if no container found await removeFromCart(cartId, [lineItem.id]); } } else { // Not the last item, just remove this one await removeFromCart(cartId, [lineItem.id]); } } else { // Regular item or box container, just remove it await removeFromCart(cartId, [lineItem.id]); } revalidateTag(TAGS.cart); } else { return 'Item not found in cart'; } } catch (e) { return 'Error removing item from cart'; } } export async function updateItemQuantity( prevState: any, payload: { merchandiseId: string; quantity: number; itemId?: string; } ) { const cookieStore = await cookies(); let cartId = cookieStore.get('cartId')?.value; if (!cartId) { return 'Missing cart ID'; } const { merchandiseId, quantity, itemId } = payload; try { const cart = await getCart(cartId); if (!cart) { return 'Error fetching cart'; } // Find the specific line item to update let lineItem; if (itemId) { // First try to find by specific item ID (for items in multiple boxes) lineItem = cart.lines.find(line => line.id === itemId); } // Fall back to finding by merchandise ID if item ID didn't work if (!lineItem) { lineItem = cart.lines.find(line => line.merchandise.id === merchandiseId); } if (lineItem && lineItem.id) { if (quantity === 0) { await removeFromCart(cartId, [lineItem.id]); } else { await updateCart(cartId, [ { id: lineItem.id, merchandiseId, quantity } ]); } } else if (quantity > 0) { // If the item doesn't exist in the cart and quantity > 0, add it await addToCart(cartId, [{ merchandiseId, quantity }]); } revalidateTag(TAGS.cart); } catch (e) { console.error(e); return 'Error updating item quantity'; } } export async function redirectToCheckout() { const cookieStore = await cookies(); let cartId = cookieStore.get('cartId')?.value; if (!cartId) { return 'No cart found'; } let cart = await getCart(cartId); if (!cart) { return 'Error fetching cart'; } if (!cart.checkoutUrl) { return 'No checkout URL available'; } redirect(cart.checkoutUrl); } export async function createCartAndSetCookie() { const cookieStore = await cookies(); let cart = await createCart(); cookieStore.set('cartId', cart.id!); } export async function validateDiscountCode(prevState: any, discountCode: string) { if (!discountCode || discountCode.trim() === '') { return { isValid: false, message: 'Please enter a discount code' }; } const cookieStore = await cookies(); let cartId = cookieStore.get('cartId')?.value; if (!cartId) { return { isValid: false, message: 'No cart found. Please add items to your cart first.' }; } try { // TODO: Implement discount code validation const isValid = Math.random() > 0.5; if (isValid) { return { isValid: true, message: 'Discount code applied successfully!' }; } else { return { isValid: false, message: 'Invalid discount code. Please try again.' }; } } catch (e) { console.error('Error validating discount code:', e); return { isValid: false, message: 'An error occurred while validating the discount code.' }; } }