From 8f5c95aec202052af48bf2d208166eb57dbc8aee Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 10 Jul 2026 09:46:07 +0000 Subject: [PATCH] refactor(telemetry): extract deriveTier to utils with tests, dedupe previewTier --- .../Organization/NewOrg/NewOrgForm.tsx | 16 ++----------- .../NewOrg/NewOrgForm.utils.test.ts | 23 +++++++++++++++++++ .../Organization/NewOrg/NewOrgForm.utils.ts | 11 +++++++++ 3 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.utils.test.ts create mode 100644 apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.utils.ts diff --git a/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.tsx b/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.tsx index 34d132db315..0d2a924abaa 100644 --- a/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.tsx +++ b/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.tsx @@ -35,6 +35,7 @@ import { type OrgKind, type OrgSize, } from './OrganizationDetailsFields' +import { deriveTier, type OrgTier } from './NewOrgForm.utils' import { UpgradeExistingOrganizationCallout } from './UpgradeExistingOrganizationCallout' import { ChargeBreakdown } from '@/components/interfaces/Billing/ChargeBreakdown' import { getStripeElementsAppearanceOptions } from '@/components/interfaces/Billing/Payment/Payment.utils' @@ -84,18 +85,6 @@ const formSchema = organizationDetailsSchema.extend({ type FormState = z.infer -type OrgTier = 'tier_free' | 'tier_pro' | 'tier_payg' | 'tier_team' - -/** - * Derives the telemetry tier from the (non-null) submitted form values. This is the single source - * of truth for translating a plan + spend cap into a tier, so callers can never emit an - * organization creation event without a valid tier. - */ -const deriveTier = (plan: (typeof plans)[number], spendCap: boolean): OrgTier => { - const dbTier = plan === 'PRO' && !spendCap ? 'PAYG' : plan - return ('tier_' + dbTier.toLowerCase()) as OrgTier -} - const stripePromise = loadStripe(STRIPE_PUBLIC_KEY) const FORM_ID = 'new-org-form' @@ -225,8 +214,7 @@ export const NewOrgForm = ({ const previewTier = useMemo(() => { if (selectedPlan === 'FREE') return undefined - const dbTier = selectedPlan === 'PRO' && !selectedSpendCap ? 'PAYG' : selectedPlan - return ('tier_' + dbTier.toLowerCase()) as 'tier_pro' | 'tier_payg' | 'tier_team' + return deriveTier(selectedPlan, selectedSpendCap) }, [selectedPlan, selectedSpendCap]) const { diff --git a/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.utils.test.ts b/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.utils.test.ts new file mode 100644 index 00000000000..232845142b9 --- /dev/null +++ b/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.utils.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it } from 'vitest' + +import { deriveTier } from './NewOrgForm.utils' + +describe('deriveTier', () => { + it('maps FREE to tier_free regardless of spend cap', () => { + expect(deriveTier('FREE', false)).toBe('tier_free') + expect(deriveTier('FREE', true)).toBe('tier_free') + }) + + it('maps PRO with spend cap enabled to tier_pro', () => { + expect(deriveTier('PRO', true)).toBe('tier_pro') + }) + + it('maps PRO with spend cap disabled to tier_payg', () => { + expect(deriveTier('PRO', false)).toBe('tier_payg') + }) + + it('maps TEAM to tier_team regardless of spend cap', () => { + expect(deriveTier('TEAM', true)).toBe('tier_team') + expect(deriveTier('TEAM', false)).toBe('tier_team') + }) +}) diff --git a/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.utils.ts b/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.utils.ts new file mode 100644 index 00000000000..528cc388f7c --- /dev/null +++ b/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.utils.ts @@ -0,0 +1,11 @@ +export type OrgTier = 'tier_free' | 'tier_pro' | 'tier_payg' | 'tier_team' + +/** + * Derives the telemetry tier from the (non-null) submitted form values. This is the single source + * of truth for translating a plan + spend cap into a tier, so callers can never emit an + * organization creation event without a valid tier. + */ +export const deriveTier = (plan: 'FREE' | 'PRO' | 'TEAM', spendCap: boolean): OrgTier => { + const dbTier = plan === 'PRO' && !spendCap ? 'PAYG' : plan + return ('tier_' + dbTier.toLowerCase()) as OrgTier +}