Skip to content

Separate Submit Quiz button from Generate Google Form button#557

Open
PunyaGowdagd66 wants to merge 3 commits intoAOSSIE-Org:mainfrom
PunyaGowdagd66:fix-output-quiz
Open

Separate Submit Quiz button from Generate Google Form button#557
PunyaGowdagd66 wants to merge 3 commits intoAOSSIE-Org:mainfrom
PunyaGowdagd66:fix-output-quiz

Conversation

@PunyaGowdagd66
Copy link
Copy Markdown

@PunyaGowdagd66 PunyaGowdagd66 commented Mar 11, 2026

Changes

  1. Fixed nested button issue:
    • Previously, the "Submit Quiz" button was inside the "Generate Google Form" button.
    • Now both buttons are siblings, preventing mixed event firing and invalid HTML.
  2. Updated quiz answer selection:
    • Converted setUserAnswers to functional state update to avoid stale state problems.
    • Added conditional styling to highlight selected options.
  3. Refactored Output.jsx for better readability and UX.
  4. Minor styling tweaks to maintain responsive design.

This PR resolves critical UI bugs and ensures a smoother quiz-taking experience.

Summary by CodeRabbit

  • New Features

    • Quiz answer options are now interactive—click to select your answers
    • Submit Quiz button calculates and displays your score
  • Bug Fixes

    • Added validation to prevent blank submissions; users receive a prompt if both text input and file upload are empty

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 11, 2026

📝 Walkthrough

Walkthrough

Two UI components were enhanced: the Output page now enables interactive answer selection with quiz scoring functionality, while the Text_Input page adds validation to prevent saving when neither file upload nor text input is provided.

Changes

Cohort / File(s) Summary
Quiz Functionality
eduaid_web/src/pages/Output.jsx
Introduced state management for user answers, handleAnswerSelect callback for option clicks, calculateScore function to compute correct answers, clickable answer options with cursor styling, and a Submit Quiz button to trigger score calculation and alert result.
Input Validation
eduaid_web/src/pages/Text_Input.jsx
Added early-return validation in handleSaveToLocalStorage to check if both text and docUrl are empty; displays alert and prevents further processing if validation fails.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A quiz now springs to life with interactive flair,
Answers clickable, scores calculated with care,
Validation guards the text input's door,
No empty saves shall pass anymore! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
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 (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main structural fix in the changeset—separating nested buttons in Output.jsx, which is a critical issue explicitly mentioned in the PR objectives.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

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 (3)
eduaid_web/src/pages/Output.jsx (3)

217-222: ⚠️ Potential issue | 🟠 Major

Hide the correct answer while the quiz is active.

The new submit flow is not meaningful while Lines 217-222 still render qaPair.answer before the user chooses anything. Gate that block behind a post-submit/show-answers state or this becomes an open-book score screen.

Also applies to: 258-263

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@eduaid_web/src/pages/Output.jsx` around lines 217 - 222, The Answer display
currently renders qaPair.answer unconditionally (blocks that include "Answer"
label and {qaPair.answer} around qaPair) which leaks correct responses during an
active quiz; wrap both occurrences (the block rendering {qaPair.answer} at lines
shown and the similar block at 258-263) behind a boolean like quizSubmitted or
showAnswers (prop/state) and only render the answer block when that flag is
true; update the component (Output.jsx) to check this flag before rendering the
"Answer" label and {qaPair.answer}, and ensure the flag is toggled when the user
submits or when show-answers mode is activated.

199-203: ⚠️ Potential issue | 🟠 Major

Keep option order stable after a selection.

Each click updates userAnswers state, triggering a rerender of the question list. Since shuffleArray() uses Math.random() and runs during render at line 203, the options reorder unpredictably after every selection. Shuffle once when loading qaPairs or memoize the shuffled options per question to maintain consistent UI.

Also applies to: 226-230

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@eduaid_web/src/pages/Output.jsx` around lines 199 - 203, The options are
being re-shuffled on every render because shuffleArray(...) is called inside
qaPairs.map during render (in the component that maps qaPairs and sets
userAnswers), causing option order to change after each selection; fix by
computing a stable shuffled options list once per question—either shuffle when
qaPairs are first loaded (in the data-loading logic) or create a memoized
mapping of questionId/index → shuffledOptions using useMemo or useState (e.g.,
build shuffledOptionsForQuestion keyed by qaPair.id or index) and reference that
inside the qaPairs.map instead of calling shuffleArray each render; update code
locations around qaPairs.map and the shuffleArray usage at lines ~203 and
~226-230 to use the stable memoized/stored shuffled options.

226-237: ⚠️ Potential issue | 🟠 Major

Replace clickable div with semantic button control and display selected state.

The current div element is not keyboard accessible (no keyboard event handlers, not a semantic interactive element), and the selected answer choice is never visually reflected in the UI despite the userAnswers state tracking selections. Users cannot reliably tell what they've selected. This should be a button element with aria-pressed state and selected styling applied based on userAnswers.

Suggested fix
-                          <div
-                            key={idx}
-                            className="mb-1 sm:mb-2 cursor-pointer"
-                            onClick={() => handleAnswerSelect(index, option)}
-                          >
+                          <button
+                            type="button"
+                            key={idx}
+                            className={`mb-1 sm:mb-2 w-full rounded-lg px-2 py-1 text-left cursor-pointer ${
+                              userAnswers[index] === option
+                                ? "bg-[`#518E8E`]/30 ring-1 ring-[`#518E8E`]"
+                                : ""
+                            }`}
+                            aria-pressed={userAnswers[index] === option}
+                            onClick={() => handleAnswerSelect(index, option)}
+                          >
                             <span className="text-[`#E4E4E4`] text-xs sm:text-sm">
                               Option {idx + 1}:
                             </span>{" "}
                             <span className="text-[`#FFF4F4`] text-sm sm:text-base">
                               {option}
                             </span>
-                          </div>
+                          </button>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@eduaid_web/src/pages/Output.jsx` around lines 226 - 237, Replace the
non-interactive div used for answer choices with a semantic button in the
mapping that calls handleAnswerSelect(index, option); use the component state
userAnswers (e.g. check userAnswers[index] === option) to set aria-pressed and
to conditionally apply "selected" styling classes so the choice is visibly
different when chosen; keep the existing key={idx}, preserve the displayed text
("Option {idx + 1}:" and {option}), and ensure the onClick still invokes
handleAnswerSelect (no extra keyboard handlers needed for a native button).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@eduaid_web/src/pages/Text_Input.jsx`:
- Around line 51-56: The empty-input guard in Text_Input.jsx uses raw text and
docUrl so whitespace-only input passes; before the check that alerts and
returns, normalize both values (e.g., create trimmedText = text?.trim() and
trimmedDocUrl = docUrl?.trim()) and branch on those trimmed values instead, and
ensure subsequent calls (like the /get_content or quiz generation path) use the
trimmed variables rather than the original text/docUrl so whitespace-only inputs
are rejected.

---

Outside diff comments:
In `@eduaid_web/src/pages/Output.jsx`:
- Around line 217-222: The Answer display currently renders qaPair.answer
unconditionally (blocks that include "Answer" label and {qaPair.answer} around
qaPair) which leaks correct responses during an active quiz; wrap both
occurrences (the block rendering {qaPair.answer} at lines shown and the similar
block at 258-263) behind a boolean like quizSubmitted or showAnswers
(prop/state) and only render the answer block when that flag is true; update the
component (Output.jsx) to check this flag before rendering the "Answer" label
and {qaPair.answer}, and ensure the flag is toggled when the user submits or
when show-answers mode is activated.
- Around line 199-203: The options are being re-shuffled on every render because
shuffleArray(...) is called inside qaPairs.map during render (in the component
that maps qaPairs and sets userAnswers), causing option order to change after
each selection; fix by computing a stable shuffled options list once per
question—either shuffle when qaPairs are first loaded (in the data-loading
logic) or create a memoized mapping of questionId/index → shuffledOptions using
useMemo or useState (e.g., build shuffledOptionsForQuestion keyed by qaPair.id
or index) and reference that inside the qaPairs.map instead of calling
shuffleArray each render; update code locations around qaPairs.map and the
shuffleArray usage at lines ~203 and ~226-230 to use the stable memoized/stored
shuffled options.
- Around line 226-237: Replace the non-interactive div used for answer choices
with a semantic button in the mapping that calls handleAnswerSelect(index,
option); use the component state userAnswers (e.g. check userAnswers[index] ===
option) to set aria-pressed and to conditionally apply "selected" styling
classes so the choice is visibly different when chosen; keep the existing
key={idx}, preserve the displayed text ("Option {idx + 1}:" and {option}), and
ensure the onClick still invokes handleAnswerSelect (no extra keyboard handlers
needed for a native button).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c981aeb3-04bb-4925-a1f4-7250a12c32b0

📥 Commits

Reviewing files that changed from the base of the PR and between fc3bf1a and 43455ca.

⛔ Files ignored due to path filters (1)
  • eduaid_web/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • eduaid_web/src/pages/Output.jsx
  • eduaid_web/src/pages/Text_Input.jsx

Comment on lines +51 to +56
if (!text && !docUrl) {
alert("Please upload a file or provide input before proceeding.");
return;
}

setLoading(true);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Trim the inputs before applying this empty-input guard.

" " currently passes the check and can still hit /get_content or quiz generation with blank content. Normalize both fields once and branch on the trimmed values instead.

Suggested fix
 const handleSaveToLocalStorage = async () => {
-    
-    if (!text && !docUrl) {
-    alert("Please upload a file or provide input before proceeding.");
-    return;
-    }
+    const trimmedText = text.trim();
+    const trimmedDocUrl = docUrl.trim();
+
+    if (!trimmedText && !trimmedDocUrl) {
+      alert("Please upload a file or provide input before proceeding.");
+      return;
+    }
 
-   setLoading(true);
+    setLoading(true);
 
     // Check if a Google Doc URL is provided
-    if (docUrl) {
+    if (trimmedDocUrl) {
       try {
-        const data = await apiClient.post("/get_content", { document_url: docUrl });
+        const data = await apiClient.post("/get_content", { document_url: trimmedDocUrl });
         setDocUrl("");
         setText(data || "Error in retrieving");
       } catch (error) {
         console.error("Error:", error);
         setText("Error retrieving Google Doc content");
       } finally {
         setLoading(false);
       }
-    } else if (text) {
+    } else if (trimmedText) {
       // Proceed with existing functionality for local storage
-      localStorage.setItem("textContent", text);
+      localStorage.setItem("textContent", trimmedText);
       localStorage.setItem("difficulty", difficulty);
       localStorage.setItem("numQuestions", numQuestions);
 
       await sendToBackend(
-        text,
+        trimmedText,
         difficulty,
         localStorage.getItem("selectedQuestionType")
       );
     }
   };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@eduaid_web/src/pages/Text_Input.jsx` around lines 51 - 56, The empty-input
guard in Text_Input.jsx uses raw text and docUrl so whitespace-only input
passes; before the check that alerts and returns, normalize both values (e.g.,
create trimmedText = text?.trim() and trimmedDocUrl = docUrl?.trim()) and branch
on those trimmed values instead, and ensure subsequent calls (like the
/get_content or quiz generation path) use the trimmed variables rather than the
original text/docUrl so whitespace-only inputs are rejected.

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.

1 participant