mirror of
https://github.com/vercel/commerce.git
synced 2025-05-18 23:46:58 +00:00
138 lines
3.3 KiB
TypeScript
138 lines
3.3 KiB
TypeScript
'use server';
|
|
|
|
import { TAGS } from 'lib/constants';
|
|
import {
|
|
addToCart,
|
|
createCart,
|
|
getCart,
|
|
getDiscountMetaobjects,
|
|
removeFromCart,
|
|
updateCart
|
|
} from 'lib/shopify';
|
|
import { formatDiscounts } from 'lib/utils';
|
|
import { revalidateTag } from 'next/cache';
|
|
import { cookies } from 'next/headers';
|
|
|
|
export async function addItem(prevState: any, selectedVariantId: string | undefined) {
|
|
let cartId = cookies().get('cartId')?.value;
|
|
let cart;
|
|
|
|
if (cartId) {
|
|
cart = await getCart(cartId);
|
|
}
|
|
|
|
if (!cartId || !cart) {
|
|
cart = await createCart();
|
|
cartId = cart.id;
|
|
cookies().set('cartId', cartId);
|
|
}
|
|
|
|
if (!selectedVariantId) {
|
|
return 'Missing product variant ID';
|
|
}
|
|
|
|
try {
|
|
await addToCart(cartId, [{ merchandiseId: selectedVariantId, quantity: 1 }]);
|
|
revalidateTag(TAGS.cart);
|
|
} catch (e) {
|
|
return 'Error adding item to cart';
|
|
}
|
|
}
|
|
|
|
export async function removeItem(prevState: any, lineId: string) {
|
|
const cartId = cookies().get('cartId')?.value;
|
|
|
|
if (!cartId) {
|
|
return 'Missing cart ID';
|
|
}
|
|
|
|
try {
|
|
await removeFromCart(cartId, [lineId]);
|
|
revalidateTag(TAGS.cart);
|
|
} catch (e) {
|
|
return 'Error removing item from cart';
|
|
}
|
|
}
|
|
|
|
export async function updateItemQuantity(
|
|
prevState: any,
|
|
payload: {
|
|
lineId: string;
|
|
variantId: string;
|
|
quantity: number;
|
|
}
|
|
) {
|
|
const cartId = cookies().get('cartId')?.value;
|
|
|
|
if (!cartId) {
|
|
return 'Missing cart ID';
|
|
}
|
|
|
|
const { lineId, variantId, quantity } = payload;
|
|
|
|
try {
|
|
if (quantity === 0) {
|
|
await removeFromCart(cartId, [lineId]);
|
|
revalidateTag(TAGS.cart);
|
|
return;
|
|
}
|
|
|
|
await updateCart(cartId, [
|
|
{
|
|
id: lineId,
|
|
merchandiseId: variantId,
|
|
quantity
|
|
}
|
|
]);
|
|
revalidateTag(TAGS.cart);
|
|
} catch (e) {
|
|
return 'Error updating item quantity';
|
|
}
|
|
}
|
|
|
|
export async function calculateDiscounts(cart: any) {
|
|
const metaobjects = await getDiscountMetaobjects('dynamic_discount');
|
|
|
|
const discountGroups = formatDiscounts(metaobjects);
|
|
|
|
if (discountGroups === undefined) {
|
|
return;
|
|
}
|
|
|
|
const subTotal = cart?.cost.subtotalAmount.amount;
|
|
const currencyCode = cart?.cost.subtotalAmount.currencyCode;
|
|
|
|
const discountGroupsSorted = discountGroups.sort(
|
|
(a, b) => a.discount.minimumSpent - b.discount.minimumSpent
|
|
);
|
|
const minSpent = Math.max(...discountGroupsSorted.map((group) => group.discount.minimumSpent));
|
|
const eligibleDiscount = discountGroupsSorted.filter(
|
|
(group) => subTotal >= group.discount.minimumSpent
|
|
);
|
|
const finalDiscount = eligibleDiscount.length
|
|
? Math.max(...eligibleDiscount.map((group) => group.discount.amount))
|
|
: 0;
|
|
const closestNextTier = discountGroupsSorted
|
|
.filter((group) => group.discount.minimumSpent > subTotal)
|
|
.shift();
|
|
|
|
const spentToNextDiscount = closestNextTier
|
|
? closestNextTier?.discount.minimumSpent - subTotal
|
|
: 0;
|
|
const nextDiscount = closestNextTier?.discount.amount;
|
|
const discountAmount = finalDiscount ? finalDiscount * 100 : 0;
|
|
// get discount code from the final discount group
|
|
const discountCode = eligibleDiscount.length ? eligibleDiscount[0]?.code : '';
|
|
|
|
return {
|
|
discountAmount,
|
|
spentToNextDiscount,
|
|
nextDiscount,
|
|
discountGroups: discountGroupsSorted,
|
|
discountCode,
|
|
minSpent,
|
|
subTotal,
|
|
currencyCode
|
|
};
|
|
}
|