Feat/anonymous doubts char limit#993
Conversation
|
@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. |
📝 WalkthroughWalkthroughTwo independent UI enhancements: ChangesLiveCodeRunner: Copy & Clear Actions
AnonymousDoubts: Character Limit Enforcement
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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 liftEnforce 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
📒 Files selected for processing (2)
src/components/studyroom/LiveCodeRunner.tsxsrc/pages/AnonymousDoubts.tsx
| 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") | ||
| ); |
There was a problem hiding this comment.
🧩 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:
- 1: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText
- 2: https://juanchi.dev/en/blog/clipboard-api-typescript-fails-undocumented-cases-copytext
- 3: https://jsguides.dev/tutorials/browser-clipboard/
- 4: https://web.dev/articles/async-clipboard
- 5: Interoperability issue:
navigator.clipboard.write()andnavigator.clipboard.writeText()user gesture requirement w3c/clipboard-apis#182
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.
| 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; } |
There was a problem hiding this comment.
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.
| <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> |
There was a problem hiding this comment.
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.
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