Subscription
<div class="purchase-container">
<!-- Special Request Input Field -->
<div class="special-request-container">
<label for="specialRequest" class="special-request-label">Special Request</label>
<input id="specialRequest" class="special-request-input">
</div>
<!-- One-time -->
<label class="purchase-type" id="oneTimeLabel">
<input type="radio" name="purchaseType" value="oneTime" checked="">
<span class="label-text">One-time</span>
<span class="price" id="oneTimePrice">—</span>
</label>
<!-- Subscribe -->
<label class="purchase-type" id="subscribeLabel">
<input type="radio" name="purchaseType" value="subscribe">
<div class="label-left">
<span class="label-text">Subscribe & save</span>
</div>
<div class="price-stack">
<span class="save-badge" id="saveBadge">Save up to 10%</span>
<span class="price-compare" id="comparePrice">—</span>
<span class="price" id="subscribePrice">—</span>
</div>
</label>
<!-- Subscribe menu (hidden unless Subscribe selected) -->
<div class="subscribe-menu hidden" id="subscribeMenu">
<div class="deliver-label">Deliver every:</div>
<div class="delivery-options" id="deliveryOptions">
<!-- Dynamic options inserted here -->
</div>
</div>
<!-- Quantity -->
<div class="quantity-container">
<button id="decrease">−</button>
<span id="quantity">1</span>
<button id="increase">+</button>
</div>
<!-- Add to Cart -->
<filled-button id="addToCartBtn">
<span class="btn-text">Add to cart</span>
<img src="https://res.cloudinary.com/dixyq8hvr/image/upload/v1747722131/cupertino_activity_indicator_zze4pb.gif" class="gif-loader" style="display: none;" alt="loading">
</filled-button>
</div>.purchase-container {
font-family: "Figtree";
display: flex;
flex-direction: column;
gap: 12px;
padding: 12px;
}
/* Special Request Input - Styled to match existing design */
.special-request-container {
display: flex;
flex-direction: column;
gap: 8px;
border-radius: 8px;
background: #fff;
}
.special-request-label {
font-weight: 600;
font-size: 16px;
color: #333;
}
.special-request-input {
padding: 10px;
border: 1px solid #ddd;
border-radius: 6px;
font-family: "Figtree";
font-size: 14px;
resize: vertical;
background: #fff;
height: 50px;
}
.special-request-input:focus {
outline: none;
border-color: #A70A10;
box-shadow: 0 0 0 2px rgba(167, 10, 16, 0.1);
}
/* Purchase type boxes */
.purchase-type {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px;
border: 1px solid #A70A10;
border-radius: 8px;
cursor: pointer;
position: relative;
background: #fff;
}
.purchase-type input[type="radio"] {
margin-right: 8px;
cursor: pointer;
/* Custom radio button styling */
accent-color: #A70A10;
/* Remove default radio button appearance */
appearance: none;
-webkit-appearance: none;
width: 16px;
height: 16px;
border: 2px solid #A70A10;
border-radius: 50%;
background: #fff;
position: relative;
}
/* Custom radio button selected state */
.purchase-type input[type="radio"]:checked::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 8px;
height: 8px;
background: #A70A10;
border-radius: 50%;
}
.purchase-type.selected {
background: #000;
color: #fff;
}
.purchase-type.selected .price,
.purchase-type.selected .price-compare {
color: #fff;
}
/* Custom radio button styling for selected state */
.purchase-type.selected input[type="radio"] {
border-color: #A70A10;
background: #fff;
}
.purchase-type.selected input[type="radio"]:checked::after {
background: #A70A10;
}
.label-text {
font-weight: 600;
font-size: 16px;
}
/* Price section in Subscribe */
.price-stack {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.price {
font-weight: 700;
font-size: 16px;
}
.price-compare {
text-decoration: line-through;
color: #888;
font-size: 14px;
}
/* Save badge */
.save-badge {
background: #A70A10;
color: #fff;
padding: 4px 8px;
border-radius: 4px 4px 4px 0;
font-size: 12px;
position: absolute;
top: -10px;
right: 8px;
}
/* Subscription panel */
.subscribe-menu {
background: #000;
color: #fff;
padding: 12px;
border-radius: 8px;
}
.benefits-list {
list-style: none;
padding: 0;
margin: 0 0 10px 0;
}
.benefits-list li {
margin-bottom: 6px;
font-size: 14px;
display: flex;
align-items: center;
}
.benefits-list li::before {
content: "✓";
margin-right: 6px;
font-size: 12px;
}
.note {
font-size: 13px;
font-weight: bold;
margin: 10px 0;
}
/* Deliver label */
.deliver-label {
font-weight: 600;
margin-top: 8px;
}
/* Delivery options */
.delivery-options {
display: flex;
gap: 8px;
margin-top: 8px;
}
.delivery-option {
padding: 8px 12px;
border-radius: 6px;
border: 2px solid #A70A10;
cursor: pointer;
font-size: 14px;
background: #e08484;
text-align: center;
min-width: 80px;
}
.delivery-option.active {
background: #A70A10;
color: #fff;
}
.delivery-option div:first-child {
font-weight: bold;
}
.delivery-option div:last-child {
font-size: 12px;
}
/* Quantity */
.quantity-container {
display: flex;
align-items: center;
justify-content: space-between;
}
.quantity-container button {
padding: 6px 12px;
background: #A70A10;
color: #fff;
border: none;
font-size: 18px;
cursor: pointer;
}
/* Add to Cart button */
filled-button {
background: #A70A10;
color: #fff;
padding: 14px;
border-radius: 8px;
text-align: center;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.gif-loader {
height: 14px;
width: auto;
display: inline-block;
object-fit: contain;
margin-left: 6px;
}
.hidden {
display: none !important;
}let quantity = 1;
let selectedPlanId = null;
let purchaseType = "oneTime";
let selectedPlanLabel = null; // Track the selected subscription plan label
const els = {
oneTimePrice: document.getElementById("oneTimePrice"),
comparePrice: document.getElementById("comparePrice"),
subscribePrice: document.getElementById("subscribePrice"),
saveBadge: document.getElementById("saveBadge"),
saveBenefit: document.getElementById("saveBenefit"),
deliveryOptions: document.getElementById("deliveryOptions"),
subscribeMenu: document.getElementById("subscribeMenu"),
quantityDisplay: document.getElementById("quantity"),
subscribeTypeLabel: document.getElementById("subscribeLabel"),
oneTimeLabel: document.getElementById("oneTimeLabel"),
addToCartBtn: document.getElementById("addToCartBtn"),
addToCartText: document.querySelector("#addToCartBtn .btn-text"),
addToCartLoader: document.querySelector("#addToCartBtn .gif-loader"),
specialRequest: document.getElementById("specialRequest"),
};
function formatMoney(amount, currency) {
if (!amount && amount !== 0) amount = 0;
return `${currency || "USD"} ${Number(amount).toFixed(2)}`;
}
function updateAddToCartState() {
const variant = VajroSDK.variables.product?.selectedVariant || null;
const outOfStock = !variant || variant.quantityAvailable < 1;
const subscribeNeedsPlan = purchaseType === "subscribe" && !selectedPlanId;
const shouldDisable = outOfStock || subscribeNeedsPlan;
els.addToCartBtn.style.opacity = shouldDisable ? "0.6" : "1";
els.addToCartBtn.style.pointerEvents = shouldDisable ? "none" : "auto";
}
function renderFromVariant(variant) {
if (!variant) return;
els.oneTimePrice.textContent = formatMoney(variant.price, variant.currencyCode);
const plans = variant.sellingPlanAllocations || [];
if (!plans.length) {
els.subscribeTypeLabel.classList.add("hidden");
els.subscribeMenu.classList.add("hidden");
purchaseType = "oneTime";
selectedPlanId = null;
selectedPlanLabel = null;
updateAddToCartState();
return;
}
els.subscribeTypeLabel.classList.remove("hidden");
els.deliveryOptions.innerHTML = "";
plans.forEach((p, idx) => {
const btn = document.createElement("div");
btn.className = "delivery-option";
btn.innerHTML = `
<div style="font-weight: 600;">${p.intervalLabel || p.label}</div>
<div style="font-size: 12px;">save ${p.percentageDiscount || 0}%</div>
`;
btn.addEventListener("click", () => {
selectedPlanId = p.sellingPlanId;
selectedPlanLabel = p.label;
[...els.deliveryOptions.children].forEach(c => c.classList.remove("active"));
btn.classList.add("active");
els.comparePrice.textContent = formatMoney(p.compareAtAmount, p.currencyCode);
els.subscribePrice.textContent = formatMoney(p.priceAmount, p.currencyCode);
updateAddToCartState();
});
els.deliveryOptions.appendChild(btn);
// Auto-select the first delivery option
if (idx === 0) {
selectedPlanId = p.sellingPlanId;
selectedPlanLabel = p.label;
btn.classList.add("active");
els.comparePrice.textContent = formatMoney(p.compareAtAmount, p.currencyCode);
els.subscribePrice.textContent = formatMoney(p.priceAmount, p.currencyCode);
}
});
updateAddToCartState();
}
document.querySelectorAll('input[name="purchaseType"]').forEach(radio => {
radio.addEventListener("change", async (e) => {
purchaseType = e.target.value;
els.oneTimeLabel.classList.toggle("selected", purchaseType === "oneTime");
els.subscribeTypeLabel.classList.toggle("selected", purchaseType === "subscribe");
els.subscribeMenu.classList.toggle("hidden", purchaseType !== "subscribe");
const variant = VajroSDK.variables.product?.selectedVariant || null;
const plans = variant?.sellingPlanAllocations || [];
if (purchaseType === "oneTime") {
selectedPlanId = null;
selectedPlanLabel = null;
[...els.deliveryOptions.children].forEach(c => c.classList.remove("active"));
els.oneTimePrice.textContent = formatMoney(variant?.price, variant?.currencyCode);
}
if (purchaseType === "subscribe" && plans.length > 0) {
const firstPlan = plans[0];
selectedPlanId = firstPlan.sellingPlanId;
selectedPlanLabel = firstPlan.label;
[...els.deliveryOptions.children].forEach(c => c.classList.remove("active"));
els.deliveryOptions.children[0]?.classList.add("active");
els.comparePrice.textContent = formatMoney(firstPlan.compareAtAmount, firstPlan.currencyCode);
els.subscribePrice.textContent = formatMoney(firstPlan.priceAmount, firstPlan.currencyCode);
}
updateAddToCartState();
await VajroSDK.actions.resizeBlock();
});
});
document.getElementById("increase").addEventListener("click", () => {
quantity++;
els.quantityDisplay.textContent = quantity;
});
document.getElementById("decrease").addEventListener("click", () => {
if (quantity > 1) quantity--;
els.quantityDisplay.textContent = quantity;
});
els.addToCartBtn.addEventListener("click", async () => {
const variant = VajroSDK.variables.product?.selectedVariant || null;
if (!variant?.id) return;
if (purchaseType === "subscribe" && !selectedPlanId) return;
els.addToCartText.style.display = "none";
els.addToCartLoader.style.display = "inline";
const specialRequest = els.specialRequest.value.trim();
const line = {
variantId: variant.id,
quantity,
attributes: []
};
if (specialRequest) {
line.attributes.push({ key: "Special Request", value: specialRequest });
}
if (purchaseType === "subscribe" && selectedPlanLabel) {
line.attributes.push({ key: "Subscription Plan", value: selectedPlanLabel });
}
if (purchaseType === "subscribe" && selectedPlanId) {
line.sellingPlanId = selectedPlanId;
}
try {
await new Promise(resolve => setTimeout(resolve, 500));
await VajroSDK.actions.addToCart([line]);
await VajroSDK.actions.showToast({ title: "Added to Cart", message: "Product added successfully!" });
} catch (err) {
await VajroSDK.actions.showToast({ title: "Error", message: err.message || "Failed to add to cart" });
} finally {
els.addToCartText.style.display = "inline";
els.addToCartLoader.style.display = "none";
}
});
// Select first variant by default on load
if (Array.isArray(VajroSDK.variables.product?.variants) && VajroSDK.variables.product.variants.length > 0) {
VajroSDK.variables.product.selectedVariant = VajroSDK.variables.product.variants[0];
}
renderFromVariant(VajroSDK.variables.product?.selectedVariant);
els.subscribeMenu.classList.add("hidden");
els.oneTimeLabel.classList.add("selected");
VajroSDK.listeners.onVariantChanged(() => {
selectedPlanId = null;
selectedPlanLabel = null;
purchaseType = "oneTime";
renderFromVariant(VajroSDK.variables.product?.selectedVariant);
});Updated 4 months ago