Part of #1946 — Redux → React Query migration (Stage 1). Part of the #1976 courseware decomposition (plan) — Target 3 (bookmarking). Stacked on the sequence conversion (owns the units model).
Goal: convert bookmarking to React Query and drop UnitButton's connect.
Tasks
- Convert
addBookmark / removeBookmark (src/courseware/course/bookmark/data/thunks.js) → useMutation, optimistically patching bookmarked / bookmarkedUpdateState on the units cache.
- De-class
src/courseware/course/sequence/sequence-navigation/UnitButton.jsx: replace its connect (state.models.units[unitId] + state.courseware.{courseId,sequenceId}) with useModel / useParams reads.
UnitTitleSlot continues to read bookmarked from the units model.
Verify: bookmark toggle works (optimistic + rollback on error); UnitButton renders bookmark/complete/title identically; no connect left in UnitButton.
Scoped-but-light; a full plan gets added when this is picked up.
Part of #1946 — Redux → React Query migration (Stage 1). Part of the #1976 courseware decomposition (plan) — Target 3 (bookmarking). Stacked on the sequence conversion (owns the
unitsmodel).Goal: convert bookmarking to React Query and drop
UnitButton'sconnect.Tasks
addBookmark/removeBookmark(src/courseware/course/bookmark/data/thunks.js) →useMutation, optimistically patchingbookmarked/bookmarkedUpdateStateon theunitscache.src/courseware/course/sequence/sequence-navigation/UnitButton.jsx: replace itsconnect(state.models.units[unitId]+state.courseware.{courseId,sequenceId}) withuseModel/useParamsreads.UnitTitleSlotcontinues to readbookmarkedfrom theunitsmodel.Verify: bookmark toggle works (optimistic + rollback on error);
UnitButtonrenders bookmark/complete/title identically; noconnectleft inUnitButton.Scoped-but-light; a full plan gets added when this is picked up.