[PM-33849] feat: Add Premium Upgrade view#2523
Conversation
|
Great job! No new security vulnerabilities introduced in this pull request |
There was a problem hiding this comment.
Pull request overview
Adds a new Billing UI flow for upgrading to Premium via Stripe checkout, and wires it into the Vault tab navigation so users can reach the upgrade screen from the vault list.
Changes:
- Introduces a new
PremiumUpgradefeature (view/state/processor/coordinator/module) that requests a Stripe checkout session and opens the returned URL. - Integrates Premium Upgrade navigation into the Vault tab (
VaultRoute,VaultCoordinator,VaultListAction/VaultListProcessor). - Extends test infrastructure to support mocking
BillingAPIServiceand adds unit tests + localization strings for the new UI.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| GlobalTestHelpers/MockAppModule.swift | Adds mock coordinator/module support for the Premium Upgrade flow in tests. |
| BitwardenShared/UI/Vault/Vault/VaultRoute.swift | Adds a new .premiumUpgrade route for Vault navigation. |
| BitwardenShared/UI/Vault/Vault/VaultList/VaultListProcessor.swift | Handles new .upgradeToPremium action by navigating to the upgrade route. |
| BitwardenShared/UI/Vault/Vault/VaultList/VaultListAction.swift | Adds upgradeToPremium action to trigger the Premium Upgrade flow. |
| BitwardenShared/UI/Vault/Vault/VaultCoordinator.swift | Presents the Premium Upgrade coordinator when navigating to .premiumUpgrade. |
| BitwardenShared/UI/Billing/PremiumUpgrade/PremiumUpgradeView.swift | New SwiftUI screen showing pricing/features and launching Stripe checkout. |
| BitwardenShared/UI/Billing/PremiumUpgrade/PremiumUpgradeState.swift | New state backing the Premium Upgrade UI (loading + checkout URL). |
| BitwardenShared/UI/Billing/PremiumUpgrade/PremiumUpgradeRoute.swift | Defines the route(s) for the Premium Upgrade coordinator (dismiss). |
| BitwardenShared/UI/Billing/PremiumUpgrade/PremiumUpgradeProcessorTests.swift | Unit tests for checkout session creation, error handling, and actions. |
| BitwardenShared/UI/Billing/PremiumUpgrade/PremiumUpgradeProcessor.swift | Implements the async checkout session request + navigation actions. |
| BitwardenShared/UI/Billing/PremiumUpgrade/PremiumUpgradeModule.swift | Adds a module factory method to build the Premium Upgrade coordinator. |
| BitwardenShared/UI/Billing/PremiumUpgrade/PremiumUpgradeEffect.swift | Defines the effect(s) for triggering checkout session creation. |
| BitwardenShared/UI/Billing/PremiumUpgrade/PremiumUpgradeCoordinatorTests.swift | Unit tests for coordinator start and dismiss navigation behavior. |
| BitwardenShared/UI/Billing/PremiumUpgrade/PremiumUpgradeCoordinator.swift | Coordinator that installs the Premium Upgrade view and handles dismiss. |
| BitwardenShared/UI/Billing/PremiumUpgrade/PremiumUpgradeAction.swift | Actions for cancel + clearing the opened checkout URL. |
| BitwardenShared/Core/Platform/Services/TestHelpers/ServiceContainer+Mocks.swift | Adds optional mock injection for BillingAPIService in test containers. |
| BitwardenShared/Core/Platform/Services/Services.swift | Reorders HasBillingAPIService in the shared Services typealias. |
| BitwardenShared/Core/Platform/Services/ServiceContainer.swift | Adds billingAPIServiceOverride and uses it when resolving billingAPIService. |
| BitwardenResources/Localizations/en.lproj/Localizable.strings | Adds new English strings for Premium Upgrade UI text. |
| BitwardenKit/Application/TestHelpers/ServiceContainer.swift | Minor typealias ordering cleanup for test services. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| defer { state.isLoading = false } | ||
| do { | ||
| state.isLoading = true | ||
| let response = try await services.billingAPIService.createCheckoutSession() | ||
| state.checkoutURL = response.checkoutSessionUrl | ||
| } catch { | ||
| services.errorReporter.log(error: error) |
There was a problem hiding this comment.
state.isLoading is cleared via defer, but because the catch path awaits coordinator.showErrorAlert, the loading state will remain true until after the alert flow completes. This can leave the UI disabled/spinning while the error alert is onscreen. Consider setting isLoading = false before awaiting the error alert (or avoid defer and explicitly reset loading in both success and failure paths).
| defer { state.isLoading = false } | |
| do { | |
| state.isLoading = true | |
| let response = try await services.billingAPIService.createCheckoutSession() | |
| state.checkoutURL = response.checkoutSessionUrl | |
| } catch { | |
| services.errorReporter.log(error: error) | |
| do { | |
| state.isLoading = true | |
| let response = try await services.billingAPIService.createCheckoutSession() | |
| state.isLoading = false | |
| state.checkoutURL = response.checkoutSessionUrl | |
| } catch { | |
| services.errorReporter.log(error: error) | |
| state.isLoading = false |
BitwardenShared/UI/Billing/PremiumUpgrade/PremiumUpgradeView.swift
Outdated
Show resolved
Hide resolved
| /// An optional override for the billing API service, used for testing. | ||
| var billingAPIServiceOverride: BillingAPIService? | ||
|
|
There was a problem hiding this comment.
billingAPIServiceOverride introduces a mutable test-only escape hatch on the production ServiceContainer. To keep the override from being modified outside test helpers, consider tightening access (e.g., private(set) / private) and injecting the override via an initializer or a dedicated test-only API (possibly behind #if DEBUG).
There was a problem hiding this comment.
Thanks forgot to delete this.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2523 +/- ##
==========================================
- Coverage 87.08% 85.96% -1.12%
==========================================
Files 1862 2104 +242
Lines 165404 180636 +15232
==========================================
+ Hits 144042 155290 +11248
- Misses 21362 25346 +3984 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
# Conflicts: # BitwardenShared/Core/Platform/Services/Services.swift
# Conflicts: # BitwardenShared/UI/Vault/Vault/VaultList/VaultListAction.swift # BitwardenShared/UI/Vault/Vault/VaultList/VaultListProcessor.swift
…on body length warning
…twarden/ios into pm-33849/premium-upgrade-view

🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-33849
📔 Objective
Adds the Premium Upgrade view that allows users to upgrade to a premium plan via Stripe checkout.
Changes
BitwardenShared/UI/Billing/PremiumUpgrade/):PremiumUpgradeView- Displays premium pricing, features list, and upgrade buttonPremiumUpgradeProcessor- Handles upgrade button tap by creating a Stripe checkout sessionPremiumUpgradeCoordinator/PremiumUpgradeModule- Navigation managementPremiumUpgradeAction,PremiumUpgradeEffect,PremiumUpgradeRoute,PremiumUpgradeState.premiumUpgraderoute and.upgradeToPremiumaction to VaultListBillingAPIServicemock support toServiceContainer📸 Screenshots
New
