feat: honor pro-trial checkout intent param on homepage - #1904
feat: honor pro-trial checkout intent param on homepage#1904sweetmantech wants to merge 1 commit into
Conversation
Visitors landing on / with ?intent=pro-trial are carried into the Stripe Pro trial checkout instead of being dropped on the homepage. Signed-in users get a checkout session and a same-tab redirect; signed-out users get the Privy login modal and continue into checkout automatically once auth completes. Unknown or absent intent values do nothing. The ordering rules live in a pure, unit-tested decision helper. A ref plus a sessionStorage flag guard against double-firing, and the checkout success URL drops the query string so returning from Stripe does not re-enter the flow. Part of #1902 (item C1). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 56 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (4)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8cd2dac35e
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
|
||
| if (action !== "checkout") return; | ||
| hasStartedCheckout.current = true; | ||
| markHandled(); |
There was a problem hiding this comment.
Move the handled flag until checkout can redirect
If an authenticated visitor lands on ?intent=pro-trial but getAccessToken() returns null or the checkout-session request fails/returns no URL, this marks the intent as handled before any redirect happens. Because wasHandled() then reads the sessionStorage flag on subsequent effect runs or reloads in the same tab, the marketing link stops trying to create checkout even though the user never reached Stripe; keep the in-flight ref for de-duping, but only persist the handled flag once a checkout URL is actually available.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
2 issues found across 6 files
Confidence score: 3/5
- In
components/Home/HomePage.tsx, marking the landing intent as handled before a checkout URL is successfully returned can permanently consume the intent after a transient token/session error, leaving users unable to retry checkout in the same tab — persist the handled flag only after a valid checkout URL is obtained (or clear it on failure). - In
lib/stripe/requestCheckoutSessionUrl.ts, checkout-session request behavior is duplicated across helpers, so endpoint/response/error-handling updates can diverge between same-tab and new-tab flows and cause inconsistent checkout behavior — centralize the request logic in one shared helper and keep only navigation differences at call sites.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="lib/stripe/requestCheckoutSessionUrl.ts">
<violation number="1" location="lib/stripe/requestCheckoutSessionUrl.ts:8">
P3: Checkout-session request logic now exists in two helpers, so endpoint or response/error-handling changes can drift between same-tab and new-tab checkout flows. Share the request helper and keep navigation as the caller-specific behavior.</violation>
</file>
<file name="components/Home/HomePage.tsx">
<violation number="1" location="components/Home/HomePage.tsx:16">
P2: A transient token or checkout-session failure leaves this landing intent permanently consumed for the tab, although no Stripe navigation occurred. Persist the handled flag only after a checkout URL is obtained (retain the in-memory guard while the request is in flight).</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| const { setFrameReady, isFrameReady } = useMiniKit(); | ||
| const router = useRouter(); | ||
| const onboarding = useOnboardingGate(); | ||
| useCheckoutIntent(); |
There was a problem hiding this comment.
P2: A transient token or checkout-session failure leaves this landing intent permanently consumed for the tab, although no Stripe navigation occurred. Persist the handled flag only after a checkout URL is obtained (retain the in-memory guard while the request is in flight).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At components/Home/HomePage.tsx, line 16:
<comment>A transient token or checkout-session failure leaves this landing intent permanently consumed for the tab, although no Stripe navigation occurred. Persist the handled flag only after a checkout URL is obtained (retain the in-memory guard while the request is in flight).</comment>
<file context>
@@ -5,13 +5,15 @@ import { useRouter } from "next/navigation";
const { setFrameReady, isFrameReady } = useMiniKit();
const router = useRouter();
const onboarding = useOnboardingGate();
+ useCheckoutIntent();
useEffect(() => {
</file context>
| * navigation. The success URL drops the query string so a returning | ||
| * visitor does not re-enter the intent flow. | ||
| */ | ||
| const requestCheckoutSessionUrl = async ( |
There was a problem hiding this comment.
P3: Checkout-session request logic now exists in two helpers, so endpoint or response/error-handling changes can drift between same-tab and new-tab checkout flows. Share the request helper and keep navigation as the caller-specific behavior.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/stripe/requestCheckoutSessionUrl.ts, line 8:
<comment>Checkout-session request logic now exists in two helpers, so endpoint or response/error-handling changes can drift between same-tab and new-tab checkout flows. Share the request helper and keep navigation as the caller-specific behavior.</comment>
<file context>
@@ -0,0 +1,34 @@
+ * navigation. The success URL drops the query string so a returning
+ * visitor does not re-enter the intent flow.
+ */
+const requestCheckoutSessionUrl = async (
+ accessToken: string,
+): Promise<string | null> => {
</file context>
What
Visitors landing on
chat.recoupable.dev/?intent=pro-trialare now carried into the Stripe Pro trial checkout instead of being dropped on the homepage.POST /api/subscriptions/sessionswith the Privy bearer token) and the browser navigates to it same-tab viawindow.location.href.Why
Part of #1902 (web UX conversion audit, item C1). Marketing links can now deep-link straight into the Pro trial purchase instead of losing the visitor on the homepage.
How
lib/checkout/shouldTriggerCheckoutIntent.ts: pure decision helper encoding the ordering rules (unknown intent, Privy readiness, auth state, account hydration, double-fire guard). Test-driven: the vitest suite was written first and run RED before implementation.lib/stripe/requestCheckoutSessionUrl.ts: creates the checkout session and returns the URL. The success URL strips the query string so returning from Stripe does not re-enter the intent flow.hooks/useCheckoutIntent.ts: composed hook reading theintentsearch param,usePrivy(ready,authenticated,login,getAccessToken), anduseUserProvider. Double-firing is guarded by refs plus a sessionStorage flag that survives the Stripe round trip. Built alongside (not on top of)useSubscribeClick, which a sibling PR is reworking.components/Home/HomePage.tsx: mounts the hook.How to test
/?intent=pro-trialwhile signed in: you should be redirected same-tab to a Stripe checkout page for the Pro trial./?intent=something-elseand plain/: no checkout or login side effects beyond the existing auto-login behavior.pnpm exec vitest run: 75 files / 284 tests pass, including the 8 newshouldTriggerCheckoutIntentcases.Preview verification to follow in a PR comment.
🤖 Generated with Claude Code
Summary by cubic
Honors the
?intent=pro-trialparam on the homepage to carry visitors straight into the Stripe Pro trial checkout. Supports deep links for marketing and reduces drop-offs. Part of #1902 (conversion audit, C1).useCheckoutIntentto read theintentparam and@privy-io/react-authstate, then trigger login or create a checkout session and same-tab redirect.shouldTriggerCheckoutIntentto handle ordering rules and double-fire guards (ref + sessionStorage).POST /api/subscriptions/sessions; success URL strips the query to avoid re-entering the flow.HomePage. Added focused tests for the decision helper.Written for commit 8cd2dac. Summary will update on new commits.