Skip to content

fix: display expanded modules if they're collapsed and have errors#943

Open
tomrndom wants to merge 1 commit into
masterfrom
fix/sponsor-page-popup-error-expand
Open

fix: display expanded modules if they're collapsed and have errors#943
tomrndom wants to merge 1 commit into
masterfrom
fix/sponsor-page-popup-error-expand

Conversation

@tomrndom
Copy link
Copy Markdown

@tomrndom tomrndom commented May 15, 2026

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

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

Summary by CodeRabbit

  • New Features
    • Form validation experience enhanced: accordion sections containing validation errors now automatically expand for immediate visibility.
    • Improved error navigation: the page now automatically scrolls to the first validation error upon form submission, reducing manual searching.

Review Change Stack

… submit

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

coderabbitai Bot commented May 15, 2026

📝 Walkthrough

Walkthrough

The form component now manages accordion expansion internally using controlled state instead of MUI's defaultExpanded. When form submission fails with validation errors, modules containing those errors are automatically expanded and the page scrolls to the first errored module.

Changes

Accordion state and error-driven scroll

Layer / File(s) Summary
Import React hooks and debounce constant
src/pages/sponsors-global/page-templates/page-template-popup/page-template-modules-form.js, src/utils/constants.js
React import adds useState hook to enable state management, and DEBOUNCE_WAIT_150 constant (150 ms) is defined for debouncing scroll-to-error behavior.
Module state and helper functions
src/pages/sponsors-global/page-templates/page-template-popup/page-template-modules-form.js
collapsedModules Set tracks which module accordions are collapsed, moduleRefMap Map stores refs to accordion DOM nodes, and getModuleId helper consistently retrieves module identifiers via _tempId or id.
Accordion toggle handler
src/pages/sponsors-global/page-templates/page-template-popup/page-template-modules-form.js
handleToggle factory updates collapsedModules when accordions expand or collapse, adding or removing the module id from the set accordingly.
Controlled accordion rendering
src/pages/sponsors-global/page-templates/page-template-popup/page-template-modules-form.js
Each Accordion becomes controlled: expanded prop reflects whether the module id is in collapsedModules, and element refs are captured into moduleRefMap keyed by module id to support scrolling.
Error-driven scroll-to-error effect
src/pages/sponsors-global/page-templates/page-template-popup/page-template-modules-form.js
Effect monitors submitCount and moduleErrors: when validation fails, it expands modules with errors and schedules a debounced smooth scroll to the first errored module using stored refs.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • smarcet

Poem

🐰 Accordions unwind when errors appear,
No scroll stress, the target draws near,
State flows smooth with sets and maps,
Collapsed no more—errors get taps! 🎯

🚥 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 clearly and concisely summarizes the main change: auto-expanding accordion modules containing validation errors when the form is submitted.
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/sponsor-page-popup-error-expand

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

🤖 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-global/page-templates/page-template-popup/page-template-modules-form.js`:
- Around line 50-70: The useEffect that scrolls to the first module error
(useEffect referencing submitCount, moduleErrors, modules, setCollapsedModules,
moduleRefMap, DEBOUNCE_WAIT_150) is missing dependencies and cleanup: include
moduleErrors and modules in the dependency array so the effect re-runs after
async validation completes, and store the setTimeout id so you can clearTimeout
on cleanup (return a cleanup function) to avoid queued scrolls across
submissions; ensure you still guard early with submitCount === 0 and
Array.isArray(moduleErrors) before computing errorIds.
🪄 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: eba33ab7-4185-4139-85f6-2820fdf52d9d

📥 Commits

Reviewing files that changed from the base of the PR and between 45ffe84 and dcb8dad.

📒 Files selected for processing (2)
  • src/pages/sponsors-global/page-templates/page-template-popup/page-template-modules-form.js
  • src/utils/constants.js

Comment on lines +50 to +70
useEffect(() => {
if (submitCount === 0 || !Array.isArray(moduleErrors)) return;

const errorIds = moduleErrors
.map((err, i) => err && getModuleId(modules[i]))
.filter(Boolean);

if (errorIds.length === 0) return;

setCollapsedModules((prev) => {
const next = new Set(prev);
errorIds.forEach((id) => next.delete(id));
return next;
});

setTimeout(() => {
moduleRefMap.current
.get(errorIds[0])
?.scrollIntoView({ behavior: "smooth" });
}, DEBOUNCE_WAIT_150);
}, [submitCount]);
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

🧩 Analysis chain

🌐 Web query:

Formik 2.4.x submission lifecycle: does submitCountincrement before async validation updateserrors, and what dependency pattern is recommended for useEffectlogic that depends on bothsubmitCountanderrors?

💡 Result:

In Formik 2.4.x, the submitCount property increments immediately when handleSubmit or submitForm is called, before any asynchronous validation has completed [1]. Because validation is asynchronous, this creates a race condition where submitCount reflects a new submission attempt while the errors object still contains results from the previous state [2][3]. To handle logic that depends on both submitCount and errors (such as triggering side effects only after a failed submission attempt), the recommended pattern is to avoid relying solely on submitCount as a trigger, as it may be out of sync with the current errors [2][3]. Instead, use a combination of submitCount and isValidating or isSubmitting to ensure the form has finished processing [1]. A common and robust pattern is to use a useEffect that monitors submitCount but includes a check to ensure the form is no longer validating [1]: useEffect( => { if (submitCount > 0 &&!isValidating) { // Logic here will run only after validation has finished if (Object.keys(errors).length > 0) { // Handle submission errors } } }, [submitCount, isValidating, errors]); This approach ensures that your effect only executes once the validation cycle triggered by the submission attempt has fully resolved, preventing the use of stale error data [2][1][3].

Citations:


🏁 Script executed:

cat -n src/pages/sponsors-global/page-templates/page-template-popup/page-template-modules-form.js | head -100

Repository: fntechgit/summit-admin

Length of output: 4219


Add missing dependencies and cleanup to handle async validation timing in scroll-to-error effect.

The effect relies on moduleErrors and modules but only declares submitCount as a dependency. Because Formik's submitCount increments immediately before async validation completes, moduleErrors may be stale on the first run. Additionally, the setTimeout callback lacks cleanup, which can cause multiple scroll attempts to queue up across submissions.

Add moduleErrors and modules to the dependency array so the effect re-runs after validation completes with fresh error data. Also clean up the timeout on unmount or when dependencies change:

Suggested fix
   useEffect(() => {
-    if (submitCount === 0 || !Array.isArray(moduleErrors)) return;
+    if (submitCount === 0 || !Array.isArray(moduleErrors)) return;
 
     const errorIds = moduleErrors
       .map((err, i) => err && getModuleId(modules[i]))
       .filter(Boolean);
 
     if (errorIds.length === 0) return;
 
     setCollapsedModules((prev) => {
       const next = new Set(prev);
       errorIds.forEach((id) => next.delete(id));
       return next;
     });
 
-    setTimeout(() => {
+    const timerId = setTimeout(() => {
       moduleRefMap.current
         .get(errorIds[0])
         ?.scrollIntoView({ behavior: "smooth" });
     }, DEBOUNCE_WAIT_150);
-  }, [submitCount]);
+
+    return () => clearTimeout(timerId);
+  }, [submitCount, moduleErrors, modules]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
if (submitCount === 0 || !Array.isArray(moduleErrors)) return;
const errorIds = moduleErrors
.map((err, i) => err && getModuleId(modules[i]))
.filter(Boolean);
if (errorIds.length === 0) return;
setCollapsedModules((prev) => {
const next = new Set(prev);
errorIds.forEach((id) => next.delete(id));
return next;
});
setTimeout(() => {
moduleRefMap.current
.get(errorIds[0])
?.scrollIntoView({ behavior: "smooth" });
}, DEBOUNCE_WAIT_150);
}, [submitCount]);
useEffect(() => {
if (submitCount === 0 || !Array.isArray(moduleErrors)) return;
const errorIds = moduleErrors
.map((err, i) => err && getModuleId(modules[i]))
.filter(Boolean);
if (errorIds.length === 0) return;
setCollapsedModules((prev) => {
const next = new Set(prev);
errorIds.forEach((id) => next.delete(id));
return next;
});
const timerId = setTimeout(() => {
moduleRefMap.current
.get(errorIds[0])
?.scrollIntoView({ behavior: "smooth" });
}, DEBOUNCE_WAIT_150);
return () => clearTimeout(timerId);
}, [submitCount, moduleErrors, modules]);
🤖 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-global/page-templates/page-template-popup/page-template-modules-form.js`
around lines 50 - 70, The useEffect that scrolls to the first module error
(useEffect referencing submitCount, moduleErrors, modules, setCollapsedModules,
moduleRefMap, DEBOUNCE_WAIT_150) is missing dependencies and cleanup: include
moduleErrors and modules in the dependency array so the effect re-runs after
async validation completes, and store the setTimeout id so you can clearTimeout
on cleanup (return a cleanup function) to avoid queued scrolls across
submissions; ensure you still guard early with submitCount === 0 and
Array.isArray(moduleErrors) before computing errorIds.

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