/*
Lexi Setup Fee Script for One-Step-Order element
Adjust LEXI_PRODUCT_ID and SETUP_FEE as needed below.
If checkout API is unavailable, visually show the fee, block submission, display error.
Script is fully namespaced under window.LexiSetupFeeHelper.
*/
(function(){
if(window.LexiSetupFeeHelper){return;} // Prevent double init
window.LexiSetupFeeHelper = true;
const LEXI_PRODUCT_ID = 'lexi-subscription'; // <-- Adjust as needed
const SETUP_FEE = 99;
const SETUP_LABEL = 'Lexi Setup Fee';
const FEE_LINE_ID = 'lexi-setup-fee-line';
const ONE_STEP_ORDER_ID = 'one-step-order-EjxpWu7Obe';
const observerConfig = {childList: true, subtree: true};
function formatCurrency(amount){
// Match One-Step-Order currency format (adjust if necessary)
return `$${amount.toFixed(2)}`;
}
function getOrderProductIds(){
// Find selected product IDs from one-step-order (replace this logic if you use custom one-step-order API)
let el = document.getElementById(ONE_STEP_ORDER_ID);
if(!el){return [];}
// Most order forms put selected products/variants as checked inputs; adjust selector as needed
let checkedInputs = el.querySelectorAll('input[type="radio"], input[type="checkbox"]');
let ids = [];
checkedInputs.forEach(input => {if(input.checked && input.value){ids.push(input.value);}});
return ids;
}
function findOrderSummary(){
// Try to find the summary area for the order
let el = document.getElementById(ONE_STEP_ORDER_ID);
if(!el) return null;
// Look for summary rows; may need to adjust selector
return el.querySelector('[class*="order-summary"], [class*="OrderSummary"], [data-summary]') || null;
}
function feeExists(summaryEl){
return !!summaryEl && !!summaryEl.querySelector(`#${FEE_LINE_ID}`);
}
function addFeeLine(summaryEl){
if(!summaryEl || feeExists(summaryEl)){return;}
// Structure: try to match structure of line-items
let row = document.createElement('div');
row.id = FEE_LINE_ID;
row.setAttribute('role','row');
row.setAttribute('aria-label', SETUP_LABEL);
row.innerHTML = `
${SETUP_LABEL}
${formatCurrency(SETUP_FEE)}
`;
// Visually style to match existing summary rows (tweak as needed)
row.style.display = 'flex';
row.style.justifyContent = 'space-between';
row.style.alignItems = 'center';
row.style.padding = '4px 0';
// Insert before the total row if possible else append at the end
let totalRow = Array.from(summaryEl.children).find(e=>e.textContent.match(/total/i));
if(totalRow){summaryEl.insertBefore(row, totalRow);}else{summaryEl.appendChild(row);}
}
function removeFeeLine(summaryEl){
if(!summaryEl){return;}
let fee = summaryEl.querySelector(`#${FEE_LINE_ID}`);
if(fee){fee.remove();}
}
function updateOrderTotal(summaryEl, addFee){
// Try to find and update the displayed order total
let totalEl = Array.from(summaryEl.querySelectorAll('span,div'))
.find(e=>/total/i.test(e.textContent||''));
if(!totalEl){return;}
// Parse/replace total with fee
let match = totalEl.textContent.match(/\$([\d,]+\.\d{2})/);
let value = match? parseFloat(match[1].replace(/,/g,'')) : null;
if(value!==null){
let newValue = addFee? (value+SETUP_FEE) : (value-SETUP_FEE);
totalEl.textContent = totalEl.textContent.replace(/\$[\d,]+\.\d{2}/, formatCurrency(newValue));
totalEl.setAttribute('aria-label',`Order total ${formatCurrency(newValue)}`);
}
}
function blockCheckout(summaryEl, msg){
// Visually prevent checkout and show error
let el = document.getElementById(ONE_STEP_ORDER_ID);
let btn = el && el.querySelector('button[type="submit"]');
if(btn){btn.disabled=true;}
let err = document.getElementById('lexi-fee-error');
if(!err){
err = document.createElement('div');
err.id = 'lexi-fee-error';
err.style.color = 'red';
err.style.marginTop = '6px';
err.setAttribute('role','alert');
err.textContent = msg||'Checkout unavailable: please contact support.';
if(summaryEl) summaryEl.appendChild(err);
}
}
function unblockCheckout(){
let el = document.getElementById(ONE_STEP_ORDER_ID);
let btn = el && el.querySelector('button[type="submit"]');
if(btn){btn.disabled=false;}
let err = document.getElementById('lexi-fee-error');
if(err){err.remove();}
}
function handle(){
let summaryEl = findOrderSummary();
if(!summaryEl){return;}
let ids = getOrderProductIds();
let hasLexi = ids.includes(LEXI_PRODUCT_ID);
let alreadyAdded = feeExists(summaryEl);
// API fallback: if no total or summary can be found, show visually and block
if(!summaryEl.querySelector(':scope [role="row"]')){
if(hasLexi && !alreadyAdded){addFeeLine(summaryEl);}
if(hasLexi){blockCheckout(summaryEl,'Checkout unavailable: Please contact support.');}
return;
}
if(hasLexi){
if(!alreadyAdded) addFeeLine(summaryEl);
updateOrderTotal(summaryEl, true);
unblockCheckout();
} else {
if(alreadyAdded) {
updateOrderTotal(summaryEl, false);
removeFeeLine(summaryEl);
}
unblockCheckout();
}
}
// Initial run and on changes
let readyTries = 0;
function tryInitListener(){
let el = document.getElementById(ONE_STEP_ORDER_ID);
if(!el){ if(++readyTries<14) setTimeout(tryInitListener,150); return; }
// Listen to input changes within the order form
el.addEventListener('change', handle);
// Observe DOM changes in the summary for dynamic updates
let summaryEl = findOrderSummary();
if(summaryEl){
let obs = new MutationObserver(handle);
obs.observe(summaryEl, observerConfig);
}
// On initial load
setTimeout(handle, 400);
// Rerun on page visibility changes (relevant for client transitions)
document.addEventListener('visibilitychange', handle);
}
tryInitListener();
})();