feat(user): add follow/unfollow on profile pages#81
Conversation
Adds the Follow model and the follow/unfollow actions as a foundation for the updates feed (issue #28). Key changes: - Add Follow join table (followerId, followingId, createdAt) with cascade deletes and a desc index on followingId for feed queries - Add userFollowersTag / userFollowingTag cache-tag helpers - Add followUser / unfollowUser server actions with self-follow guard, target-existence check, and targeted cache invalidation - Add getFollowStats cached query (follower count, following count, viewer isFollowing) with per-user cache tags - Add FollowButton client component with optimistic count toggle - Surface follower/following counts and Follow button on the profile page header (button hidden for owner or unauthenticated viewers) - Ignore docs/backlog/** in ESLint (backlog scratch files were causing lint errors on untracked JS) - 9 new unit tests covering all action branches
|
Warning Review limit reached
Next review available in: 46 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: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis PR adds a user follow/unfollow feature: a new Prisma ChangesUser Follow Feature
Lint Configuration
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@app/_components/user/follow-button.tsx`:
- Around line 24-25: Block follow/unfollow re-entry while a mutation is in
flight in follow-button.tsx, because rapid clicks can trigger overlapping
followUser and unfollowUser actions. Add an in-flight guard around the
FollowButton interaction and use it in the click handler that calls
startTransition so subsequent clicks are ignored until the current transition
settles. Update the optimistic state handling in useTransition/useOptimistic
flow to disable or short-circuit the button during the pending mutation,
ensuring the latest user intent wins in the FollowButton component.
In `@app/`(ui)/u/[username]/page.tsx:
- Around line 136-154: The profile header is still rendering the server-side
follower count instead of the optimistic count maintained by FollowButton, so
the visible number doesn’t update immediately. Update the follower count display
in app/(ui)/u/[username]/page.tsx to consume the optimistic count state from
FollowButton (or lift that state up and pass it into the header) so the rendered
count stays in sync with the button’s immediate follow/unfollow changes. Use the
FollowButton component and the followStats.followerCount display block as the
key places to wire the optimistic value through.
In `@prisma/migrations/20260630181407_add_user_follows/migration.sql`:
- Around line 2-17: The follow table currently allows rows where follower_id
equals following_id, so add a database-level no-self-follow constraint in the
migration to match the app validation. Update the follow table definition in the
migration to enforce follower_id <> following_id (or an equivalent CHECK
constraint) so invalid self-follow rows cannot be inserted by seeds, scripts, or
future write paths. Keep the change localized to the follow table creation in
the migration and preserve the existing primary key, index, and foreign key
setup.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 2f21ec12-12e9-4a4e-83a1-8ad89423a5ae
📒 Files selected for processing (9)
app/(ui)/u/[username]/page.tsxapp/_actions/__tests__/user-follows.test.tsapp/_actions/user-follows.tsapp/_components/user/follow-button.tsxeslint.config.mjslib/deck/cache-tags.tslib/user/queries.tsprisma/migrations/20260630181407_add_user_follows/migration.sqlprisma/schema.prisma
Guard rapid follow/unfollow clicks, surface optimistic follower count, and block self-follows at the DB level. Key changes: - FollowButton wires isPending to disable the button mid-transition - FollowButton renders the optimistic follower count itself, so the number updates immediately on click; page.tsx falls back to the static count only when no FollowButton is rendered (owner view or logged-out viewer) - Add CHECK (follower_id <> following_id) constraint via a new migration, since the original migration was already applied locally
getFollowStats had zero tests; external adapters, edhrec meta
fallback, and printing-heuristics edge cases were missing branch
coverage. Two truly unreachable defensive fallbacks (string ops
that can't return undefined) are marked v8 ignore per existing
convention.
- lib/user/queries.ts: add getFollowStats tests (viewer/no-viewer,
following/not-following)
- lib/deck/external/{archidekt,moxfield}.ts: cover missing-field
fallback branches (cards/categories/quantity/format)
- lib/edhrec/recommendations.ts: cover meta-miss synergy/inclusion
fallback
- lib/card/printing-heuristics.ts: cover canonicalFirstPrinting
empty-list and out-of-order reduce branches
- workflows/scryfall/steps.ts: cover missing `data` field on
search response
- app/_actions/deck/bulk-printings.ts, lib/search/card-search.ts:
mark unreachable ?? fallbacks with v8 ignore
Adds the Follow model and the follow/unfollow actions as a foundation for the updates feed (issue #28).
Key changes:
Description
Fixes: #26
Checklist
pnpm test) and lint is cleanrevalidate/dynamic/unstable_cache— used'use cache'+cacheLife/cacheTag<Link>imported fromapp/_components/link.tsx, notnext/linkScreenshots / notes
Summary by CodeRabbit
Summary by CodeRabbit
New Features
Bug Fixes
Tests