Skip to content

feat: add popups for import and add users on sponsors global#963

Open
tomrndom wants to merge 8 commits into
masterfrom
feature/sponsor-global-user-add-import
Open

feat: add popups for import and add users on sponsors global#963
tomrndom wants to merge 8 commits into
masterfrom
feature/sponsor-global-user-add-import

Conversation

@tomrndom

@tomrndom tomrndom commented Jun 3, 2026

Copy link
Copy Markdown

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

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

Summary by CodeRabbit

  • New Features
    • Added sponsor user dialogs: invite (sponsor picker + email validation) and global import (summit picker, sponsor picker, multi-user checkbox list, and “load more” pagination).
    • Import supports “select all” for bulk selection.
  • Bug Fixes & Improvements
    • Sponsor user invite can target a specified sponsor; otherwise it uses the currently active sponsor.
    • Sponsor user fetching now includes the relevant company context.
  • Tests
    • Added/extended unit tests for both dialogs, covering validation, loading/disabled states, selection changes, pagination behavior, and correct action dispatch.

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

coderabbitai Bot commented Jun 3, 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

Adds global sponsor-user invite and import popups, updates sponsor query and invite payload handling, integrates the popups into the sponsor users page, and adds tests for both flows.

Changes

Sponsor User Management Popups

Layer / File(s) Summary
Sponsor data enrichment with companyId mapping
src/actions/sponsor-actions.js
Updated querySponsors to include companyId in each sponsor option alongside name; minor import formatting change.
Flexible sponsor targeting in sendSponsorUserInvite action
src/actions/sponsor-users-actions.js
Modified sendSponsorUserInvite to accept optional sponsorId and use it for sponsor_id when provided, while preserving the existing loading and POST flow.
New user invitation popup with sponsor selection
src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-new-user-popup.js
Added SponsorGlobalNewUserPopup with Formik/Yup sponsor and email inputs, invite submission, post-submit refresh, and Redux-connected export.
Bulk import users popup with summit and sponsor targeting
src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js
Added SponsorGlobalImportUsersPopup with summit selection, sponsor lookup, paginated sponsor-user fetching, checkbox selection, select-all, and import submission.
SponsorUsersListPage integration of new popups
src/pages/sponsors/sponsor-users-list-page/index.js
Replaced placeholder popup renders with the new global popups and passed summitId from Redux.
Tests for SponsorGlobalImportUsersPopup
src/pages/sponsors/sponsor-users-list-page/components/__tests__/sponsor-global-import-users-popup.test.js
Added RTL coverage for selection, fetch, import payloads, select-all, pagination, and close behavior.
Tests for SponsorGlobalNewUserPopup
src/pages/sponsors/sponsor-users-list-page/components/__tests__/sponsor-global-new-user-popup.test.js
Added RTL coverage for rendering, successful invite flow, error handling, and validation guards.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly Related PRs

  • fntechgit/summit-admin#888: Introduces related sponsor-user import flow changes that overlap with the new import popup and action payload shape.

Suggested Reviewers

  • smarcet

Poem

🐰 I hopped through summits, sponsor by sponsor,
New invites and imports now wander and ponder.
A checkbox, a form, and a cheerful new call,
Then users appear — or get gathered in all.
🥕

🚥 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 matches the main change: adding global sponsor popups for importing and adding users.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/sponsor-global-user-add-import

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

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

🤖 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/actions/sponsor-users-actions.js`:
- Around line 535-547: The current promise chain swallows errors with
catch(console.log) and calls dispatch(stopLoading()) twice; remove the
catch(console.log) so rejections propagate to callers (or replace it with a
catch that logs and rethrows), and remove the stopLoading() call inside the
.then handler so stopLoading is invoked only from .finally; update the chain
around dispatch, stopLoading, snackbarSuccessHandler, and
T.translate("sponsor_users.new_user.success") accordingly so success still shows
the snackbar but loading is stopped exactly once in .finally.

In
`@src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js`:
- Around line 86-95: The handleImport handler currently calls
importSponsorUsers(...).then(() => onClose()) which will close the dialog even
on failure; change it to await the thunk result from importSponsorUsers in
handleImport (or handle its returned promise) and only call onClose() when the
thunk returns an explicit success flag (e.g., { success: true }) or resolves
truthy; update importSponsorUsers so it resolves/rejects or returns an explicit
success value on completion, and gate onClose() on that success result (and
handle or surface errors when it fails instead of closing).
- Around line 49-50: The code reads the selected sponsor's id from
formik.values.sponsor?.value but the select stores {id, name, companyId}, so
sponsorId becomes undefined; update both occurrences (the sponsorId assignment
and the other similar block around lines where companyId is used) to use
formik.values.sponsor?.id instead of .value, and ensure any downstream uses
(e.g., the import target and candidate list loader) reference this corrected
sponsorId and continue to use formik.values.sponsor?.companyId for companyId.

In
`@src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-new-user-popup.js`:
- Around line 37-41: The handler handleOnSave currently closes the popup in a
finally block so failures also dismiss the form; change it to call
sendSponsorUserInvite(values.email, values.sponsor.id).then(() => {
getSponsorUsers(); handleClose(); }).catch((err) => { /* keep popup open and
surface error to user */ }); and ensure the sendSponsorUserInvite thunk returns
a rejected Promise on failure so the catch runs; reference handleOnSave,
sendSponsorUserInvite, getSponsorUsers, and handleClose when making the change.
🪄 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: 67165833-76a2-4a0f-91a7-33147faa7006

📥 Commits

Reviewing files that changed from the base of the PR and between 38c8fc5 and 338a22d.

📒 Files selected for processing (5)
  • src/actions/sponsor-actions.js
  • src/actions/sponsor-users-actions.js
  • src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js
  • src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-new-user-popup.js
  • src/pages/sponsors/sponsor-users-list-page/index.js

Comment thread src/actions/sponsor-users-actions.js
Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
@tomrndom tomrndom requested a review from smarcet June 4, 2026 13:21

@smarcet smarcet 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.

@tomrndom please review comments

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

♻️ Duplicate comments (3)
src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-new-user-popup.js (1)

43-49: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Success path is still triggered on failed invites.

Line 43 chains .then(...), but the thunk currently swallows errors in src/actions/sponsor-users-actions.js (.catch(console.log)), so this block can still run after a failed API call and close/refresh the dialog incorrectly. Gate close/refresh on an explicit success result (or make the thunk reject on failure).

🤖 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/sponsors/sponsor-users-list-page/components/sponsor-global-new-user-popup.js`
around lines 43 - 49, The success path currently runs even when the invite fails
because sendSponsorUserInvite swallows errors; update the flow so
sendSponsorUserInvite (the thunk in src/actions/sponsor-users-actions.js)
returns a rejected promise on failure (remove the terminal .catch(console.log)
or re-throw the error) or have the caller inspect an explicit success result
before proceeding; then in sponsor-global-new-user-popup.js, only call
getSponsorUsers() and handleClose() when sendSponsorUserInvite resolves
successfully (or when the resolved payload indicates success) and ensure
setIsSaving(false) still runs in finally.
src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js (2)

94-96: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Import dialog can close even when import fails.

Line 95 closes in .then(...), but the current thunk contract in src/actions/sponsor-users-actions.js swallows failures, so this can still execute on failed imports. Only close after a verifiable success result (or make thunk reject on failure).

🤖 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/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js`
around lines 94 - 96, The import dialog is closed unconditionally in the then()
callback of importSponsorUsers even though the import thunk in
sponsor-users-actions.js swallows failures; change the flow so onClose is only
called after a verifiable success: either update the thunk importSponsorUsers to
reject the promise on failure, or change the caller to inspect the resolved
value (e.g., check a success flag or returned result) before calling onClose;
keep setIsSaving(false) in finally() but move onClose into the branch that
confirms success so failures do not close the dialog.

51-52: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Use sponsor id, not value, for selected sponsor state.

Line 51 reads formik.values.sponsor?.value, but Line 156-160 stores { id, name, companyId }. This leaves sponsorId undefined and breaks candidate loading/import targeting.

Proposed fix
-  const sponsorId = formik.values.sponsor?.value;
+  const sponsorId = formik.values.sponsor?.id;

Also applies to: 156-160

🤖 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/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js`
around lines 51 - 52, The selected sponsor was read from
formik.values.sponsor?.value but the stored object uses { id, name, companyId },
so sponsorId becomes undefined; update the code to read
formik.values.sponsor?.id (leave companyId as formik.values.sponsor?.companyId)
wherever sponsorId is derived (e.g., the sponsorId and companyId consts and any
import/targeting logic) so it matches the stored { id, name, companyId } shape
and restores correct candidate loading/import targeting.
🤖 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/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js`:
- Around line 94-96: The import dialog is closed unconditionally in the then()
callback of importSponsorUsers even though the import thunk in
sponsor-users-actions.js swallows failures; change the flow so onClose is only
called after a verifiable success: either update the thunk importSponsorUsers to
reject the promise on failure, or change the caller to inspect the resolved
value (e.g., check a success flag or returned result) before calling onClose;
keep setIsSaving(false) in finally() but move onClose into the branch that
confirms success so failures do not close the dialog.
- Around line 51-52: The selected sponsor was read from
formik.values.sponsor?.value but the stored object uses { id, name, companyId },
so sponsorId becomes undefined; update the code to read
formik.values.sponsor?.id (leave companyId as formik.values.sponsor?.companyId)
wherever sponsorId is derived (e.g., the sponsorId and companyId consts and any
import/targeting logic) so it matches the stored { id, name, companyId } shape
and restores correct candidate loading/import targeting.

In
`@src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-new-user-popup.js`:
- Around line 43-49: The success path currently runs even when the invite fails
because sendSponsorUserInvite swallows errors; update the flow so
sendSponsorUserInvite (the thunk in src/actions/sponsor-users-actions.js)
returns a rejected promise on failure (remove the terminal .catch(console.log)
or re-throw the error) or have the caller inspect an explicit success result
before proceeding; then in sponsor-global-new-user-popup.js, only call
getSponsorUsers() and handleClose() when sendSponsorUserInvite resolves
successfully (or when the resolved payload indicates success) and ensure
setIsSaving(false) still runs in finally.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5c64094e-48bc-48bc-8ff6-a00458e2f6bf

📥 Commits

Reviewing files that changed from the base of the PR and between b3c4f7a and fc08562.

📒 Files selected for processing (4)
  • src/pages/sponsors/sponsor-users-list-page/components/__tests__/sponsor-global-import-users-popup.test.js
  • src/pages/sponsors/sponsor-users-list-page/components/__tests__/sponsor-global-new-user-popup.test.js
  • src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js
  • src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-new-user-popup.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/pages/sponsors/sponsor-users-list-page/components/tests/sponsor-global-new-user-popup.test.js
  • src/pages/sponsors/sponsor-users-list-page/components/tests/sponsor-global-import-users-popup.test.js

@smarcet smarcet self-requested a review June 23, 2026 20:41
Comment thread src/actions/sponsor-users-actions.js Outdated

@smarcet smarcet 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.

@tomrndom please review comments

@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.

♻️ Duplicate comments (2)
src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js (2)

102-108: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Gate onClose() on a confirmed successful import.

With the current thunk contract, importSponsorUsers resolves even on failure (its internal .catch), so this .then runs and the dialog closes / selection is lost even when nothing was imported, and there is no explicit .catch. Have the thunk reject or return an explicit success flag and only call onClose() on 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/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js`
around lines 102 - 108, The `handleImport` flow closes the popup too early
because `importSponsorUsers` currently resolves even when the import fails, so
the `.then(() => onClose())` path runs unconditionally. Update the thunk
contract used by `handleImport` in `sponsor-global-import-users-popup.js` so
`importSponsorUsers` either rejects on failure or returns an explicit success
result, then gate `onClose()` behind a confirmed success check and add a failure
path that keeps the dialog open.

52-53: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Read the selected sponsor's id, not value.

formatSelectedValue stores { id, name, companyId }, so formik.values.sponsor?.value is always undefined. As a result sponsorId stays falsy: the fetch effect (Line 56) never runs, the user checklist (Line 175) never renders, and import (Line 105) sends an undefined target sponsor.

Proposed fix
-  const sponsorId = formik.values.sponsor?.value;
+  const sponsorId = formik.values.sponsor?.id;
🤖 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/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js`
around lines 52 - 53, The sponsor lookup is reading the wrong field from the
selected sponsor object: in sponsor-global-import-users-popup.js, use the id
stored by formatSelectedValue instead of sponsor.value when deriving sponsorId
in the popup logic. Update the sponsorId assignment near the Formik value reads
so the fetch effect, checklist rendering, and import flow all receive the actual
sponsor identifier, while keeping companyId sourced from the same selected
sponsor object.
🤖 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/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js`:
- Around line 102-108: The `handleImport` flow closes the popup too early
because `importSponsorUsers` currently resolves even when the import fails, so
the `.then(() => onClose())` path runs unconditionally. Update the thunk
contract used by `handleImport` in `sponsor-global-import-users-popup.js` so
`importSponsorUsers` either rejects on failure or returns an explicit success
result, then gate `onClose()` behind a confirmed success check and add a failure
path that keeps the dialog open.
- Around line 52-53: The sponsor lookup is reading the wrong field from the
selected sponsor object: in sponsor-global-import-users-popup.js, use the id
stored by formatSelectedValue instead of sponsor.value when deriving sponsorId
in the popup logic. Update the sponsorId assignment near the Formik value reads
so the fetch effect, checklist rendering, and import flow all receive the actual
sponsor identifier, while keeping companyId sourced from the same selected
sponsor object.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bfc6f2b3-f74f-407a-840d-25af6ce009df

📥 Commits

Reviewing files that changed from the base of the PR and between fc08562 and 3b2bc70.

📒 Files selected for processing (2)
  • src/actions/sponsor-users-actions.js
  • src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js
💤 Files with no reviewable changes (1)
  • src/actions/sponsor-users-actions.js

…omise errors

Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
@tomrndom tomrndom force-pushed the feature/sponsor-global-user-add-import branch from 3b2bc70 to cbc2f4b Compare June 24, 2026 15:15

@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

♻️ Duplicate comments (1)
src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js (1)

52-53: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Use sponsor.id instead of sponsor.value for the selected sponsor key.

Line 52 reads formik.values.sponsor?.value, but this form stores id (Line 41, Line 44, Line 168). That leaves sponsorId undefined for fetch/render/import paths (Line 56, Line 105, Line 176).

Proposed fix
-  const sponsorId = formik.values.sponsor?.value;
+  const sponsorId = formik.values.sponsor?.id;

Also applies to: 105-106, 176-176

🤖 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/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js`
around lines 52 - 53, The selected sponsor key is being read from sponsor.value
even though this form stores the sponsor identifier on sponsor.id, which leaves
sponsorId undefined in the fetch/render/import flows. Update
sponsor-global-import-users-popup.js in the relevant sponsorId reads and any
dependent logic in the import/render paths to use the sponsor object’s id field
consistently, keeping companyId unchanged, and verify the same identifier is
used anywhere the selected sponsor is passed into the query or import handlers.
🤖 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/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js`:
- Around line 77-93: The load-more handler in
sponsor-global-import-users-popup.js can merge stale results and crash when the
current userOptions state is null. Update handleLoadMoreUsers to guard the
setUserOptions merge against a missing previous state, and ensure the response
from fetchSponsorUsersBySummit is only applied if it still matches the current
sponsor/summit context (for example by checking currentSummit.id,
selectedSummit, and companyId against the request that was issued). Keep the
protection around isLoadingMore and the pagination check, but avoid appending
userData.data to a stale or null value.data.

---

Duplicate comments:
In
`@src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js`:
- Around line 52-53: The selected sponsor key is being read from sponsor.value
even though this form stores the sponsor identifier on sponsor.id, which leaves
sponsorId undefined in the fetch/render/import flows. Update
sponsor-global-import-users-popup.js in the relevant sponsorId reads and any
dependent logic in the import/render paths to use the sponsor object’s id field
consistently, keeping companyId unchanged, and verify the same identifier is
used anywhere the selected sponsor is passed into the query or import handlers.
🪄 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: b38f6943-66e0-4fb0-9496-c633764c25e1

📥 Commits

Reviewing files that changed from the base of the PR and between 3b2bc70 and cbc2f4b.

📒 Files selected for processing (2)
  • src/actions/sponsor-users-actions.js
  • src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js
💤 Files with no reviewable changes (1)
  • src/actions/sponsor-users-actions.js

@smarcet smarcet requested review from Copilot and santipalenque June 30, 2026 18:53

@smarcet smarcet 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.

Code review findings - @tomdom please check the inline comments below.

Copilot AI 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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI 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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 8 comments.

Comment on lines +147 to +151
onChange={(val) => {
setSelectedSummit(val);
setUserOptions(null);
setSelectedUsers([]);
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@tomrndom Confirmed — SummitsDropdown's onChange only resets userOptions/selectedUsers, not the Formik sponsor field, and MuiFormikAsyncAutocomplete only fetches options once on mount (no re-fetch on queryParams change). So after picking summit A → sponsor X, switching to summit B keeps sponsor X selected (now stale/wrong-summit) with stale options in the dropdown, until the user manually reselects. Suggest resetting formik.setFieldValue("sponsor", { id: "", name: "" }) (or resetForm) in the SummitsDropdown onChange handler alongside the existing setUserOptions(null)/setSelectedUsers([]).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@tomrndom Following up on this thread - the suggested fix was applied (formik.setFieldValue("sponsor", { id: "", name: "" }) now runs in the SummitsDropdown onChange, alongside setUserOptions(null)/setSelectedUsers([])), but that only clears the selected value. The other half of the original report - the sponsor dropdown's options list staying stale after switching summits - is not fixed by it and is still reproducible.

Root cause: MuiFormikAsyncAutocomplete only fetches options on mount and on searchTerm changes; its effects don't depend on queryParams. Since this popup doesn't key the component on selectedSummit, the same instance stays mounted across a summit switch and keeps showing the previous summit's sponsor list until the user types a search character.

Verified this empirically (not just by reading the code): rendered MuiFormikAsyncAutocomplete directly with a mocked queryFunction, then re-rendered with a different queryParams value with no search term in between:

const queryFunction = jest.fn((input, param, callback) => {
  callback([{ id: 1, name: `sponsor-for-${param}` }]);
  return Promise.resolve();
});

// 1st render: queryParams=["summitA"] -> queryFunction called once
// rerender with queryParams=["summitB"], no search term typed
// queryFunction call count stayed at 1 -> confirmed no refetch happened

Suggested fix: key the Autocomplete on selectedSummit to force a remount on summit change (simplest, scoped to this popup), or add queryParams to the preload effect's dependency array in the shared mui-formik-async-select.js component (fixes it for every consumer, but is a shared-component change worth its own review).

Comment thread src/actions/sponsor-users-actions.js Outdated
Comment on lines +527 to +534
return postRequest(
null,
createAction(DUMMY_ACTION),
`${window.SPONSOR_USERS_API_URL}/api/v1/sponsor-users`,
payload,
snackbarErrorHandler,
entity
)(params)(dispatch)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@tomrndom Confirmed. I traced postRequest's internal handler (oe in the minified openstack-uicore-foundation bundle) — on error it dispatches the error handler and calls reject(...), so removing the .catch(console.log) here does make the returned promise reject on failure where it previously always resolved. new-user-popup.js:38 (sendSponsorUserInvite(values.email).finally(...)) has no .catch(), so a failed invite from that (untouched) screen will now surface as an unhandled promise rejection. Needs a .catch() added there (or a rethrow-and-log wrapper kept in the action) as part of this PR, since it's the one changing the contract.

Comment thread src/pages/sponsors/sponsor-users-list-page/index.js
Comment thread src/actions/sponsor-users-actions.js
Comment thread src/pages/sponsors/sponsor-users-list-page/index.js

@smarcet smarcet 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.

@tomrndom please re review

tomrndom added 3 commits July 8, 2026 01:51
Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
…nsor user tab

Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
…sers

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

Copilot AI 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.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Comment on lines +44 to +49
initialValues: { sponsor: { id: "", name: "" } },
validationSchema: yup.object({
sponsor: yup.object({
id: yup.string().required(T.translate("validation.required"))
})
}),
Comment on lines +180 to +185
onChange={(val) => {
setSelectedSummit(val);
formik.setFieldValue("sponsor", { id: "", name: "" });
setUserOptions(null);
setSelectedUsers([]);
}}
});
sendSponsorUserInvite(values.email)
.catch(() => {})
.finally(() => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@tomrndom This handler closes the dialog and refreshes the list unconditionally via .finally(), even when sendSponsorUserInvite rejects (duplicate email, validation error, etc.) - the typed email is lost with no chance to correct and retry.

This is inconsistent with the sibling popup added in this same PR, sponsor-global-new-user-popup.js, which gates the close/refresh on success only:

// sponsor-global-new-user-popup.js
sendSponsorUserInvite(values.email, values.sponsor.id)
  .then(() => {
    getSponsorUsers();
    handleClose(); // only runs on success
  })
  .catch(() => {})
  .finally(() => setIsSaving(false));

vs. this file:

// new-user-popup.js
sendSponsorUserInvite(values.email)
  .catch(() => {})
  .finally(() => {
    getSponsorUsers(sponsorId);
    handleClose(); // runs on success AND failure
  });

Both call the same action, which now genuinely rejects on failure since this PR removed its internal catch(console.log). Moving getSponsorUsers/handleClose into the .then() here (matching the new popup) would fix it and align with the documented pattern: https://github.com/fntechgit/ftn-docsnsklz/blob/main/patterns/show-admin/summit-admin-popup-dialog-pattern.md - "Rejected saves keep the dialog open and re-enable controls."

importSponsorUsers
} from "../../../../actions/sponsor-users-actions";
import SummitsDropdown from "../../../../components/mui/summits-dropdown";
import MuiFormikAsyncAutocomplete from "../../../../components/mui/formik-inputs/mui-formik-async-select";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@tomrndom This popup (and the legacy ones touched in this PR) import several components from local src/components/mui/* that already exist in openstack-uicore-foundation (currently installed at 5.0.36):

  • SummitsDropdown (this file, and import-users-popup.js) -> openstack-uicore-foundation/lib/components/mui/summits-dropdown
  • MuiFormikAsyncAutocomplete (this line) -> openstack-uicore-foundation/lib/components/mui/formik-inputs/async-select
  • CheckBoxList (used in the legacy import-users-popup.js - this file already imports it correctly from uicore) -> openstack-uicore-foundation/lib/components/mui/checkbox-list
  • MuiFormikTextField (used in the legacy new-user-popup.js - sponsor-global-new-user-popup.js already imports it correctly from uicore) -> openstack-uicore-foundation/lib/components/mui/formik-inputs/textfield
  • CustomAlert (used in both new popups) -> openstack-uicore-foundation/lib/components/mui/custom-alert

This is the documented pattern: https://github.com/fntechgit/ftn-docsnsklz/blob/main/patterns/show-admin/summit-admin-reuse-before-build.md - check uicore for an existing equivalent before adding/using a local one.

Two of these aren't just import-path noise: CustomAlert's local copy renders {message} as plain text where uicore's uses dangerouslySetInnerHTML (so it won't render HTML in a translation the way uicore's does), and MuiFormikAsyncAutocomplete's local copy carries the same "doesn't refetch on queryParams change" bug flagged in the thread above - switching to the uicore import would fix it for every consumer instead of just this popup. SummitsDropdown's divergence looks intentional (it reads allSummits from Redux instead of fetching on its own), so that one's probably fine to keep local.

None of these 5 local files were introduced by this PR - just flagging since this PR already imports CheckBoxList and MuiSponsorInput/MuiFormikTextField from uicore in the new popups, so switching the remaining two is a small diff away from being fully consistent.

@smarcet smarcet 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.

@tomrndom please review

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.

3 participants