Skip to content

Commit e36e4e3

Browse files
dante01yoonampagent
andcommitted
fix: expose 3DS action for plan changes
Amp-Thread-ID: https://ampcode.com/threads/T-019fabb4-5565-73c7-8629-7d9b4a0e6d1a Co-authored-by: Amp <amp@ampcode.com>
1 parent 47da0fa commit e36e4e3

3 files changed

Lines changed: 46 additions & 1 deletion

File tree

src/platform/workspace/components/SubscriptionRequiredDialogContentUnified.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
:preview-data="previewData!"
6565
:team-plan="selectedTeamStop!"
6666
:is-loading="isSubscribing || isPolling"
67+
:action-url="activeCheckoutActionUrl"
6768
@confirm="handleTeamSubscribe"
6869
@back="handleBackToPricing"
6970
/>
@@ -93,6 +94,7 @@
9394
v-else-if="previewVariant === 'personal-change'"
9495
:preview-data="previewData!"
9596
:is-loading="isSubscribing || isPolling"
97+
:action-url="activeCheckoutActionUrl"
9698
@confirm="handleConfirmTransition"
9799
@back="handleBackToPricing"
98100
/>

src/platform/workspace/components/SubscriptionTransitionPreviewWorkspace.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { render, screen } from '@testing-library/vue'
2+
import userEvent from '@testing-library/user-event'
23
import { describe, expect, it, vi } from 'vitest'
34

45
import type {
@@ -122,6 +123,31 @@ describe('SubscriptionTransitionPreviewWorkspace', () => {
122123
expect(screen.getByText('$82.50')).toBeTruthy()
123124
})
124125

126+
it('opens verification only from its button without exposing the URL', async () => {
127+
const actionUrl = 'https://verify.example/sensitive-token'
128+
const open = vi.spyOn(window, 'open').mockReturnValue({} as Window)
129+
const { container } = render(SubscriptionTransitionPreviewWorkspace, {
130+
props: {
131+
previewData: preview({}),
132+
actionUrl
133+
},
134+
global: globalOptions
135+
})
136+
137+
expect(open).not.toHaveBeenCalled()
138+
expect(container.innerHTML).not.toContain(actionUrl)
139+
await userEvent.click(
140+
screen.getByRole('button', {
141+
name: 'subscription.preview.completeVerification'
142+
})
143+
)
144+
expect(open).toHaveBeenCalledWith(
145+
actionUrl,
146+
'_blank',
147+
'noopener,noreferrer'
148+
)
149+
})
150+
125151
it('renders a scheduled downgrade with the after-that block and no charge', () => {
126152
render(SubscriptionTransitionPreviewWorkspace, {
127153
props: {

src/platform/workspace/components/SubscriptionTransitionPreviewWorkspace.vue

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,16 @@
122122
<div class="flex flex-col gap-2 pt-8">
123123
<SubscriptionTermsNote />
124124

125+
<Button
126+
v-if="actionUrl"
127+
variant="primary"
128+
size="lg"
129+
class="w-full rounded-lg"
130+
@click="openVerification"
131+
>
132+
{{ $t('subscription.preview.completeVerification') }}
133+
</Button>
134+
125135
<Button
126136
variant="tertiary"
127137
size="lg"
@@ -160,13 +170,15 @@ type PersonalTierKey = 'standard' | 'creator' | 'pro'
160170
const {
161171
previewData,
162172
isLoading = false,
163-
teamPlan = null
173+
teamPlan = null,
174+
actionUrl = null
164175
} = defineProps<{
165176
previewData: PreviewSubscribeResponse
166177
isLoading?: boolean
167178
/** Set for a team credit-commit change: plan name + refill credits come from
168179
* the selected slider stop; all proration money stays driven by previewData. */
169180
teamPlan?: TeamPlanSelection | null
181+
actionUrl?: string | null
170182
}>()
171183
172184
defineEmits<{
@@ -176,6 +188,11 @@ defineEmits<{
176188
177189
const { t, n } = useI18n()
178190
191+
function openVerification() {
192+
if (!actionUrl) return
193+
window.open(actionUrl, '_blank', 'noopener,noreferrer')
194+
}
195+
179196
function formatTierName(tier: string): string {
180197
return t(`subscription.tiers.${tier.toLowerCase()}.name`)
181198
}

0 commit comments

Comments
 (0)