[PM-37691] feat: Surface pending cancellation status on Premium plan view#6957
Conversation
Bitwarden Claude Code ReviewOverall Assessment: APPROVE Reviewed the introduction of Code Review DetailsNo findings — implementation, state handling, and test coverage all look in order. Observations recorded for context (not findings):
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #6957 +/- ##
==========================================
+ Coverage 85.49% 86.46% +0.96%
==========================================
Files 1023 870 -153
Lines 66231 63487 -2744
Branches 9308 9211 -97
==========================================
- Hits 56623 54891 -1732
+ Misses 6422 5432 -990
+ Partials 3186 3164 -22
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…view Closing the Stripe customer portal previously left the app unaware the user had returned, and the subscription payload's `active + cancelAt` combination collapsed to ACTIVE — so a scheduled cancellation was never surfaced until period-end. Route the portal launch through AuthTab via a dedicated launcher to detect return, map `cancelAt != null` on active or trialing subscriptions to a new PENDING_CANCELLATION status, and refetch the subscription on portal close so the badge reconciles immediately.
9fa9d28 to
1c35c7c
Compare
| } | ||
|
|
||
| private val authTabLaunchers by lazy { | ||
| AuthTabLaunchers( |
There was a problem hiding this comment.
I assume this is to ensure that we only build them once?
🎟️ Tracking
📔 Objective
After canceling a subscription via the Stripe customer portal, the badge on the Premium plan screen stayed on "Active" until the user manually refreshed. The
/account/billing/vnext/subscriptionpayload at that point reportsstatus: activewithcancelAt: <future-instant>, and the app never sees a push notification for the transition. Two gaps caused this:intentManager.launchUri(...)(plain Chrome Custom Tab) with no return signal.statusfield, soactive + cancelAtcollapsed toPremiumSubscriptionStatus.ACTIVE.This PR routes the portal launch through
startAuthTabwith a dedicatedstripePortalLauncher, so closing the tab firesMainAction.StripePortalResult→SpecialCircumstance.StripePortal→ a fresh/subscriptionfetch. A newPremiumSubscriptionStatus.PENDING_CANCELLATIONis derived whenstatus ∈ {active, trialing}andcancelAtis non-null, rendering a warning badge plus "Your subscription is scheduled to cancel on {date}. You can reinstate it anytime before then."📸 Screenshots