How to add free gift products to cart
This guide will help you to add free gift products to cart.
Introduction
This guide will help you to add free gift products to cart.
Hooks
manage-cart-after-response
This hook helps to manage the cart after the response.It can be used to add free gift products to cart.
appmakerFunctions.registerAppmakerFn({
trigger: 'manage-cart-after-response',
namespace: 'free-gift', // your namespace
function: AddFreeGiftToCart, // your function
});Steps
- Use the
manage-cart-after-responsehook to add free gift products to cart. You can register the hook in theindex.jsfile.
import appmakerFunctions from '@appmaker-xyz/core';
import addFreeGift from './lib/addFreeGift'; // your function file
export function activate() {
appmakerFunctions.registerAppmakerFn({
trigger: 'manage-cart-after-response',
namespace: 'free-gift', // your namespace
function: addFreeGift, // your function
});
}
// Register the plugin or theme. let's take example of plugin
const Plugin = {
id: 'custom-free-gift', // your plugin id
name: 'custom-free-gift', // your plugin name
activate,
};
export default Plugin;- Create a function file
addFreeGift.jsin a folderliband add the following code.
import { parse } from '@appmaker-xyz/core';
import { shopifyIdHelper, productsStore } from '@appmaker-xyz/shopify';
import getConditionalCartSum from './lib/getConditionalCartSum'; // your function to get cart total
import { isEmpty } from 'lodash';
export function addFreeGift(input, dependencies) {
const {
cartHelpers: { hasVariantInCart },
coreDispatch,
} = dependencies;
const freeGiftsToAdd = [];
const existingFreeGifts = [];
const freeGiftToRemove = [];
let nextFreeGiftIndex = false;
let cartTotals = [];
// Logger for debugging
function log(...args) {
if (debugLog) {
console.log('free-gift', ...args);
}
}
const freeGiftDependencies = {
log,
...dependencies,
};
// set cart message if any
function setCartMessage(message, product) {
coreDispatch({
type: 'SET_APP_STORAGE_STATE',
value: {
cart_custom_message: message,
next_free_gift_product: product,
},
});
}
// get freeGifts
const freeGifts = getFreeGifts(); // your function to get free gifts
if (Array.isArray(freeGifts) && freeGifts.length > 0) {
// Sort freeGift by cart_value_amount
freeGifts.sort((a, b) => a.cart_value_amount - b.cart_value_amount);
nextFreeGiftIndex = 0;
for (const [freeGiftIndex, gift] of freeGifts.entries()) {
const cartTotal = getConditionalCartSum({
input,
cartSumCondition: gift?.cart_value_condition,
collections: gift?.collections,
dependencies: freeGiftDependencies,
}); // your function to get cart total
cartTotals[freeGiftIndex] = cartTotal;
const { products, cart_value_amount } = gift;
const cart_value_required = parseFloat(cart_value_amount);
if (cartTotal >= cart_value_required) {
log('free gift condition met', {
cartTotal,
cart_value_required,
});
for (const product of products) {
let availableVariantId = await getAvailableVariant();// your function to get available variant
// Check if product is available
if (
availableVariantId &&
!hasVariantInCart(input, availableVariantId)
) {
log('Adding free gift', availableVariantId);
freeGiftsToAdd.push({
variantId: availableVariantId,
quantity: 1,
customAttributes: [
{
key: 'appmaker_free_gift',
value: 'Free Gift',
},
...(gift?.attributes || []),
],
});
} else if (availableVariantId) {
log('Free gift already in cart', availableVariantId);
existingFreeGifts.push(availableVariantId);
} else {
log('Not adding as all gift unavailable', availableVariantId);
}
}
nextFreeGiftIndex = freeGifts[freeGiftIndex + 1]
? freeGiftIndex + 1
: false;
} else if (cartTotal < cart_value_required) {
log('free gift condition not met', {
cartTotal,
cart_value_required,
});
}
}
// Remove all non-elgible free gifts
if (input?.currentCart?.lineItems?.edges?.length > 0) {
input.currentCart.lineItems.edges.forEach((item) => {
const currentLineItem = item.node;
const { customAttributes } = currentLineItem;
const isFreeGift = customAttributes.find(
(attribute) => attribute.key === 'appmaker_free_gift',
);
if (isFreeGift) {
const variantId = currentLineItem.variant.id;
// check if variant is in existingFreeGifts
const isExistingFreeGift = existingFreeGifts.find(
(existingFreeGiftItem) => existingFreeGiftItem === variantId,
);
if (!isExistingFreeGift) {
log('Removing free gift', variantId);
freeGiftToRemove.push({
id: currentLineItem.id,
variantId: variantId,
quantity: 0,
});
}
} else {
// log('not a free gift', currentLineItem);
}
});
}
log('nextFreeGiftIndex', nextFreeGiftIndex);
/**
* Add free gift message if any free gift is pending to add and message is set
*/
if (
nextFreeGiftIndex !== false &&
!isEmpty(freeGifts[nextFreeGiftIndex].pre_offer_apply_cart_message)
) {
const nextFreeGift = freeGifts[nextFreeGiftIndex];
const difference =
nextFreeGift.cart_value_amount - cartTotals[nextFreeGiftIndex];
const cartMessage = parse({
template: {
message: nextFreeGift.pre_offer_apply_cart_message,
},
data: {
difference: difference.toFixed(2),
currentCart: input.currentCart,
freeGift: nextFreeGift,
},
});
log('cart message added', cartMessage?.message);
const nextFreeGiftProduct = nextFreeGift?.products[0]?.product_gid;
const productData = await productsStore.getProduct(
shopifyIdHelper(nextFreeGiftProduct),
);
log('productData', nextFreeGift.products[0].product_gid, productData);
setCartMessage(cartMessage?.message, { productData, nextFreeGift });
} else {
log('cart message removed');
setCartMessage('', {});
}
}
// Merge freeGiftsToAdd and lineItemsToUpdate to input. This will be used to update cart
input.lineItemsToAdd = input.lineItemsToAdd
? [...input.lineItemsToAdd, ...freeGiftsToAdd]
: freeGiftsToAdd;
input.lineItemsToUpdate = input.lineItemsToUpdate
? [...input.lineItemsToUpdate, ...freeGiftToRemove]
: freeGiftToRemove;
return input;
};
Above is a sample code for free gift. You can use this as a reference to create your own custom logic.