/* Copyright © 2026 K2B NETWORK SOLUTIONS LLC. All Rights Reserved. Proprietary and confidential. Unauthorized copying, distribution, or use of this file, via any medium, is strictly prohibited. Original work product. */ // JBREWS DMS — F&I Menu Presentation (customer-facing). // Clean 3-4 column option menu: each column shows payment, term, and an // itemized list of included protection products with one-line descriptions. // Figures pull from the desked deal (buyersOrder / financeWorksheet drafts); // products come from the F&I Products registry (jbProducts). const FIM_DESC = [ [/vsc|service contract|warrant/i, "Covers major mechanical & electrical repairs after factory warranty."], [/gap/i, "Pays the difference between insurance payout and loan balance if totaled."], [/tire|wheel/i, "Repairs or replaces tires & wheels damaged by road hazards."], [/maint/i, "Prepaid factory-scheduled maintenance — oil, rotations, inspections."], [/etch|theft/i, "VIN etching & theft deterrent with replacement benefit."], [/appear|paint|fabric|env/i, "Protects paint, fabric & trim against stains and environmental damage."], [/key/i, "Replaces lost or damaged keys and remotes."], ]; const fimDesc = (p) => { const hit = FIM_DESC.find(([re]) => re.test((p.name || "") + " " + (p.code || ""))); return p.desc || (hit ? hit[1] : "Ask your F&I manager for full coverage details."); }; const fimPrice = (p) => +((p.retail != null ? p.retail : p.price != null ? p.price : p.msrp) || 0); const fim$ = (n) => "$" + (Number(n) || 0).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); const fimPmt = (principal, apr, term) => { const r = (+apr || 0) / 1200, n = +term || 72; return r ? principal * r / (1 - Math.pow(1 + r, -n)) : principal / n; }; const FiMenu = ({ onClose, go }) => { const [, force] = React.useReducer(n => n + 1, 0); const bo = window.loadJbForm ? window.loadJbForm("buyersOrder") : {}; const fw = window.loadJbForm ? window.loadJbForm("financeWorksheet") : {}; const num = (v) => parseFloat(String(v ?? "").replace(/[^0-9.\-]/g, "")) || 0; // Base amount financed WITHOUT products (menu adds each column's own). const base = num(bo.salePrice) + num(bo.docFee) + num(bo.salesTax) + num(bo.license) - num(bo.tradeAllow) + num(bo.tradePayoff) - num(bo.cashDown) - num(bo.rebate); // K2B-005: the worksheet's APR as entered — an explicit 0.00 stays 0%. A blank one takes the SAME default as the // Finance Deal (RC18: window.fwDefaultApr — the dealership's Default APR % when set, else 6.49; was a separate 6.99 here). const [apr, setApr] = React.useState(/\d/.test(String(fw.apr ?? "")) ? num(fw.apr) : (window.fwDefaultApr ? window.fwDefaultApr() : 6.49)); const [term, setTerm] = React.useState(parseInt(fw.term) || 72); const products = (window.jbProducts ? window.jbProducts.list() : []).filter(p => p.active !== false && fimPrice(p) > 0); const find = (re) => products.filter(p => re.test((p.name || "") + " " + (p.code || ""))); const vsc = find(/vsc|service contract|warrant/i), gap = find(/gap/i), tw = find(/tire|wheel/i); const rest = products.filter(p => !vsc.includes(p) && !gap.includes(p) && !tw.includes(p)); const COLUMNS = [ { name: "PLATINUM", tone: "#11337A", items: [...vsc, ...gap, ...tw, ...rest], tag: "Total protection" }, { name: "GOLD", tone: "#8a6d1f", items: [...vsc, ...gap, ...tw], tag: "Most popular" }, { name: "SILVER", tone: "#5A6472", items: [...vsc.slice(0, 1), ...gap.slice(0, 1)], tag: "Core coverage" }, { name: "BASE", tone: "#8a8f98", items: [], tag: "No added protection" }, ]; const printMenu = () => { const cols = COLUMNS.map(c => { const tot = c.items.reduce((s, p) => s + fimPrice(p), 0); const pm = fimPmt(base + tot, apr, term); return `