From be0e6e769993678d7bd9a60e35c832f73c26a723 Mon Sep 17 00:00:00 2001 From: Jennie Robinson Faber Date: Sat, 18 Apr 2026 17:19:05 +0100 Subject: [PATCH] refactor(config): cadence-keyed plan id, add getTierAmount, drop per-tier helcimPlanId --- app/config/contributions.js | 98 ++++---------------- server/config/contributions.js | 105 ++++++---------------- tests/server/config/contributions.test.js | 20 +++++ 3 files changed, 64 insertions(+), 159 deletions(-) create mode 100644 tests/server/config/contributions.test.js diff --git a/app/config/contributions.js b/app/config/contributions.js index ceee0a8..985de53 100644 --- a/app/config/contributions.js +++ b/app/config/contributions.js @@ -1,82 +1,22 @@ -// Central configuration for Ghost Guild Contribution Levels and Helcim Plans +// Central configuration for Ghost Guild Contribution Levels export const CONTRIBUTION_TIERS = { - FREE: { - value: "0", - amount: 0, - label: "$0 - I need support right now", - tier: "free", - helcimPlanId: null, // No Helcim plan needed for free tier - }, - SUPPORTER: { - value: "5", - amount: 5, - label: "$5 - I can contribute", - tier: "supporter", - helcimPlanId: "supporter-monthly-5", - }, - MEMBER: { - value: "15", - amount: 15, - label: "$15 - I can sustain the community", - tier: "member", - helcimPlanId: "member-monthly-15", - }, - ADVOCATE: { - value: "30", - amount: 30, - label: "$30 - I can support others too", - tier: "advocate", - helcimPlanId: "advocate-monthly-30", - }, - CHAMPION: { - value: "50", - amount: 50, - label: "$50 - I want to sponsor multiple members", - tier: "champion", - helcimPlanId: "champion-monthly-50", - }, -}; + FREE: { value: "0", amount: 0, label: "$0 - I need support right now", tier: "free" }, + SUPPORTER: { value: "5", amount: 5, label: "$5 - I can contribute", tier: "supporter" }, + MEMBER: { value: "15", amount: 15, label: "$15 - I can sustain the community", tier: "member" }, + ADVOCATE: { value: "30", amount: 30, label: "$30 - I can support others too", tier: "advocate" }, + CHAMPION: { value: "50", amount: 50, label: "$50 - I want to sponsor multiple members", tier: "champion" }, +} -// Get all contribution options as an array (useful for forms) -export const getContributionOptions = () => { - return Object.values(CONTRIBUTION_TIERS); -}; +export const getContributionOptions = () => Object.values(CONTRIBUTION_TIERS) +export const getValidContributionValues = () => Object.values(CONTRIBUTION_TIERS).map(t => t.value) +export const getContributionTierByValue = (value) => + Object.values(CONTRIBUTION_TIERS).find(t => t.value === value) +export const requiresPayment = (value) => (getContributionTierByValue(value)?.amount ?? 0) > 0 +export const isValidContributionValue = (value) => getValidContributionValues().includes(value) +export const getPaidContributionTiers = () => + Object.values(CONTRIBUTION_TIERS).filter(t => t.amount > 0) -// Get valid contribution values for validation -export const getValidContributionValues = () => { - return Object.values(CONTRIBUTION_TIERS).map((tier) => tier.value); -}; - -// Get contribution tier by value -export const getContributionTierByValue = (value) => { - return Object.values(CONTRIBUTION_TIERS).find((tier) => tier.value === value); -}; - -// Get Helcim plan ID for a contribution tier -export const getHelcimPlanId = (contributionValue) => { - const tier = getContributionTierByValue(contributionValue); - return tier?.helcimPlanId || null; -}; - -// Check if a contribution tier requires payment -export const requiresPayment = (contributionValue) => { - const tier = getContributionTierByValue(contributionValue); - return tier?.amount > 0; -}; - -// Check if a contribution value is valid -export const isValidContributionValue = (value) => { - return getValidContributionValues().includes(value); -}; - -// Get contribution tier by Helcim plan ID -export const getContributionTierByHelcimPlan = (helcimPlanId) => { - return Object.values(CONTRIBUTION_TIERS).find( - (tier) => tier.helcimPlanId === helcimPlanId, - ); -}; - -// Get paid tiers only (excluding free tier) -export const getPaidContributionTiers = () => { - return Object.values(CONTRIBUTION_TIERS).filter((tier) => tier.amount > 0); -}; +export function getTierAmount(tier, cadence = 'monthly') { + const base = parseFloat(tier.amount) + return cadence === 'annual' ? base * 10 : base +} diff --git a/server/config/contributions.js b/server/config/contributions.js index 0802bf0..d871bd5 100644 --- a/server/config/contributions.js +++ b/server/config/contributions.js @@ -1,85 +1,30 @@ // Server-side contribution config -// Copy of the client-side config for server use - -// Central configuration for Ghost Guild Contribution Levels and Helcim Plans export const CONTRIBUTION_TIERS = { - FREE: { - value: "0", - amount: 0, - label: "$0 - I need support right now", - tier: "free", - helcimPlanId: null, // No Helcim plan needed for free tier - }, - SUPPORTER: { - value: "5", - amount: 5, - label: "$5 - I can contribute", - tier: "supporter", - helcimPlanId: 20162, - }, - MEMBER: { - value: "15", - amount: 15, - label: "$15 - I can sustain the community", - tier: "member", - helcimPlanId: 21596, - }, - ADVOCATE: { - value: "30", - amount: 30, - label: "$30 - I can support others too", - tier: "advocate", - helcimPlanId: 21597, - }, - CHAMPION: { - value: "50", - amount: 50, - label: "$50 - I want to sponsor multiple members", - tier: "champion", - helcimPlanId: 21598, - }, -}; + FREE: { value: "0", amount: 0, label: "$0 - I need support right now", tier: "free" }, + SUPPORTER: { value: "5", amount: 5, label: "$5 - I can contribute", tier: "supporter" }, + MEMBER: { value: "15", amount: 15, label: "$15 - I can sustain the community", tier: "member" }, + ADVOCATE: { value: "30", amount: 30, label: "$30 - I can support others too", tier: "advocate" }, + CHAMPION: { value: "50", amount: 50, label: "$50 - I want to sponsor multiple members", tier: "champion" }, +} -// Get all contribution options as an array (useful for forms) -export const getContributionOptions = () => { - return Object.values(CONTRIBUTION_TIERS); -}; +export const getContributionOptions = () => Object.values(CONTRIBUTION_TIERS) +export const getValidContributionValues = () => Object.values(CONTRIBUTION_TIERS).map(t => t.value) +export const getContributionTierByValue = (value) => + Object.values(CONTRIBUTION_TIERS).find(t => t.value === value) +export const requiresPayment = (value) => (getContributionTierByValue(value)?.amount ?? 0) > 0 +export const isValidContributionValue = (value) => getValidContributionValues().includes(value) +export const getPaidContributionTiers = () => + Object.values(CONTRIBUTION_TIERS).filter(t => t.amount > 0) -// Get valid contribution values for validation -export const getValidContributionValues = () => { - return Object.values(CONTRIBUTION_TIERS).map((tier) => tier.value); -}; +export function getTierAmount(tier, cadence = 'monthly') { + const base = parseFloat(tier.amount) + return cadence === 'annual' ? base * 10 : base +} -// Get contribution tier by value -export const getContributionTierByValue = (value) => { - return Object.values(CONTRIBUTION_TIERS).find((tier) => tier.value === value); -}; - -// Get Helcim plan ID for a contribution tier -export const getHelcimPlanId = (contributionValue) => { - const tier = getContributionTierByValue(contributionValue); - return tier?.helcimPlanId || null; -}; - -// Check if a contribution tier requires payment -export const requiresPayment = (contributionValue) => { - const tier = getContributionTierByValue(contributionValue); - return tier?.amount > 0; -}; - -// Check if a contribution value is valid -export const isValidContributionValue = (value) => { - return getValidContributionValues().includes(value); -}; - -// Get contribution tier by Helcim plan ID -export const getContributionTierByHelcimPlan = (helcimPlanId) => { - return Object.values(CONTRIBUTION_TIERS).find( - (tier) => tier.helcimPlanId === helcimPlanId, - ); -}; - -// Get paid tiers only (excluding free tier) -export const getPaidContributionTiers = () => { - return Object.values(CONTRIBUTION_TIERS).filter((tier) => tier.amount > 0); -}; +// Cadence-keyed plan-id lookup. Throws via createError at call site if env missing; +// this helper just returns the raw runtime-config value. +export function getHelcimPlanId(cadence) { + const config = useRuntimeConfig() + if (cadence === 'annual') return config.helcimAnnualPlanId || null + return config.helcimMonthlyPlanId || null +} diff --git a/tests/server/config/contributions.test.js b/tests/server/config/contributions.test.js new file mode 100644 index 0000000..b0e916b --- /dev/null +++ b/tests/server/config/contributions.test.js @@ -0,0 +1,20 @@ +import { describe, it, expect } from 'vitest' +import { getTierAmount } from '../../../server/config/contributions.js' + +describe('getTierAmount', () => { + it('returns monthly amount as-is', () => { + expect(getTierAmount({ amount: 5 }, 'monthly')).toBe(5) + }) + + it('returns annual amount as base * 10', () => { + expect(getTierAmount({ amount: 5 }, 'annual')).toBe(50) + }) + + it('returns annual amount for $50 tier', () => { + expect(getTierAmount({ amount: 50 }, 'annual')).toBe(500) + }) + + it('defaults cadence to monthly', () => { + expect(getTierAmount({ amount: 15 })).toBe(15) + }) +})