diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/premium/plan/PlanScreen.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/premium/plan/PlanScreen.kt index 20946f07d6..d80f6a60a4 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/premium/plan/PlanScreen.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/premium/plan/PlanScreen.kt @@ -269,6 +269,7 @@ private fun FreeCloudContent( handlers: PlanHandlers, modifier: Modifier = Modifier, ) { + var shouldShowUpgradeDialog by rememberSaveable { mutableStateOf(false) } Column( modifier = modifier .fillMaxSize() @@ -285,7 +286,7 @@ private fun FreeCloudContent( BitwardenFilledButton( label = stringResource(id = BitwardenString.upgrade_now), - onClick = handlers.onUpgradeNowClick, + onClick = { shouldShowUpgradeDialog = true }, icon = rememberVectorPainter(id = BitwardenDrawable.ic_external_link), modifier = Modifier .standardHorizontalMargin() @@ -296,7 +297,10 @@ private fun FreeCloudContent( Spacer(modifier = Modifier.height(12.dp)) Text( - text = stringResource(id = BitwardenString.stripe_checkout_footer), + text = stringResource( + id = BitwardenString + .youll_go_to_stripes_secure_checkout_to_complete_your_purchase, + ), style = BitwardenTheme.typography.bodyMedium, color = BitwardenTheme.colorScheme.text.secondary, textAlign = TextAlign.Center, @@ -309,6 +313,24 @@ private fun FreeCloudContent( Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.navigationBarsPadding()) } + + if (shouldShowUpgradeDialog) { + BitwardenTwoButtonDialog( + title = stringResource(id = BitwardenString.continue_to_stripe), + message = stringResource( + id = BitwardenString + .youll_go_to_stripes_secure_checkout_to_complete_your_purchase, + ), + confirmButtonText = stringResource(id = BitwardenString.continue_text), + dismissButtonText = stringResource(id = BitwardenString.cancel), + onConfirmClick = { + shouldShowUpgradeDialog = false + handlers.onUpgradeNowClick() + }, + onDismissClick = { shouldShowUpgradeDialog = false }, + onDismissRequest = { shouldShowUpgradeDialog = false }, + ) + } } @Suppress("MaxLineLength") diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/premium/plan/PlanScreenTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/premium/plan/PlanScreenTest.kt index 7bf9127644..c3ba27512b 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/premium/plan/PlanScreenTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/premium/plan/PlanScreenTest.kt @@ -136,14 +136,66 @@ class PlanScreenTest : BitwardenComposeTest() { } @Test - fun `upgrade now button click should send UpgradeNowClick action`() { + fun `upgrade now button click should show continue to Stripe confirmation dialog`() { + composeTestRule + .onAllNodesWithText("Continue to Stripe?") + .filterToOne(hasAnyAncestor(isDialog())) + .assertDoesNotExist() + composeTestRule .onNodeWithTag("UpgradeNowButton") .performScrollTo() .performClick() - verify { - viewModel.trySendAction(PlanAction.UpgradeNowClick) - } + + composeTestRule + .onAllNodesWithText("Continue to Stripe?") + .filterToOne(hasAnyAncestor(isDialog())) + .assertExists() + composeTestRule + .onAllNodesWithText( + "You’ll go to Stripe’s secure checkout to complete your purchase.", + ) + .filterToOne(hasAnyAncestor(isDialog())) + .assertExists() + verify(exactly = 0) { viewModel.trySendAction(PlanAction.UpgradeNowClick) } + } + + @Test + fun `upgrade now dialog continue click should send UpgradeNowClick action and dismiss`() { + composeTestRule + .onNodeWithTag("UpgradeNowButton") + .performScrollTo() + .performClick() + + composeTestRule + .onAllNodesWithText("Continue") + .filterToOne(hasAnyAncestor(isDialog())) + .performClick() + + verify { viewModel.trySendAction(PlanAction.UpgradeNowClick) } + composeTestRule + .onAllNodesWithText("Continue to Stripe?") + .filterToOne(hasAnyAncestor(isDialog())) + .assertDoesNotExist() + } + + @Test + fun `upgrade now dialog cancel click should dismiss without sending action`() { + composeTestRule + .onNodeWithTag("UpgradeNowButton") + .performScrollTo() + .performClick() + + composeTestRule + .onAllNodesWithText("Cancel") + .filterToOne(hasAnyAncestor(isDialog())) + .performClick() + + verify(exactly = 0) { viewModel.trySendAction(PlanAction.UpgradeNowClick) } + composeTestRule + .onAllNodesWithText("Continue to Stripe?") + .filterToOne(hasAnyAncestor(isDialog())) + .assertDoesNotExist() } @Test diff --git a/ui/src/main/res/values/strings.xml b/ui/src/main/res/values/strings.xml index 3baca079ce..83bd98b565 100644 --- a/ui/src/main/res/values/strings.xml +++ b/ui/src/main/res/values/strings.xml @@ -1278,7 +1278,7 @@ Do you want to switch to this account? Secure file storage Breach monitoring Upgrade now - You’ll go to Stripe’s secure checkout to complete your purchase. + You’ll go to Stripe’s secure checkout to complete your purchase. Opening checkout… Secure checkout didn’t load We had trouble opening the payment page, so try again.