Skip to content

Feat/anonymous doubts char limit#993

Open
OmanshiRaj wants to merge 2 commits into
durdana3105:mainfrom
OmanshiRaj:feat/anonymous-doubts-char-limit
Open

Feat/anonymous doubts char limit#993
OmanshiRaj wants to merge 2 commits into
durdana3105:mainfrom
OmanshiRaj:feat/anonymous-doubts-char-limit

Conversation

@OmanshiRaj

@OmanshiRaj OmanshiRaj commented Jun 15, 2026

Copy link
Copy Markdown

Closes #927
Added a 500-character limit and live counter to the doubt submission textarea:

MAX_CHARS = 500 constant defined at the top of the file
Live X/500 counter positioned bottom-right of the textarea using absolute positioning
Counter turns amber at ≥90% (450+ chars) and red when over limit
Textarea border turns red when over limit
Submit button is disabled when over limit
addDoubt handler also guards against over-limit submission with a toast error

Summary by CodeRabbit

  • New Features
    • Copy output: Added button to copy code output directly to clipboard with confirmation feedback
    • Clear code: Added button to reset code and output in the editor
    • Doubt character limit: Enforced 500-character maximum for doubt submissions with live character counter and visual feedback when approaching the limit

@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

Two independent UI enhancements: LiveCodeRunner gains copy-output and clear-code actions with corresponding toolbar buttons and icon imports; AnonymousDoubts enforces a 500-character limit via a MAX_CHARS constant, a live character counter with threshold-based styling, submit-time validation, and an extended button disabled condition.

Changes

LiveCodeRunner: Copy & Clear Actions

Layer / File(s) Summary
Copy/Clear handlers and toolbar UI
src/components/studyroom/LiveCodeRunner.tsx
Adds Clipboard and Trash2 icon imports, defines handleCopyOutput (clipboard write with toast feedback) and handleClearCode (resets code and output), inserts a disabled-aware Clear button in the toolbar, and conditionally renders a Copy button in the output panel header when output is non-empty.

AnonymousDoubts: Character Limit Enforcement

Layer / File(s) Summary
MAX_CHARS constant, submit guard, counter UI, and button disable
src/pages/AnonymousDoubts.tsx
Introduces MAX_CHARS = 500, adds an early return with an error toast in addDoubt when text.length > MAX_CHARS, replaces the plain textarea with a relative container showing a live X/500 counter styled amber at ≥90% and red when over limit, and extends the Post Doubt button disabled condition to include text.length > MAX_CHARS.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

  • #927 (feat: add character limit and live counter to AnonymousDoubts textarea) — This PR implements exactly the feature described: MAX_CHARS = 500, live X/500 counter with amber/red styling thresholds, submit-time toast enforcement, and button disablement.
  • #928 — This PR implements the copy-output and clear-code actions for LiveCodeRunner that the issue requests, including the matching icons and handler logic.

Poem

🐇 Hop hop, the rabbit taps away,
Five hundred chars — no more today!
A clipboard click, the output flies,
A trash swipe clears before your eyes.
Clean code, clean doubts, the warren cheers —
Small buttons bring such big ideas! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes changes to LiveCodeRunner.tsx (copy/clear button features) that are unrelated to the anonymous doubts character limit requirement specified in issue #927, representing out-of-scope additions. Remove changes to LiveCodeRunner.tsx as they address a different feature and should be submitted in a separate PR focused on code runner improvements.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Feat/anonymous doubts char limit' directly describes the main change: implementing a character limit for anonymous doubts, which is the primary focus of the changeset.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #927: MAX_CHARS constant, live character counter with correct positioning, color-coded feedback (amber at ≥90%, red when exceeded), textarea border styling, disabled submit button logic, and validation with toast error in the addDoubt handler.

✏️ 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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/pages/AnonymousDoubts.tsx (1)

48-57: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Enforce max length at the database boundary, not only in UI.

The client guard at Line 48 is bypassable; inserts at Line 52–57 can still accept oversized content through direct API calls. The schema/policy context shows no DB-side length check, so abuse mitigation is incomplete.

🤖 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 - 57, The client-side
MAX_CHARS validation in the condition at line 48 can be bypassed through direct
API calls since the database has no corresponding length constraint. Add a
database-side check constraint or character limit on the "content" column in the
"doubts" table to enforce the maximum length requirement at the database
boundary. This ensures that oversized doubts cannot be inserted regardless of
how the request is made, protecting against direct API manipulation that
circumvents the UI validation.
🤖 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/studyroom/LiveCodeRunner.tsx`:
- Around line 83-88: The handleCopyOutput function calls
navigator.clipboard.writeText without verifying that the Clipboard API is
available, which can throw a synchronous error in non-secure (HTTP) contexts or
restricted environments, bypassing the promise-based error handling. Add a guard
check to verify that navigator.clipboard exists before attempting to call
writeText; if it is unavailable, show an error toast indicating that the
clipboard is not accessible instead of attempting the operation.

In `@src/pages/AnonymousDoubts.tsx`:
- Line 48: The length validation at lines 48 and 111 checks text.length, but the
actual submission at line 54 uses trimmedText, creating an inconsistency where
valid submissions get rejected. In both validation checks in the condition at
line 48 and line 111, replace the validation of text.length with a validation of
trimmedText.length to ensure the UI validation matches the actual behavior of
what gets submitted to the database. This requires computing trimmedText (the
trimmed version of the input) before performing the length check so that the
validation reflects what will actually be stored.
- Around line 85-94: The code snippet shows only the character counter display
element but is missing the actual textarea input control. To fix this, add a
textarea element within the relative div that binds to the text state variable
so users can type input. The textarea should update the text state as users
type, which will allow the character counter to display correctly and the submit
button at line 111 to become enabled when text is present (currently the button
remains disabled because the !text.trim() check never evaluates to false when
there is no textarea to capture user input). Ensure the textarea is positioned
properly and integrated with the MAX_CHARS validation logic already present in
the counter display.

---

Outside diff comments:
In `@src/pages/AnonymousDoubts.tsx`:
- Around line 48-57: The client-side MAX_CHARS validation in the condition at
line 48 can be bypassed through direct API calls since the database has no
corresponding length constraint. Add a database-side check constraint or
character limit on the "content" column in the "doubts" table to enforce the
maximum length requirement at the database boundary. This ensures that oversized
doubts cannot be inserted regardless of how the request is made, protecting
against direct API manipulation that circumvents the UI validation.
🪄 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: 0a314ce4-f95b-4f55-8f84-d5ad8c3adb98

📥 Commits

Reviewing files that changed from the base of the PR and between 7200d81 and 61b4c6e.

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

Comment on lines +83 to +88
const handleCopyOutput = () => {
if (!output) { toast.error("No output to copy"); return; }
navigator.clipboard.writeText(output).then(
() => toast.success("Output copied!"),
() => toast.error("Failed to copy output")
);

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

🧩 Analysis chain

🌐 Web query:

Is navigator.clipboard.writeText guaranteed to be available in all browsers/contexts, or does it require secure contexts (HTTPS) and user gesture constraints?

💡 Result:

The navigator.clipboard.writeText method is not guaranteed to be available in all contexts and is subject to several strict requirements [1][2][3]. It is not a universally available API, and its usage requires handling potential failures gracefully [4][2]. Key requirements include: 1. Secure Contexts: The API is only available in secure contexts (HTTPS or localhost) [1][2]. In insecure (HTTP) contexts, navigator.clipboard is typically undefined [2][3]. 2. User Gesture/Activation: Most browsers require a transient user activation (such as a click or keypress) to trigger a write operation [4][5][3]. While browser implementation of this requirement can vary, relying on it without a user-triggered event often leads to rejected promises [5][3]. 3. Active Tab/Focus: In many browsers, clipboard access is restricted to the active tab [4][5]. If a page is in the background, the operation may be blocked [5]. 4. Cross-Origin Iframes: If your code is running inside a cross-origin iframe, the parent page must explicitly grant permission via the Permissions Policy (e.g., allow="clipboard-write") [2][3]. Even if the API is technically available, it will throw a NotAllowedError if these permissions are not configured [2]. Because of these constraints, it is standard practice to wrap calls to navigator.clipboard.writeText in try-catch blocks and provide a fallback mechanism for cases where the API is unavailable or denied [4][2][3].

Citations:


Guard navigator.clipboard availability before calling writeText.

The Clipboard API is unavailable in non-secure contexts (HTTP) and certain restricted environments. Attempting to access navigator.clipboard when it doesn't exist will throw a synchronous error, bypassing your promise-based error handling. Add an availability check before invoking writeText.

Suggested fix
  const handleCopyOutput = () => {
    if (!output) { toast.error("No output to copy"); return; }
+   if (!navigator.clipboard?.writeText) {
+     toast.error("Clipboard is not available in this browser/context");
+     return;
+   }
    navigator.clipboard.writeText(output).then(
      () => toast.success("Output copied!"),
      () => toast.error("Failed to copy output")
    );
  };
📝 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
const handleCopyOutput = () => {
if (!output) { toast.error("No output to copy"); return; }
navigator.clipboard.writeText(output).then(
() => toast.success("Output copied!"),
() => toast.error("Failed to copy output")
);
const handleCopyOutput = () => {
if (!output) { toast.error("No output to copy"); return; }
if (!navigator.clipboard?.writeText) {
toast.error("Clipboard is not available in this browser/context");
return;
}
navigator.clipboard.writeText(output).then(
() => toast.success("Output copied!"),
() => toast.error("Failed to copy output")
);
};
🤖 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/studyroom/LiveCodeRunner.tsx` around lines 83 - 88, The
handleCopyOutput function calls navigator.clipboard.writeText without verifying
that the Clipboard API is available, which can throw a synchronous error in
non-secure (HTTP) contexts or restricted environments, bypassing the
promise-based error handling. Add a guard check to verify that
navigator.clipboard exists before attempting to call writeText; if it is
unavailable, show an error toast indicating that the clipboard is not accessible
instead of attempting the operation.

const trimmedText = text.trim();
const trimmedSubject = subject.trim();
if (!trimmedText || !trimmedSubject) return;
if (text.length > MAX_CHARS) { toast.error(`Doubt exceeds ${MAX_CHARS} character limit.`); 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

Length validation is inconsistent with persisted content.

Line 48 and Line 111 validate text.length, but insert uses trimmedText (Line 54). This can reject submissions that would be <=500 after trimming. Validate against trimmedText.length (or a shared derived value) to keep UI/submit behavior consistent.

Also applies to: 111-111

🤖 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 48, The length validation at lines 48
and 111 checks text.length, but the actual submission at line 54 uses
trimmedText, creating an inconsistency where valid submissions get rejected. In
both validation checks in the condition at line 48 and line 111, replace the
validation of text.length with a validation of trimmedText.length to ensure the
UI validation matches the actual behavior of what gets submitted to the
database. This requires computing trimmedText (the trimmed version of the input)
before performing the length check so that the validation reflects what will
actually be stored.

Comment on lines +85 to +94
<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>

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

Missing textarea control breaks posting flow.

Line 85–94 renders only the counter, not the textarea itself, so text is never editable and Line 111 keeps the button disabled (!text.trim()). This is a blocker for the whole feature.

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 ${
+      text.length > MAX_CHARS ? "border-red-500 focus:ring-red-500" : ""
+    }`}
+    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>

Also applies to: 111-111

🤖 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 - 94, The code snippet shows
only the character counter display element but is missing the actual textarea
input control. To fix this, add a textarea element within the relative div that
binds to the text state variable so users can type input. The textarea should
update the text state as users type, which will allow the character counter to
display correctly and the submit button at line 111 to become enabled when text
is present (currently the button remains disabled because the !text.trim() check
never evaluates to false when there is no textarea to capture user input).
Ensure the textarea is positioned properly and integrated with the MAX_CHARS
validation logic already present in the counter display.

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.

feat: add character limit and live counter to AnonymousDoubts textarea

1 participant