feat: route refunds through Session's own two links, and branch the non-originating screen - #2182
Draft
Bilb wants to merge 4 commits into
Draft
feat: route refunds through Session's own two links, and branch the non-originating screen#2182Bilb wants to merge 4 commits into
Bilb wants to merge 4 commits into
Conversation
…on-originating screen Three connected corrections to the refund CTA. **The links.** The refund action used the provider's `refund_platform_url`/`refund_support_url`. It now uses two Session-owned short links chosen on the quick-refund window alone: `ProUrls.QUICK_REFUND` while the store will still take the request, `ProUrls.SUPPORT` once it will not. Being ours, the destinations can be repointed without a client release, and all three clients now agree on them. The old support value for Google Play redirected to the Play store, so a screen promising the request was handled by Session Support sent the user to the one place it cannot be actioned. **The non-originating screen now branches.** It served both the <48h and >48h states with one rendering: the former's button under the latter's link. The window was already resolved at the dispatch site and simply was not passed on, so this threads it through and branches the button, the body copy and the link together. Past the window the copy is `proPlanPlatformRefundLong`, which is the same sentence iOS already shows for this state. **The CTA names the store, not the platform.** `getPlatformDisplayName()` exists for exactly this and was already used by the cancel, choose-plan and no-billing screens; only the two refund screens still passed the raw platform name, rendering "Open Google Website" where the designs say "Open Google Play Store Website". iOS and Desktop both apply the same rule. Verified against a QA build: all four @android pro_refund_screens specs pass, and iOS and Desktop pass the same assertions against their own builds. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The quick-refund link redirects into the Play store, so it is only a usable route for a plan bought there. An App Store plan reports its refund window open for the whole subscription, so gating on the window alone sent an Apple subscriber to the wrong store's refund flow — reachable on the non-originating screen, which is the one that shows plans bought elsewhere. Gated on the provider slug as well as the window. iOS and Desktop take the same gate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…g it libsession owns the per-provider url table and says so in `pro_backend.h`: "libsession owns them as the single source of truth rather than each client duplicating them". The store refund route now reads `providerUrls(slug).refundSupportUrl` through the wrapper this app already used for the other four provider urls, and the copy added earlier is gone. Worth knowing for anyone reading the call site: the slot's NAME is misleading. For Google Play, libsession's `refund_support_url` is the Session short link that redirects into the Play store — so the value the window-OPEN route needs sits under libsession's "support" name, while the window-CLOSED route uses `ProUrls.SUPPORT`, which mirrors `url_pro_support`. Those two are different destinations with confusingly similar names. `ProUrls.SUPPORT` stays a copy: the `url_pro_*` registry is a C struct of `const char*` with no Kotlin accessor, which is what that file already documents. Verified against a QA build: all four @android pro_refund_screens specs pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Added in the previous commit to stop an Apple plan reaching the Play-store link — a case that cannot happen. `providerData` is the ORIGINATING provider's table, so an Apple plan already yields Apple's own refund page there. The check replaced that correct page with Session's support form, which contradicts the design's "Apple processes all refund requests, we do not get a say". The window alone is the right condition; the per-provider behaviour falls out of libsession's table rather than a client check. Verified against a QA build: all four @android pro_refund_screens specs pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bilb
marked this pull request as draft
August 24, 2026 07:26
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #2178 (now merged). Three connected corrections to the refund CTA.
The links
The refund action used the provider's
refund_platform_url/refund_support_url. It now uses two Session-owned short links, chosen on the quick-refund window alone:ProUrls.QUICK_REFUND(getsession.org/android-refund)ProUrls.SUPPORT(getsession.org/pro-support)Being ours, the destinations can be repointed without a client release, and all three clients now agree on them. This matters because the old support value for Google Play redirects to the Play store — so a screen whose copy promises the request is handled by Session Support was sending the user to the one place a
>48hrequest cannot be actioned.The non-originating screen now branches
It rendered one screen for both the
<48hand>48hstates: the former's button under the latter's link. The window was already resolved at the dispatch site and simply was not passed on. This threads it through and branches the button, the body copy and the link together. Past the window the body isproPlanPlatformRefundLong, which is the same sentence iOS already shows for this state.The CTA names the store, not the platform
getPlatformDisplayName()exists for exactly this and was already used by the cancel, choose-plan and no-billing screens — only the two refund screens still passed the raw platform name, rendering "Open Google Website" where the designs say "Open Google Play Store Website". iOS and Desktop both apply the same rule.Verification
Built as a QA APK and run against an emulator: all four
@android pro_refund_screensspecs pass, including the non-originating window-closed case that previously had no assertable URL. iOS and Desktop pass the equivalent assertions against their own builds.🤖 Generated with Claude Code