FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Convert course-home tab data to React Query · Issue #1975 · openedx/frontend-app-learning · GitHub

Convert course-home tab data to React Query #1975

Description

Part of #1946 — Redux → React Query migration (Stage 1).

Goal: all course-tab data fetching on React Query; remove the courseHome reducer.

Two prerequisites were tracked as their own sub-issues: courseware search (#1979) and the CTA toast → ToastProvider (#1980) — the shared TabPage had to be off Redux before the tabs converted.

Done (each its own sub-issue of #1946, stacked in #2062)

Remaining — one layer, closes this issue

  • The slice is down to one live field, proctoringPanelStatus: written by ProctoringInfoPanel when its getProctoringInfoData fetch settles, read by OutlineTab (defers the weekly-goal card) and ProductTours (holds the outline tour until the card exists). Four other initial-state fields (courseStatus, courseId, errorMessage, errorCode) are dead.
  • Convert getProctoringInfoData to a useProctoringInfoData query; both readers read "settled" off the query's status (same key → one fetch); the panel derives its display state from data instead of six useStates.
  • Delete slice.js and course-home/data/index.js; drop courseHome from store.ts and setupTest.js's initializeTestStore.

Verify: courseHome reducer gone (store.ts = models + specialExams + plugins); outline tab still defers the weekly-goal card until the proctoring panel settles; outline-tab tour still waits for it; git grep courseHome src/store.ts src/setupTest.js empty; Pact test green.

Note

The plan below was written by Claude (Claude Code) and reviewed before posting.

Plan for the close-out layer

Why a query, not lifted state

The Redux field is a hand-rolled loading flag for one fetch. The tab conversions already replaced such flags (courseStatus strings) with query state, so the same move applies: make the fetch a query and read isPending off it. Both readers call the hook; React Query dedupes by key; no new context or lifted useState.

Pieces

  1. course-home/data/queryKeys.ts + apiHooks.ts — proctoringInfo(courseId, username) key; useProctoringInfoData(courseId, username, enabled = true) wrapping the unchanged getProctoringInfoData (its 404 → {} mapping stays in the api).
  2. ProctoringInfoPanel.jsx — replace the mount effect + six useStates with the query and plain derivation from data (status, link, expiry → readable status, release date, past-due, show-panel = non-empty response). The response is raw snake_case today; keep the reads or camelCase in the hook — same rendered output either way. useDispatch, the slice import, and the exhaustive-deps disable leave.
  3. OutlineTab.jsx — (!enableProctoredExams || proctoringPanelStatus === 'loaded') → (!enableProctoredExams || !isPending) from the same hook (username already in scope from courseHomeMeta).
  4. ProductTours.jsx — same hook with enabled: outlineTabActive (the panel only ever mounted on the outline tab, so no new request elsewhere). Username must be the courseHomeMeta one the panel keys on (masquerade-aware), not getAuthenticatedUser().username, or the query key forks under masquerade — LoadedTabPage already reads courseHomeMeta and passes it as a prop (revisit at code review).
  5. Delete slice.js, course-home/data/index.js; drop courseHome from store.ts and initializeTestStore. Check whether LOADED in constants.ts loses its last importer.

Settled-vs-error (decided: !isPending + retry: false)

The panel's .catch(() => {}) and .finally(resolve) were added together in PR #727 (2021) so the goals widget would never stay hidden because of this request — settling on any outcome is the intent. The catch's "API throws 404" comment was already wrong when written (the api had mapped 404 → {} since the panel's first commits), and before #727 a 5xx surfaced as an unhandled rejection, so silencing real failures was a side effect, not a choice. The query keeps the intent and drops the accident: readers gate on !isPending (never isSuccess); retry: false so a failure settles immediately as #727 designed rather than after the app default's ~7s of 5xx retries; no swallow in queryFn, so the error reaches the app QueryCache.onError and is logged. Rendered output on error is unchanged (no data → panel hidden).

Tests

  • apiHooks.test.tsx: payload resolves; 404 → {}; enabled: false idle; non-404 → isError.
  • OutlineTab.test.jsx: the existing proctoring block renders the panel against a mocked endpoint and should pass unchanged; add a weekly-goal-deferral case if none asserts the gate today.
  • ProductTours.test.jsx: already mocks the proctoring URL (404) so the outline tour proceeds; passes once the hook keys on the same username the mock uses.

Commit

refactor: retire the courseHome Redux slice — Closes #1975. Not breaking: proctoringPanelStatus was never a documented or plugin-facing surface.

After this layer

Stack #2062 layer 16. Then #2017 (plugins reducer) and #1977 (models reducer), leaving store.ts at specialExams only — #1978's endpoint.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions


Back | FazBrowse Home | New Git URL