feat: Similar Profiles suggestions - #825
Conversation
Welcome to OSSfolio, @Aditya8369! 🎉Thank you for opening this pull request and contributing to the open-source community! 🚀 To ensure a smooth review process, please make sure you have:
We will review your PR as soon as possible. Happy coding! 💻✨ |
📝 WalkthroughWalkthroughAdds similar-profile suggestions to profile pages. A Supabase RPC ranks public profiles by shared languages and organizations. A cached API route exposes the results. A lazy client component renders loading states, profile cards, match reasons, and empty results. ChangesSimilar profile suggestions
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant ProfileView
participant SimilarProfiles
participant API
participant Database
ProfileView->>SimilarProfiles: pass username and score
SimilarProfiles->>API: fetch similar profiles
API->>Database: invoke find_similar_profiles
Database-->>API: return ranked public profiles
API-->>SimilarProfiles: return cached JSON
SimilarProfiles-->>ProfileView: render suggestion cards
Possibly related PRs
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Biome (2.5.6)src/app/globals.cssFile contains syntax errors that prevent linting: Line 6: Tailwind-specific syntax is disabled.; Line 224: Tailwind-specific syntax is disabled. 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 `@src/components/profile/SimilarProfiles.tsx`:
- Around line 44-60: Update the skeleton elements in SimilarProfiles by
replacing each inline borderRadius value of "6px" with the design token
var(--radius-sm), including both changed blocks.
- Around line 297-323: Update the useEffect tied to username changes to clear
the existing profiles and setIsLoading(true) before starting load(), ensuring
the new request cannot display stale suggestions. Preserve the existing
cancellation and completion handling for the refreshed request.
In `@supabase/migrations/20260806000000_add_find_similar_profiles.sql`:
- Around line 58-73: Update the target organization extraction that populates
v_target_orgs and the candidate query grouped by ps_cand.snapshot to use only
the latest profile_snapshot for each username before expanding orgs or
calculating matches. Ensure each candidate username is represented by at most
one latest snapshot so obsolete organizations are excluded and duplicate
usernames cannot consume the six-result limit.
🪄 Autofix
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: ASSERTIVE
Plan: Pro Plus
Run ID: 04b4ad56-a5e8-4a10-89e8-ede65dec770f
📒 Files selected for processing (6)
src/app/api/similar-profiles/[username]/route.tssrc/app/globals.csssrc/components/profile/ProfileView.tsxsrc/components/profile/SimilarProfiles.tsxsrc/lib/db.tssupabase/migrations/20260806000000_add_find_similar_profiles.sql
| <div | ||
| style={{ | ||
| height: "14px", | ||
| width: "80%", | ||
| borderRadius: "6px", | ||
| backgroundColor: "var(--color-hairline)", | ||
| animation: "pulse 1.5s ease-in-out infinite", | ||
| }} | ||
| /> | ||
| <div | ||
| style={{ | ||
| height: "11px", | ||
| width: "55%", | ||
| borderRadius: "6px", | ||
| backgroundColor: "var(--color-hairline)", | ||
| animation: "pulse 1.5s ease-in-out infinite", | ||
| }} |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Use the radius token for the skeleton elements.
Replace each changed borderRadius: "6px" value with var(--radius-sm).
Based on learnings, inline borderRadius: "6px" values must use var(--radius-sm) during the design-token migration.
Also applies to: 340-346
🤖 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/components/profile/SimilarProfiles.tsx` around lines 44 - 60, Update the
skeleton elements in SimilarProfiles by replacing each inline borderRadius value
of "6px" with the design token var(--radius-sm), including both changed blocks.
Source: Learnings
| useEffect(() => { | ||
| let cancelled = false; | ||
|
|
||
| async function load() { | ||
| try { | ||
| const res = await fetch(`/api/similar-profiles/${username}`); | ||
| if (cancelled) return; | ||
| if (!res.ok) { | ||
| setIsLoading(false); | ||
| return; | ||
| } | ||
| const json = await res.json(); | ||
| if (!cancelled && Array.isArray(json.profiles)) { | ||
| setProfiles(json.profiles); | ||
| } | ||
| } catch { | ||
| // Silent fail — the section simply won't appear. | ||
| } finally { | ||
| if (!cancelled) setIsLoading(false); | ||
| } | ||
| } | ||
|
|
||
| load(); | ||
| return () => { | ||
| cancelled = true; | ||
| }; | ||
| }, [username]); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Reset result state when username changes.
The effect starts a new request without clearing profiles or restoring isLoading. During that request, the new profile can display suggestions for the previous username. If the request fails, those stale suggestions remain visible.
Proposed fix
useEffect(() => {
let cancelled = false;
+ setProfiles([]);
+ setIsLoading(true);
async function load() {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| useEffect(() => { | |
| let cancelled = false; | |
| async function load() { | |
| try { | |
| const res = await fetch(`/api/similar-profiles/${username}`); | |
| if (cancelled) return; | |
| if (!res.ok) { | |
| setIsLoading(false); | |
| return; | |
| } | |
| const json = await res.json(); | |
| if (!cancelled && Array.isArray(json.profiles)) { | |
| setProfiles(json.profiles); | |
| } | |
| } catch { | |
| // Silent fail — the section simply won't appear. | |
| } finally { | |
| if (!cancelled) setIsLoading(false); | |
| } | |
| } | |
| load(); | |
| return () => { | |
| cancelled = true; | |
| }; | |
| }, [username]); | |
| useEffect(() => { | |
| let cancelled = false; | |
| setProfiles([]); | |
| setIsLoading(true); | |
| async function load() { | |
| try { | |
| const res = await fetch(`/api/similar-profiles/${username}`); | |
| if (cancelled) return; | |
| if (!res.ok) { | |
| setIsLoading(false); | |
| return; | |
| } | |
| const json = await res.json(); | |
| if (!cancelled && Array.isArray(json.profiles)) { | |
| setProfiles(json.profiles); | |
| } | |
| } catch { | |
| // Silent fail — the section simply won't appear. | |
| } finally { | |
| if (!cancelled) setIsLoading(false); | |
| } | |
| } | |
| load(); | |
| return () => { | |
| cancelled = true; | |
| }; | |
| }, [username]); |
🧰 Tools
🪛 React Doctor (0.9.3)
[error] 297-297: This setter runs after await, so overlapping re-runs of the effect can resolve out of order and write stale state; gate it behind a cancellation/ignore flag or return a cleanup that cancels the work.
In a useEffect whose dependencies can change, guard any setter call that runs after an await behind a cancellation/ignore flag, or return a cleanup that cancels the async work.
(no-set-state-after-await-in-effect)
🤖 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/components/profile/SimilarProfiles.tsx` around lines 297 - 323, Update
the useEffect tied to username changes to clear the existing profiles and
setIsLoading(true) before starting load(), ensuring the new request cannot
display stale suggestions. Preserve the existing cancellation and completion
handling for the refreshed request.
| select coalesce( | ||
| array( | ||
| select lower(org_elem->>'login') | ||
| from public.profile_snapshots ps, | ||
| jsonb_array_elements( | ||
| case | ||
| when jsonb_typeof(ps.snapshot->'orgs') = 'array' | ||
| then ps.snapshot->'orgs' | ||
| else '[]'::jsonb | ||
| end | ||
| ) as org_elem | ||
| where ps.username = p_username | ||
| and (org_elem->>'login') is not null | ||
| ), | ||
| '{}'::text[] | ||
| ) into v_target_orgs; |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Read only the latest snapshot for each profile.
Lines 58-73 aggregate organizations from every target snapshot. Lines 140-185 join every candidate snapshot and group by ps_cand.snapshot.
This violates the latest-profile_snapshot contract. It can score obsolete organizations and return the same username more than once, which can consume the six-result limit.
Select one latest snapshot for the target and one latest snapshot per candidate before expanding orgs.
Also applies to: 140-185
🤖 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 `@supabase/migrations/20260806000000_add_find_similar_profiles.sql` around
lines 58 - 73, Update the target organization extraction that populates
v_target_orgs and the candidate query grouped by ps_cand.snapshot to use only
the latest profile_snapshot for each username before expanding orgs or
calculating matches. Ensure each candidate username is represented by at most
one latest snapshot so obsolete organizations are excluded and duplicate
usernames cannot consume the six-result limit.
Summary
Related Issue
Closes #730
Type of Change
Changes Made
Checklist
mainconsole.logleft insrc/schema.sqland a new migration file are includedDESIGN.mdand followed the design system (colors, spacing, typography, components)feat:,fix:,docs:, etc.)Summary by CodeRabbit