feat(shhhhh): polish card share asset for Twitter (peanut blue, hero card, clean year)#2196
feat(shhhhh): polish card share asset for Twitter (peanut blue, hero card, clean year)#2196Hugo0 wants to merge 6 commits into
Conversation
… card, clean year
Addresses the Waitlist Feedback doc (share-asset half):
- BG #efe4ff lavender → #90A8ED peanut blue (reused from the prod LP
businessBgColor / --background-color) so the asset pops on a timeline; the
lavender was off-brandbook and washed out.
- Card is the hero now: CARD_W 620→760 (~63% of canvas), centred — was ~52%
and read as "card too small / whitespace huge".
- Stamp year drops the leading apostrophe ('25 → 2025) — the tick read as a
buggy stray mark on the stamp.
- Low badge-count stamps bumped for thumbnail legibility; high counts unchanged
(the circumscribing-circle non-overlap invariant + jitter leaves no headroom).
- LP hero scale compensated 0.645→0.526 so its on-screen footprint is unchanged
by the shared CARD_W bump (hero left as-is; its framing is a separate follow-up).
Layout non-overlap + bounds tests stay green.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughBrand-color and layout updates for shared card assets; add persistent skip-celebration field and POST API; retire the synthetic card-unlock activity entry when seen; update HomeHistory truncation, tests, and the Shhhhh landing page to implement new waitlist/skip CTA flows and hook renames. ChangesShare Asset Card Styling and Layout
Card skip-celebration lifecycle and activity feed; Shhhhh waitlist
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
Comment |
deriveCardUnlockEntry derived the row from permanent inputs (skip badge / cardAccessGrantedAt) with no seen-gate, and HomeHistory force-kept it past the 5-item cap → it never left the feed (Hugo: "always there, buggy"). - deriveCardUnlockEntry now takes celebrationSeenAt and returns null once set. - HomeHistory passes cardInfo.cardWaitlistSkipCelebrationSeenAt + no longer pins the row (it ages out like any other entry). - card/page.tsx stamps the BE column (cardApi.markCelebrationSeen) when the celebration is acknowledged, alongside the localStorage gate. - CardInfoResponse + cardApi.markCelebrationSeen added; regression test asserts the row clears once celebrationSeenAt is set. Pairs with peanut-api-ts #990 (exposes + writes the column).
Pure rename — the hook returns generic /card info (waitlist state + gates), nothing Pioneer-specific. Renames the hook + its 4 call sites. No behaviour change.
…p Pass Per Hugo (2026-06-07): visiting /shhhhh is NOT a bypass. The plain "Try the door" + "or join the waitlist" now join the waitlist directly (cardApi.joinWaitlist) and show an inline "✓ You're on the waitlist · #N" confirmation — no flowEarlyAccess stamp, no /card detour, no badge. (Signed-out → signup with a redirect back to /shhhhh + a cookie that finishes the join on return.) Only /shhhhh?campaign=skip — the Skip Pass link — awards the WAITLIST_SKIP badge (same contract as /invite?campaign=skip, via useZeroDev's post-signup campaignTag branch) → the user is in. Pairs with the BE gate (peanut-api-ts #990): pre-launch only Skip Pass holders get a card; everyone else waits. The /card outer-gate (flowEarlyAccess) is no longer stamped from the bare door — the waitlist screen lives behind that gate, so a direct inline join is the only way to honour "no flowEarlyAccess grant". Removes the now-unused prefetch.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/app/shhhhh/ShhhhhLandingPage.tsx`:
- Around line 214-220: The invitesApi.awardBadge method returns an object with a
success property instead of throwing an error on failure. In the try block
containing the awardBadge call, you need to check the result of awaiting
invitesApi.awardBadge(SKIP_CAMPAIGN) and verify that the returned object has
success: true before proceeding with the posthog.capture call for
ANALYTICS_EVENTS.INVITE_ACCEPTED and the subsequent router.push to /home. If the
success property is false, handle the failure appropriately in the catch block
or add conditional logic to prevent tracking and routing when the badge award
fails.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 90713730-ab3a-4c23-8fa1-36876e12546e
📒 Files selected for processing (6)
src/app/(mobile-ui)/home/page.tsxsrc/app/shhhhh/ShhhhhLandingPage.tsxsrc/components/Home/HomeHistory.tsxsrc/components/Profile/index.tsxsrc/hooks/useCardInfo.tssrc/hooks/useHomeCarouselCTAs.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/Home/HomeHistory.tsx
| await invitesApi.awardBadge(SKIP_CAMPAIGN) | ||
| posthog.capture(ANALYTICS_EVENTS.INVITE_ACCEPTED, { campaign_tag: SKIP_CAMPAIGN }) | ||
| await fetchUser() | ||
| } catch (err) { | ||
| console.error('[shhhhh] awardBadge(skip) failed:', err) | ||
| } | ||
| router.push('/home') |
There was a problem hiding this comment.
Check awardBadge result before tracking success and routing.
Line 214 awaits invitesApi.awardBadge(...), but the API returns { success: false } for non-OK responses instead of throwing. The current flow still tracks INVITE_ACCEPTED (Line 215) and routes to /home (Line 220), which can silently drop the skip-badge award.
💡 Suggested fix
- try {
- await invitesApi.awardBadge(SKIP_CAMPAIGN)
- posthog.capture(ANALYTICS_EVENTS.INVITE_ACCEPTED, { campaign_tag: SKIP_CAMPAIGN })
- await fetchUser()
- } catch (err) {
- console.error('[shhhhh] awardBadge(skip) failed:', err)
- }
- router.push('/home')
+ try {
+ const award = await invitesApi.awardBadge(SKIP_CAMPAIGN)
+ if (!award.success) {
+ console.error('[shhhhh] awardBadge(skip) failed: unsuccessful response')
+ return
+ }
+ posthog.capture(ANALYTICS_EVENTS.INVITE_ACCEPTED, { campaign_tag: SKIP_CAMPAIGN })
+ await fetchUser()
+ router.push('/home')
+ } catch (err) {
+ console.error('[shhhhh] awardBadge(skip) failed:', err)
+ }
returnBased on learnings from src/services/invites.ts, invitesApi.awardBadge returns { success: false } for non-OK responses instead of throwing.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/shhhhh/ShhhhhLandingPage.tsx` around lines 214 - 220, The
invitesApi.awardBadge method returns an object with a success property instead
of throwing an error on failure. In the try block containing the awardBadge
call, you need to check the result of awaiting
invitesApi.awardBadge(SKIP_CAMPAIGN) and verify that the returned object has
success: true before proceeding with the posthog.capture call for
ANALYTICS_EVENTS.INVITE_ACCEPTED and the subsequent router.push to /home. If the
success property is false, handle the failure appropriately in the catch block
or add conditional logic to prevent tracking and routing when the badge award
fails.
…erender) useSearchParams() bailed /shhhhh out of static generation → prerender error in next build (Vercel red). Read ?campaign=skip from window.location.search in a mount effect instead, keeping the marketing page statically prerendered.
/code-review: isSkipCampaign was useState+useEffect but only used in handleCTA, not render — needless state + a theoretical mount-race on the gating path. Read it inline in the handler instead (still client-only, no prerender impact).
What
Visual polish of the card share asset (
ShareAssetD3) per the Waitlist Feedback doc, optimised for how it reads on a Twitter timeline.#efe4fflavender →#90A8EDpeanut blue (reused from the prod LPbusinessBgColor/--background-color, as one DRY const)CARD_W620→760 (52%→63% of canvas), centred'''look buggy"'25→2025(the leading apostrophe read as a stray tick)The
/shhhhhLP hero uses the samePixelatedCardFace, so its scale was compensated (0.645→0.526) to keep its on-screen footprint unchanged by the sharedCARD_Wbump.Gate (local)
prettier --checkclean ·typecheckexit 0 ·npm test= 1306 passed / 76 suitesshareAssetLayout.test.tsnon-overlap + canvas-bounds invariants stay green (24/24)Notes
chore/sync-main-dev-0606so the diff is just these 3 files; GitHub auto-retargets todevonce chore: sync main into dev (2026-06-06) #2190 merges./shhhhhdesktop hero card bleeds slightly off the right (pre-existing rotation overflow) — left for a deliberate hero-framing pass; and theSINCE OCT '25stat keeps its apostrophe (reads as a normal date, unlike the stamp tick).