Skip to content

feat: migrate track chair list and edit to mui components#918

Open
tomrndom wants to merge 4 commits into
masterfrom
fix/track-chair-list-mui
Open

feat: migrate track chair list and edit to mui components#918
tomrndom wants to merge 4 commits into
masterfrom
fix/track-chair-list-mui

Conversation

@tomrndom
Copy link
Copy Markdown

@tomrndom tomrndom commented May 6, 2026

ref: https://app.clickup.com/t/86b9pc89t

image image

Signed-off-by: Tomás Castillo tcastilloboireau@gmail.com

Summary by CodeRabbit

  • New Features

    • Added a modal dialog for creating/editing track chairs with member autocomplete and multi-track selection.
  • Refactor

    • Rewrote the track chair list to a hooks-based component and migrated the UI to Material-UI for a cleaner, consistent table and dialog workflow.
  • Bug Fixes

    • Improved error feedback with snackbars, ensured loading indicators always clear, and fixed CSV export flow.
  • Documentation

    • Updated track chair deletion confirmation text.

Review Change Stack

Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fbb4488a-4c68-4e6b-b7cc-8e455c139770

📥 Commits

Reviewing files that changed from the base of the PR and between 0cb4096 and d6f6226.

📒 Files selected for processing (2)
  • src/pages/track_chairs/components/track-chair-dialog.js
  • src/pages/track_chairs/track-chair-list-page.js

📝 Walkthrough

Walkthrough

Refactors Track Chairs to a hooks-based MUI page, adds a Formik-based TrackChairDialog, updates track-chair action requests/error handling (adds member.id, passes meta, uses snackbarErrorHandler and .finally()), adjusts reducer reset/perPage behavior, and tweaks an i18n delete warning string.

Changes

Track Chairs UI Modernization & Error Handling

Layer / File(s) Summary
Action creators: requests & error handling
src/actions/track-chair-actions.js
Adds member.id to fields; getTrackChairs now sends meta { trackId, term, order, orderDir, perPage }; replaces authErrorHandler with snackbarErrorHandler; uses .finally() to ensure stopLoading().
Reducer: reset & perPage
src/reducers/track_chairs/track-chair-list-reducer.js
Resets reducer on SET_CURRENT_SUMMIT and LOGOUT_USER; REQUEST_TRACK_CHAIRS stores perPage; RECEIVE_TRACK_CHAIRS uses shorthand for trackChairs.
TrackChairDialog component
src/pages/track_chairs/components/track-chair-dialog.js
New TrackChairDialog: Formik form with Yup validation (member required, >=1 track), async member autocomplete helpers, multi-select tracks with removable chips, reinitialization on entity change, PropTypes, default export.
TrackChairListPage functional rewrite & MUI table
src/pages/track_chairs/track-chair-list-page.js
Replaces class component with functional hooks-based component using MUI: search/filter/sort/pagination handlers, MuiTable wiring, dialog open/edit/save/delete flows, and export action wiring.
Localization tweak
src/i18n/en.json
Updated track_chairs.delete_warning to "Are you sure you want to remove track chair for".

Sequence Diagram(s)

sequenceDiagram
participant UI as TrackChairListPage
participant Dialog as TrackChairDialog
participant Actions as track-chair-actions
participant API as BackendAPI

UI->>Actions: getTrackChairs(meta: trackId, term, order, perPage)
Actions->>API: GET /track-chairs?meta...
API-->>Actions: 200 + track chairs
Actions->>UI: dispatch RECEIVE_TRACK_CHAIRS
UI->>Dialog: open (new/edit)
Dialog->>Actions: addTrackChair / saveTrackChair (payload)
Actions->>API: POST/PUT /track-chairs
API-->>Actions: 200/201 or error
Actions->>UI: success -> refresh list
Actions->>UI: error -> snackbarErrorHandler shows message
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • smarcet

"I'm a rabbit in the code-filled glade,
I hop through dialogs that devs have made,
Hooks and snackbars line the track,
Chips fall off, I put them back,
I celebrate with a carrot cascade 🥕"

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: migrate track chair list and edit to mui components' directly and accurately reflects the main changes: rewriting the track chair list page from class to functional component with MUI components, and adding a new MUI-based dialog for editing/adding track chairs.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/track-chair-list-mui

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: 2

Caution

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

⚠️ Outside diff range comments (1)
src/actions/track-chair-actions.js (1)

149-157: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Always clear loading state on add failures.

This path still dispatches stopLoading() only on success. If postRequest rejects, the global loading state stays active and the new dialog flow gets stuck after a failed create.

Suggested fix
     return postRequest(
       null,
       createAction(TRACK_CHAIR_ADDED),
       `${window.API_BASE_URL}/api/v1/summits/${currentSummit.id}/track-chairs`,
       { member_id: member.id, categories: trackIds },
       snackbarErrorHandler
-    )(params)(dispatch).then(() => {
+    )(params)(dispatch).finally(() => {
       dispatch(stopLoading());
     });
🤖 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/actions/track-chair-actions.js` around lines 149 - 157, The
add-track-chair flow only calls dispatch(stopLoading()) in the success .then,
leaving the global loading state active on postRequest rejection; update the
returned promise chain that wraps postRequest(...)(params)(dispatch) so that
dispatch(stopLoading()) runs regardless of outcome (use .finally or a .catch
that rethrows after dispatching stopLoading()). Reference the postRequest call
that uses createAction(TRACK_CHAIR_ADDED), snackbarErrorHandler, and ensure
stopLoading is dispatched in the failure path as well.
🤖 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/pages/track_chairs/track-chair-list-page.js`:
- Around line 125-131: The current handleSave treats a changed member in edit
mode as an add, causing duplicate assignments; update handleSave to perform an
explicit replace instead of add when dialogEntity?.originalMemberId !==
member?.value and id exists: either call a replaceTrackChair(member.value, id,
trackIds) helper (preferred) or sequentially call removeTrackChair(id) then
addTrackChair({ id: member.value }, trackIds), and finally clear the dialog;
alternatively, if reassignment is not allowed make the member field read-only in
edit mode (in the dialog render) so the branch to addTrackChair never runs for
edits. Ensure you reference dialogEntity.originalMemberId, handleSave,
addTrackChair, saveTrackChair and remove/replace helper names when implementing
the change.
- Around line 57-63: The early return based on currentSummit.id happens before
hooks run and can cause hook-order errors; keep the declarations (e.g., const
[dialogEntity, setDialogEntity] = useState(null)) and the useEffect hook in
place, move the render guard that checks currentSummit.id below the hooks (so
hooks always register), and change the effect to depend on currentSummit?.id
(useEffect(() => { if (currentSummit?.id) getTrackChairs(); },
[currentSummit?.id])) so getTrackChairs runs when the summit arrives.

---

Outside diff comments:
In `@src/actions/track-chair-actions.js`:
- Around line 149-157: The add-track-chair flow only calls
dispatch(stopLoading()) in the success .then, leaving the global loading state
active on postRequest rejection; update the returned promise chain that wraps
postRequest(...)(params)(dispatch) so that dispatch(stopLoading()) runs
regardless of outcome (use .finally or a .catch that rethrows after dispatching
stopLoading()). Reference the postRequest call that uses
createAction(TRACK_CHAIR_ADDED), snackbarErrorHandler, and ensure stopLoading is
dispatched in the failure path as well.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: f4ec317b-b43b-40a7-8d38-7a99aa796a4b

📥 Commits

Reviewing files that changed from the base of the PR and between 8607ac5 and e7841ab.

📒 Files selected for processing (5)
  • src/actions/track-chair-actions.js
  • src/i18n/en.json
  • src/pages/track_chairs/components/track-chair-dialog.js
  • src/pages/track_chairs/track-chair-list-page.js
  • src/reducers/track_chairs/track-chair-list-reducer.js

Comment thread src/pages/track_chairs/track-chair-list-page.js Outdated
Comment on lines +125 to +131
const handleSave = ({ id, member, trackIds }) => {
const newMember = dialogEntity?.originalMemberId !== member?.value;
const action =
!id || newMember
? addTrackChair({ id: member.value }, trackIds)
: saveTrackChair(id, trackIds);
action.then(() => setDialogEntity(null));
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 | 🟠 Major | ⚡ Quick win

Editing the member currently creates a second assignment.

saveTrackChair only updates categories, so this branch to addTrackChair(...) leaves the original record in place when the member changes. In edit mode that turns a reassignment into a duplicate track-chair entry.

Suggested fix
   const handleSave = ({ id, member, trackIds }) => {
-    const newMember = dialogEntity?.originalMemberId !== member?.value;
-    const action =
-      !id || newMember
-        ? addTrackChair({ id: member.value }, trackIds)
-        : saveTrackChair(id, trackIds);
+    const action = !id
+      ? addTrackChair({ id: member.value }, trackIds)
+      : saveTrackChair(id, trackIds);
     action.then(() => setDialogEntity(null));
   };

If member reassignment is supposed to be supported here, it needs an explicit replace flow; otherwise the member field should be read-only in edit mode.

🤖 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/pages/track_chairs/track-chair-list-page.js` around lines 125 - 131, The
current handleSave treats a changed member in edit mode as an add, causing
duplicate assignments; update handleSave to perform an explicit replace instead
of add when dialogEntity?.originalMemberId !== member?.value and id exists:
either call a replaceTrackChair(member.value, id, trackIds) helper (preferred)
or sequentially call removeTrackChair(id) then addTrackChair({ id: member.value
}, trackIds), and finally clear the dialog; alternatively, if reassignment is
not allowed make the member field read-only in edit mode (in the dialog render)
so the branch to addTrackChair never runs for edits. Ensure you reference
dialogEntity.originalMemberId, handleSave, addTrackChair, saveTrackChair and
remove/replace helper names when implementing the change.

Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
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.

♻️ Duplicate comments (1)
src/pages/track_chairs/track-chair-list-page.js (1)

57-63: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Runtime crash: currentSummit.tracks accessed before guard.

Line 63 accesses currentSummit.tracks before the guard at line 157. If currentSummit is undefined, this crashes. Additionally, the useEffect has an empty dependency array, so getTrackChairs won't be called when the summit loads after mount.

Move chairTracks derivation and the early return guard together, and add proper dependencies to the effect:

Proposed fix
   const [dialogEntity, setDialogEntity] = useState(null);

+  const chairTracks = currentSummit?.tracks?.filter((t) => t.chair_visible) ?? [];
+
   useEffect(() => {
-    if (currentSummit) getTrackChairs();
-  }, []);
+    if (currentSummit?.id) getTrackChairs();
+  }, [currentSummit?.id]);
 
-  const chairTracks = currentSummit.tracks.filter((t) => t.chair_visible);
+  if (!currentSummit?.id) return <div />;

Then remove the duplicate guard at line 157.

🤖 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/pages/track_chairs/track-chair-list-page.js` around lines 57 - 63, Move
the derivation of chairTracks so it runs only after the early-return guard that
checks currentSummit (i.e., return/loading when !currentSummit) to avoid
accessing currentSummit.tracks when currentSummit is undefined; update the
useEffect that calls getTrackChairs to include currentSummit and getTrackChairs
in its dependency array (useEffect(() => { if (currentSummit) getTrackChairs();
}, [currentSummit, getTrackChairs])) so the fetch runs when the summit loads,
and remove the now-duplicate early-return guard later in the component;
references: chairTracks, currentSummit, getTrackChairs, useEffect.
🤖 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.

Duplicate comments:
In `@src/pages/track_chairs/track-chair-list-page.js`:
- Around line 57-63: Move the derivation of chairTracks so it runs only after
the early-return guard that checks currentSummit (i.e., return/loading when
!currentSummit) to avoid accessing currentSummit.tracks when currentSummit is
undefined; update the useEffect that calls getTrackChairs to include
currentSummit and getTrackChairs in its dependency array (useEffect(() => { if
(currentSummit) getTrackChairs(); }, [currentSummit, getTrackChairs])) so the
fetch runs when the summit loads, and remove the now-duplicate early-return
guard later in the component; references: chairTracks, currentSummit,
getTrackChairs, useEffect.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1b6b9930-5b7b-4fbd-8a77-4a9210e5efbe

📥 Commits

Reviewing files that changed from the base of the PR and between e7841ab and 0cb4096.

📒 Files selected for processing (1)
  • src/pages/track_chairs/track-chair-list-page.js

Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
@tomrndom tomrndom requested a review from smarcet May 6, 2026 21:47
Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
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