[FOSSOVERFLOW-26] feat: add functionality to friends button (#160)#198
[FOSSOVERFLOW-26] feat: add functionality to friends button (#160)#198VarshiniGunti wants to merge 4 commits intoOpenLake:mainfrom
Conversation
…ake#160) # Conflicts: # app/src/App.jsx # app/src/components/CodeforcesTable.jsx
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughAdded a protected Changes
Sequence DiagramsequenceDiagram
participant User as User (Browser)
participant App as FriendsPage Component
participant Auth as Auth System
participant Backend as Backend API
participant UI as Friend Display
User->>App: Navigate to /friends
App->>Auth: request access token
Auth-->>App: return access token
rect rgba(100,150,200,0.5)
Note over App,Backend: Concurrent fetches for each platform
App->>Backend: GET /codeforcesFL/ + Bearer token
App->>Backend: GET /codechefFL/ + Bearer token
App->>Backend: GET /leetcodeFL/ + Bearer token
App->>Backend: GET /githubFL/ + Bearer token
App->>Backend: GET /openlakeFL/ + Bearer token
end
Backend-->>App: responses (JSON or non-JSON)
App->>App: readJsonIfAvailable() -> validate arrays
App->>App: merge/sort -> build friendsByPlatform
App->>UI: render platform friend tables
User->>UI: click "Remove"
UI->>Backend: POST /<platform>FD/ { friendName } + Bearer token
Backend-->>UI: success
UI->>App: update local friendsByPlatform (filter out)
App->>User: re-render updated tables
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 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 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 |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
Implements an end-to-end Friends workflow by adding a dedicated /friends page and wiring navigation + Codeforces backend friend actions so users can view and manage friends across leaderboards.
Changes:
- Added a new
FriendsPagethat fetches and displays friends per platform with computed ranks and per-row “Remove” actions. - Updated sidebar navigation to route the Friends item to
/friends. - Replaced Codeforces localStorage-only friends logic with backend API integration for list/add/remove.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| app/src/components/Navbar.jsx | Routes the Friends sidebar item to /friends. |
| app/src/components/FriendsPage.jsx | New friends management page that aggregates friends across platforms and supports removal. |
| app/src/components/CodeforcesTable.jsx | Integrates Codeforces friend list/add/remove with backend endpoints instead of localStorage. |
| app/src/App.jsx | Registers the /friends route and supplies leaderboard datasets to the Friends page. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/src/components/CodeforcesTable.jsx (1)
115-118:⚠️ Potential issue | 🟠 MajorImplement timeout handling using AbortController for all three fetch calls.
The
timeoutoption is not supported by the native fetch API and will be silently ignored. These requests at lines 115-118, 128-131, and 195-198 could hang indefinitely if the server doesn't respond.Use AbortController with setTimeout to enforce timeouts:
🛠️ Proposed fix using AbortController
+ const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 10000); + try { const cfResponse = await fetch( `https://codeforces.com/api/user.info?handles=${currentUsername}`, - { timeout: 10000 } + { signal: controller.signal } ); + clearTimeout(timeoutId);Apply similar changes to lines 128-131 and 195-198.
Alternatively, modern browsers support
AbortSignal.timeout()for a cleaner approach:{ signal: AbortSignal.timeout(10000) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/components/CodeforcesTable.jsx` around lines 115 - 118, The fetch calls in CodeforcesTable.jsx that use the unsupported { timeout: 10000 } option (e.g., the fetch to `https://codeforces.com/api/user.info?handles=${currentUsername}` and the two other fetches at the other sites) must be changed to use AbortController: create an AbortController (or use AbortSignal.timeout(10000) if available), pass its signal to fetch instead of timeout, start a setTimeout to call controller.abort() after 10s (or rely on AbortSignal.timeout), and clear the timer on success; update each fetch invocation (the three fetch calls referenced) to use the controller.signal and handle the abort error path appropriately.
🧹 Nitpick comments (3)
app/src/components/CodeforcesTable.jsx (2)
322-334: Same UX issue with error alerts indropfriend.Apply the same improvement to provide meaningful error messages instead of "ERROR!!!!".
♻️ Proposed improvement
if (!response.ok) { console.error("Failed to remove Codeforces friend:", parsed.message); - alert("ERROR!!!!"); + alert(parsed.message || "Failed to remove friend. Please try again."); return; } setCodeforcesfriends((current) => current.filter((friendName) => friendName !== username), ); } catch (error) { console.error("Failed to remove Codeforces friend:", error); - alert("ERROR!!!!"); + alert("Network error. Please check your connection and try again."); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/components/CodeforcesTable.jsx` around lines 322 - 334, The UX uses generic alert("ERROR!!!!") in the dropfriend flow; update both the non-ok response branch and the catch block to display meaningful error text instead: when response is not ok use the parsed.message returned by readJsonIfAvailable (include fallback like "Failed to remove {username}") and in the catch block use error.message (or String(error)) so users see the actual failure; locate the logic around readJsonIfAvailable, response, parsed, username and the setCodeforcesfriends call to make these replacements.
293-302: Improve error message clarity for better UX.The generic "ERROR!!!!" alert provides no useful context. Consider showing the actual error message.
♻️ Proposed improvement
if (!response.ok) { console.error("Failed to add Codeforces friend:", parsed.message); - alert("ERROR!!!!"); + alert(parsed.message || "Failed to add friend. Please try again."); return; } setCodeforcesfriends((current) => [...current, username]); } catch (error) { console.error("Failed to add Codeforces friend:", error); - alert("ERROR!!!!"); + alert("Network error. Please check your connection and try again."); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/components/CodeforcesTable.jsx` around lines 293 - 302, Replace the generic alert("ERROR!!!!") with a user-friendly message that includes the actual error details: inside the response.ok false branch use alert(`Failed to add Codeforces friend: ${parsed?.message || 'Unknown error'}`) (keep the console.error call), and inside the catch block use alert(`Failed to add Codeforces friend: ${error?.message || String(error)}`); update the related blocks around the response.ok check and the catch for the add-friend routine (the code that calls setCodeforcesfriends and handles response.ok) so users see the real error text instead of "ERROR!!!!".app/src/components/FriendsPage.jsx (1)
78-95: Consider extractingreadJsonIfAvailableto a shared utility.This helper function is duplicated in
CodeforcesTable.jsx. Extracting it to a shared module (e.g.,utils/api.js) would improve maintainability.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/components/FriendsPage.jsx` around lines 78 - 95, Extract the duplicated helper readJsonIfAvailable into a shared utility module (e.g., utils/api.js): move the function body into the new module, export it (named export), and replace the local implementations in FriendsPage.jsx and CodeforcesTable.jsx with imports from the new module (import { readJsonIfAvailable } from '...'). Ensure the new utility preserves behavior (content-type check, response.json try/catch, same return shape) and update any tooling/exports so both components use the single shared function.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/src/components/FriendsPage.jsx`:
- Around line 247-258: The removeFriend network call can throw on network
failures; update the removeFriend function to wrap the fetch call (the block
that calls fetch(BACKEND + platform.removeEndpoint, ...)) in a try-catch, handle
errors the same way as other operations (e.g., show the alert "Could not remove
friend. Please try again." or log the error via your existing logger), and
return early on catch to avoid uncaught exceptions; ensure you still check
response.ok inside the try and keep Authorization, headers and body behavior
unchanged.
---
Outside diff comments:
In `@app/src/components/CodeforcesTable.jsx`:
- Around line 115-118: The fetch calls in CodeforcesTable.jsx that use the
unsupported { timeout: 10000 } option (e.g., the fetch to
`https://codeforces.com/api/user.info?handles=${currentUsername}` and the two
other fetches at the other sites) must be changed to use AbortController: create
an AbortController (or use AbortSignal.timeout(10000) if available), pass its
signal to fetch instead of timeout, start a setTimeout to call
controller.abort() after 10s (or rely on AbortSignal.timeout), and clear the
timer on success; update each fetch invocation (the three fetch calls
referenced) to use the controller.signal and handle the abort error path
appropriately.
---
Nitpick comments:
In `@app/src/components/CodeforcesTable.jsx`:
- Around line 322-334: The UX uses generic alert("ERROR!!!!") in the dropfriend
flow; update both the non-ok response branch and the catch block to display
meaningful error text instead: when response is not ok use the parsed.message
returned by readJsonIfAvailable (include fallback like "Failed to remove
{username}") and in the catch block use error.message (or String(error)) so
users see the actual failure; locate the logic around readJsonIfAvailable,
response, parsed, username and the setCodeforcesfriends call to make these
replacements.
- Around line 293-302: Replace the generic alert("ERROR!!!!") with a
user-friendly message that includes the actual error details: inside the
response.ok false branch use alert(`Failed to add Codeforces friend:
${parsed?.message || 'Unknown error'}`) (keep the console.error call), and
inside the catch block use alert(`Failed to add Codeforces friend:
${error?.message || String(error)}`); update the related blocks around the
response.ok check and the catch for the add-friend routine (the code that calls
setCodeforcesfriends and handles response.ok) so users see the real error text
instead of "ERROR!!!!".
In `@app/src/components/FriendsPage.jsx`:
- Around line 78-95: Extract the duplicated helper readJsonIfAvailable into a
shared utility module (e.g., utils/api.js): move the function body into the new
module, export it (named export), and replace the local implementations in
FriendsPage.jsx and CodeforcesTable.jsx with imports from the new module (import
{ readJsonIfAvailable } from '...'). Ensure the new utility preserves behavior
(content-type check, response.json try/catch, same return shape) and update any
tooling/exports so both components use the single shared function.
🪄 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: 6513d6ed-20bb-4683-a7d5-a9777a56b175
📒 Files selected for processing (4)
app/src/App.jsxapp/src/components/CodeforcesTable.jsxapp/src/components/FriendsPage.jsxapp/src/components/Navbar.jsx
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
app/src/components/FriendsPage.jsx (1)
248-259:⚠️ Potential issue | 🟡 MinorWrap
removeFriendintry/catch.A rejected
fetchstill escapes here as an uncaught promise rejection on network failures.💡 Suggested change
- const response = await fetch(BACKEND + platform.removeEndpoint, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + accessToken, - }, - body: JSON.stringify({ friendName: username }), - }); - if (!response.ok) { - alert("Could not remove friend. Please try again."); - return; - } - - setFriendsByPlatform((current) => ({ - ...current, - [platformKey]: current[platformKey].filter((friend) => friend !== username), - })); + try { + const response = await fetch(BACKEND + platform.removeEndpoint, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + accessToken, + }, + body: JSON.stringify({ friendName: username }), + }); + if (!response.ok) { + alert("Could not remove friend. Please try again."); + return; + } + + setFriendsByPlatform((current) => ({ + ...current, + [platformKey]: current[platformKey].filter((friend) => friend !== username), + })); + } catch (error) { + console.error("Failed to remove friend:", error); + alert("Could not remove friend. Please try again."); + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/components/FriendsPage.jsx` around lines 248 - 259, The current removeFriend call that performs fetch in FriendsPage.jsx can throw on network errors; wrap the async fetch/response logic inside a try/catch in the removeFriend (or the handler calling this snippet) so promise rejections are caught; in the catch block log the error (console.error or processLogger) and show the same user-facing alert ("Could not remove friend. Please try again.") or a more specific message, and return/exit to avoid further processing; keep the existing response.ok check inside the try and ensure Authorization and body handling remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/src/components/CodeforcesTable.jsx`:
- Around line 257-260: The current branch that checks if (!response.ok ||
!parsed.isJson) incorrectly collapses backend/auth/JSON errors into an empty
friends list; instead add/use an explicit error state (e.g., setCodeforcesError
or setCodeforcesFetchError) in the CodeforcesTable component and set that error
when response.ok is false or parsed.isJson is false (and do not call
setCodeforcesfriends([]) in that error branch). Update the UI to render the
error state accordingly and apply the same change to the other identical branch
around the setCodeforcesfriends call (the second occurrence you flagged at lines
~265-266) so network/401/5xx/non-JSON responses are surfaced as errors rather
than treated as an empty friends list.
- Around line 262-263: When updating the friends list via setCodeforcesfriends,
also refresh the cached contestStandings' isFriend flags so badges and the "Show
Friends Only" filter reflect the new friend set; specifically, after you compute
newData in the code that calls setCodeforcesfriends, derive a Set of friend
handles from newData and call the contest standings state updater (e.g.,
setContestStandings or the function that holds contestStandings) to map over
each standing entry and replace its isFriend value with a lookup against that
new friend Set; apply the same pattern to the other update sites referenced (the
blocks around lines 298-299 and 328-330) to keep all snapshots in sync.
In `@app/src/components/FriendsPage.jsx`:
- Around line 153-194: The code treats any fetch rejection or non-OK/non-JSON
response the same as an empty friends list, so update the handling in the
Promise.allSettled/parsed -> nextState flow to distinguish "error" from "empty":
when mapping responses (responses, parsed, readJsonIfAvailable, PLATFORM_CONFIG)
set nextState[platform.key] to a sentinel (e.g., null or an object like { error:
true }) for fetch rejections (responseResult.status !== "fulfilled") or when
response.ok is false or result.isJson is false, and only assign the array when
response.ok && result.isJson && Array.isArray(result.data); keep existing keys
(codeforces, codechef, etc.) but ensure rendering logic checks for the error
sentinel versus an empty array so failed platform loads show an error state
instead of "0 friends".
---
Duplicate comments:
In `@app/src/components/FriendsPage.jsx`:
- Around line 248-259: The current removeFriend call that performs fetch in
FriendsPage.jsx can throw on network errors; wrap the async fetch/response logic
inside a try/catch in the removeFriend (or the handler calling this snippet) so
promise rejections are caught; in the catch block log the error (console.error
or processLogger) and show the same user-facing alert ("Could not remove friend.
Please try again.") or a more specific message, and return/exit to avoid further
processing; keep the existing response.ok check inside the try and ensure
Authorization and body handling remain unchanged.
🪄 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: c31014d0-9e79-4463-b4bd-7fc064785084
📒 Files selected for processing (2)
app/src/components/CodeforcesTable.jsxapp/src/components/FriendsPage.jsx
@check-spelling-bot Report🔴 Please reviewSee the 📂 files view, the 📜action log, or 📝 job summary for details.Unrecognized words (26)These words are not needed and should be removedCRASome files were automatically ignored 🙈These sample patterns would exclude them: You should consider adding them to: File matching is via Perl regular expressions. To check these files, more of their words need to be in the dictionary than not. You can use To accept these unrecognized words as correct, update file exclusions, and remove the previously acknowledged and now absent words, you could run the following commands... in a clone of the git@github.com:VarshiniGunti/Leaderboard-Pro.git repository curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/main/apply.pl' |
perl - 'https://github.com/OpenLake/Leaderboard-Pro/actions/runs/23383474790/attempts/1' &&
git commit -m 'Update check-spelling metadata'Available 📚 dictionaries could cover words (expected and unrecognized) not in the 📘 dictionaryThis includes both expected items (592) from .github/actions/spelling/expect.txt and unrecognized words (26)
Consider adding them (in with:
extra_dictionaries: |
cspell:django/dict/django.txt
cspell:software-terms/dict/softwareTerms.txt
cspell:python/src/common/extra.txt
cspell:npm/dict/npm.txt
cspell:fullstack/dict/fullstack.txtTo stop checking additional dictionaries, add (in check_extra_dictionaries: ""Warnings
|
| Count | |
|---|---|
| 1 |
See
If you see a bunch of garbage
If it relates to a ...
well-formed pattern
See if there's a pattern that would match it.
If not, try writing one and adding it to the patterns.txt file.
Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.
Note that patterns can't match multiline strings.
binary-ish string
Please add a file path to the excludes.txt file instead of just accepting the garbage.
File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.
^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).
Title
[FOSSOVERFLOW-26] feat: add functionality to friends button (#160)Description
This PR implements the Friends button workflow end-to-end by introducing a dedicated Friends management page and wiring all required friend actions across leaderboards.
It is needed to resolve issue
#160, where users should be able to view friended users with ranking/info and unfriend from one place.Related Issue(s)
Changes
/friendspage to show friends across Codeforces, CodeChef, LeetCode, GitHub, and OpenLake.Friendsnavigation item to route to/friends./codeforcesFL,/codeforcesFA,/codeforcesFD) and removed localStorage-only fallback logic.Screenshots of relevant screens
None (will be added in follow-up update).
Type of Change
Checklist
Notes
npm run lintinapp/).Summary by CodeRabbit
New Features
Bug Fixes
UI