diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 863dea1d4f..5d00d38d66 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -2631,10 +2631,11 @@ "preview": { "confirmPayment": "Confirm your payment", "confirmPlanChange": "Confirm your plan change", - "startingToday": "Starting today", + "startingToday": "Starts today", "starting": "Starting {date}", "ends": "Ends {date}", "eachMonthCreditsRefill": "Each month credits refill to", + "eachYearCreditsRefill": "Each year credits refill to", "everyMonthStarting": "Every month starting {date}", "creditsRefillTo": "Credits refill to", "youllBeCharged": "You'll be charged", diff --git a/src/platform/workspace/components/SubscriptionAddPaymentPreviewWorkspace.test.ts b/src/platform/workspace/components/SubscriptionAddPaymentPreviewWorkspace.test.ts index 2511f653fa..0744b16789 100644 --- a/src/platform/workspace/components/SubscriptionAddPaymentPreviewWorkspace.test.ts +++ b/src/platform/workspace/components/SubscriptionAddPaymentPreviewWorkspace.test.ts @@ -2,8 +2,42 @@ import userEvent from '@testing-library/user-event' import { render, screen } from '@testing-library/vue' import { describe, expect, it, vi } from 'vitest' +import type { + PreviewSubscribeResponse, + SubscriptionDuration +} from '@/platform/workspace/api/workspaceApi' + import SubscriptionAddPaymentPreviewWorkspace from './SubscriptionAddPaymentPreviewWorkspace.vue' +function previewFixture( + duration: SubscriptionDuration, + priceCents: number +): PreviewSubscribeResponse { + return { + allowed: true, + transition_type: 'new_subscription', + effective_at: '2026-06-19T00:00:00Z', + is_immediate: true, + cost_today_cents: priceCents, + cost_next_period_cents: priceCents, + credits_today_cents: 0, + credits_next_period_cents: 0, + new_plan: { + slug: 'creator', + tier: 'CREATOR', + duration, + price_cents: priceCents, + credits_cents: 0, + seat_summary: { + seat_count: 1, + total_cost_cents: priceCents, + total_credits_cents: 0 + }, + period_end: '2027-06-19T00:00:00Z' + } + } +} + vi.mock('vue-i18n', () => ({ useI18n: () => ({ t: (key: string) => key, @@ -42,6 +76,67 @@ describe('SubscriptionAddPaymentPreviewWorkspace', () => { expect(screen.getByText('$380.00')).toBeTruthy() }) + it('shows the monthly-equivalent price and annual total for a yearly preview', () => { + render(SubscriptionAddPaymentPreviewWorkspace, { + props: { + tierKey: 'creator', + billingCycle: 'yearly', + previewData: previewFixture('ANNUAL', 33_600) + }, + global: globalOptions + }) + expect(screen.getByText('subscription.usdPerMonth')).toBeTruthy() + expect(screen.getByText('$28')).toBeTruthy() + expect(screen.getByText('subscription.billedYearly')).toBeTruthy() + expect(screen.getByText('$336.00')).toBeTruthy() + expect( + screen.getByText('subscription.preview.eachYearCreditsRefill') + ).toBeTruthy() + expect(screen.getByText('88,800')).toBeTruthy() + }) + + it('divides the yearly price by twelve in the fallback path', () => { + render(SubscriptionAddPaymentPreviewWorkspace, { + props: { tierKey: 'creator', billingCycle: 'yearly' }, + global: globalOptions + }) + expect(screen.getByText('$28')).toBeTruthy() + expect(screen.getByText('subscription.billedYearly')).toBeTruthy() + expect(screen.getByText('$336.00')).toBeTruthy() + }) + + it('omits the billed-yearly note for a monthly subscription', () => { + render(SubscriptionAddPaymentPreviewWorkspace, { + props: { + tierKey: 'creator', + billingCycle: 'monthly', + previewData: previewFixture('MONTHLY', 3_500) + }, + global: globalOptions + }) + expect(screen.getByText('$35')).toBeTruthy() + expect(screen.queryByText('subscription.billedYearly')).toBeNull() + expect( + screen.getByText('subscription.preview.eachMonthCreditsRefill') + ).toBeTruthy() + expect( + screen.queryByText('subscription.preview.eachYearCreditsRefill') + ).toBeNull() + }) + + it('shows the annual total for a yearly team plan', () => { + render(SubscriptionAddPaymentPreviewWorkspace, { + props: { + billingCycle: 'yearly', + teamPlan: { usd: 400, credits: 84_400, discountedUsd: 380 } + }, + global: globalOptions + }) + expect(screen.getByText('$380')).toBeTruthy() + expect(screen.getByText('subscription.billedYearly')).toBeTruthy() + expect(screen.getByText('$4560.00')).toBeTruthy() + }) + it('emits addCreditCard from the team confirm CTA', async () => { const { emitted } = render(SubscriptionAddPaymentPreviewWorkspace, { props: { teamPlan: { usd: 400, credits: 84_400, discountedUsd: 380 } }, diff --git a/src/platform/workspace/components/SubscriptionAddPaymentPreviewWorkspace.vue b/src/platform/workspace/components/SubscriptionAddPaymentPreviewWorkspace.vue index 199c16b317..b2a8baf7cd 100644 --- a/src/platform/workspace/components/SubscriptionAddPaymentPreviewWorkspace.vue +++ b/src/platform/workspace/components/SubscriptionAddPaymentPreviewWorkspace.vue @@ -19,13 +19,9 @@ {{ $t('subscription.usdPerMonth') }} -