Skip to content

feat(rq): migrate data-fetching hooks to React Query - #12

Merged
Truella merged 7 commits into
masterfrom
feat/react-query
Jul 29, 2026
Merged

feat(rq): migrate data-fetching hooks to React Query#12
Truella merged 7 commits into
masterfrom
feat/react-query

Conversation

@Truella

@Truella Truella commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary
Migrates all data-fetching hooks to React Query (@tanstack/react-query). Benefits: automatic caching (navigating back to My Quizzes is instant), request deduplication, background refetching on window focus, and 30-second polling on stats and quiz attempt counts so creators see updated numbers without refreshing. Mutations in useQuizDetail now invalidate related queries automatically instead of manually patching local state. No UI changes — purely the data layer.

New dependency: @tanstack/react-query

Changed files

  • package.json
  • src/components/ReactQueryProvider.tsx (new)
  • app/layout.tsx
  • src/hooks/useQuizzes.ts
  • src/hooks/useStats.ts
  • src/hooks/useQuizBank.ts
  • src/hooks/useQuizDetail.ts
  • src/hooks/useRating.ts
  • src/hooks/useTakeQuiz.ts

Checklist

  • npm install @tanstack/react-query completed

  • npx tsc --noEmit passes

  • npx next lint passes with zero warnings

  • My Quizzes loads — navigating away and back is instant (cached)

  • Dashboard stats poll every 30 seconds

  • Quiz detail attempt count updates without refresh

  • Quiz Bank filter changes trigger new fetch

  • Taking a quiz still works end-to-end

  • Rating submission still works

  • Branch up to date with main

  • No console.log statements

Summary by CodeRabbit

  • New Features
    • Added React Query integration to centralize data fetching for quizzes, quiz details, ratings, statistics, and quiz-taking.
    • Automatic polling for quiz attempts and refreshed statistics, with filter-aware refetching and smoother cached navigation.
  • Bug Fixes
    • Improved edit/delete/rating flows using cache updates/invalidation and more consistent success/error toasts.
    • Reduced loading flashes during navigation and state transitions.
  • Documentation
    • Added a step-by-step React Query migration guide with a verification checklist.
  • Tests
    • Updated hook tests to use a React Query provider and improved async assertions for query-driven state changes.

- Refactored useRating to utilize useQuery for fetching ratings and useMutation for submitting ratings, improving data handling and caching.
- Migrated useStats to useQuery with polling for real-time stats updates.
- Updated useTakeQuiz to replace manual data fetching with useQuery for quiz and questions, maintaining local state for UI.
- Created ReactQueryProvider to wrap the application with QueryClientProvider for React Query setup.
- Cleaned up unused imports across various hooks after migration.
- Ensured all hooks maintain the same return shape and functionality, with no UI changes.
@vercel

vercel Bot commented Jul 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
prep Ready Ready Preview, Comment Jul 29, 2026 4:06pm

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The application adds a shared React Query provider and migrates quiz, statistics, rating, quiz-detail, quiz-bank, and quiz-taking data fetching to React Query queries and mutations with caching, invalidation, and polling.

Changes

React Query migration

Layer / File(s) Summary
Query provider and application wiring
package.json, src/components/ReactQueryProvider.tsx, app/layout.tsx, docs/PREP_REACT_QUERY_PRT.md
Adds TanStack React Query, configures a persistent QueryClient, wraps the application provider tree, and documents the staged migration and verification steps.
Dashboard and catalog queries
src/hooks/useQuizzes.ts, src/hooks/useStats.ts, src/hooks/useQuizBank.ts, src/hooks/useQuizBank.test.ts
Replaces manual fetching with cached queries, derived loading and error state, stats polling, filter-based keys, and optimistic quiz deletion updates; updates query-specific test setup and asynchronous assertions.
Quiz detail and rating mutations
src/hooks/useQuizDetail.ts, src/hooks/useRating.ts, src/hooks/useRating.test.ts
Splits quiz-detail data into queries, adds attempt polling, migrates persistence to mutations, synchronizes related caches, and preserves toast feedback.
Quiz-taking query integration
src/hooks/useTakeQuiz.ts, src/hooks/useTakeQuiz.test.ts
Loads quiz metadata and questions with React Query while retaining local timer and progress state, including saved-result restoration and expired-attempt submission.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant ReactQueryProvider
  participant QuizHook
  participant Supabase
  App->>ReactQueryProvider: render application subtree
  ReactQueryProvider->>QuizHook: provide QueryClient
  QuizHook->>Supabase: request quiz data
  Supabase-->>QuizHook: return query data
  QuizHook->>ReactQueryProvider: update query cache
Loading

Possibly related PRs

  • Truella/prep#1: Both changes modify useTakeQuiz data-fetching and question transformation logic.
  • Truella/prep#2: Adds tests for the useTakeQuiz hook migrated here.
  • Truella/prep#11: Overlaps with the React Query rewrite of useQuizDetail and its quiz-detail CRUD behavior.
🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: migrating data-fetching hooks to React Query.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/react-query

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

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

⚠️ Outside diff range comments (1)
src/hooks/useTakeQuiz.ts (1)

152-160: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Await the auto-submit insert before advancing. This branch starts supabase.from("quiz_attempts").insert(...) without awaiting it, so the try/catch cannot handle a failure and the hook still clears the deadline and shows results even if persistence fails. Await the insert, handle the returned error, and transition only after success.

🤖 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/hooks/useTakeQuiz.ts` around lines 152 - 160, Update the auto-submit
persistence branch in useTakeQuiz to await the
supabase.from("quiz_attempts").insert operation, inspect its returned error, and
handle failures through the existing catch path. Only clear the deadline and
advance to the results state after the insert succeeds.
🤖 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/hooks/useQuizDetail.ts`:
- Around line 62-65: Add the same enabled: !!quizId guard used by questionsQuery
and attemptsQuery to the quizQuery options, ensuring fetchQuiz does not run
until quizId is truthy.
- Around line 171-174: Update the saving value in useQuizDetail to include
deleteQuizMutation.isPending alongside the existing mutation pending states, so
it remains true while quiz deletion is in progress.
- Around line 159-163: Update the error computation in useQuizDetail so it also
reports failures from questionsQuery and attemptsQuery, rather than only
quizQuery.error. Preserve the existing null result when all three queries
succeed, and use the first available query error’s message consistently.

In `@src/hooks/useQuizzes.ts`:
- Around line 48-63: Update deleteQuiz to invalidate the ["stats"] query after a
successful quiz deletion, alongside the existing ["quizzes"] cache update,
matching useQuizDetail's deleteQuizMutation behavior.

In `@src/hooks/useRating.ts`:
- Around line 54-62: Update the onSuccess handler in the useMutation
configuration within useRating to also invalidate the quiz-detail query keyed by
["quiz", quizId], while preserving the existing rating cache update and quizBank
invalidation.

In `@src/hooks/useStats.ts`:
- Around line 10-49: Remove the separate quizCount query from fetchStats and use
userQuizzes.length for totalQuizzes, while preserving the existing quizIds,
question, and attempt counting behavior.

In `@src/hooks/useTakeQuiz.ts`:
- Around line 138-150: Update the deadline initialization in useTakeQuiz so a
new deadline is created only when deadline is absent, not when it is expired.
Preserve the existing expired deadline and its storage value, allowing the
remaining <= 0 branch to set the timer to zero and trigger auto-submit.
- Around line 79-95: Update the useTakeQuiz query destructuring to capture
questionsError from the questions useQuery, then include it when deriving the
returned error alongside quizError. Preserve the existing loading behavior and
message extraction, while ensuring either query failure produces a non-null
error.
- Around line 124-129: Replace the global boolean guard in useTakeQuiz with
tracking for the initialized quiz ID, and update the initialization check to
allow setup when the current quizId differs. Store the current quizId after
initializing so switching quizzes reinitializes the deadline and timer while
preventing duplicate initialization for the same quiz.

---

Outside diff comments:
In `@src/hooks/useTakeQuiz.ts`:
- Around line 152-160: Update the auto-submit persistence branch in useTakeQuiz
to await the supabase.from("quiz_attempts").insert operation, inspect its
returned error, and handle failures through the existing catch path. Only clear
the deadline and advance to the results state after the insert succeeds.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 87ace30d-16fa-4295-bf01-ed72e56ead90

📥 Commits

Reviewing files that changed from the base of the PR and between c84e916 and 24a4226.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • app/layout.tsx
  • docs/PREP_REACT_QUERY_PRT.md
  • package.json
  • src/components/ReactQueryProvider.tsx
  • src/hooks/useQuizBank.ts
  • src/hooks/useQuizDetail.ts
  • src/hooks/useQuizzes.ts
  • src/hooks/useRating.ts
  • src/hooks/useStats.ts
  • src/hooks/useTakeQuiz.ts

Comment thread src/hooks/useQuizDetail.ts
Comment thread src/hooks/useQuizDetail.ts Outdated
Comment thread src/hooks/useQuizDetail.ts Outdated
Comment thread src/hooks/useQuizzes.ts
Comment thread src/hooks/useRating.ts
Comment thread src/hooks/useStats.ts Outdated
Comment thread src/hooks/useTakeQuiz.ts Outdated
Comment thread src/hooks/useTakeQuiz.ts Outdated
Comment thread src/hooks/useTakeQuiz.ts Outdated
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Mistura <101476258+Truella@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
src/hooks/useStats.ts (2)

47-55: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Scope the stats cache by user.

useQuery uses the shared key ["stats"], but fetchStats() reads the authenticated user at runtime. Include the user ID in the key or reset this query on auth changes so a new session can’t reuse the previous account’s cached totals.

🤖 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/hooks/useStats.ts` around lines 47 - 55, Update useAnalyticsStats to
include the authenticated user ID in the useQuery queryKey, ensuring stats
caches are isolated per account and a new session cannot reuse another user’s
totals; keep fetchStats and the existing loading/default behavior unchanged.

10-17: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Throw Supabase errors and scope the stats cache by user. The auth, quiz, question, and attempt queries currently collapse failures into zero stats, so React Query treats them as success and won’t retry. queryKey: ["stats"] is also shared across sessions, and select("id") without pagination can truncate at Supabase’s 1,000-row cap; include user.id in the key or clear it on auth changes, and page through quiz IDs.

🤖 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/hooks/useStats.ts` around lines 10 - 17, Update fetchStats and its React
Query configuration to propagate errors from the auth, quiz, question, and
attempt Supabase queries instead of converting failures into zero values, while
preserving the unauthenticated zero-stats result. Scope the stats queryKey by
user.id (or clear the cache on auth changes), and paginate the quizzes query so
all quiz IDs are processed beyond Supabase’s 1,000-row limit.
🤖 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/hooks/useStats.ts`:
- Around line 14-20: Update the quiz-loading logic in useStats to avoid
Supabase’s 1,000-row limit before deriving quizIds and quizCount: either
paginate all matching quizzes or use a server-side aggregate/RPC that returns
the required quiz, question, and attempt counts. Ensure totalQuizzes,
totalQuestions, and totalAttempts remain accurate for users with more than 1,000
quizzes.

---

Outside diff comments:
In `@src/hooks/useStats.ts`:
- Around line 47-55: Update useAnalyticsStats to include the authenticated user
ID in the useQuery queryKey, ensuring stats caches are isolated per account and
a new session cannot reuse another user’s totals; keep fetchStats and the
existing loading/default behavior unchanged.
- Around line 10-17: Update fetchStats and its React Query configuration to
propagate errors from the auth, quiz, question, and attempt Supabase queries
instead of converting failures into zero values, while preserving the
unauthenticated zero-stats result. Scope the stats queryKey by user.id (or clear
the cache on auth changes), and paginate the quizzes query so all quiz IDs are
processed beyond Supabase’s 1,000-row limit.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 03ddd908-e1c6-4cb3-ab45-a1ababbd285d

📥 Commits

Reviewing files that changed from the base of the PR and between 24a4226 and 774ab29.

📒 Files selected for processing (1)
  • src/hooks/useStats.ts

Comment thread src/hooks/useStats.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (3)
src/hooks/useRating.ts (2)

48-67: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Surface rating fetch failures. fetchRating ignores Supabase errors, so a failed load still resolves to null and looks like “no rating.” Propagate the query error, then return it alongside mutation.error, and add a fetch-failure test.

🤖 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/hooks/useRating.ts` around lines 48 - 67, Update fetchRating and the
useQuery flow in useRating so Supabase fetch errors are propagated instead of
resolving as null. Return the query’s fetch error alongside any mutation error
through the hook’s error field, and add a test covering a failed rating fetch
and the resulting error.

16-42: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Remove the client-side average recomputation.
The database trigger on quiz_ratings already keeps quizzes.average_rating in sync; this extra select/update can race with concurrent ratings and overwrite the correct value with a stale average. Delete the post-upsert update.

🤖 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/hooks/useRating.ts` around lines 16 - 42, Remove the post-upsert ratings
select and average calculation from upsertRating; leave only the quiz_ratings
upsert and its existing error handling, relying on the database trigger to
maintain quizzes.average_rating.
src/hooks/useTakeQuiz.ts (1)

165-176: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Persist expired auto-submit before clearing state src/hooks/useTakeQuiz.ts:165-176 — this branch fires quiz_attempts.insert(...) without awaiting it and never writes quiz_results_${quizId}. Reuse the same saveAttempt/localStorage path as handleTimerExpire, and clear the deadline/set submitted state only after persistence succeeds.

🤖 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/hooks/useTakeQuiz.ts` around lines 165 - 176, The expired auto-submit
branch in useTakeQuiz must persist the attempt before clearing state. Reuse the
existing saveAttempt and quiz_results_${quizId} localStorage flow from
handleTimerExpire, await persistence, and only then call clearDeadline,
setShowResults, and setIsSubmitted; remove the unawaited direct supabase insert
and empty catch.
🤖 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/hooks/useQuizBank.test.ts`:
- Around line 7-8: Name the QueryClientProvider wrapper returned by the test
helper to satisfy the react/display-name rule. Update the anonymous component
around QueryClientProvider by defining a named wrapper or assigning its
displayName before returning it, while preserving the existing queryClient and
children behavior.

In `@src/hooks/useRating.test.ts`:
- Around line 7-8: In the QueryClientProvider wrapper returned by the test
setup, replace the anonymous component with a named wrapper or assign it an
explicit displayName before returning it, while preserving the existing
queryClient and children behavior.

In `@src/hooks/useTakeQuiz.test.ts`:
- Around line 5-8: Update createWrapper to return a named ReactQueryTestWrapper
component instead of an anonymous function, preserving the existing
QueryClientProvider setup and retry configuration.

---

Outside diff comments:
In `@src/hooks/useRating.ts`:
- Around line 48-67: Update fetchRating and the useQuery flow in useRating so
Supabase fetch errors are propagated instead of resolving as null. Return the
query’s fetch error alongside any mutation error through the hook’s error field,
and add a test covering a failed rating fetch and the resulting error.
- Around line 16-42: Remove the post-upsert ratings select and average
calculation from upsertRating; leave only the quiz_ratings upsert and its
existing error handling, relying on the database trigger to maintain
quizzes.average_rating.

In `@src/hooks/useTakeQuiz.ts`:
- Around line 165-176: The expired auto-submit branch in useTakeQuiz must
persist the attempt before clearing state. Reuse the existing saveAttempt and
quiz_results_${quizId} localStorage flow from handleTimerExpire, await
persistence, and only then call clearDeadline, setShowResults, and
setIsSubmitted; remove the unawaited direct supabase insert and empty catch.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: af2de30f-45ab-47f2-9629-b13c738f31f9

📥 Commits

Reviewing files that changed from the base of the PR and between 774ab29 and fd2e291.

📒 Files selected for processing (5)
  • src/hooks/useQuizBank.test.ts
  • src/hooks/useRating.test.ts
  • src/hooks/useRating.ts
  • src/hooks/useTakeQuiz.test.ts
  • src/hooks/useTakeQuiz.ts

Comment thread src/hooks/useQuizBank.test.ts Outdated
Comment thread src/hooks/useRating.test.ts Outdated
Comment thread src/hooks/useTakeQuiz.test.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
src/hooks/useTakeQuiz.ts (2)

203-226: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Claim the submission guard before starting expiry persistence.

This path starts saveAttempt while submittedRef.current remains false. A timer callback or manual confirmation during the pending insert can pass the same guard and create duplicate quiz_attempts rows. Set the guard before the async call; reset it and surface an error only if persistence fails.

🤖 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/hooks/useTakeQuiz.ts` around lines 203 - 226, Update the expiry handler
in useTakeQuiz around saveAttempt to claim submittedRef.current before starting
the asynchronous persistence, preventing timer or manual-submit callbacks from
entering concurrently. If saveAttempt fails, reset the guard and surface the
persistence error; otherwise preserve the existing result-display and
localStorage flow.

173-210: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Restore saved progress before scoring an expired quiz.

The expiry effect runs before the restoration effect at Lines 239-268. On reload after expiry, saveAttempt captures the initial empty selectedAnswers, so persisted in-progress answers are replaced by a zero-score auto-submission. Gate deadline initialization/auto-submit on completion of progress restoration, and add a regression test with saved answers plus an expired deadline.

🤖 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/hooks/useTakeQuiz.ts` around lines 173 - 210, Update the initialization
effect around initializedQuizIdRef and its expired-deadline auto-submit so it
waits for the progress-restoration flow to complete before calculating or saving
the attempt. Ensure restored selectedAnswers are used when saveAttempt runs for
an already expired quiz, while preserving normal deadline initialization and
auto-submit behavior; add a regression test covering saved answers with an
expired deadline.
🤖 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/hooks/useStats.ts`:
- Around line 43-51: Move the question and attempt count aggregation out of the
client-side quizIds filter in the stats-loading flow of useStats: replace both
.in("quiz_id", quizIds) queries with a server-side RPC or view that scopes
results by the current user's created_by value. Preserve the existing count
results and Promise.all behavior without serializing the full quiz ID list into
the request.

In `@src/hooks/useTakeQuiz.ts`:
- Around line 208-226: Update the async submission flow in useTakeQuiz so the
effect creates a cancellation flag tied to the current quizId and returns
cleanup that marks it inactive. After saveAttempt(elapsedTotal) resolves, verify
the effect is still active and quizId remains current before calling
clearDeadline, setShowResults, setIsSubmitted, or saving quiz results; ensure
the async callback does not update state for an older quiz.
- Around line 159-167: Update the quiz-attempt persistence flow in useTakeQuiz
around the supabase.from("quiz_attempts").insert call to capture and inspect its
returned error before returning true. On database failure, propagate or handle
the error through the existing catch path so deadline clearing and result
display only occur after a successful insert.

---

Outside diff comments:
In `@src/hooks/useTakeQuiz.ts`:
- Around line 203-226: Update the expiry handler in useTakeQuiz around
saveAttempt to claim submittedRef.current before starting the asynchronous
persistence, preventing timer or manual-submit callbacks from entering
concurrently. If saveAttempt fails, reset the guard and surface the persistence
error; otherwise preserve the existing result-display and localStorage flow.
- Around line 173-210: Update the initialization effect around
initializedQuizIdRef and its expired-deadline auto-submit so it waits for the
progress-restoration flow to complete before calculating or saving the attempt.
Ensure restored selectedAnswers are used when saveAttempt runs for an already
expired quiz, while preserving normal deadline initialization and auto-submit
behavior; add a regression test covering saved answers with an expired deadline.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: eb8f0bf4-1713-4b73-a15d-18e244592084

📥 Commits

Reviewing files that changed from the base of the PR and between fd2e291 and 19e11f1.

📒 Files selected for processing (8)
  • src/hooks/useQuizBank.test.ts
  • src/hooks/useQuizDetail.ts
  • src/hooks/useQuizzes.ts
  • src/hooks/useRating.test.ts
  • src/hooks/useRating.ts
  • src/hooks/useStats.ts
  • src/hooks/useTakeQuiz.test.ts
  • src/hooks/useTakeQuiz.ts

Comment thread src/hooks/useStats.ts Outdated
Comment thread src/hooks/useTakeQuiz.ts
Comment thread src/hooks/useTakeQuiz.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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/hooks/useStats.ts`:
- Around line 16-33: Update fetchStats to accept and use the query’s user.id
instead of independently calling supabase.auth.getUser(), then pass that ID
through the stats query configuration. Add enabled: !!user to prevent execution
without an authenticated user while preserving the existing query key.

In `@src/hooks/useTakeQuiz.test.ts`:
- Around line 266-288: Extend the expired-deadline test around useTakeQuiz to
inspect the quiz_attempts insert call and assert its payload preserves the saved
answer { 0: 3 } instead of submitting an empty answers object. Keep the existing
UI assertions, and target the mocked Supabase insert invocation after
auto-submission completes.

In `@src/hooks/useTakeQuiz.ts`:
- Around line 213-220: Update the submission flow in useTakeQuiz around
readSavedResults and saveAttempt to hydrate completion state before inserting an
attempt: skip saveAttempt when completed quiz_results already exist, and
otherwise restore answers from quiz_progress when no completed results are
available. Ensure the restored progress answers, rather than an empty fallback,
are passed to setSelectedAnswers and saveAttempt.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ea59ac84-4c47-42b3-903b-86390eb8c3b1

📥 Commits

Reviewing files that changed from the base of the PR and between 19e11f1 and d7d0f10.

📒 Files selected for processing (3)
  • src/hooks/useStats.ts
  • src/hooks/useTakeQuiz.test.ts
  • src/hooks/useTakeQuiz.ts

Comment thread src/hooks/useStats.ts
Comment thread src/hooks/useTakeQuiz.test.ts
Comment thread src/hooks/useTakeQuiz.ts Outdated
@Truella
Truella merged commit bef5349 into master Jul 29, 2026
5 checks passed
@Truella
Truella deleted the feat/react-query branch July 29, 2026 16:08
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