| 1 |
// <mnw-price-mode>, the list/founder toggle on /pricing. |
| 2 |
// |
| 3 |
// The tier radios' `value` is what hx-include sends to /pricing/compare, so it |
| 4 |
// is the price the server computes the visitor's outcome on. While the founder |
| 5 |
// window is open the page renders founder prices into those values, and this |
| 6 |
// element lets the visitor flip to list prices to see the post-window number. |
| 7 |
// |
| 8 |
// Both prices are already in the DOM as data-price-std / data-price-founder, |
| 9 |
// so flipping is a local swap: no round trip for the prices themselves. The |
| 10 |
// recompute is the calculator's existing one, re-fired by dispatching `change` |
| 11 |
// on the checked tier radio, which is what hx-trigger already listens for. |
| 12 |
// |
| 13 |
// Inert on a page with no toggle (founder window shut), which is the whole of |
| 14 |
// its no-JS story: the server has already rendered the correct default, so |
| 15 |
// nothing here is load-bearing for correctness, only for the flip. |
| 16 |
|
| 17 |
import { MnwElement, define } from './base.ts'; |
| 18 |
import { priceFor, formatMonthly, type PriceMode } from './price-mode.logic.ts'; |
| 19 |
|
| 20 |
class PriceModeToggle extends MnwElement { |
| 21 |
protected init(): void { |
| 22 |
const modeInputs = Array.from( |
| 23 |
this.querySelectorAll<HTMLInputElement>('input[name="price-mode"]'), |
| 24 |
); |
| 25 |
if (modeInputs.length === 0) return; // founder window shut: nothing to flip |
| 26 |
|
| 27 |
const tierInputs = Array.from(this.querySelectorAll<HTMLInputElement>('input[name="tier"]')); |
| 28 |
|
| 29 |
const apply = (mode: PriceMode): void => { |
| 30 |
for (const tier of tierInputs) { |
| 31 |
const price = priceFor( |
| 32 |
{ |
| 33 |
std: tier.getAttribute('data-price-std'), |
| 34 |
founder: tier.getAttribute('data-price-founder'), |
| 35 |
}, |
| 36 |
mode, |
| 37 |
); |
| 38 |
if (price === null) continue; |
| 39 |
tier.value = price; |
| 40 |
const display = tier.parentElement?.querySelector<HTMLElement>('[data-price-display]'); |
| 41 |
if (display) display.textContent = formatMonthly(price); |
| 42 |
} |
| 43 |
|
| 44 |
// Re-run the calculator against the prices just written. hx-trigger on |
| 45 |
// #pricing-calculator listens for `change from:input[name='tier']`, so |
| 46 |
// this reuses the existing fetch rather than adding a second one. |
| 47 |
const checked = tierInputs.find((t) => t.checked); |
| 48 |
checked?.dispatchEvent(new Event('change', { bubbles: true })); |
| 49 |
}; |
| 50 |
|
| 51 |
for (const input of modeInputs) { |
| 52 |
input.addEventListener('change', () => { |
| 53 |
if (input.checked) apply(input.value as PriceMode); |
| 54 |
}); |
| 55 |
} |
| 56 |
} |
| 57 |
} |
| 58 |
|
| 59 |
define('mnw-price-mode', PriceModeToggle); |
| 60 |
|