feat(onboarding): invite 3 friends, get free Plus funnel step - #6366
Closed
tsahimatsliah wants to merge 1 commit into
Closed
feat(onboarding): invite 3 friends, get free Plus funnel step#6366tsahimatsliah wants to merge 1 commit into
tsahimatsliah wants to merge 1 commit into
Conversation
Adds a FunnelStepType.InviteFriends onboarding step that fires referral
intent at the highest-motivation moment: invite friends via the generic
referral campaign, with a 0/3 progress indicator from referredUsersCount
and a confetti celebration when the target is reached. Skip is always
available, the reward copy ({reward} placeholder, default "1 month") is
A/B-able straight from the funnel JSON, and the whole step is gated
behind the new onboarding_invite_reward flag (default false).
Frontend-only: the step needs the backend funnel JSON to include it and
a backend Plus-grant mechanism to award the reward; no Plus state is
ever set client-side.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
tomeredlich
added a commit
that referenced
this pull request
Sep 1, 2026
…source - ProfileHeader is an h-36 cover with a 7.5rem rounded-16 avatar pinned over its bottom-left and a right-aligned action row above the name, not beside it. Snapshot already ships in that row; Follow/Award/... render only for a visitor, below the handle. The widgets all carry a snapshot already, and their real contents are summary cards, a tag-progress grid and the heatmap. - /settings/invite is three sections with a labelled TextField, a Primary Copy link action button and the seven-target social row. The reward copy belongs to #6366's unbuilt onboarding step, not this page. - The leaderboard row is score, rank badge, avatar, name and handle, with the snapshot fading in at XSmall Float. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tomeredlich
added a commit
that referenced
this pull request
Sep 1, 2026
The settings page is complete and unreachable: a labelled TextField, a Primary Copy link and the seven-target row, buried three levels into settings, long after the moment a new account is most willing to bring someone with them. So the invite is not a payload problem, it is a placement one — which makes it a surface of its own rather than a suggestion attached to the feed export. The new page draws #6366's step on the real funnel chrome: FunnelStepCtaWrapper's glass branch, the 32rem rail, StepHeadline, three invite slots, the glass bar CTA and step dots. Snapshot is deliberately absent throughout — a referral image cannot be clicked. Invite & feed export becomes Copy my feed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
What
A new onboarding funnel step — "Invite 3 friends, get 1 month of Plus on us" — that fires referral intent at the highest-motivation moment of the funnel. Part of the sharing-visibility initiative (PR 20), based on PR #6343.
FunnelStepType.InviteFriends('inviteFriends') +FunnelStepInviteFriendstyped step, registered inFunnelStepper'sstepComponentMap.useReferralCampaign(ReferralCampaignKey.Generic),InviteLinkInput,SocialShareList(native share sheet feature-detected on mobile viauseShareOrCopyLink), and the existingGivebackConfettiBurstfor the 3/3 celebration.0/3 friends joined) readsreferredUsersCount; reaching the target swaps to a celebratory reveal (confetti + headline) with a Continue CTA.skiptransition; onboarding is never hard-gated on inviting.{count}/{reward}placeholders (default "1 month"), so the 1-month vs 3-months arms are A/B-able from the funnel JSON alone — no frontend change needed.FunnelTargetIdvalues (invite friends,invite friends copy,invite friends share,invite friends skip) on the tracked elements, plus the standard transition events carrying{ referredUsersCount, targetReached, invited }details. ExistingLogEvent.CopyReferralLink/LogEvent.InviteReferralfire withTargetId.Onboarding(nolog.tschanges needed).Flag
onboarding_invite_reward(featureOnboardingInviteReward), defaultfalse. Evaluated viauseConditionalFeaturewithshouldEvaluateonly when a logged-in user mounts a funnel containing the step, so enrollment matches exposure. Intentionally not gated onuseSharingVisibility()— this is an onboarding experiment with its own lifecycle. Flag off (or step absent from the funnel JSON) → the step auto-registers as skipped and the funnel behaves exactly as before.This PR is frontend-only by explicit decision. Two hard backend dependencies must land before this can be enabled for anyone:
1. Funnel JSON (
/boot/funnels/:key)Onboarding steps are emitted by the backend funnel JSON. The new step will not appear in any real flow until the backend adds it. Required shape:
{ "id": "invite_friends", "type": "inviteFriends", "parameters": { // all optional — sensible defaults ship in the component "headline": "Invite {count} friends, get {reward} of Plus on us", "explainer": "...", "celebrationHeadline": "...", "celebrationExplainer": "...", "celebrationCta": "Continue", "reward": "1 month", // A/B lever: "1 month" vs "3 months" (copy only) "targetCount": 3 }, "transitions": [ { "on": "complete", "destination": "<next-step-or-finish>" }, { "on": "skip", "destination": "<next-step-or-finish>" } // REQUIRED — the in-step skip button only renders when this transition exists ] }The step must be placed after registration (it auto-skips for anonymous users because referral links are per-user).
2. Plus grant mechanism
There is no frontend path to grant Plus —
isPlusis backend-set and this PR deliberately never fakes or sets any Plus state client-side. Backend needs a new reward mechanism. The frontend contract it should build against:referredUsersCountsemantics of the generic referral campaign (referralCampaign(referralOrigin: "generic")) — a user who signs up through the inviter's referral link/token. The step reads this exact field for progress, so grant eligibility and the progress UI stay in sync by construction.referredUsersCountreaches the target (3), backend grants the reward automatically (server-side observer on referral attribution — not triggered by any frontend call). The step'scompletetransition details ({ referredUsersCount, targetReached, invited }) are analytics, not a grant request.rewardcopy parameter; the actual granted duration must be configured backend-side to match the arm the funnel JSON is serving.user.isPlusflips via boot as it does today; no new client API is required. (A follow-up notification/email when the reward lands would be a backend/product nicety, not required by this UI.)Testing
packages/shared/src/features/onboarding/steps/FunnelInviteFriends.spec.tsx— 12 tests: progress fromreferredUsersCount(0/3, 1/3), reward-copy A/B parameter, copy → clipboard + toast, mobile →navigator.share, skip transition (+ JSON-provided skip copy), funnel target ids, 3/3 celebration → complete, flag-off / anonymous auto-skip registration, flag-on registration.FunnelStepper.spec.tsx— 2 new tests: the registered step renders inside the stepper with the real flag plumbing on, and renders nothing with the flag off; all 18 pre-existing stepper tests untouched and passing (nostepComponentMapregression).stories/components/onboarding/FunnelInviteFriends.stories.tsx— 0/3, 1/3, 3/3 celebration, 3-months reward arm, and missing-skip-transition states (renders the unguarded step; flag gating is Jest-verified since the repo-wide Storybook flag mock can't represent flag-off).node ./scripts/typecheck-strict-changed.js✅ ·pnpm --filter shared lint✅ ·NODE_ENV=test pnpm --filter shared test→ 295 suites / 1999 tests ✅ ·NODE_ENV=test pnpm --filter webapp test→ 44 suites / 297 tests ✅🤖 Generated with Claude Code
Preview domain
https://claude-onboarding-invite-reward.preview.app.daily.dev