feat(referral): redesign the invite friends settings page - #6367
feat(referral): redesign the invite friends settings page#6367tsahimatsliah wants to merge 21 commits into
Conversation
…romo Rebuild /settings/invite as a campaign surface: a marketing-inspired hero with a cabbage-to-onion gradient headline promoting "invite 3 friends, get 1 month of Plus free", a 3-slot progress chain filled with referred users' avatars ending in a Plus reward chip, a how-it-works step grid, and a giveback cross-promo card (gated on featureGiveback) inviting users to contribute to the community. The reward framing is driven by referredUsersCount from the generic referral campaign; share link input, social share list, and the referrals list stay intact. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ions Replace the aurora hero and per-section bespoke styling with one visual language: every block is a standard settings AccountContentSection, the progress chain shrinks to a compact inline row (size-8 avatar slots + neutral connectors + a single Plus-accent chip), how-it-works becomes a flat numbered list, and the giveback promo becomes a plain float card with a gift icon instead of gradients and mascot art. No gradients, glows, blend modes, or animations — one accent color, one card treatment, one section rhythm. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reuse the visual language of GivebackFoundingAward for the invite page's giveback promo: a 1px avocado/cabbage/cheese gradient frame over an opaque base washed with the same gradient at 8% via color-mix, a gradient-text eyebrow, callout title, footnote body, primary CTA, and the Giveback charm on a glow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tighten the offer copy to one short line, name Plus in the reward chip, and switch the chip and empty invite slots from pills/circles to rounded-10 rectangles so they match the ProfilePicture shape. The progress caption moves above the slot row, the invite link and social buttons get their own 'Your invitation link' section, and the how-it-works list is removed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
UserList hard-codes px-6 on each row and overrides the consumer's className, so referral rows sat 24px right of every heading. Cancel the section padding on the list wrapper so rows line up and the hover highlight spans the card, drop the dead className config, and make the empty state a compact left-aligned row instead of a centered block. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Move the two bespoke pieces of the invite page - the reward progress tracker and the giveback cross-promo card - into shared/src/features/referral so Storybook can render the real components (the page body itself lives in webapp and isn't importable there). Add Features/Referral/Invite friends page covering 0/1/2/3+ referrals, the unlocked reward, the existing-Plus-member note, the giveback flag off, mobile width, and component-level showcases. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Engineering pass over the invite page redesign: - Gate the "invite 3, get 1 month of Plus" promo behind a new referral_plus_reward flag (default off). Nothing in the product grants the free month yet, so with the flag off the page describes referrals and promises nothing. - Fix the unlocked copy claiming "3 friends joined" for any count at or above the goal; it is now count-agnostic, and the tracker clamps 0..INVITE_GOAL internally. - Move the two new components to their conventional homes (components/referral, features/giveback) and delete the single-export components/referral barrel per the repo's no-barrel rule. - Wrap the whole referrals list in the negative margin instead of passing it through scrollingProps, which only reached the loaded branch and let skeleton rows sit 24px off before snapping into place. - Let the progress row wrap and drop its connector below mobileL, where the reward chip was clipped at 320px. - Drop the never-attached scrollingContainer ref, the redundant clamp, an aria-label duplicating visible text, decorative alt text, and a border that resized the chip on unlock. - Storybook: match the real settings chrome, add the flag-off story, and remove an inert isPlus decorator option. - Tests: assert the exact giveback href and click logging, cover the flag-off and past-the-goal states, and exercise the avatar path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🧭 Task context (auto-maintained by /fresh)
Current focus: PR is engineering-ready and pushed. Awaiting review; no known open work. Decisions (and why):
Key files:
Done:
Next:
Gotchas:
To continue this task in a fresh chat: check out |
The charm render sits on solid black and needs mix-blend-screen to drop it, which only works over a dark surface — on the light theme it blended away entirely. Give it its own tile in the artwork's own black so the treatment holds in both themes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The unlocked state only recoloured a chip border, so hitting the goal looked the same as missing it. Once the goal is met the tracker now becomes a full-width Plus card that names the reward, marks it earned and states the period the free month covers. The period is derived client-side from the join date of the third referral; no backend field carries the grant yet. Adds the two notification types the feature would emit — a per-join "friend joined through your invite" and the one-off "free month unlocked" — with their icon/category mapping and rows in the notifications page mock. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The dark tile made the card carry a box it didn't need. Derive the alpha channel from the artwork's own brightness instead, so the black background falls out and the charm reads on any surface without a blend mode or a backdrop. Also drops the em dashes from this feature's copy. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Smaller headline and reward tile, less padding, and a one-size-down avatar row in the footer, so the card sits at the same weight as the other cards on the page. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the accent border and let the tinted background carry the card on its own, matching the flat treatment the rest of the page uses. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the invite link's copy button with the split control from the sharing-visibility work: the left half copies with a cross-fade confirmation, the chevron drops the standard share menu. Its own DS border is the seam, and both halves tighten one padding step so the hairline is not sitting in a canyon. The menu holds the same eight networks the "or invite via" row did, so that row goes; keeping both duplicated it 40px apart. The split halves stop their own clicks — the field container focuses its input on click, which dismissed the menu the instant it opened. Drop `referral_plus_reward` with it: the "invite 3 friends, get 1 month of Plus" promo, its tracker and the Plus-member note now ship to everyone, and the "Grow the community" fallback and its test go away. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`.claude/launch.json` is local preview tooling and has nothing to do with the referral page, so it leaves the PR. `logProps` only drove InviteLinkInput's built-in copy button. The invite page replaces that button, so the prop was passed and never read; make it optional and stop passing it where it does nothing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pull the reworked control from `claude/share-split-copy-button`: the geometry moves into a standalone `SplitShareButton`, the copy glyph swap into `CopyStateIcon`, and `ShareActions` composes them. The dropdown changes with it. The "Share" heading goes — the control it drops from is already labelled, so it only repeated it. The list is a 4-column grid rather than `flex-wrap`, so the columns divide the content box exactly and the padding reads equal on all four sides, and the padding needs `!p-4` to beat the dropdown's own `p-1.5` at equal specificity. The chevron loses `pressed`: it renders `aria-pressed`, which paints a held-down fill, and Radix already sets `aria-expanded`. The two local deltas ride along unchanged — `shortenUrl` for the referral link, and each half stopping its own click so the surrounding field cannot steal focus and dismiss the menu. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The events were verified by inspection but not asserted: the split control's copy half, a social button reporting its provider, and the page firing `copy referral link` / `invite friends page` on copy — the same event the old field button fired, so the metric is guarded against the switch to the split control. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The split control reported a native share as `invite referral` with a `native` provider. Production's invite page logged the native path through the same `useShareOrCopyLink` logObject as the copy path, i.e. as `copy referral link`. Match that so the referral copy metric keeps counting native shares the way it always did. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
capJavert
left a comment
There was a problem hiding this comment.
Blocking as documented in the PR: this unflagged page promises and displays a free Plus month, but no backend grants it and the displayed reward period is inferred from referral timestamps rather than entitlement data. Please either land fulfillment/authoritative entitlement data first or remove/flag the reward promise. The new notification types should not be treated as complete until the backend can emit them.
Review feedback (capJavert): the page promised and displayed a free Plus month with no backend granting it and a reward period inferred from referral timestamps rather than entitlement data. Put the promise back behind `referral_plus_reward` (default false): with it off the page reads "Grow the community" and promises nothing; flip it on only once fulfillment / authoritative entitlement data lands. Mark the two referral notification types as placeholders in code — no backend emits them yet, so they are not complete. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@capJavert thanks, addressed in 73071ab.
Fulfillment / entitlement data is backend work outside this repo, so it can't land in this PR — the flag keeps the promise dark until it does. |
capJavert
left a comment
There was a problem hiding this comment.
The reward promise is correctly gated behind referral_plus_reward with a false default, and the placeholder notification types are now explicitly documented. I found no remaining code blocker. Approved; sync with main before merge.
Changes
Redesigns
/settings/inviteinto a compact, flat page with one section rhythm, adds a giveback cross-promo, and replaces the copy-link button with a split copy/share control.Invite 3 friends, get 1 month of Pluswith a compact tracker: three rounded-rect slots that fill with the referred developers' avatars, ending in a1 month of Pluschip. Once the goal is met the tracker becomes a flat Plus-tinted card naming the reward and the month it covers. Progress comes fromreferredUsersCounton the generic referral campaign and is clamped to the goal inside the component. Behindreferral_plus_reward; with it off the section reads "Grow the community" and promises nothing.GivebackInviteCard, wearing the same treatment as the giveback founding-reward card (1px gradient frame over an opaque base washed with the same gradient at 8% viacolor-mix). Gated on the existinggivebackflag.referral_friend_joinedandreferral_plus_unlocked, both deep-linking to/settings/invite. Marked as placeholders in code: no backend emits either one yet, so they are not complete and nothing produces them in production — they exist for the client to render and for Storybook to demo.Features/Referral/Invite friends pagecovers 0/1/2/3+ referrals, unlocked, existing-Plus member, reward flag off, giveback off, mobile width, the share menu open, and the two notification rows.Caution
Nothing grants the free month yet, so the reward is behind
referral_plus_reward(default off). No backend gives a Plus month on the third referral, and the dates shown are derived on the client from the third referral's join date rather than entitlement data. With the flag off — the default, and what ships on merge — the page reads "Grow the community" and promises nothing. Flip the flag on only once fulfillment / authoritative entitlement data lands, and revisit the client-derived dates then.Notes for reviewers
ShareActions,SplitShareButtonandCopyStateIconare ported verbatim from the sharing-visibility branch (claude/share-split-copy-button), which ships them with its own PR and its own surfaces. Only thesplitvariant is used here; theicon/inlinevariants come along so the two copies stay identical and the files dedupe cleanly whichever lands first. The two local additions areshortenUrl(the referral URL carries its own attribution, so it must go out unshortened) and astopPropagationon each half of the split control — the text field's container focuses its input on click, which dismissed the menu the instant it opened.InviteLinkInputtakes an optionalactionButtonthat replaces its built-in copy button. Gated on the new prop, so the other five consumers keep their exact DOM and their existing copy handling.logPropsis now optional for the same reason: it only drives the built-in button.UserListhard-codespx-6on its rows and on its loading placeholder, and overrides the consumer'suserInfoProps.className. Alignment is therefore handled with-mx-6on a wrapper around the whole list, so rows, skeletons, and the empty state all line up with the headings.components/referral/index.tsbarrel per the repo's no-barrel rule; the only other consumer (settings/organization) now imports the source file directly.GivebackInviteCardsizes its own charm rather than reusingGivebackMascot: that component bakesh-44 tablet:h-56into the same class string a caller would override, and class names are concatenated rather than merged, so the hero size always wins. The charm render ships on solid black, so it is cut out with an SVG luminance-to-alpha filter —mix-blend-screenonly works on a dark surface and made it vanish in light mode.Events
No new event names. Existing events fire from new places:
target_id: invite friends pagetarget_idis the providertarget_id: invite friends pageExperiment
referral_plus_reward— new flag, defaultfalse. A kill-switch for unfulfillable copy rather than an experiment: it gates the entire reward promise (title, Plus-member note, and tracker) so nothing ships to users until the backend grants the free month. Not enrolled as an experiment; if it should run as one, that enrolment needs approving before the flag is turned on. The existinggivebackflag still gates the cross-promo section separately.Manual Testing
Caution
Please make sure existing components are not breaking/affected by this PR
The page is auth-gated and the local webapp shell does not boot without a backend, so review it on the Vercel preview at
/settings/invite, and the states in Storybook (pnpm --filter storybook dev) — the Storybook deployment is Ignored for PRs.Verified locally: webapp suite (45 suites / 305 tests), shared suites for referral/share/fields/notifications (13 suites / 80 tests),
pnpm --filter shared lintandpnpm --filter webapp lintclean, and the changed-file strict typecheck guard. The split control was checked in light and dark, on desktop and at mobile width, with the menu open and closed.🤖 Generated with Claude Code
Preview domain
https://claude-refer-friend-settings-red.preview.app.daily.dev