Skip to content
// Selectors for different page types
let itemSelector, titleSelector, priceSelector, imageSelector;
if (isCheckout) {
console.log('Checkout page detected, initializing updates...');
// Checkout page selectors - try multiple common Shopify checkout selectors
itemSelector = '.product-table__row, .order-summary__section__table__row, [data-product], .product, .order-summary__section__table tbody tr, .product__description, .order-summary__section__table__row';
titleSelector = '.product__description__name, .product-title, [data-product-title], .product__description__name a, h3.product__description__name, .order-summary__section__table__cell--product';
priceSelector = '.product__price, .order-summary__section__table__cell--total, [data-product-price], .product__price .order-summary__emphasis, .product__price .money, .order-summary__section__table__cell--total .money';
imageSelector = '.product__image img, .product__media img, [data-product-image] img, .product-thumbnail__image, .product__image img, .order-summary__section__table__cell--image img';
console.log('Checkout page detected, updating gift cards...');
} else {
// Cart page selectors (already handled by main-cart.liquid, but as fallback)
console.log('Not checkout page, skipping...');
return;
}
console.log('Using selectors:', {
itemSelector: itemSelector,
titleSelector: titleSelector,
priceSelector: priceSelector,
imageSelector: imageSelector
});
const items = document.querySelectorAll(itemSelector);
console.log('Checkout items found:', items ? items.length : 0, 'with selector:', itemSelector);
if (!items || items.length === 0) {
console.warn('No checkout items found. Available elements:', {
products: document.querySelectorAll('.product, [data-product]').length,
rows: document.querySelectorAll('tr, .product-table__row').length,
allItems: document.querySelectorAll('*').length
});
return;
}
const shopifyRoot = (window.Shopify && window.Shopify.routes && window.Shopify.routes.root) ? window.Shopify.routes.root : '/';
// Fetch cart data
console.log('Fetching cart data from:', shopifyRoot + 'cart.js');
fetch(shopifyRoot + 'cart.js')
.then(response => {
if (!response.ok) {
console.error('Cart fetch failed:', response.status, response.statusText);
throw new Error('Cart fetch failed');
}
return response.json();
})
.then(cartData => {
console.log('Cart data received:', cartData);
// Get all gift card items from cart
const giftCardItems = cartData.items.filter(function(cartItem) {
return cartItem.product_title && cartItem.product_title.toLowerCase().includes('gift card');
});
console.log('Gift card items found:', giftCardItems.length);
if (giftCardItems.length === 0) {
console.warn('No gift cards in cart');
return;
}
// Update each gift card item in DOM - match by order
let giftCardIndex = 0;
items.forEach(function(item) {
// Null check
if (!item || !item.querySelector) {
console.warn('Checkout item is null or has no querySelector, skipping');
return;
}
const itemTitle = item.querySelector(titleSelector);
if (!itemTitle) {
console.warn('Checkout item title not found, skipping');
return;
}
const titleText = itemTitle.textContent ? itemTitle.textContent.toLowerCase() : '';
const isGiftCard = titleText.includes('gift card');
if (!isGiftCard) return;
// Get matching cart item by index
const cartItemData = giftCardItems[giftCardIndex];
if (!cartItemData) {
console.warn('Checkout cart item data not found for index:', giftCardIndex);
giftCardIndex++;
return;
}
giftCardIndex++;
console.log('Processing checkout gift card:', cartItemData);
// Get Amount and Design from properties
let amountValue = null;
let designNumber = null;
// First try to read from cart API properties (more reliable for checkout)
// DOM might not have properties in checkout
let itemDetails = null;
if (item && item.querySelector) {
itemDetails = item.querySelector('.product__description, .order-summary__section__table__cell, [data-product-details], .product__description__property-list');
}
if (!itemDetails && item && item.closest) {
// Try parent element
itemDetails = item.closest('.product, .product-table__row, tr');
}
if (!itemDetails && item) {
// Try the entire item as fallback
itemDetails = item;
}
if (itemDetails) {
const detailsText = itemDetails.textContent || '';
console.log('Checkout item details text:', detailsText.substring(0, 200));
// Extract Amount from DOM (format: "Amount: 50.00 USD")
const amountMatch = detailsText.match(/Amount:\s*([\d.]+)\s*USD/i);
if (amountMatch) {
amountValue = parseFloat(amountMatch[1]);
console.log('Found amount from checkout DOM:', amountValue);
}
// Extract Design from DOM (format: "Design: Design 4")
const designMatch = detailsText.match(/Design:\s*Design\s*(\d+)/i);
if (designMatch) {
designNumber = designMatch[1];
console.log('Found design from checkout DOM:', designNumber);
}
}
// Always read from cart API properties for checkout (more reliable)
if (cartItemData.properties) {
console.log('Reading from checkout cart API properties:', cartItemData.properties);
if (Array.isArray(cartItemData.properties)) {
// Always read from API for checkout
const amountProp = cartItemData.properties.find(function(prop) {
return prop && (prop.first === 'Amount' || prop.name === 'Amount');
});
if (amountProp) {
const amountText = amountProp.last || amountProp.value || '';
const amountMatch = amountText.match(/([\d.]+)/);
if (amountMatch) {
amountValue = parseFloat(amountMatch[1]);
console.log('Found amount from checkout API array:', amountValue);
}
}
const designProp = cartItemData.properties.find(function(prop) {
return prop && (prop.first === 'Design' || prop.name === 'Design');
});
if (designProp) {
const designText = designProp.last || designProp.value || '';
const designMatch = designText.match(/Design\s*(\d+)/i);
if (designMatch) {
designNumber = designMatch[1];
console.log('Found design from checkout API array:', designNumber);
}
}
} else if (typeof cartItemData.properties === 'object') {
// Always read from API for checkout
if (cartItemData.properties.Amount) {
const amountText = String(cartItemData.properties.Amount);
const amountMatch = amountText.match(/([\d.]+)/);
if (amountMatch) {
amountValue = parseFloat(amountMatch[1]);
console.log('Found amount from checkout API object:', amountValue);
}
}
if (cartItemData.properties.Design) {
const designText = String(cartItemData.properties.Design);
const designMatch = designText.match(/Design\s*(\d+)/i);
if (designMatch) {
designNumber = designMatch[1];
console.log('Found design from checkout API object:', designNumber);
}
}
}
}
// Update price - try multiple selectors aggressively
if (amountValue && amountValue > 0 && !isNaN(amountValue)) {
console.log('Attempting to update checkout price with amount:', amountValue);
let priceElement = null;
// Try all possible selectors - checkout sayfası için daha geniş arama
const selectors = [
priceSelector,
'.product__price',
'.order-summary__section__table__cell--total',
'[data-product-price]',
'.money',
'.product__price .money',
'.order-summary__section__table__cell--total .money',
'.order-summary__section__table__cell--total',
'.product__price .order-summary__emphasis',
'.order-summary__emphasis',
'[data-price]',
'.total-line__price',
'.payment-due__price'
];
// First try in the item itself
for (let i = 0; i < selectors.length; i++) {
if (item && item.querySelector) {
priceElement = item.querySelector(selectors[i]);
if (priceElement && priceElement.textContent && priceElement.textContent.match(/[\d.,]/)) {
console.log('Found price element with selector:', selectors[i]);
break;
}
}
}
// Try parent elements (checkout sayfasında fiyat genelde parent'ta)
if (!priceElement && item && item.closest) {
const parents = [
item.closest('.product, tr, .product-table__row, .order-summary__section__table__row'),
item.closest('tbody'),
item.closest('table'),
item.parentElement,
item.parentElement ? item.parentElement.parentElement : null
].filter(Boolean);
for (let p = 0; p < parents.length; p++) {
const parent = parents[p];
if (parent && parent.querySelector) {
for (let i = 0; i < selectors.length; i++) {
priceElement = parent.querySelector(selectors[i]);
if (priceElement && priceElement.textContent && priceElement.textContent.match(/[\d.,]/)) {
console.log('Found price element in parent with selector:', selectors[i]);
break;
}
}
if (priceElement) break;
}
}
}
// Try document-wide search for price near the item (checkout sayfası için)
if (!priceElement && item) {
const itemRect = item.getBoundingClientRect();
const allPriceElements = document.querySelectorAll('.money, [data-price], .product__price, .order-summary__section__table__cell--total');
for (let i = 0; i < allPriceElements.length; i++) {
const el = allPriceElements[i];
const elRect = el.getBoundingClientRect();
// Check if element is near the item (within 200px)
if (Math.abs(elRect.top - itemRect.top) < 200 && Math.abs(elRect.left - itemRect.left) < 200) {
if (el.textContent && el.textContent.match(/[\d.,]/)) {
priceElement = el;
console.log('Found price element near item');
break;
}
}
}
}
if (priceElement) {
const existingPrice = priceElement.textContent ? priceElement.textContent.trim() : '';
const currencySymbol = existingPrice.match(/[$\u20AC\u00A3SGD]/)?.[0] || '$';
const formattedPrice = currencySymbol + amountValue.toFixed(2);
// Update the element
priceElement.textContent = formattedPrice;
priceElement.innerHTML = formattedPrice; // Also update innerHTML
console.log('Updated checkout price to:', formattedPrice, 'in element:', priceElement.className || priceElement.tagName);
// Also try to update any nested money elements
const moneyElements = priceElement.querySelectorAll('.money');
moneyElements.forEach(function(moneyEl) {
moneyEl.textContent = formattedPrice;
moneyEl.innerHTML = formattedPrice;
});
// Also try to find and update all price elements in the item and nearby
if (item) {
const allPriceElements = item.querySelectorAll('.money, [data-price], .product__price, .order-summary__section__table__cell--total');
allPriceElements.forEach(function(priceEl) {
if (priceEl.textContent && priceEl.textContent.match(/[\d.,]/)) {
priceEl.textContent = formattedPrice;
priceEl.innerHTML = formattedPrice;
}
});
}
// Force a re-render by triggering a mutation
if (priceElement.parentElement) {
const observer = new MutationObserver(function() {});
observer.observe(priceElement, { childList: true, characterData: true, subtree: true });
priceElement.dispatchEvent(new Event('input', { bubbles: true }));
observer.disconnect();
}
} else {
console.warn('Checkout price element not found. Tried selectors:', selectors);
console.warn('Item HTML:', item ? item.outerHTML.substring(0, 500) : 'null');
console.warn('Available price elements on page:', document.querySelectorAll('.money, [data-price], .product__price').length);
}
} else {
console.warn('Checkout amount value not found or invalid:', amountValue, 'cartItemData:', cartItemData);
}
// Update image - try multiple selectors aggressively
if (designNumber) {
const designImageUrl = 'https://cdn.shopify.com/s/files/1/0660/0936/6646/files/giftcard-product-h25-carte-cadeau-0' + designNumber + '.jpg?v=176496510' + (parseInt(designNumber) > 3 ? '7' : '6');
console.log('Attempting to update checkout image with design:', designNumber, 'URL:', designImageUrl);
let imageElement = null;
// Try all possible selectors
const imageSelectors = [
imageSelector,
'.product__image img',
'.product-thumbnail__image',
'.order-summary__section__table__cell--image img',
'img'
];
for (let i = 0; i < imageSelectors.length; i++) {
if (item && item.querySelector) {
imageElement = item.querySelector(imageSelectors[i]);
if (imageElement) {
console.log('Found image element with selector:', imageSelectors[i]);
break;
}
}
}
// Try parent elements
if (!imageElement && item && item.closest) {
const parent = item.closest('.product, tr, .product-table__row, .order-summary__section__table__row');
if (parent) {
for (let i = 0; i < imageSelectors.length; i++) {
imageElement = parent.querySelector(imageSelectors[i]);
if (imageElement) {
console.log('Found image element in parent with selector:', imageSelectors[i]);
break;
}
}
}
}
if (imageElement) {
imageElement.src = designImageUrl;
imageElement.srcset = designImageUrl;
// Also try to update data-src if exists
if (imageElement.hasAttribute('data-src')) {
imageElement.setAttribute('data-src', designImageUrl);
}
console.log('Updated checkout image to:', designImageUrl);
} else {
console.warn('Checkout image element not found. Tried selectors:', imageSelectors);
console.warn('Item HTML:', item ? item.outerHTML.substring(0, 500) : 'null');
}
} else {
console.warn('Checkout design number not found:', designNumber, 'cartItemData:', cartItemData);
}
// Add properties to checkout page
if (cartItemData.properties) {
// Find where to insert properties (usually after product title/description)
let propertiesContainer = item.querySelector('.product__description__property-list, .product__description, .order-summary__section__table__cell');
if (!propertiesContainer) {
// Try to find product description area
const productDesc = item.querySelector('.product__description__name, .product-title');
if (productDesc && productDesc.parentElement) {
propertiesContainer = productDesc.parentElement;
} else if (item.closest) {
propertiesContainer = item.closest('.product, tr, .product-table__row');
}
}
if (propertiesContainer) {
// Check if properties already exist
let existingProps = propertiesContainer.querySelector('.checkout-gift-card-properties');
if (!existingProps) {
// Create properties container
existingProps = document.createElement('div');
existingProps.className = 'checkout-gift-card-properties';
existingProps.style.cssText = 'margin-top: 8px; font-size: 14px; color: #576ead;';
const propsList = document.createElement('ul');
propsList.style.cssText = 'list-style: none; padding: 0; margin: 0;';
// Get properties from cart API
let propertiesArray = [];
if (Array.isArray(cartItemData.properties)) {
propertiesArray = cartItemData.properties;
} else if (typeof cartItemData.properties === 'object') {
propertiesArray = Object.keys(cartItemData.properties).map(function(key) {
return { first: key, last: cartItemData.properties[key] };
});
}
// Add each property (except Amount and Design)
propertiesArray.forEach(function(prop) {
if (!prop) return;
const propKey = prop.first || prop.name || '';
const propValue = prop.last || prop.value || '';
// Skip hidden properties
if (!propKey || propKey.charAt(0) === '_' || !propValue) return;
// Skip Amount and Design (shown in price and image)
if (propKey === 'Amount' || propKey === 'Design') return;
const li = document.createElement('li');
li.style.cssText = 'margin: 4px 0;';
if (propValue.includes('/uploads/')) {
const link = document.createElement('a');
link.href = propValue;
link.textContent = propValue.split('/').pop();
li.appendChild(link);
} else {
const strong = document.createElement('strong');
strong.textContent = propKey + ': ';
li.appendChild(strong);
li.appendChild(document.createTextNode(propValue));
}
propsList.appendChild(li);
});
if (propsList.children.length > 0) {
existingProps.appendChild(propsList);
// Insert after product title or at the end of description
const productTitle = propertiesContainer.querySelector('.product__description__name, .product-title');
if (productTitle && productTitle.parentElement) {
productTitle.parentElement.insertBefore(existingProps, productTitle.nextSibling);
} else {
propertiesContainer.appendChild(existingProps);
}
console.log('Added properties to checkout:', propsList.children.length);
}
}
} else {
console.warn('Could not find properties container in checkout');
}
}
});
})
.catch(function(error) {
console.warn('Error updating gift cards:', error);
});
}
// Run on page load - multiple retries for checkout
let checkoutUpdateCount = 0;
const MAX_CHECKOUT_UPDATES = 10;
function initializeCheckoutUpdate() {
const isCheckout = window.location.pathname.includes('/checkouts/') || window.location.pathname.includes('/checkout');
if (!isCheckout) {
return; // Only run for checkout pages
}
console.log('Initializing checkout gift card updates...');
function runUpdate() {
if (checkoutUpdateCount < MAX_CHECKOUT_UPDATES) {
console.log('Checkout update attempt:', checkoutUpdateCount + 1);
updateGiftCardItems();
checkoutUpdateCount++;
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
setTimeout(runUpdate, 500);
setTimeout(runUpdate, 1500);
setTimeout(runUpdate, 3000);
setTimeout(runUpdate, 5000);
setTimeout(runUpdate, 8000);
});
} else {
setTimeout(runUpdate, 500);
setTimeout(runUpdate, 1500);
setTimeout(runUpdate, 3000);
setTimeout(runUpdate, 5000);
setTimeout(runUpdate, 8000);
}
}
initializeCheckoutUpdate();
// Also run immediately if already on checkout page
const pathname = window.location.pathname || '';
const href = window.location.href || '';
const mightBeCheckout = pathname.includes('/checkouts/') ||
pathname.includes('/checkout') ||
href.includes('/checkouts/') ||
href.includes('/checkout');
if (mightBeCheckout) {
console.log('Checkout URL detected, running immediate update...');
// Run immediately
updateGiftCardItems();
// Also listen for checkout updates (Shopify checkout can update dynamically)
// But limit updates to prevent infinite loops
if (typeof MutationObserver !== 'undefined') {
let checkoutUpdateTimeout = null;
const checkoutObserver = new MutationObserver(function(mutations) {
let shouldUpdate = false;
mutations.forEach(function(mutation) {
if (mutation.addedNodes.length > 0 || mutation.type === 'childList') {
shouldUpdate = true;
}
});
if (shouldUpdate && checkoutUpdateCount < MAX_CHECKOUT_UPDATES) {
if (checkoutUpdateTimeout) {
clearTimeout(checkoutUpdateTimeout);
}
checkoutUpdateTimeout = setTimeout(function() {
updateGiftCardItems();
checkoutUpdateCount++;
}, 2000);
}
});
// Try multiple selectors for checkout container
let checkoutMain = document.querySelector('.main__content, .order-summary, .product-table, .checkout, .checkout__main, [data-checkout]');
if (!checkoutMain) {
checkoutMain = document.body;
}
if (checkoutMain) {
console.log('Setting up checkout MutationObserver');
checkoutObserver.observe(checkoutMain, {
childList: true,
subtree: true
});
}
}
}
})();