From cd0d3f7167bc55b18451a93a0b057f268f9fde61 Mon Sep 17 00:00:00 2001 From: Jennie Robinson Faber Date: Sat, 18 Apr 2026 17:59:10 +0100 Subject: [PATCH] =?UTF-8?q?feat(join):=20cadence=20selector=20with=20annua?= =?UTF-8?q?l=20pricing=20(monthly=C3=9710)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Radio-pair cadence selector (Monthly / Annual) added to the join form, reusing the existing .circle-radio styling. contributionItems computed reactively; all tier labels and the left-column price list update on toggle. cadence submitted with the subscription payload. payment-setup hardcoded to monthly (annual upgrades go through /join). --- app/pages/join.vue | 73 ++++++++++++++++++++++++------ app/pages/member/payment-setup.vue | 3 +- 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/app/pages/join.vue b/app/pages/join.vue index fc1ae21..80bd80f 100644 --- a/app/pages/join.vue +++ b/app/pages/join.vue @@ -116,19 +116,19 @@

Pay what you can

@@ -234,9 +234,39 @@
+
+ +
+
+ + +
+
+ + +
+
+
{{ cadence === 'annual' ? 'Annual' : 'Monthly' }} Contribution { + const isAnnual = cadence.value === "annual"; + return Object.values(CONTRIBUTION_TIERS).map((tier) => { + const base = tier.amount; + if (base === 0) return { value: tier.value, label: "$0" }; + const amt = isAnnual ? base * 10 : base; + const suffix = isAnnual ? "/yr" : "/mo"; + const hint = tier.value === "15" && !isAnnual ? " (suggested)" : ""; + return { value: tier.value, label: `$${amt}${suffix}${hint}` }; + }); +}); // Initialize composables const { @@ -585,6 +622,7 @@ const createSubscription = async (cardToken = null) => { customerId: customerId.value, customerCode: customerCode.value, contributionTier: form.contributionTier, + cadence: cadence.value, cardToken: cardToken, }, }); @@ -863,6 +901,13 @@ onUnmounted(() => { color: var(--text-faint); } +/* ---- CADENCE RADIOS ---- */ +.cadence-radios { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 10px; +} + /* ---- CIRCLE RADIOS ---- */ .circle-radios { display: grid; diff --git a/app/pages/member/payment-setup.vue b/app/pages/member/payment-setup.vue index b604e17..584a5be 100644 --- a/app/pages/member/payment-setup.vue +++ b/app/pages/member/payment-setup.vue @@ -128,7 +128,8 @@ const openModal = async () => { await $fetch('/api/members/update-contribution', { method: 'POST', - body: { contributionTier: targetTier.value }, + // cadence: annual upgrades go through /join; this page is monthly-only + body: { contributionTier: targetTier.value, cadence: 'monthly' }, }); await checkMemberStatus();