Skip to content

fix: clarify sandbox subscription success states#249

Merged
BASIC-BIT merged 9 commits intomainfrom
feat/issue-243-sandbox-success-ux
Mar 27, 2026
Merged

fix: clarify sandbox subscription success states#249
BASIC-BIT merged 9 commits intomainfrom
feat/issue-243-sandbox-success-ux

Conversation

@BASIC-BIT
Copy link
Owner

Summary

  • centralize subscribe-flow sandbox detection so checkout and celebrate views use the same sandbox context
  • show additive sandbox notices on pay and celebrate pages while preserving warning semantics for Discord role sync issues
  • extend unit and visual coverage for sandbox success-with-warning states in the member subscribe flow

Testing

  • npm run typecheck
  • npm run lint
  • npm run test:unit
  • npm run test:e2e:visual

Closes #243

@vercel
Copy link

vercel bot commented Mar 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
entexchange_perkcord Ready Ready Preview, Comment Mar 26, 2026 10:38am
perkcord Ready Ready Preview, Comment Mar 26, 2026 10:38am

Request Review

@BASIC-BIT
Copy link
Owner Author

@perkcord preview

@github-actions
Copy link

Manual Vercel Preview

Triggered from PR comment for branch feat/issue-243-sandbox-success-ux.
Preview URL: https://perkcord-fufif9zh2-basicbit.vercel.app

Use @perkcord preview or /vercel-preview on this PR when you need a fresh manual preview deployment.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 26, 2026

Greptile Summary

This PR centralises sandbox detection for the member subscribe flow so that both the checkout (pay) and post-payment (celebrate) pages use the same detection utilities, and surfaces additive "this was a test transaction" notices at the appropriate points in each flow.\n\nKey changes:\n- subscribeSandbox.ts (new): single source of truth for all sandbox detection — resolveCheckoutSandboxContext / resolveCheckoutSandboxContexts for the pay page, buildSandboxInfo / resolveGrantSandboxContext for the celebrate page. Authorize.Net correctly defaults to \"production\" when AUTHORIZE_NET_ENV is unset (resolves the previously flagged false-sandbox-banner risk).\n- access-status-helpers.ts: StatusResponse gains a required sandbox field; derivePhase routes sandbox users with pending/in-progress role sync to \"warning\" instead of \"syncing\" (avoids a misleading spinner when no real bot is active in sandbox), and deriveMessage surfaces sandbox-specific copy.\n- sandboxSummary.ts (new): lightweight celebrate-page helpers that decide whether to show the sandbox note and format its text; the previously flagged unreachable branch has been removed.\n- CombinedCheckout.tsx: renders a single global banner when exactly one payment method is visible and it is in sandbox mode; falls back to per-method inline notices when multiple methods are shown or methods are in mixed sandbox/production state.\n- status.ts: API response now includes the sandbox shape derived from buildSandboxInfo, keeping the client free of any env-var access.\n- Test coverage: new unit suites for subscribeSandbox, sandboxSummary, and AccessStatus, extended CombinedCheckout tests, and an updated e2e visual spec that exercises the sandbox celebrate state with a failed role-sync fixture.

Confidence Score: 5/5

Safe to merge — all three previously raised concerns are resolved and the new logic is well-covered by unit, integration, and visual tests.

All prior review concerns (production-default for missing AUTHORIZE_NET_ENV, leaking provider fields on non-sandbox grants, unreachable branch in shouldShowSandboxCelebrateNote) have been addressed. The remaining comment is a P2 style nit about a redundant call to resolveCheckoutSandboxContexts inside helpers.ts — non-blocking and trivially cheap at runtime. The logic across checkout and celebrate paths is internally consistent and the test suite covers the key edge cases.

apps/web/app/subscribe/pay/helpers.ts — minor double computation worth tidying, no correctness impact.

Important Files Changed

Filename Overview
apps/web/lib/subscribeSandbox.ts New module centralising all sandbox detection and formatting helpers; correctly defaults Authorize.Net to production when env is unset, clears provider fields for non-sandbox grants, and handles the single-vs-multi-method global banner logic cleanly.
apps/web/app/subscribe/celebrate/access-status-helpers.ts Adds required sandbox field to StatusResponse, routes sandbox pending/in_progress role-sync states to "warning" phase instead of "syncing", and provides sandbox-aware messages — all consistent with the new centralized detection layer.
apps/web/app/subscribe/celebrate/AccessStatus.tsx Extends the warning block to cover pending/in_progress role-sync states and adds additive sandbox notices for both "success" and "warning" phases; the two data-testid="sandbox-success-note" sites are mutually exclusive (phase guards) so no duplicate rendering.
apps/web/app/subscribe/celebrate/sandboxSummary.ts New celebrate-page helpers; shouldShowSandboxCelebrateNote correctly gates on isSandbox, non-null grant, non-past_due status, and success/warning phase only — the previously flagged unreachable branch has been removed.
apps/web/app/subscribe/pay/CombinedCheckout.tsx Adds a single-method global sandbox banner and per-method sandbox notices controlled by shouldRenderPerMethodSandboxNotices; the two display paths are mutually exclusive and well-tested.
apps/web/app/subscribe/pay/helpers.ts Wires sandbox context resolution into resolvePaymentMethods; minor inefficiency: resolveCheckoutSandboxContexts is called twice (once directly, once internally via resolveCheckoutSandboxContext).
apps/web/lib/api/subscribe/status.ts Adds sandbox field to the status API response using buildSandboxInfo; correctly handles missing AUTHORIZE_NET_ENV (defaults to production) and absent Stripe key.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph Pay Page
        HP[helpers.ts resolvePaymentMethods] --> SC[resolveCheckoutSandboxContexts\nper-provider contexts]
        HP --> SCX[resolveCheckoutSandboxContext\nsingle global context]
        SC --> CCX{sandboxContext\nnon-null?}
        CCX -- Yes - single method all-sandbox --> GB[Global sandbox banner]
        CCX -- No --> PMN[Per-method inline notices]
    end
    subgraph Status API
        ST[status.ts resolveSubscribeStatus] --> BSI[buildSandboxInfo\ngrant source + env vars]
        BSI --> SR[StatusResponse\nsandbox field]
    end
    subgraph Celebrate Page
        SR --> DPH[derivePhase]
        DPH -- sandbox + pending/in_progress/failed roleSync --> WP[phase = warning]
        DPH -- sandbox + completed roleSync --> SP[phase = success]
        WP --> SHN[shouldShowSandboxCelebrateNote]
        SP --> SHN
        SHN -- true --> SN[sandbox-success-note rendered]
    end
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/web/app/subscribe/pay/helpers.ts
Line: 114-143

Comment:
**`resolveCheckoutSandboxContexts` computed twice**

`resolveCheckoutSandboxContexts` is invoked directly to produce `sandboxContexts`, and then invoked a second time inside `resolveCheckoutSandboxContext` (which calls it internally). Both calls receive the identical argument object, so the same work is done twice.

You could either expose a two-value variant that returns both artefacts at once, or derive `sandboxContext` from the already-computed `sandboxContexts`:

```ts
const sandboxContexts = resolveCheckoutSandboxContexts({
  showAuthorizeNet,
  showStripe,
  showNmi,
  authorizeNetEnv: authorizeNetState.env,
  stripeEnvironment,
  nmiSandbox: false,
});
const visibleSandboxContexts = Object.values(sandboxContexts).filter(
  (c): c is SandboxContext => c !== null,
);
const visibleMethodCount =
  Number(showAuthorizeNet) + Number(showStripe) + Number(showNmi);
const sandboxContext =
  visibleMethodCount === 1 &&
  visibleSandboxContexts.length === 1 &&
  visibleSandboxContexts.length === visibleMethodCount
    ? visibleSandboxContexts[0]
    : null;
```

This is a minor efficiency concern and not a functional bug, but it avoids duplicating the resolution logic.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (8): Last reviewed commit: "test: refresh celebrate visual baselines" | Re-trigger Greptile

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 401e23e2b0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@github-actions
Copy link

github-actions bot commented Mar 26, 2026

Snapshot Preview

7 changed snapshot file(s) in this PR.
Run: https://github.com/BASIC-BIT/perkcord/actions/runs/23616655078
Artifact: pr-snapshot-preview

Storybook snapshots

No changed snapshots.

Playwright visual snapshots (7)

  • apps/web/e2e/visual.spec.ts-snapshots/subscribe-celebrate-full-chromium-linux.png
    apps/web/e2e/visual.spec.ts-snapshots/subscribe-celebrate-full-chromium-linux.png
  • apps/web/e2e/visual.spec.ts-snapshots/subscribe-celebrate-full-chromium-win32.png
    apps/web/e2e/visual.spec.ts-snapshots/subscribe-celebrate-full-chromium-win32.png
  • apps/web/e2e/visual.spec.ts-snapshots/subscribe-celebrate-viewport-chromium-linux.png
    apps/web/e2e/visual.spec.ts-snapshots/subscribe-celebrate-viewport-chromium-linux.png
  • apps/web/e2e/visual.spec.ts-snapshots/subscribe-celebrate-viewport-chromium-win32.png
    apps/web/e2e/visual.spec.ts-snapshots/subscribe-celebrate-viewport-chromium-win32.png
  • apps/web/e2e/visual.spec.ts-snapshots/subscribe-pay-age-gate-full-chromium-linux.png
    apps/web/e2e/visual.spec.ts-snapshots/subscribe-pay-age-gate-full-chromium-linux.png
  • apps/web/e2e/visual.spec.ts-snapshots/subscribe-pay-age-gate-full-chromium-win32.png
    apps/web/e2e/visual.spec.ts-snapshots/subscribe-pay-age-gate-full-chromium-win32.png
  • apps/web/e2e/visual.spec.ts-snapshots/subscribe-pay-full-chromium-linux.png
    apps/web/e2e/visual.spec.ts-snapshots/subscribe-pay-full-chromium-linux.png

Copilot AI review requested due to automatic review settings March 26, 2026 15:33
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Centralizes sandbox detection/formatting for the subscribe flow and updates pay/celebrate UI to show sandbox “success with warning” messaging consistently.

Changes:

  • Added subscribeSandbox helpers to resolve sandbox context across checkout and grant/celebrate flows.
  • Updated subscribe status API + celebrate/pay UIs to surface sandbox notices alongside role-sync warnings.
  • Added/extended unit + visual coverage for sandbox success-with-warning states.

Reviewed changes

Copilot reviewed 12 out of 16 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
apps/web/lib/subscribeSandbox.ts New centralized sandbox context resolution + formatting utilities
apps/web/lib/subscribeSandbox.test.ts Unit tests for sandbox context resolution and formatting
apps/web/lib/api/subscribe/status.ts Adds sandbox info to subscribe status response
apps/web/lib/api/subscribe/status.test.ts Adds tests around sandbox info construction
apps/web/e2e/visual.spec.ts Visual coverage for celebrate sandbox success note
apps/web/app/subscribe/pay/helpers.ts Resolves sandbox contexts for checkout methods in pay flow
apps/web/app/subscribe/pay/CombinedCheckout.tsx Renders sandbox notices globally and per payment method
apps/web/app/subscribe/pay/CombinedCheckout.test.tsx Unit tests for sandbox notice rendering behavior
apps/web/app/subscribe/celebrate/sandboxSummary.ts New helpers to decide and format sandbox celebrate copy
apps/web/app/subscribe/celebrate/sandboxSummary.test.ts Unit tests for celebrate sandbox note logic
apps/web/app/subscribe/celebrate/access-status-helpers.ts Adds sandbox-aware phase/message semantics
apps/web/app/subscribe/celebrate/AccessStatus.tsx Displays sandbox success note for success/warning states

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Remove the literal HTML entity from the celebrate retry copy and lock the global checkout sandbox notice to a single rendered banner. Refresh the Linux pay-page snapshot to match the intended single-banner layout.
@BASIC-BIT BASIC-BIT merged commit 5e1ba8f into main Mar 27, 2026
24 checks passed
@BASIC-BIT BASIC-BIT deleted the feat/issue-243-sandbox-success-ux branch March 27, 2026 01:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Treat sandbox subscribe success as success-with-warning and centralize intentional mode handling

2 participants