Skip to main content

max / makenotwork

2.5 KB · 60 lines History Blame Raw
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