`;
lensTbody.appendChild(trLimit);
});
}
function renderStaticUpgradesMenu(tbodyId, dataItems, prefix) {
const tbody = document.getElementById(tbodyId);
if(!tbody) return;
tbody.innerHTML = "";
Object.entries(dataItems).forEach(([name, wholesale]) => {
const safeId = name.replace(/[^a-zA-Z0-9]/g, "");
const trItem = document.createElement("tr");
trItem.className = "clickable-row";
trItem.id = `row-${prefix}-${safeId}`;
trItem.onclick = function() { handleUpgradeRowClick(prefix, safeId); };
trItem.innerHTML = `
${name} ($${wholesale.toFixed(2)})
|
$0.00 |
`;
tbody.appendChild(trItem);
const trLimit = document.createElement("tr");
trLimit.id = `limit-${prefix}-row-${safeId}`;
trLimit.className = "limit-row hidden";
trLimit.innerHTML = `
|
`;
tbody.appendChild(trLimit);
});
}
function handleUpgradeRowClick(prefix, safeId, checkboxClicked = false) {
const cb = document.getElementById(`chk-${prefix}-${safeId}`);
if (!cb) return;
if (!checkboxClicked) cb.checked = !cb.checked;
const trItem = document.getElementById(`row-${prefix}-${safeId}`);
const trLimit = document.getElementById(`limit-${prefix}-row-${safeId}`);
if (cb.checked) {
trItem.classList.add("selected-row");
trLimit.classList.remove("hidden");
} else {
trItem.classList.remove("selected-row");
trLimit.classList.add("hidden");
}
renderMasterSheet();
}
function toggleStyleSelection(safeId) {
const trLimit = document.getElementById(`limit-style-row-${safeId}`);
const trItem = document.getElementById(`row-style-${safeId}`);
if (trLimit.classList.contains("hidden")) {
trLimit.classList.remove("hidden");
trItem.classList.add("selected-row");
selectedStylesActive[safeId] = true;
} else {
trLimit.classList.add("hidden");
trItem.classList.remove("selected-row");
selectedStylesActive[safeId] = false;
}
}
function saveLocalLimit(type, safeId, limitType, value) {
if (!localLimits[type][safeId]) localLimits[type][safeId] = { min: "", max: "" };
localLimits[type][safeId][limitType] = value !== "" ? parseFloat(value) : "";
renderMasterSheet();
}
function changeCategory() {
const category = document.querySelector("input[name=\"lensCategory\"]:checked").value;
const matSection = document.getElementById("materialsMenuSection");
const addSection = document.getElementById("addonsMenuSection");
const standardControls = document.getElementById("standardMarkupControls");
const safetyControls = document.getElementById("safetyMarkupControls");
const menuTitle = document.getElementById("lensMenuTitle");
if (category === "safety") {
matSection.classList.add("hidden");
addSection.classList.add("hidden");
standardControls.classList.add("hidden");
safetyControls.classList.remove("hidden");
menuTitle.textContent = "Safety Lens Styles Menu";
} else {
matSection.classList.remove("hidden");
addSection.classList.remove("hidden");
standardControls.classList.remove("hidden");
safetyControls.classList.add("hidden");
menuTitle.textContent = "Lens Styles Menu";
}
renderLensMenuStructure();
renderMasterSheet();
}
function handleStrategyChange() {
const strategy = document.querySelector("input[name=\"markupStrategy\"]:checked").value;
document.getElementById("separateMarkupContainer").className = (strategy === "separate") ? "radio-toggle" : "hidden";
renderMasterSheet();
}
function renderMasterSheet() {
const category = document.querySelector("input[name=\"lensCategory\"]:checked").value;
const strategy = document.querySelector("input[name=\"markupStrategy\"]:checked").value;
const rounding = parseInt(document.getElementById("rounding").value);
let baseMultiplier, baseFlat;
if (category === "safety") {
baseMultiplier = parseFloat(document.getElementById("safetyMultiplier").value) || 0;
baseFlat = parseFloat(document.getElementById("safetyFlat").value) || 0;
} else {
baseMultiplier = parseFloat(document.getElementById("baseMultiplier").value) || 0;
baseFlat = parseFloat(document.getElementById("baseFlat").value) || 0;
}
const upgradeMultiplier = parseFloat(document.getElementById("upgradeMultiplier").value) || 0;
const upgradeFlat = parseFloat(document.getElementById("upgradeFlat").value) || 0;
let selectedUpgradesWholesale = 0;
if (category !== "safety") {
document.querySelectorAll(".mat-chk:checked, .add-chk:checked").forEach(cb => {
selectedUpgradesWholesale += parseFloat(cb.value);
});
}
Object.entries(pricingData[category]).forEach(([lensName, lensWholesale]) => {
const safeId = lensName.replace(/[^a-zA-Z0-9]/g, "");
let coreLensRetail = (lensWholesale * baseMultiplier) + baseFlat;
let combinedAddonsRetail = 0;
if (selectedUpgradesWholesale > 0 && category !== "safety") {
if (strategy === "consistent") {
combinedAddonsRetail = selectedUpgradesWholesale * baseMultiplier;
} else {
combinedAddonsRetail = (selectedUpgradesWholesale * upgradeMultiplier) + upgradeFlat;
}
}
let rawAggregateTotal = coreLensRetail + combinedAddonsRetail;
const limits = localLimits.style[safeId];
if (limits) {
if (limits.min !== "" && !isNaN(limits.min) && rawAggregateTotal < limits.min) rawAggregateTotal = limits.min;
if (limits.max !== "" && !isNaN(limits.max) && rawAggregateTotal > limits.max) rawAggregateTotal = limits.max;
}
let finalLensRetailPrice = applyRoundingCeiling(rawAggregateTotal, rounding);
const displayCell = document.getElementById(`retail-style-${safeId}`);
if (displayCell) displayCell.textContent = `$${finalLensRetailPrice.toFixed(2)}`;
});
if (category !== "safety") {
updateUpgradeMenuPrices(pricingData.materials, "mat", strategy, baseMultiplier, upgradeMultiplier, upgradeFlat, rounding);
updateUpgradeMenuPrices(pricingData.addons, "add", strategy, baseMultiplier, upgradeMultiplier, upgradeFlat, rounding);
}
}
function updateUpgradeMenuPrices(dataObject, prefix, strategy, baseMult, upMult, upFlat, rounding) {
Object.entries(dataObject).forEach(([name, wholesale]) => {
const safeId = name.replace(/[^a-zA-Z0-9]/g, "");
let rawRetailValue = 0;
if (strategy === "consistent") {
rawRetailValue = wholesale * baseMult;
} else {
rawRetailValue = (wholesale * upMult) + upFlat;
}
const limits = localLimits[prefix][safeId];
if (limits) {
if (limits.min !== "" && !isNaN(limits.min) && rawRetailValue < limits.min) rawRetailValue = limits.min;
if (limits.max !== "" && !isNaN(limits.max) && rawRetailValue > limits.max) rawRetailValue = limits.max;
}
let finalRetailValue = applyRoundingCeiling(rawRetailValue, rounding);
const cell = document.getElementById(`retail-${prefix}-${safeId}`);
if (cell) cell.textContent = `$${finalRetailValue.toFixed(2)}`;
});
}
function applyRoundingCeiling(value, threshold) {
if (threshold > 0 && value > 0) {
return Math.ceil(value / threshold) * threshold;
}
return value;
}
initCalculator();