Skip to content

Fix/peer card view profile navigation#995

Open
OmanshiRaj wants to merge 3 commits into
durdana3105:mainfrom
OmanshiRaj:fix/peer-card-view-profile-navigation
Open

Fix/peer card view profile navigation#995
OmanshiRaj wants to merge 3 commits into
durdana3105:mainfrom
OmanshiRaj:fix/peer-card-view-profile-navigation

Conversation

@OmanshiRaj

@OmanshiRaj OmanshiRaj commented Jun 15, 2026

Copy link
Copy Markdown

Closes #926
The "View Profile" button in PeerCard had no onClick handler, making it a dead no-op since the component was created. Fixed by importing useNavigate from react-router-dom and navigating to /profile/${peer.id} on click. The peer.id field already exists on the User type so no type changes were needed.

Summary by CodeRabbit

  • New Features
    • Profile navigation now available from peer cards
    • Code runner now supports copying output and clearing code
    • Doubt submissions now include a character limit with live counter display

@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

@OmanshiRaj is attempting to deploy a commit to the durdana3105's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Three independent UI improvements: PeerCard's "View Profile" button is wired to useNavigate to route to /profile/${peer.id}; LiveCodeRunner gains handleCopyOutput and handleClearCode helpers with corresponding "Copy" and "Clear" buttons; AnonymousDoubts adds a MAX_CHARS limit with client-side enforcement, an error toast, a live character counter, and a disabled submit button when over-limit.

Changes

UI Improvements

Layer / File(s) Summary
PeerCard View Profile navigation fix
src/components/PeerCard.tsx
Imports useNavigate, creates a navigate instance inside PeerCard, and binds the "View Profile" button's onClick to navigate to /profile/${peer.id}.
LiveCodeRunner copy output and clear code actions
src/components/studyroom/LiveCodeRunner.tsx
Adds Clipboard and Trash2 icon imports, implements handleCopyOutput (copies non-empty output to clipboard with success/error toasts) and handleClearCode (resets code and output state). Renders a "Clear" toolbar button and a conditional "Copy" button in the Output panel header, both disabled while isRunning.
AnonymousDoubts character limit and live counter
src/pages/AnonymousDoubts.tsx
Adds MAX_CHARS constant, an early-exit guard in addDoubt that emits an error toast when the limit is exceeded, a live character-counter overlay with conditional color/weight styling, and extends the "Post Doubt" button's disabled condition to block submission when over-limit.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

  • #926 — The PeerCard changes directly implement the fix described: importing useNavigate, wiring the "View Profile" button to navigate(\/profile/${peer.id}`)`.
  • #927 — The AnonymousDoubts changes implement the character limit, live counter with conditional styling, and error toast enforcement described in this issue.
  • #928 — The LiveCodeRunner changes implement the copy-output and clear-code feature described in this issue, including the same handler names, icon imports, and disabled-while-running states.

Suggested labels

type:bug, level:beginner, quality:clean

🐇 Hoppity hop, three fixes in one go,
A button that navigates — watch the profile show!
Clear and Copy shine in the code runner's glow,
With a char counter ticking, red when words overflow.
The warren of bugs grows smaller below! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes changes to LiveCodeRunner.tsx and AnonymousDoubts.tsx that are unrelated to the primary objective of fixing the PeerCard View Profile button in issue #926. Remove unrelated changes to LiveCodeRunner.tsx and AnonymousDoubts.tsx, or create separate PRs for these features to maintain scope alignment with issue #926.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix/peer card view profile navigation' directly relates to the primary change in the PR (fixing the non-functional View Profile button in PeerCard).
Linked Issues check ✅ Passed The PR successfully implements the fix described in issue #926: adding useNavigate import and onClick handler to navigate to /profile/${peer.id}, directly fulfilling the stated objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 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/PeerCard.tsx`:
- Line 183: The onClick handler in PeerCard.tsx navigates to
`/profile/${peer.id}`, but this route doesn't exist in the router configuration.
The router only defines `/profile` which expects the Profile page to read
identity from the session user. Add a new parameterized route `/profile/:id` to
your router configuration and update the Profile page component to read the id
parameter from the URL and fetch the corresponding user when the id parameter is
present, falling back to session-based loading when no parameter is provided.

In `@src/pages/AnonymousDoubts.tsx`:
- Around line 48-49: The character limit validation uses the raw text length but
the actual persisted content uses trimmedText, causing valid submissions with
trailing spaces to be rejected. At line 48 in the AnonymousDoubts.tsx file,
refactor the limit check to use trimmedText.length instead of text.length by
first trimming the text variable before performing the character limit
validation. Apply the same fix at line 111-112 in the same file to ensure
consistency across all limit checks. This ensures the validation matches what
will actually be stored in the database.
- Line 6: The MAX_CHARS constant in AnonymousDoubts.tsx is only enforced on the
client side and can be bypassed. Add a database-level CHECK constraint in the
migration file (supabase/migrations/20260608000001_anonymous_doubts.sql) on the
doubts.content column to enforce a maximum length of 500 characters. This
constraint should be added to the table definition in the CREATE TABLE statement
to ensure that the backend reliably enforces the length limit regardless of
client-side checks. The client-side MAX_CHARS definition and its usage in
AnonymousDoubts.tsx (referenced at lines 6 and 48-49) remain as UI validations
but will now be backed by database enforcement.
- Around line 85-95: The text counter UI spanning the relative div is present
but the input element is missing its onChange handler binding. Add an onChange
event handler to the input or textarea element that captures user input and
updates the text state by calling setText with the trimmed or raw input value.
This will ensure that as users type, the text state is updated, enabling the
"Post Doubt" button (currently disabled due to the !text.trim() condition at
line 111) to become clickable when text is entered.
🪄 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: 312b55b2-1801-4207-8ae8-767bf38b8206

📥 Commits

Reviewing files that changed from the base of the PR and between 7200d81 and 29ce73e.

📒 Files selected for processing (3)
  • src/components/PeerCard.tsx
  • src/components/studyroom/LiveCodeRunner.tsx
  • src/pages/AnonymousDoubts.tsx

<Button
size="sm"
variant="outline"
onClick={() => navigate(`/profile/${peer.id}`)}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Navigation target does not match current route contract.

Line 183 navigates to /profile/${peer.id}, but the router defines /profile and the Profile page resolves identity from session user id. This breaks the intended "view peer profile" flow.

Suggested fix direction
- onClick={() => navigate(`/profile/${peer.id}`)}
+ onClick={() => navigate(`/profile/${peer.id}`)}

Keep this line only if you also add the matching route + param-based profile loading:

  • Route: /profile/:id (or a dedicated /users/:id)
  • Profile page: read id from params and fetch that user when present
🤖 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/PeerCard.tsx` at line 183, The onClick handler in PeerCard.tsx
navigates to `/profile/${peer.id}`, but this route doesn't exist in the router
configuration. The router only defines `/profile` which expects the Profile page
to read identity from the session user. Add a new parameterized route
`/profile/:id` to your router configuration and update the Profile page
component to read the id parameter from the URL and fetch the corresponding user
when the id parameter is present, falling back to session-based loading when no
parameter is provided.

import { toast } from "sonner";
import { Loader2 } from "lucide-react";

const MAX_CHARS = 500;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

MAX_CHARS is only enforced in UI; backend currently accepts unlimited content.

MAX_CHARS client checks are bypassable. Cross-file evidence shows doubts.content is unrestricted text and insert policy has no length predicate (supabase/migrations/20260608000001_anonymous_doubts.sql, Lines 1-9 and 20-29). Add a DB-level constraint/check to enforce this contract reliably.

Also applies to: 48-49

🤖 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/pages/AnonymousDoubts.tsx` at line 6, The MAX_CHARS constant in
AnonymousDoubts.tsx is only enforced on the client side and can be bypassed. Add
a database-level CHECK constraint in the migration file
(supabase/migrations/20260608000001_anonymous_doubts.sql) on the doubts.content
column to enforce a maximum length of 500 characters. This constraint should be
added to the table definition in the CREATE TABLE statement to ensure that the
backend reliably enforces the length limit regardless of client-side checks. The
client-side MAX_CHARS definition and its usage in AnonymousDoubts.tsx
(referenced at lines 6 and 48-49) remain as UI validations but will now be
backed by database enforcement.

Comment on lines +48 to 49
if (text.length > MAX_CHARS) { toast.error(`Doubt exceeds ${MAX_CHARS} character limit.`); return; }
if (!user) { toast.error("Please log in to post a doubt."); return; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use trimmed length for limit checks to match persisted content.

At Line 48 and Line 111, the limit uses text.length, but insert uses trimmedText (Line 54). This can reject valid submissions with trailing spaces even when stored content is within limit. Use a single trimmedText.length-based check for consistency.

Also applies to: 111-112

🤖 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/pages/AnonymousDoubts.tsx` around lines 48 - 49, The character limit
validation uses the raw text length but the actual persisted content uses
trimmedText, causing valid submissions with trailing spaces to be rejected. At
line 48 in the AnonymousDoubts.tsx file, refactor the limit check to use
trimmedText.length instead of text.length by first trimming the text variable
before performing the character limit validation. Apply the same fix at line
111-112 in the same file to ensure consistency across all limit checks. This
ensures the validation matches what will actually be stored in the database.

Comment on lines +85 to 95
<div className="relative">

<span className={`absolute bottom-2 right-2 text-xs select-none ${
text.length > MAX_CHARS ? "text-red-500 font-semibold"
: text.length >= MAX_CHARS * 0.9 ? "text-amber-500"
: "text-slate-400"}`}
>
{text.length}/{MAX_CHARS}
</span>
</div>
<input

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Text entry control is missing, so posting is effectively broken.

The new counter UI at Line 85 appears without a bound text input/textarea, and setText is never invoked from this section. Combined with disabled={... || !text.trim() ...} at Line 111, “Post Doubt” stays disabled and users cannot submit.

Proposed fix
-<div className="relative">
-   <span className={`absolute bottom-2 right-2 text-xs select-none ${
-     text.length > MAX_CHARS ? "text-red-500 font-semibold"
-    : text.length >= MAX_CHARS * 0.9 ? "text-amber-500"
-    : "text-slate-400"}`}
-  >
-     {text.length}/{MAX_CHARS}
-   </span>
- </div>
+<div className="relative">
+  <textarea
+    className="border p-2 w-full rounded min-h-28 pr-16"
+    placeholder="Write your doubt..."
+    value={text}
+    onChange={(e) => setText(e.target.value)}
+  />
+  <span
+    className={`absolute bottom-2 right-2 text-xs select-none ${
+      text.length > MAX_CHARS
+        ? "text-red-500 font-semibold"
+        : text.length >= MAX_CHARS * 0.9
+        ? "text-amber-500"
+        : "text-slate-400"
+    }`}
+  >
+    {text.length}/{MAX_CHARS}
+  </span>
+</div>
📝 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.

Suggested change
<div className="relative">
<span className={`absolute bottom-2 right-2 text-xs select-none ${
text.length > MAX_CHARS ? "text-red-500 font-semibold"
: text.length >= MAX_CHARS * 0.9 ? "text-amber-500"
: "text-slate-400"}`}
>
{text.length}/{MAX_CHARS}
</span>
</div>
<input
<div className="relative">
<textarea
className="border p-2 w-full rounded min-h-28 pr-16"
placeholder="Write your doubt..."
value={text}
onChange={(e) => setText(e.target.value)}
/>
<span
className={`absolute bottom-2 right-2 text-xs select-none ${
text.length > MAX_CHARS
? "text-red-500 font-semibold"
: text.length >= MAX_CHARS * 0.9
? "text-amber-500"
: "text-slate-400"
}`}
>
{text.length}/{MAX_CHARS}
</span>
</div>
🤖 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/pages/AnonymousDoubts.tsx` around lines 85 - 95, The text counter UI
spanning the relative div is present but the input element is missing its
onChange handler binding. Add an onChange event handler to the input or textarea
element that captures user input and updates the text state by calling setText
with the trimmed or raw input value. This will ensure that as users type, the
text state is updated, enabling the "Post Doubt" button (currently disabled due
to the !text.trim() condition at line 111) to become clickable when text is
entered.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix: "View Profile" button in PeerCard is a dead no-op

1 participant