feat: interactive quiz UX - single question + navigation + progress (…#482
feat: interactive quiz UX - single question + navigation + progress (…#482Tanushreesmallikarjuna wants to merge 5 commits intoAOSSIE-Org:mainfrom
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughReplaced per-item PDF mode and multi-view rendering with a single currentIndex-driven UI showing one QA pair at a time; added Previous/Next navigation, per-view editing tied to currentIndex, consolidated localStorage loading into qaPairs, revamped option shuffling, and updated Google Form generation/error handling. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant UI as Output.jsx (UI)
participant Storage as localStorage
participant Google as Google Form API
rect rgba(135,206,235,0.5)
User->>UI: Click Next / Previous / Edit / Save
UI->>UI: Update currentIndex, editing state, shuffledOptions
UI->>Storage: Read/Write qaPairs (persist edits)
Storage-->>UI: Acknowledge
end
rect rgba(144,238,144,0.5)
User->>UI: Click "Generate Google Form"
UI->>Google: POST form payload (qaPairs)
Google-->>UI: Success / Error
UI-->>User: Show success / error notification
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ 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 |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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/Output.jsx`:
- Around line 36-37: The bug is that currentIndex can point past the newly
loaded qaPairs (and shuffledOptionsMap) causing blank renders; update the
component to reset currentIndex to a valid value whenever the loaded QA data
changes (e.g., when qaPairs length changes or new data is assigned) — inside the
effect or handler that sets qaPairs/shuffledOptionsMap, call setCurrentIndex(0)
or clamp it to Math.max(0, Math.min(currentIndex, qaPairs.length - 1)), and
similarly ensure any uses of shuffledOptionsMap[currentIndex] handle the new
index (reinitialize or clamp shuffledOptionsMap indices) so both the references
around qaPairs/currentIndex and shuffledOptionsMap/currentIndex are safe after
reload.
- Around line 157-246: The screen currently only supports navigation and editing
(qaPair, shuffledOptions, currentIndex, qaPairs, isEditing, handleEditQuestion,
handleSaveQuestion, handleCancelEdit, handlePrevious, handleNext,
generateGoogleForm) but lacks answer attempt flow, immediate feedback, scoring,
and retry-incorrect behavior; implement: add local state for selectedAnswer and
per-question result (correct/incorrect) and score summary, render clickable
answer buttons for shuffledOptions that call an attempt handler (e.g.,
handleAttemptAnswer(questionIndex, option)), show immediate feedback UI
(correct/incorrect) and disable further attempts for that question, track score
and list of incorrect question indices, add end-of-quiz summary view showing
total correct, percentage, and a "Retry Incorrect" action that resets only the
incorrect questions (or navigates through them) while preserving edits, and wire
these flows into navigation (handleNext/handlePrevious) so feedback and attempt
state persist when paging between questions.
- Around line 145-147: The progress and nav controls don't handle an empty
qaPairs list or editing state: change the progress header that uses currentIndex
and qaPairs to conditionally render a friendly empty state (e.g., "No questions"
or nothing) when qaPairs.length === 0, and only render "Question {currentIndex +
1} of {qaPairs.length}" when qaPairs.length > 0; additionally, disable the
navigation buttons (Prev/Next) and any handlers like handlePrev/handleNext when
qaPairs.length === 0 or when the editing flag (e.g., isEditing) is true so
navigation is unavailable while editing or when there are no questions.
- Around line 30-33: The shuffledOptionsMap useMemo currently appends qa.answer
unconditionally which can create duplicates when qa.answer already exists in
qa.options; update the logic inside useMemo (where shuffledOptionsMap is
computed from qaPairs and uses shuffleArray) to first build a deduplicated
options array—e.g., take qa.options || [], filter out any entries equal to
qa.answer, then push qa.answer once (or use a Set) before calling
shuffleArray—so shuffledOptionsMap contains unique choices with the correct
answer included exactly once.
- Around line 95-118: The effect reading localStorage in useEffect can throw if
the stored value is missing or malformed and will crash when accessing nested
arrays like stored.output_mcq.questions or stored.output.forEach; wrap the
JSON.parse in a try/catch and guard downstream accesses by verifying stored is
an object and using Array.isArray before iterating (e.g., check
stored.output_mcq && Array.isArray(stored.output_mcq.questions) and
stored.output && Array.isArray(stored.output)), and handle fallback empty arrays
so combined building always iterates safely without throwing (retain existing
fields question/question_statement, answer, options, question_type).
|
Thanks for the detailed review 🙌 I’m extending this PR to add: Answer attempt interaction with immediate correct/incorrect feedback Per-question result persistence across navigation Final summary screen with score and weak areas Retry-incorrect flow I’m also addressing the noted robustness fixes (deduplicated options, index reset on reload, localStorage guards, and empty-state handling). Will update shortly for re-review. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
eduaid_web/src/pages/Output.jsx (2)
178-180: Consider adding an empty-state message.When
qaPairsis empty, the content area renders nothing. A user-friendly message like "No questions available" would improve the experience when there's no data to display.💡 Suggested empty state UI
<div className="flex-1 overflow-y-auto px-6 mt-4"> - {qaPair && ( + {!hasQuestions ? ( + <div className="text-gray-400 text-center py-8"> + No questions available. Please generate questions first. + </div> + ) : qaPair && ( <div className="bg-[`#ffffff0d`] p-4 rounded-xl">🤖 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 178 - 180, The UI currently renders nothing when there are no qaPairs; update the render logic in Output.jsx around the qaPair/qaPairs usage so that when qaPairs is empty (or qaPair is falsy) you render a simple empty-state message/component (e.g., "No questions available" with subtle styling inside the same container) instead of nothing; change the conditional that now only shows the <div className="bg-[`#ffffff0d`] p-4 rounded-xl"> when qaPair exists to render the empty-state element when qaPairs.length === 0 or !qaPair, keeping the same layout container and class names for consistent spacing.
165-176: Duplicate progress indicator is intentional but consider consolidating.The "Question X of Y" text appears both in the header (line 167) and in the navigation footer (line 250). If this duplication is intentional for visibility, consider differentiating their styling or removing one to reduce visual redundancy.
🤖 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 165 - 176, The UI shows a duplicated progress indicator "Question {hasQuestions ? currentIndex + 1 : 0} of {totalQuestions}" in both the header and navigation footer; decide whether to remove one or differentiate them: either remove the header instance (the div using hasQuestions/currentIndex/totalQuestions) or adjust its styling/text (e.g., shorten to "Q {currentIndex+1}/{totalQuestions}" or move into an aria-label) so it doesn't visually duplicate the footer; update the JSX where that expression is rendered and ensure any related logic (hasQuestions, currentIndex, totalQuestions) remains used where needed and accessibility is preserved.
🤖 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/Output.jsx`:
- Around line 202-233: The edit UI is missing a field to modify editedAnswer
(initialized in handleEditQuestion) so the answer never changes; add a
controlled input (or textarea) bound to editedAnswer with onChange to
setEditedAnswer inside the edit block that renders editedQuestion/editedOptions
(near the map over editedOptions and before the Save/Cancel buttons) and ensure
handleSaveQuestion uses editedAnswer when updating the question at currentIndex
so saved edits include the new answer.
---
Nitpick comments:
In `@eduaid_web/src/pages/Output.jsx`:
- Around line 178-180: The UI currently renders nothing when there are no
qaPairs; update the render logic in Output.jsx around the qaPair/qaPairs usage
so that when qaPairs is empty (or qaPair is falsy) you render a simple
empty-state message/component (e.g., "No questions available" with subtle
styling inside the same container) instead of nothing; change the conditional
that now only shows the <div className="bg-[`#ffffff0d`] p-4 rounded-xl"> when
qaPair exists to render the empty-state element when qaPairs.length === 0 or
!qaPair, keeping the same layout container and class names for consistent
spacing.
- Around line 165-176: The UI shows a duplicated progress indicator "Question
{hasQuestions ? currentIndex + 1 : 0} of {totalQuestions}" in both the header
and navigation footer; decide whether to remove one or differentiate them:
either remove the header instance (the div using
hasQuestions/currentIndex/totalQuestions) or adjust its styling/text (e.g.,
shorten to "Q {currentIndex+1}/{totalQuestions}" or move into an aria-label) so
it doesn't visually duplicate the footer; update the JSX where that expression
is rendered and ensure any related logic (hasQuestions, currentIndex,
totalQuestions) remains used where needed and accessibility is preserved.
c67afae to
eb21f1a
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
eduaid_web/src/pages/Output.jsx (2)
203-217:⚠️ Potential issue | 🟠 Major
editedAnsweris still not editable in edit mode.Line 74 initializes
editedAnswerand Line 83 saves it, but there is no bound input in the edit UI, so answer edits cannot be made.🔧 Proposed fix
<textarea value={editedQuestion} onChange={(e) => setEditedQuestion(e.target.value)} className="w-full p-2 bg-black text-white rounded" /> + <input + value={editedAnswer} + onChange={(e) => setEditedAnswer(e.target.value)} + className="w-full p-2 mt-2 bg-black text-white rounded" + placeholder="Correct answer" + /> {editedOptions.map((opt, i) => ( <input🤖 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 203 - 217, The edit UI is missing a bound input for editedAnswer so edits are not saved; add a controlled input (e.g., a textarea or input) bound to editedAnswer with an onChange that calls setEditedAnswer(value) placed alongside the existing editedQuestion textarea and the editedOptions mapping (near editedQuestion, editedOptions, handleOptionChange). Ensure the new input uses the same styling pattern and a unique key if in a list so the saved editedAnswer (used when saving on line ~83) reflects user changes.
178-272:⚠️ Potential issue | 🟠 MajorIssue
#474flow is still incomplete in this screen.Line 185–193 only displays options; there is still no answer-attempt interaction, immediate correct/incorrect feedback, final summary, or retry-incorrect flow required by
#474.🤖 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 178 - 272, The UI currently only displays options (shuffledOptions) and lacks answer-attempt flow, immediate feedback, final summary and retry-incorrect flow required by `#474`; implement an interactive answer flow by adding state (selectedOption, attemptsByIndex, feedbackMessage, incorrectIndices, showSummary) and new handlers (handleOptionSelect/handleAnswerSubmit/handleRetryIncorrect) to the Output component: render radio/buttons for options that call handleOptionSelect, validate submissions in handleAnswerSubmit (compare selectedOption to qaPair.correctAnswer or canonical answer), update attemptsByIndex and incorrectIndices, set feedbackMessage to immediate correct/incorrect feedback and optionally show the correct answer, disable navigation while answering (use isEditing-like guard), and at the end (when currentIndex === totalQuestions-1 or via a dedicated finish button) show a summary view (showSummary) with total correct, list of incorrect questions and a "Retry Incorrect" button that calls handleRetryIncorrect to reset currentIndex to the first incorrect index and clear only those question attempt states; ensure existing functions (handlePrevious, handleNext, generateGoogleForm) respect the new guards and that shuffledOptions usage integrates with answer checking.
🤖 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/Output.jsx`:
- Around line 145-150: The response handling for the POST to /generate_gform
uses res.form_link directly and calls window.open without security flags; update
the code around apiClient.post("/generate_gform", ...) to unwrap the actual
response payload (e.g., use res.data or the shape returned by your client),
validate that the form link is a non-empty string (throw or show an error if
missing), and open it with window.open(validUrl, "_blank",
"noopener,noreferrer") (or create a temporary anchor with rel="noopener
noreferrer") to prevent opener exposure; ensure checks are applied before
calling window.open to avoid silent failures.
---
Duplicate comments:
In `@eduaid_web/src/pages/Output.jsx`:
- Around line 203-217: The edit UI is missing a bound input for editedAnswer so
edits are not saved; add a controlled input (e.g., a textarea or input) bound to
editedAnswer with an onChange that calls setEditedAnswer(value) placed alongside
the existing editedQuestion textarea and the editedOptions mapping (near
editedQuestion, editedOptions, handleOptionChange). Ensure the new input uses
the same styling pattern and a unique key if in a list so the saved editedAnswer
(used when saving on line ~83) reflects user changes.
- Around line 178-272: The UI currently only displays options (shuffledOptions)
and lacks answer-attempt flow, immediate feedback, final summary and
retry-incorrect flow required by `#474`; implement an interactive answer flow by
adding state (selectedOption, attemptsByIndex, feedbackMessage,
incorrectIndices, showSummary) and new handlers
(handleOptionSelect/handleAnswerSubmit/handleRetryIncorrect) to the Output
component: render radio/buttons for options that call handleOptionSelect,
validate submissions in handleAnswerSubmit (compare selectedOption to
qaPair.correctAnswer or canonical answer), update attemptsByIndex and
incorrectIndices, set feedbackMessage to immediate correct/incorrect feedback
and optionally show the correct answer, disable navigation while answering (use
isEditing-like guard), and at the end (when currentIndex === totalQuestions-1 or
via a dedicated finish button) show a summary view (showSummary) with total
correct, list of incorrect questions and a "Retry Incorrect" button that calls
handleRetryIncorrect to reset currentIndex to the first incorrect index and
clear only those question attempt states; ensure existing functions
(handlePrevious, handleNext, generateGoogleForm) respect the new guards and that
shuffledOptions usage integrates with answer checking.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
eduaid_web/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (1)
eduaid_web/src/pages/Output.jsx
There was a problem hiding this comment.
🧹 Nitpick comments (5)
eduaid_web/src/pages/Output.jsx (5)
143-160: Consider providing user feedback on form generation failure.The error handling logs to console but the user receives no indication when form generation fails. Consider adding a toast notification or error state.
💡 Example approach using state
+ const [formError, setFormError] = useState(null); + const generateGoogleForm = async () => { + setFormError(null); try { const res = await apiClient.post("/generate_gform", { qa_pairs: qaPairs, question_type: questionType, }); const formUrl = res?.form_link; if (formUrl) { window.open(formUrl, "_blank", "noopener,noreferrer"); } else { console.error("Form link missing in response", res); + setFormError("Failed to generate form. Please try again."); } } catch (err) { console.error("Failed to generate Google Form:", err); + setFormError("Failed to generate form. Please try again."); } };Then render
{formError && <p className="text-red-500 text-sm">{formError}</p>}near the 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 143 - 160, The generateGoogleForm function currently only logs errors to the console; add user-facing feedback by introducing a state variable (e.g., formError or use a toast utility) and set it inside both the "else" branch when formUrl is missing and inside the catch block when the request fails, including a short, user-friendly message plus optional details; then update the component render to show {formError && <p className="text-red-500 text-sm">{formError}</p>} near the generate button (or trigger the toast) so users see failures related to qaPairs/questionType and API errors.
226-232: Answer editor field placement after options may confuse users.The answer input appears after the options list, which could lead users to think it's another option rather than the correct answer field. Consider adding a label or moving it to a more prominent position (e.g., immediately after the question textarea).
💡 Add a label for clarity
{/* ✅ Answer editor (CodeRabbit fix) */} +<label className="text-gray-400 text-sm mt-3 block">Correct Answer</label> <input value={editedAnswer} onChange={(e) => setEditedAnswer(e.target.value)} placeholder="Correct answer" - className="w-full p-2 mt-3 bg-black text-white rounded border border-gray-600" + className="w-full p-2 mt-1 bg-black text-white rounded border border-green-600" />🤖 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 - 232, The answer input (controlled by editedAnswer and setEditedAnswer) is currently rendered after the options list and may be mistaken for an option; relocate this input immediately after the question textarea or add a clear label (e.g., "Correct answer") and associate it with the input so users can’t confuse it with options—update the JSX where editedAnswer is used to either move the input node to just below the question textarea component or wrap it with a <label> and accessible attributes to clarify its purpose.
217-224: Inconsistent indentation in option inputs.The
<input>elements for editing options have inconsistent indentation compared to surrounding code (they're not indented within the parent block). This doesn't affect functionality but reduces readability.🧹 Consistent indentation
- {editedOptions.map((opt, i) => ( - <input - key={i} - value={opt} - onChange={(e) => handleOptionChange(i, e.target.value)} - className="w-full p-2 mt-2 bg-black text-white rounded" - /> -))} + {editedOptions.map((opt, i) => ( + <input + key={i} + value={opt} + onChange={(e) => handleOptionChange(i, e.target.value)} + className="w-full p-2 mt-2 bg-black text-white rounded" + /> + ))}🤖 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 - 224, The JSX block rendering editedOptions has inconsistent indentation for the input elements; tidy the formatting inside the map callback so the <input> is properly indented under the JSX expression for readability—locate the map over editedOptions and the onChange that calls handleOptionChange and align/indent the <input> tag and its props consistently with surrounding JSX.
202-207: Icon components render as separate elements without visible alignment.The icon components (
FiEdit2,FiCheck,FiX) are rendered adjacent to text without flex alignment, which may cause inconsistent vertical positioning. Addingflex items-center gap-1to these buttons would ensure proper alignment.💅 Proposed fix for button styling
- <button - className="mt-4 bg-teal-600 px-4 py-2 rounded text-white" + <button + className="mt-4 bg-teal-600 px-4 py-2 rounded text-white flex items-center gap-1" onClick={() => handleEditQuestion(currentIndex)} > <FiEdit2 /> Edit </button> ... - <button - onClick={() => handleSaveQuestion(currentIndex)} - className="bg-green-600 px-4 py-2 rounded text-white" + <button + onClick={() => handleSaveQuestion(currentIndex)} + className="bg-green-600 px-4 py-2 rounded text-white flex items-center gap-1" > <FiCheck /> Save </button> - <button - onClick={handleCancelEdit} - className="bg-gray-600 px-4 py-2 rounded text-white" + <button + onClick={handleCancelEdit} + className="bg-gray-600 px-4 py-2 rounded text-white flex items-center gap-1" > <FiX /> Cancel </button>Also applies to: 234-246
🤖 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 202 - 207, The button icons (FiEdit2, FiCheck, FiX) are not vertically aligned with their button text; update the button elements in Output.jsx (the buttons that call handleEditQuestion and the other buttons around lines with FiCheck/FiX) to include the Tailwind classes "flex items-center gap-1" on their className so the icon and text render as a single aligned inline row; adjust the className strings for the Edit button and the corresponding Confirm/Cancel buttons to include those classes.
172-175: Progress indicator is duplicated in header and navigation footer.The "Question X of Y" text appears both at line 174 (header) and line 265 (footer nav). While this may be intentional for UX, consider whether both are necessary since they show identical information and the page is a single-question view.
Also applies to: 264-266
🤖 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 172 - 175, The "Question X of Y" progress indicator is rendered twice in Output.jsx (header block inside the div with className "flex justify-between items-center px-6" and again in the footer nav around lines 264-266); remove the duplicate by keeping the indicator in the preferred location (either header or footer) and deleting the other JSX, or make it conditional (e.g., renderProgress && ...) so it only shows in one place; update any references to hasQuestions/currentIndex/totalQuestions in the removed location to avoid unused variables or dead JSX and ensure the remaining instance uses the existing state variables (hasQuestions, currentIndex, totalQuestions) to preserve functionality.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@eduaid_web/src/pages/Output.jsx`:
- Around line 143-160: The generateGoogleForm function currently only logs
errors to the console; add user-facing feedback by introducing a state variable
(e.g., formError or use a toast utility) and set it inside both the "else"
branch when formUrl is missing and inside the catch block when the request
fails, including a short, user-friendly message plus optional details; then
update the component render to show {formError && <p className="text-red-500
text-sm">{formError}</p>} near the generate button (or trigger the toast) so
users see failures related to qaPairs/questionType and API errors.
- Around line 226-232: The answer input (controlled by editedAnswer and
setEditedAnswer) is currently rendered after the options list and may be
mistaken for an option; relocate this input immediately after the question
textarea or add a clear label (e.g., "Correct answer") and associate it with the
input so users can’t confuse it with options—update the JSX where editedAnswer
is used to either move the input node to just below the question textarea
component or wrap it with a <label> and accessible attributes to clarify its
purpose.
- Around line 217-224: The JSX block rendering editedOptions has inconsistent
indentation for the input elements; tidy the formatting inside the map callback
so the <input> is properly indented under the JSX expression for
readability—locate the map over editedOptions and the onChange that calls
handleOptionChange and align/indent the <input> tag and its props consistently
with surrounding JSX.
- Around line 202-207: The button icons (FiEdit2, FiCheck, FiX) are not
vertically aligned with their button text; update the button elements in
Output.jsx (the buttons that call handleEditQuestion and the other buttons
around lines with FiCheck/FiX) to include the Tailwind classes "flex
items-center gap-1" on their className so the icon and text render as a single
aligned inline row; adjust the className strings for the Edit button and the
corresponding Confirm/Cancel buttons to include those classes.
- Around line 172-175: The "Question X of Y" progress indicator is rendered
twice in Output.jsx (header block inside the div with className "flex
justify-between items-center px-6" and again in the footer nav around lines
264-266); remove the duplicate by keeping the indicator in the preferred
location (either header or footer) and deleting the other JSX, or make it
conditional (e.g., renderProgress && ...) so it only shows in one place; update
any references to hasQuestions/currentIndex/totalQuestions in the removed
location to avoid unused variables or dead JSX and ensure the remaining instance
uses the existing state variables (hasQuestions, currentIndex, totalQuestions)
to preserve functionality.
|
Thanks for the review! ✅ Added user-facing error feedback for Google Form generation I’ve intentionally kept the progress indicator in both header and footer for better visibility while navigating questions. Please let me know if you’d like any further tweaks! |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
eduaid_web/src/pages/Output.jsx (2)
27-33: Options are re-shuffled for all questions when any question is edited.When
handleSaveQuestionupdatesqaPairs, thisuseMemorecomputes and callsshuffleArrayfor every question with freshMath.random()calls. This causes all questions' options to be reshuffled unexpectedly after editing a single question.Consider computing the shuffled options once (on initial load or explicit shuffle) and storing them in state, updating only the specific question's options when edited.
♻️ Suggested approach
-const shuffledOptionsMap = useMemo(() => { - return qaPairs.map((qa) => - qa.options - ? shuffleArray([...new Set([...(qa.options || []), qa.answer].filter(Boolean))]) - : [] - ); -}, [qaPairs]); +const [shuffledOptionsMap, setShuffledOptionsMap] = useState([]); + +// Compute shuffled options once when qaPairs is loaded +useEffect(() => { + setShuffledOptionsMap( + qaPairs.map((qa) => + qa.options + ? shuffleArray([...new Set([...(qa.options || []), qa.answer].filter(Boolean))]) + : [] + ) + ); +}, [qaPairs.length]); // Only recompute when count changes, not on editsThen update
handleSaveQuestionto also update the specific index inshuffledOptionsMapif options changed.🤖 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 27 - 33, The current useMemo for shuffledOptionsMap calls shuffleArray on every qaPairs change, causing all questions to reshuffle whenever any question is edited; instead initialize shuffledOptionsMap as component state (e.g., useState(() => ...)) once from qaPairs on mount or when explicitly shuffling, and remove the useMemo, then update only the specific index inside handleSaveQuestion when that question's options or answer change (use the same shuffleArray to generate the new options for that index and setState immutably); keep the symbols shuffledOptionsMap, shuffleArray, handleSaveQuestion and qaPairs to locate and modify the logic.
169-237: Add a friendly empty state when no questions are available.When
qaPairsis empty, the content area renders nothing. Consider showing a user-friendly message to guide users.💡 Proposed enhancement
<div className="flex-1 overflow-y-auto px-6 mt-4"> + {!hasQuestions && ( + <div className="text-gray-400 text-center py-8"> + No questions available. Please generate questions first. + </div> + )} {qaPair && (🤖 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 169 - 237, The view renders nothing when there are no questions (qaPairs empty / qaPair falsy); add a friendly empty state in the same container (inside the div with className "flex-1 overflow-y-auto px-6 mt-4") that displays a message like "No questions yet" and guidance plus an action button (e.g., "Create Question" or "Upload Questions") which calls an existing handler (or a new handler such as handleCreateQuestion) to start adding questions; ensure the empty-state is shown when qaPair is falsy or qaPairs.length === 0 and removed when currentIndex/qaPair exists so the existing edit/view UI (using qaPair, shuffledOptions, handleEditQuestion, handleSaveQuestion, handleCancelEdit) continues to work unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@eduaid_web/src/pages/Output.jsx`:
- Around line 27-33: The current useMemo for shuffledOptionsMap calls
shuffleArray on every qaPairs change, causing all questions to reshuffle
whenever any question is edited; instead initialize shuffledOptionsMap as
component state (e.g., useState(() => ...)) once from qaPairs on mount or when
explicitly shuffling, and remove the useMemo, then update only the specific
index inside handleSaveQuestion when that question's options or answer change
(use the same shuffleArray to generate the new options for that index and
setState immutably); keep the symbols shuffledOptionsMap, shuffleArray,
handleSaveQuestion and qaPairs to locate and modify the logic.
- Around line 169-237: The view renders nothing when there are no questions
(qaPairs empty / qaPair falsy); add a friendly empty state in the same container
(inside the div with className "flex-1 overflow-y-auto px-6 mt-4") that displays
a message like "No questions yet" and guidance plus an action button (e.g.,
"Create Question" or "Upload Questions") which calls an existing handler (or a
new handler such as handleCreateQuestion) to start adding questions; ensure the
empty-state is shown when qaPair is falsy or qaPairs.length === 0 and removed
when currentIndex/qaPair exists so the existing edit/view UI (using qaPair,
shuffledOptions, handleEditQuestion, handleSaveQuestion, handleCancelEdit)
continues to work unchanged.
|
All CodeRabbit feedback has been addressed. This signals confidence and closure. |
…fixes #474
Addressed Issues:
Fixes #474
Demo Flow:
Additional Notes:
Checklist
AI Usage Disclosure
Summary by CodeRabbit
New Features
UI/UX Changes
Improvements