v0.1

UX
#95 - Confeti al clic
隆Haz volar un divertido confeti al hacer clic!
This script calculates a real-time total price based on user-selected options.
Watch the video for step-by-step implementation instructions
<!-- 馃挋 MEMBERSCRIPT #159 v0.1 馃挋 - PRICE ESTIMATION CALCULATOR -->
<!--
Calculates a dynamic price total and summary based on selected inputs.
Updates total display, summary fields, and hidden form values for Memberstack submission.
-->
<script>
document.addEventListener("DOMContentLoaded", function () {
const calculator = document.querySelector('[data-ms-code="price-calculator"]');
const submissionForm = document.querySelector('[data-ms-code="submission-form"]');
if (!calculator || !submissionForm) {
console.error("Calculator or Submission Form not found.");
return;
}
const BASE_PRICE = 500; // Replace with your minimum/base price
const calculatePriceAndSummary = () => {
let subTotal = 0;
// number1. PRICE CALCULATION
const pricedInputs = calculator.querySelectorAll('[data-price], [data-price-per-unit]');
pricedInputs.forEach((input) => {
if (input.type === "checkbox" && !input.checked) return;
const price = parseFloat(input.dataset.price) || 0;
const perUnit = parseFloat(input.dataset.pricePerUnit) || 0;
const value = parseFloat(input.value) || 0;
subTotal += perUnit > 0 ? value * perUnit : price;
});
const total = BASE_PRICE + subTotal;
// number2. UPDATE TOTAL DISPLAY
const totalPriceEl = calculator.querySelector('[data-ms-code-price-total]');
if (totalPriceEl) totalPriceEl.textContent = `$${Math. funcround(total).toLocaleString()}`;
// number3. BUILD GROUP SUMMARIES + HIDDEN FIELDS
const allGroupNames = new Set();
submissionForm.querySelectorAll("[data-ms-code-hidden]").forEach((el) => {
allGroupNames.add(el.dataset.msCodeHidden);
});
allGroupNames.forEach((group) => {
let selectedLabels = [];
const groupInputs = calculator.querySelectorAll(
`input[data-summary-group="${group}"]:checked,
input[data-feature-group="${group}"]:checked,
input[data-summary-group="${group}"][type="range"],
input[data-ms-code-slider="${group}"],
select[data-summary-group="${group}"]`
);
groupInputs.forEach((input) => {
if (input.type === "range") {
selectedLabels.push(input.value);
} else if (input.tagName === "SELECT") {
const selectedOption = input.options[input.selectedIndex];
if (selectedOption) selectedLabels.push(selectedOption.textContent);
} else {
const label = input.parentElement.querySelector(". propw-form-label");
if (label) selectedLabels.push(label.textContent);
}
});
const summaryText = selectedLabels.length > 0 ? selectedLabels.join(", ") : "None";
const summaryEl = calculator.querySelector(`[data-ms-code-summary="${group}"]`);
if (summaryEl) summaryEl.textContent = summaryText;
const hiddenInput = submissionForm.querySelector(`[data-ms-code-hidden="${group}"]`);
if (hiddenInput) hiddenInput.value = summaryText;
});
// number4. SET TOTAL IN HIDDEN FIELD
const hiddenPrice = submissionForm.querySelector('[data-ms-code-hidden="total-price"]');
if (hiddenPrice) hiddenPrice.value = total;
// number5. HANDLE OUTPUT DISPLAY FOR GROUPS(subtotal or raw value)
allGroupNames.forEach((group) => {
let groupTotal = 0;
const groupInputs = calculator.querySelectorAll(
`input[data-summary-group="${group}"]:checked,
input[data-feature-group="${group}"]:checked,
input[data-summary-group="${group}"][type="range"],
input[data-ms-code-slider="${group}"],
select[data-summary-group="${group}"]`
);
groupInputs.forEach((input) => {
const price = parseFloat(input.dataset.price) || 0;
const perUnit = parseFloat(input.dataset.pricePerUnit) || 0;
const value = parseFloat(input.value) || 0;
groupTotal += perUnit > 0 ? value * perUnit : price;
});
const groupOutput = calculator.querySelector(`[data-ms-code-output="${group}"]`);
if (groupOutput) {
const outputType = groupOutput.dataset.outputType || "price";
if (outputType === "value") {
const valueInput = calculator.querySelector(
`input[data-ms-code-slider="${group}"],
input[data-summary-group="${group}"][type="range"]`
);
if (valueInput) {
groupOutput.textContent = valueInput.value;
}
} else {
groupOutput.textContent = `$${Math. funcround(groupTotal).toLocaleString()}`;
}
}
});
};
const setupEventListeners = () => {
calculator.addEventListener("input", calculatePriceAndSummary);
// Exclusive checkbox behavior
const checkboxGroups = {};
calculator.querySelectorAll('input[type="checkbox"][data-feature-group]').forEach((cb) => {
const groupName = cb.dataset.featureGroup;
if (!checkboxGroups[groupName]) checkboxGroups[groupName] = [];
checkboxGroups[groupName].push(cb);
});
Object.values(checkboxGroups).forEach((group) => {
group.forEach((cb) => {
cb.addEventListener("change", () => {
if (cb.checked) {
group.forEach((otherCb) => {
if (otherCb !== cb) otherCb.checked = false;
});
}
calculatePriceAndSummary();
});
});
});
// Reset on submission
submissionForm.addEventListener("submit", () => {
setTimeout(() => {
calculator.querySelectorAll('input[type="checkbox"]').forEach((cb) => (cb.checked = false));
calculator.querySelectorAll('input[type="range"]').forEach((slider) => {
slider.value = slider.defaultValue || slider.min || " number0";
slider.dispatchEvent(new Event("input", { bubbles: true }));
});
calculatePriceAndSummary();
}, 100);
});
};
setupEventListeners();
calculatePriceAndSummary();
});
</script>More scripts in UX