Skip to content

feat: cart tab - add form flow #797

Open
santipalenque wants to merge 2 commits intomasterfrom
feature/add-form-to-cart
Open

feat: cart tab - add form flow #797
santipalenque wants to merge 2 commits intomasterfrom
feature/add-form-to-cart

Conversation

@santipalenque
Copy link

@santipalenque santipalenque commented Feb 19, 2026

https://app.clickup.com/t/86b66n5kf

Summary by CodeRabbit

  • New Features

    • Added sponsor cart management interface with form selection and item editing capabilities
    • Added dynamic form fields support with quantity, notes, and settings management
    • Added pricing display with multiple rate tiers and discount functionality
    • Added cart item organization with searchable form templates
  • Tests

    • Added comprehensive test suite for form item table rendering and interactions
    • Added test coverage for form template selection dialog

@coderabbitai
Copy link

coderabbitai bot commented Feb 19, 2026

📝 Walkthrough

Walkthrough

This PR introduces a comprehensive sponsor cart forms feature, including new form selection, editing, and metadata handling workflows. It refactors querySummitAddons to an async function, adds MUI form input components, creates FormItemTable with dynamic field rendering, and establishes new Redux actions/reducers for sponsor form cart management.

Changes

Cohort / File(s) Summary
Sponsor Actions
src/actions/sponsor-actions.js, src/actions/sponsor-cart-actions.js
Replaced debounced querySummitAddons with non-debounced async function changing signature from (input, summitId, callback) to (summitId, callback). Added new cart form actions (REQUEST_CART_AVAILABLE_FORMS, RECEIVE_CART_AVAILABLE_FORMS, RECEIVE_CART_SPONSOR_FORM, FORM_CART_SAVED) and thunks (getSponsorFormsForCart, getSponsorForm, addCartForm) with pagination and filtering support.
MUI Form Input Components
src/components/mui/formik-inputs/mui-formik-dropdown-checkbox.js, src/components/mui/formik-inputs/mui-formik-dropdown-radio.js, src/components/mui/formik-inputs/mui-formik-timepicker.js, src/components/mui/formik-inputs/mui-formik-summit-addon-select.js
Added new Formik-integrated MUI components: multi-select dropdown with "Select All" option, radio-styled dropdown, time picker with timezone support, and wrapped summit addon selector. Removed original SummitAddonSelect from formik-inputs.
Addon Select Components
src/components/mui/summit-addon-select.js, src/components/mui/sponsor-addon-select.js, src/components/forms/sponsor-general-form/manage-tier-addons-popup.js
Added new summit and sponsor addon select components for independent use. Updated ManageTierAddonsPopup to use MuiFormikSummitAddonSelect with revised prop structure (inputProps instead of fullWidth).
FormItemTable and Dynamic Fields
src/components/mui/FormItemTable/index.js, src/components/mui/FormItemTable/components/GlobalQuantityField.js, src/components/mui/FormItemTable/components/ItemTableField.js, src/components/mui/FormItemTable/__tests__/FormItemTable.test.js
Introduced FormItemTable component with dynamic column generation from meta_fields, rate calculation logic, and per-item quantity handling. Added GlobalQuantityField for row-level quantity input and ItemTableField for rendering various field types (CheckBox, DateTime, Quantity, ComboBox, etc.). Comprehensive Jest test suite validates rendering, interactions, and calculations.
Sponsor Cart Modal Components
src/components/mui/NotesModal/index.js, src/components/mui/ItemSettingsModal/index.js
Added modals for editing per-item notes and item-level settings with form integration and save callbacks.
Sponsor Cart Tab Feature
src/pages/sponsors/sponsor-cart-tab/index.js, src/pages/sponsors/sponsor-cart-tab/components/cart-view.js, src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/index.js, src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/__tests__/select-page-template-dialog.test.js, src/pages/sponsors/sponsor-cart-tab/components/edit-form/index.js, src/pages/sponsors/sponsor-cart-tab/components/edit-form/new-cart-form.js
Refactored SponsorCartTab to use local state-driven composition with CartView, SelectFormDialog, and EditForm. CartView displays cart with management actions. SelectFormDialog enables form/addon selection with search. EditForm provides comprehensive form editing with dynamic field rendering, validation, and nested data remapping. NewCartForm fetches and initializes form data.
Redux State Management
src/reducers/sponsors/sponsor-page-cart-list-reducer.js
Extended sponsor cart reducer with new availableForms state (forms, pagination, search/sort) and sponsorForm object. Added handlers for REQUEST_CART_AVAILABLE_FORMS, RECEIVE_CART_AVAILABLE_FORMS, RECEIVE_CART_SPONSOR_FORM with mapForm helper for augmenting form metadata.
Page Integration
src/pages/sponsors/edit-sponsor-page.js
Integrated getSponsorPurchasesMeta action into sponsor editing flow and wired history prop to SponsorCartTab for potential navigation support.
Styling and Configuration
src/components/CustomTheme.js, src/i18n/en.json, src/utils/constants.js
Added absolute positioning for MuiFormHelperText. Extended translations with cart tab labels (items, add_form_to_cart, edit_form fields). Added FORM_DISCOUNT_OPTIONS constant (PERCENTAGE, RATE).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CartView as Cart View
    participant SelectForm as Select Form Dialog
    participant Redux as Redux/Actions
    participant API as API
    participant EditForm as Edit Form
    
    User->>CartView: Click "Add Form"
    CartView->>SelectForm: Open dialog
    User->>SelectForm: Search forms
    SelectForm->>Redux: getSponsorFormsForCart(term)
    Redux->>API: GET /show-forms?search=term
    API->>Redux: Form list
    Redux->>SelectForm: Update availableForms
    SelectForm->>User: Display forms + addon selector
    User->>SelectForm: Select form & addon, Click Save
    SelectForm->>CartView: onSave(form, addon)
    CartView->>Redux: getSponsorForm(formId)
    Redux->>API: GET /V2/sponsor-forms/:formId
    API->>Redux: Form with meta_fields
    CartView->>EditForm: Render with form + addon
    User->>EditForm: Fill item fields, quantities, notes
    User->>EditForm: Click Save
    EditForm->>Redux: addCartForm(formId, addonId, values)
    Redux->>API: POST /sponsor/:sponsorId/cart-forms
    API->>Redux: Form saved
    Redux->>CartView: Update cart state
    CartView->>User: Show updated cart
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • smarcet
  • tomrndom
  • romanetar

🐰 Hops through the cart with glee,
Forms and addons dance so free,
Quantity fields bloom with care,
Modal dialogs everywhere!
A sponsor's dream, complete and neat,
This feature makes the bundle sweet! 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: cart tab - add form flow' is concise and clearly describes the main feature being added—a form addition flow for the cart tab, which aligns well with the significant changes across multiple files implementing sponsor cart form selection, editing, and management functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/add-form-to-cart

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

Copy link

@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: 10

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (12)
src/components/mui/sponsor-addon-select.js-14-26 (1)

14-26: ⚠️ Potential issue | 🟡 Minor

Refetch when sponsor/summit props change and guard missing sponsorships.

Lines 14-26: The effect runs only once with an empty dependency array, so changes to sponsor or summitId won't trigger a refetch. Additionally, accessing sponsor.sponsorships without optional chaining will crash if sponsorships is unset. The debug log should also be removed.

🔧 Suggested fix
-  const sponsorshipIds = sponsor.sponsorships.map((e) => e.id);
+  const sponsorshipIds = sponsor?.sponsorships?.map((e) => e.id) ?? [];

   useEffect(() => {
-    querySponsorAddons(summitId, sponsor.id, sponsorshipIds,(results) => {
-      console.log("RESULTS: ", results);
+    if (!sponsor?.id || sponsorshipIds.length === 0) {
+      setOptions([]);
+      return;
+    }
+    querySponsorAddons(summitId, sponsor.id, sponsorshipIds, (results) => {
       const normalized = results.map((r) => ({
         value: r.id,
         label: r.name
       }));
       setOptions(normalized);
     });
-  }, []);
+  }, [summitId, sponsor?.id, sponsorshipIds.join(",")]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/sponsor-addon-select.js` around lines 14 - 26, The effect
currently runs only once and reads sponsor.sponsorships unsafely and logs debug
output; fix by moving the sponsorshipIds computation into the useEffect, guard
sponsorships with optional chaining or a default (e.g., const sponsorshipIds =
sponsor?.sponsorships?.map(e => e.id) || []), remove the console.log, and update
the useEffect dependency array to include summitId and the sponsor (or
sponsor.id and sponsor.sponsorships) so querySponsorAddons is re-run when those
props change; keep setOptions and the normalized mapping as-is and call
querySponsorAddons(summitId, sponsor.id, sponsorshipIds, ...) inside the updated
effect.
src/components/mui/summit-addon-select.js-15-23 (1)

15-23: ⚠️ Potential issue | 🟡 Minor

Add summitId to the effect dependency array to refetch addons when the summit changes.

Lines 15-23: The effect runs only on mount with an empty dependency array, so if the summitId prop changes, the component will display stale addon options. Add summitId as a dependency to ensure the effect re-runs when the summit changes.

🔧 Suggested fix
  useEffect(() => {
    querySummitAddons(summitId, (results) => {
      const normalized = results.map((r) => ({
        value: r,
        label: r
      }));
      setOptions(normalized);
    });
-  }, []);
+  }, [summitId]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/summit-addon-select.js` around lines 15 - 23, The
useEffect that calls querySummitAddons currently has an empty dependency array
and will not refetch when summitId changes; update the effect for the component
(the useEffect that invokes querySummitAddons and calls setOptions) to include
summitId in its dependency array so the effect re-runs whenever the summitId
prop changes, ensuring options are reloaded for the new summit.
src/pages/sponsors/sponsor-cart-tab/components/cart-view.js-47-49 (1)

47-49: ⚠️ Potential issue | 🟡 Minor

Remove or convert debug console.log statements.

Multiple handlers contain placeholder console.log statements that should be removed or replaced with actual implementation before merging. This aligns with the PR title noting "WIP".

Also applies to: 59-65

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/cart-view.js` around lines 47
- 49, The debug console.log in handleManageItems should be removed and replaced
with the real implementation or a call to the existing cart update handlers;
specifically update the handleManageItems function to perform the intended
action (e.g., open a manage modal, dispatch an action, or call functions like
removeItem/updateQuantity) instead of logging, and likewise remove/replace any
other placeholder console.log statements in the nearby handlers (the handlers
around lines 59-65) with their proper implementations or calls to shared
utilities so no debug logs remain.
src/components/mui/FormItemTable/components/ItemTableField.js-13-79 (1)

13-79: ⚠️ Potential issue | 🟡 Minor

Missing default case in switch statement.

The switch statement doesn't handle unknown field.type values, causing the function to implicitly return undefined. This could cause silent rendering failures for unrecognized field types.

Proposed fix to add default case
     case "TextArea":
       return (
         <MuiFormikTextField
           name={name}
           label={label}
           fullWidth
           size="small"
           multiline
           rows={3}
         />
       );
+    default:
+      console.warn(`Unknown field type: ${field.type}`);
+      return null;
   }
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/components/ItemTableField.js` around lines
13 - 79, The switch over field.type in the ItemTableField component lacks a
default branch, so unknown field.type values cause an implicit undefined render;
add a default case to the switch (in the same switch handling "CheckBox",
"CheckBoxList", "RadioButtonList", etc.) that returns a safe fallback (e.g.,
null) and logs a warning with the offending field.type (use console.warn or your
app logger) so unrecognized types fail loudly instead of producing silent
rendering errors.
src/components/mui/formik-inputs/mui-formik-dropdown-checkbox.js-16-18 (1)

16-18: ⚠️ Potential issue | 🟡 Minor

Edge case: allSelected is true when options is empty.

Array.every() returns true for an empty array. If options is empty, allSelected will be true, causing the "All" checkbox to appear checked and renderValue to show "All" text even though nothing is actually selected.

Proposed fix
-  const allSelected = options.every(({ value }) =>
-    field.value?.includes(value)
-  );
+  const allSelected = options.length > 0 && options.every(({ value }) =>
+    field.value?.includes(value)
+  );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/formik-inputs/mui-formik-dropdown-checkbox.js` around
lines 16 - 18, The bug is that allSelected is true when options is empty because
Array.every returns true for empty arrays; update the allSelected calculation in
mui-formik-dropdown-checkbox.js (the allSelected constant) to require
options.length > 0 and that field.value is an array before checking every option
(e.g., guard with options.length > 0 && Array.isArray(field.value) &&
options.every(({ value }) => field.value.includes(value))) so the "All" checkbox
and renderValue only show "All" when there are options and they are actually all
selected.
src/pages/sponsors/sponsor-cart-tab/components/edit-form.js-1-9 (1)

1-9: ⚠️ Potential issue | 🟡 Minor

Placeholder file with unused imports should be removed or repurposed.

This file defines an EditForm component that returns null and imports unused React and T. Meanwhile, the actual EditForm implementation exists at src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-form.js. This placeholder may cause import confusion.

If this file is intended as a barrel/re-export, update it to re-export from the actual implementation. Otherwise, consider removing it.

Option 1: Convert to re-export
-import React from "react";
-import T from "i18n-react/dist/i18n-react";
-
-const EditForm = () => {
-
-  return null;
-}
-
-export default EditForm;
+export { default } from "./edit-form/edit-form";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form.js` around lines 1 -
9, This placeholder EditForm component imports React and T but returns null and
shadows the real implementation; either remove this file and update any imports
to point to the real component, or turn it into a simple re-export of the real
implementation (stop importing unused React/T and export the default from the
actual edit-form implementation so consumers resolve correctly). Locate the
symbol EditForm in this file and replace the body with a re-export of the real
implementation (or delete the file) and run a quick search to update any broken
imports.
src/components/mui/FormItemTable/components/GlobalQuantityField.js-14-17 (1)

14-17: ⚠️ Potential issue | 🟡 Minor

Missing helpers in useEffect dependency array.

The effect uses helpers.setValue and helpers.setTouched but doesn't include helpers in the dependency array. This could cause stale closure issues. Additionally, unconditionally setting touched: true on value changes may display validation errors before user interaction.

Proposed fix
   useEffect(() => {
     helpers.setValue(value);
-    helpers.setTouched(true);
-  }, [value]);
+    // Only mark as touched if the value actually changed from user interaction
+  }, [value, helpers]);

Note: The eslint-disable comment suggests this was intentionally omitted, but could cause issues if helpers reference changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/components/GlobalQuantityField.js` around
lines 14 - 17, The effect currently uses helpers.setValue and helpers.setTouched
but only lists [value] as a dependency which can lead to stale closures; update
the useEffect to include helpers in its dependency array (e.g., [value,
helpers]) and stop unconditionally calling helpers.setTouched(true) on every
value change — either remove the setTouched call so programmatic updates don't
mark the field touched, or guard it behind an explicit condition/prop (e.g.,
only mark touched for user-driven changes). Ensure you update the effect around
the existing useEffect that references helpers.setValue and helpers.setTouched.
src/pages/sponsors/sponsor-cart-tab/components/cart-view.js-136-136 (1)

136-136: ⚠️ Potential issue | 🟡 Minor

Hardcoded English string breaks internationalization.

The text "forms in Cart" is hardcoded while the rest of the component uses T.translate(). This should use a translation key for consistency.

Proposed fix
-          <Box component="span">{cart?.forms.length} forms in Cart</Box>
+          <Box component="span">
+            {T.translate("edit_sponsor.cart_tab.forms_in_cart", { count: cart?.forms.length })}
+          </Box>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/cart-view.js` at line 136,
Replace the hardcoded English label inside the Box component so it uses the app
i18n helper like the other strings: call T.translate with an appropriate key
(e.g., "sponsors.cart.formsInCart") and interpolate cart?.forms.length into that
localized message instead of the literal "forms in Cart"; update the usage near
the Box component that currently renders {cart?.forms.length} forms in Cart to
use T.translate(...) and pass the count as a variable so translations can render
pluralization/localized text correctly.
src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/index.js-57-64 (1)

57-64: ⚠️ Potential issue | 🟡 Minor

State not reset when dialog closes via backdrop/escape.

The Dialog's onClose prop calls onClose directly (Line 111), bypassing handleClose which resets selectedRows. Additionally, selectedAddon is never reset. This causes stale selections when the dialog reopens.

🐛 Proposed fix
   const handleClose = () => {
     setSelectedRows([]);
+    setSelectedAddon(null);
     onClose();
   };

   // ...

-    <Dialog open={open} onClose={onClose} maxWidth="md" fullWidth>
+    <Dialog open={open} onClose={handleClose} maxWidth="md" fullWidth>

Also applies to: 111-111

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/index.js`
around lines 57 - 64, The Dialog's onClose currently calls onClose directly,
bypassing handleClose so selectedRows and selectedAddon aren't reset; change the
Dialog to use handleClose for its onClose handler and update handleClose (and
any other close paths like confirm/cancel handlers) to reset both selectedRows
and selectedAddon (e.g., setSelectedRows([]) and
setSelectedAddon(null/initialValue)) before calling onClose(), and ensure
handleOnCheck continues to set selectedRows as before.
src/components/mui/FormItemTable/__tests__/FormItemTable.test.js-446-452 (1)

446-452: ⚠️ Potential issue | 🟡 Minor

Property name mismatch in test mock data.

The test uses class: "Form" but the ItemTableField component constructs the field name using field.class_field (see relevant snippet line 10: const name = \i-${rowId}-c-${field.class_field}-f-${field.type_id}`;`). This inconsistency will cause the test to not render inputs with the expected test IDs.

🐛 Proposed fix
           meta_fields: [
             {
               type_id: 100,
-              class: "Form",
+              class_field: "Form",
               name: "Description",
               type: "Text"
             }
           ]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/__tests__/FormItemTable.test.js` around
lines 446 - 452, The mock field in the test uses "class" whereas the component
(ItemTableField) reads field.class_field to build the input name (const name =
`i-${rowId}-c-${field.class_field}-f-${field.type_id}`), so update the test
fixture to include a class_field property (e.g. class_field: "Form") or rename
the existing "class" key to "class_field" so the generated test IDs match and
the inputs render correctly.
src/components/mui/FormItemTable/__tests__/FormItemTable.test.js-19-23 (1)

19-23: ⚠️ Potential issue | 🟡 Minor

Property name mismatch in MOCK_RATE_DATES.

The mock uses onsite_end_date but the FormItemTable component expects onsite_price_end_date based on the relevant code snippet (lines 45-47 in FormItemTable/index.js). This mismatch will cause the onsite rate logic to behave unexpectedly in tests.

🐛 Proposed fix
 const MOCK_RATE_DATES = {
   early_bird_end_date: EARLY_BIRD_DATE,
   standard_price_end_date: STANDARD_DATE,
-  onsite_end_date: ONSITE_DATE
+  onsite_price_end_date: ONSITE_DATE
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/__tests__/FormItemTable.test.js` around
lines 19 - 23, The mock object MOCK_RATE_DATES uses the wrong property name for
the onsite date; update MOCK_RATE_DATES so the key matches what FormItemTable
expects (onsite_price_end_date) instead of onsite_end_date, keeping
EARLY_BIRD_DATE and STANDARD_DATE mapped to early_bird_end_date and
standard_price_end_date respectively; this ensures the FormItemTable logic that
reads onsite_price_end_date will get ONSITE_DATE from the test fixture.
src/components/mui/FormItemTable/__tests__/FormItemTable.test.js-558-578 (1)

558-578: ⚠️ Potential issue | 🟡 Minor

Incorrect property name used in rate highlighting tests.

The tests use MOCK_RATE_DATES.early_bird_rate and MOCK_RATE_DATES.standard_rate, but MOCK_RATE_DATES is defined with early_bird_end_date and standard_price_end_date properties. This will result in accessing undefined values, causing the tests to not behave as intended.

🐛 Proposed fix
     it("highlights standard rate when current time is between early_bird and standard", () => {
       jest
         .spyOn(Date, "now")
         .mockImplementation(
           () =>
-            (MOCK_RATE_DATES.early_bird_rate + TIME_OFFSET) *
+            (MOCK_RATE_DATES.early_bird_end_date + TIME_OFFSET) *
             MILLISECONDS_MULTIPLIER
         );
       // ...
     });

     it("highlights onsite rate when current time is after standard_rate", () => {
       jest
         .spyOn(Date, "now")
         .mockImplementation(
           () =>
-            (MOCK_RATE_DATES.standard_rate + TIME_OFFSET) *
+            (MOCK_RATE_DATES.standard_price_end_date + TIME_OFFSET) *
             MILLISECONDS_MULTIPLIER
         );
       // ...
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/__tests__/FormItemTable.test.js` around
lines 558 - 578, The test is referencing non-existent properties on
MOCK_RATE_DATES (early_bird_rate and standard_rate); update the test to use the
correct properties (early_bird_end_date and standard_price_end_date) when
building the mocked Date.now value used in the "highlights standard rate..."
spec (the Date.now mock in the test and any other tests referencing those wrong
keys), or alternatively adjust MOCK_RATE_DATES to include the expected keys;
ensure the Date.now mock multiplies the correct end-date field by
MILLISECONDS_MULTIPLIER so the time comparison in FormItemTable rendering uses
real values.
🧹 Nitpick comments (8)
src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-form.js (1)

126-129: Use .forEach() instead of .map() for side effects.

Using .map() when the return value is not used is misleading. These iterations are purely for side effects (building accumulator objects), so .forEach() is more appropriate.

Proposed fix
 const buildInitialValues = (items, timeZone) =>
   items.reduce((acc, item) => {
-    item.meta_fields.map((f) => {
+    item.meta_fields.forEach((f) => {
       acc[`i-${item.form_item_id}-c-${f.class_field}-f-${f.type_id}`] =
         parseValue(f, timeZone);
     });
     // ...
   }, {});

 const buildValidationSchema = (items, t) =>
   items.reduce((acc, item) => {
     item.meta_fields
       .filter((f) => f.class_field === "Form")
-      .map((f) => {
+      .forEach((f) => {
         acc[`i-${item.form_item_id}-c-${f.class_field}-f-${f.type_id}`] =
           getYupValidation(f, t);
       });
     // ...
   }, {});

Also applies to: 142-145

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-form.js` around
lines 126 - 129, Replace uses of .map() that are used only for side effects with
.forEach() to avoid misleading code: change item.meta_fields.map((f) => { ... })
to item.meta_fields.forEach((f) => { ... }) in the accumulator-building blocks
(the snippet using
acc[`i-${item.form_item_id}-c-${f.class_field}-f-${f.type_id}`] = parseValue(f,
timeZone);) and apply the same change for the similar occurrence around the
other block (the code at the second occurrence that mirrors lines 142-145).
src/components/mui/FormItemTable/index.js (2)

80-86: calculateTotal is not memoized, causing potential performance issues.

calculateTotal is a regular function that gets recreated on every render and is used in totalAmount useMemo. Since it's not stable, changes to unrelated state could trigger unnecessary recalculations.

Consider memoizing calculateTotal
-  const calculateTotal = (row) => {
+  const calculateTotal = useCallback((row) => {
     const qty =
       values[`i-${row.form_item_id}-c-global-f-quantity`] ||
       calculateQuantity(row);
     if (currentApplicableRate === "expired") return 0;
     return qty * row.rates[currentApplicableRate];
-  };
+  }, [values, calculateQuantity, currentApplicableRate]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/index.js` around lines 80 - 86,
calculateTotal is recreated each render which invalidates the totalAmount
useMemo; wrap calculateTotal in React.useCallback so it is stable between
renders (keep its signature calculateTotal(row)), and include as dependencies:
currentApplicableRate, values, and calculateQuantity (and any other helper it
uses). Ensure you reference the same calculateTotal in the totalAmount useMemo
so the memo depends on the stable callback rather than a new function each
render.

64-78: calculateQuantity dependency on valuesStr may cause stale closures.

The useCallback depends on valuesStr (stringified values) but references extraColumns directly. If extraColumns changes without valuesStr changing, the callback will use stale extraColumns. Also, stringifying the entire values object on every render for dependency comparison is inefficient.

Proposed fix
   const calculateQuantity = useCallback(
     (row) => {
       const qtyEXC = extraColumns.filter((exc) => exc.type === "Quantity");
       return qtyEXC.reduce((res, exc) => {
         const start = res > 0 ? res : 1;
         return (
           start *
           (values?.[
             `i-${row.form_item_id}-c-${exc.class_field}-f-${exc.type_id}`
           ] || 0)
         );
       }, 0);
     },
-    [valuesStr]
+    [values, extraColumns]
   );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/index.js` around lines 64 - 78, The
calculateQuantity callback currently lists only valuesStr as a dependency and
reads extraColumns and values directly, which can produce stale closures; update
the useCallback dependencies to include extraColumns and values (or a stable
memoized reference to values) instead of relying on valuesStr stringification,
or memoize extraColumns where it’s created and then include that memoized
symbol; ensure the dependency array is [values, extraColumns] (or
[memoizedValues, memoizedExtraColumns]) so calculateQuantity always sees the
latest extraColumns and values.
src/components/mui/formik-inputs/mui-formik-dropdown-checkbox.js (1)

35-72: Missing validation error display for users.

The component binds error={meta.touched && Boolean(meta.error)} to FormControl, which sets error styling, but doesn't render the actual error message. Other similar components (e.g., MuiFormikCheckbox) include a FormHelperText to display the error text.

Proposed fix to display validation errors
+import {
+  Checkbox,
+  Divider,
+  FormControl,
+  FormHelperText,
+  ListItemText,
+  MenuItem,
+  Select
+} from "@mui/material";
...
       </Select>
+      {meta.touched && meta.error && (
+        <FormHelperText>{meta.error}</FormHelperText>
+      )}
     </FormControl>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/formik-inputs/mui-formik-dropdown-checkbox.js` around
lines 35 - 72, The FormControl is marking errors via error={meta.touched &&
Boolean(meta.error)} but the component (MuiFormikDropdownCheckbox) never renders
the error text; add a FormHelperText under the Select that displays the
validation message when meta.touched && meta.error is truthy (e.g.,
<FormHelperText>{meta.touched && meta.error}</FormHelperText>), and ensure
FormHelperText is imported from `@mui/material` so the visual error text matches
the FormControl error state.
src/pages/sponsors/sponsor-cart-tab/components/cart-view.js (1)

35-37: Missing getSponsorCart in useEffect dependency array.

The effect calls getSponsorCart() but doesn't include it in the dependency array. While this works due to how connect works, adding it follows React hooks best practices and prevents lint warnings.

Proposed fix
   useEffect(() => {
     getSponsorCart();
-  }, []);
+  }, [getSponsorCart]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/cart-view.js` around lines 35
- 37, The useEffect invoking getSponsorCart is missing getSponsorCart in its
dependency array; update the useEffect that calls getSponsorCart to include
getSponsorCart in the deps so React hooks linters are satisfied, and if
getSponsorCart is not a stable reference (e.g., coming from props via
mapDispatchToProps or recreated each render) make it stable by memoizing it
(move to a stable mapDispatchToProps, wrap it in useCallback where defined, or
otherwise ensure the reference is stable) before adding to the dependency array.
src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/index.js (2)

173-177: Incomplete PropTypes definition.

Several props are used but not declared in PropTypes: availableForms, sponsor, open, and getSponsorFormsForCart. This reduces type safety and developer experience.

♻️ Suggested improvement
 SelectFormDialog.propTypes = {
+  availableForms: PropTypes.shape({
+    forms: PropTypes.array,
+    currentPage: PropTypes.number,
+    term: PropTypes.string,
+    order: PropTypes.string,
+    orderDir: PropTypes.number,
+    total: PropTypes.number
+  }).isRequired,
   summitId: PropTypes.number.isRequired,
+  sponsor: PropTypes.shape({}).isRequired,
+  open: PropTypes.bool.isRequired,
   onClose: PropTypes.func.isRequired,
-  onSave: PropTypes.func.isRequired
+  onSave: PropTypes.func.isRequired,
+  getSponsorFormsForCart: PropTypes.func.isRequired
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/index.js`
around lines 173 - 177, SelectFormDialog.propTypes is missing several props used
by the component; add PropTypes entries for availableForms (array.isRequired or
array), sponsor (object.isRequired or shape), open (bool.isRequired), and
getSponsorFormsForCart (func.isRequired) to match how they're used. Update the
SelectFormDialog.propTypes declaration to include these keys with appropriate
PropTypes types (e.g., PropTypes.array, PropTypes.object or PropTypes.shape,
PropTypes.bool, PropTypes.func) and mark as required where the component depends
on them.

38-40: Missing dependency in useEffect.

The getSponsorFormsForCart function from props should be included in the dependency array. While it's a Redux-bound action creator that typically doesn't change, including it follows React's exhaustive-deps rule and prevents potential stale closure issues.

♻️ Suggested improvement
   useEffect(() => {
     getSponsorFormsForCart();
-  }, []);
+  }, [getSponsorFormsForCart]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/index.js`
around lines 38 - 40, The useEffect that calls getSponsorFormsForCart is missing
getSponsorFormsForCart in its dependency array; update the effect in
select-form-dialog's component so the dependency array includes
getSponsorFormsForCart (or alternatively ensure the prop is stable by wrapping
the action in useCallback where it's defined) to satisfy exhaustive-deps and
avoid stale closures—specifically modify the useEffect that currently calls
getSponsorFormsForCart() to depend on getSponsorFormsForCart.
src/pages/sponsors/sponsor-cart-tab/index.js (1)

24-29: No mechanism to exit edit mode.

There's no handler to set formEdit back to null after editing is complete or cancelled. The EditForm component's cancel button calls navigate(-1) (based on relevant snippet), which navigates away rather than returning to the cart view within this tab.

♻️ Suggested approach

Consider adding an onCancel or onComplete callback to EditForm that resets formEdit:

+  const handleEditComplete = () => {
+    setFormEdit(null);
+  };

   // ...

-      {formEdit && <EditForm form={formEdit} />}
+      {formEdit && (
+        <EditForm
+          form={formEdit.form}
+          addOnId={formEdit.addOnId}
+          onCancel={handleEditComplete}
+          onSave={handleEditComplete}
+        />
+      )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/index.js` around lines 24 - 29, The
component lacks a way to exit edit mode because formEdit is never reset; add a
handler (e.g., handleCloseEdit or handleCancelEdit) that calls setFormEdit(null)
and pass it into the EditForm as an onCancel/onComplete prop so the EditForm can
invoke it when the user cancels or finishes editing; also update EditForm usage
to call this callback instead of relying on navigate(-1) (or call
setFormEdit(null) alongside navigation) and ensure handleAddForm still sets
formEdit({ form, addOnId }) as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/actions/sponsor-cart-actions.js`:
- Around line 226-261: In saveCartForm, the request is using the wrong base URL,
missing sponsorId, and returns an incorrect success message—retrieve sponsorId
from currentSponsorState (similar to other cart actions), switch the request
base to window.PURCHASES_API_URL, and post to the path
/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/carts/current/forms/${formId}
(keep the normalizedEntity payload), then replace the snackbarSuccessHandler
translation key sponsor_list.sponsor_added with the correct cart-form success
key used elsewhere in this file; ensure the postRequest call still uses
createAction(FORM_CART_SAVED) and existing error handler.

In `@src/components/mui/FormItemTable/components/GlobalQuantityField.js`:
- Around line 25-32: The slotProps currently use slotProps.input for native
input attributes in GlobalQuantityField (and the Quantity case in
ItemTableField); change those to slotProps.htmlInput so native attributes
(readOnly, min, max) are applied to the underlying <input> element—update the
slotProps object in GlobalQuantityField (and the Quantity branch inside
ItemTableField) to move readOnly, min: 0 and the conditional max
(row.quantity_limit_per_sponsor) into htmlInput instead of input.

In `@src/components/mui/FormItemTable/components/ItemTableField.js`:
- Around line 46-53: Update the TextField's slotProps in ItemTableField.js so
the numeric constraints go to the native input element: move min
(field.minimum_quantity) and conditional max (field.maximum_quantity > 0 ?
field.maximum_quantity : undefined) from slotProps.input to slotProps.htmlInput
so the actual <input> receives these attributes; locate the slotProps object in
the ItemTableField component and replace the input key with htmlInput carrying
the min/max values.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-cart-form.js`:
- Line 30: The saveForm handler currently references an undefined variable
form_id which will throw at runtime; change the call in saveForm to pass the
correct identifier (use form.id) so it becomes saveForm = (values) =>
updateCartForm(form.id, values), ensuring you update the reference to the
defined prop/object used elsewhere in this component (verify the component
exports/props that provide form and that updateCartForm is the expected
function).
- Around line 16-19: Replace the non-existent imports updateCartForm and
getCartForm with the actual exported action creators getSponsorFormsForCart and
saveCartForm from sponsor-cart-actions, and update all uses in this component to
call saveCartForm instead of updateCartForm and getSponsorFormsForCart instead
of getCartForm; also fix the undefined variable by replacing form_id with
form.id wherever referenced (e.g., in event handlers or payload construction) so
the component uses the correct property names and action creators.
- Around line 32-34: The wrapper is passing the wrong props to EditForm and also
references form_id incorrectly; update the return to pass the props EditForm
expects: provide form={form} (fix any form_id -> form.id usage),
addOnId={addOnId}, cartFormId={cartFormId}, showMetadata={showMetadata},
showTimeZone={showTimeZone}, and rename saveForm to saveCartForm
(saveCartForm={saveForm}) so the prop names match EditForm’s signature; ensure
any internal references use form.id instead of form_id.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-form.js`:
- Line 240: In handleSave, replace the undefined variable formId with the
correct identifier form.id when calling saveCartForm so the call becomes
saveCartForm(form.id, addOnId, items); update any references inside handleSave
that expect formId to use form.id instead; ensure this change is applied in the
edit-form component where handleSave is declared and where saveCartForm is
invoked.
- Around line 306-316: The file is using NotesModal and ItemSettingsModal in the
JSX but they are not imported; add import statements for NotesModal and
ItemSettingsModal at the top of the module (same module that defines the edit
form) so the components referenced in the JSX (NotesModal, ItemSettingsModal)
are resolved at runtime; ensure the import paths point to the correct files
(e.g., import NotesModal from "./NotesModal" and import ItemSettingsModal from
"./ItemSettingsModal" or the correct relative paths) and save.
- Line 24: The import for FormItemTable is pointing to the wrong directory;
update the import statement that references FormItemTable in the edit-form.js
module so it includes the mui folder (i.e., import the FormItemTable from the
components/mui/FormItemTable location) so the module resolves the component
correctly.

In
`@src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/__tests__/select-page-template-dialog.test.js`:
- Around line 11-21: The test imports and mocks refer to the wrong component and
Redux pieces; update the test to import the actual component exported from the
tested module (use SelectFormDialog instead of SelectPageTemplateDialog from
"../index"), replace the mocked action module
"../../../actions/page-template-actions" with the correct actions module for the
form dialog (mock "../../../actions/sponsor-cart-actions" and the specific
action(s) used by SelectFormDialog), and adjust the mocked Redux state to the
slice shape SelectFormDialog expects (replace pageTemplateListState with the
correct state key and structure used by SelectFormDialog, e.g.,
sponsorCart/formTemplate list or whatever prop name SelectFormDialog reads).
Ensure the mocked action names and state keys match the component’s usage so the
test mounts the correct component with the expected props.

---

Nitpick comments:
In `@src/components/mui/formik-inputs/mui-formik-dropdown-checkbox.js`:
- Around line 35-72: The FormControl is marking errors via error={meta.touched
&& Boolean(meta.error)} but the component (MuiFormikDropdownCheckbox) never
renders the error text; add a FormHelperText under the Select that displays the
validation message when meta.touched && meta.error is truthy (e.g.,
<FormHelperText>{meta.touched && meta.error}</FormHelperText>), and ensure
FormHelperText is imported from `@mui/material` so the visual error text matches
the FormControl error state.

In `@src/components/mui/FormItemTable/index.js`:
- Around line 80-86: calculateTotal is recreated each render which invalidates
the totalAmount useMemo; wrap calculateTotal in React.useCallback so it is
stable between renders (keep its signature calculateTotal(row)), and include as
dependencies: currentApplicableRate, values, and calculateQuantity (and any
other helper it uses). Ensure you reference the same calculateTotal in the
totalAmount useMemo so the memo depends on the stable callback rather than a new
function each render.
- Around line 64-78: The calculateQuantity callback currently lists only
valuesStr as a dependency and reads extraColumns and values directly, which can
produce stale closures; update the useCallback dependencies to include
extraColumns and values (or a stable memoized reference to values) instead of
relying on valuesStr stringification, or memoize extraColumns where it’s created
and then include that memoized symbol; ensure the dependency array is [values,
extraColumns] (or [memoizedValues, memoizedExtraColumns]) so calculateQuantity
always sees the latest extraColumns and values.

In `@src/pages/sponsors/sponsor-cart-tab/components/cart-view.js`:
- Around line 35-37: The useEffect invoking getSponsorCart is missing
getSponsorCart in its dependency array; update the useEffect that calls
getSponsorCart to include getSponsorCart in the deps so React hooks linters are
satisfied, and if getSponsorCart is not a stable reference (e.g., coming from
props via mapDispatchToProps or recreated each render) make it stable by
memoizing it (move to a stable mapDispatchToProps, wrap it in useCallback where
defined, or otherwise ensure the reference is stable) before adding to the
dependency array.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-form.js`:
- Around line 126-129: Replace uses of .map() that are used only for side
effects with .forEach() to avoid misleading code: change
item.meta_fields.map((f) => { ... }) to item.meta_fields.forEach((f) => { ... })
in the accumulator-building blocks (the snippet using
acc[`i-${item.form_item_id}-c-${f.class_field}-f-${f.type_id}`] = parseValue(f,
timeZone);) and apply the same change for the similar occurrence around the
other block (the code at the second occurrence that mirrors lines 142-145).

In `@src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/index.js`:
- Around line 173-177: SelectFormDialog.propTypes is missing several props used
by the component; add PropTypes entries for availableForms (array.isRequired or
array), sponsor (object.isRequired or shape), open (bool.isRequired), and
getSponsorFormsForCart (func.isRequired) to match how they're used. Update the
SelectFormDialog.propTypes declaration to include these keys with appropriate
PropTypes types (e.g., PropTypes.array, PropTypes.object or PropTypes.shape,
PropTypes.bool, PropTypes.func) and mark as required where the component depends
on them.
- Around line 38-40: The useEffect that calls getSponsorFormsForCart is missing
getSponsorFormsForCart in its dependency array; update the effect in
select-form-dialog's component so the dependency array includes
getSponsorFormsForCart (or alternatively ensure the prop is stable by wrapping
the action in useCallback where it's defined) to satisfy exhaustive-deps and
avoid stale closures—specifically modify the useEffect that currently calls
getSponsorFormsForCart() to depend on getSponsorFormsForCart.

In `@src/pages/sponsors/sponsor-cart-tab/index.js`:
- Around line 24-29: The component lacks a way to exit edit mode because
formEdit is never reset; add a handler (e.g., handleCloseEdit or
handleCancelEdit) that calls setFormEdit(null) and pass it into the EditForm as
an onCancel/onComplete prop so the EditForm can invoke it when the user cancels
or finishes editing; also update EditForm usage to call this callback instead of
relying on navigate(-1) (or call setFormEdit(null) alongside navigation) and
ensure handleAddForm still sets formEdit({ form, addOnId }) as before.

Comment on lines 226 to 261
export const saveCartForm = (formId, addOnId, items) => async (dispatch, getState) => {
const { currentSummitState } = getState();
const accessToken = await getAccessTokenSafely();
const { currentSummit } = currentSummitState;

const params = {
access_token: accessToken
};

dispatch(startLoading());

const normalizedEntity = {
form_id: formId,
add_on_id: addOnId,
items: items.map((item) => ({
quantity: item.quantity,
add_on_item_id: item.id
}))
}

return postRequest(
null,
createAction(FORM_CART_SAVED),
`${window.API_BASE_URL}/api/v2/summits/${currentSummit.id}/sponsors`,
normalizedEntity,
snackbarErrorHandler
)(params)(dispatch).then(() => {
dispatch(stopLoading());
dispatch(
snackbarSuccessHandler({
title: T.translate("general.success"),
html: T.translate("sponsor_list.sponsor_added")
})
);
});
}; No newline at end of file
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how other cart actions construct their URLs and handle sponsorId
echo "=== Searching for PURCHASES_API_URL pattern in cart actions ==="
rg -n "PURCHASES_API_URL" src/actions/sponsor-cart-actions.js -A 3

echo ""
echo "=== Check for cart/forms endpoint patterns ==="
rg -n "carts.*forms\|forms.*cart" src/actions/ -B 2 -A 2

echo ""
echo "=== Check if sponsorId is retrieved in other functions ==="
rg -n "sponsorId" src/actions/sponsor-cart-actions.js -B 2 -A 2

echo ""
echo "=== Check what endpoints use /sponsors path ==="
rg -n "/summits/.*sponsors" src/actions/sponsor-cart-actions.js -B 3 -A 3

Repository: fntechgit/summit-admin

Length of output: 3688


🏁 Script executed:

#!/bin/bash
# Check translation keys for cart and sponsor operations
echo "=== Search for translation keys containing sponsor_added, cart_saved, form_saved ==="
rg -n "sponsor.*added\|cart.*saved\|form.*saved" src/i18n/ 

echo ""
echo "=== Check context around the success message translation ==="
rg -n "sponsor_list.sponsor_added" src/ -B 5 -A 5

Repository: fntechgit/summit-admin

Length of output: 1475


🏁 Script executed:

#!/bin/bash
# Get file size and examine the full sponsor-cart-actions.js to understand patterns
wc -l src/actions/sponsor-cart-actions.js

echo ""
echo "=== Check for other similar addOn or form-related functions ==="
rg -n "export const.*Form\|export const.*addOn" src/actions/sponsor-cart-actions.js -A 1

Repository: fntechgit/summit-admin

Length of output: 170


Fix incorrect API endpoint, retrieve sponsorId, and use appropriate success message.

The saveCartForm function posts to the wrong endpoint. It should follow the pattern of other cart actions in this file:

  • Use ${window.PURCHASES_API_URL} instead of ${window.API_BASE_URL}
  • Include the sponsorId (retrieved from currentSponsorState like other functions in this file)
  • Use the path /api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/carts/current/forms/${formId} instead of /api/v2/summits/${currentSummit.id}/sponsors
  • The success message translation key sponsor_list.sponsor_added is meant for sponsor creation operations, not cart form saves—use an appropriate translation key for this operation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/actions/sponsor-cart-actions.js` around lines 226 - 261, In saveCartForm,
the request is using the wrong base URL, missing sponsorId, and returns an
incorrect success message—retrieve sponsorId from currentSponsorState (similar
to other cart actions), switch the request base to window.PURCHASES_API_URL, and
post to the path
/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/carts/current/forms/${formId}
(keep the normalizedEntity payload), then replace the snackbarSuccessHandler
translation key sponsor_list.sponsor_added with the correct cart-form success
key used elsewhere in this file; ensure the postRequest call still uses
createAction(FORM_CART_SAVED) and existing error handler.

Comment on lines +25 to +32
slotProps={{
input: {
readOnly: isReadOnly,
min: 0,
...(row.quantity_limit_per_sponsor
? { max: row.quantity_limit_per_sponsor }
: {})
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's verify the file structure and locate the relevant files
ls -la src/components/mui/FormItemTable/components/ 2>/dev/null | head -20

Repository: fntechgit/summit-admin

Length of output: 315


🏁 Script executed:

#!/bin/bash
# Check the GlobalQuantityField component
cat src/components/mui/FormItemTable/components/GlobalQuantityField.js 2>/dev/null || echo "File not found"

Repository: fntechgit/summit-admin

Length of output: 1448


🏁 Script executed:

#!/bin/bash
# Check the MuiFormikTextField component
find . -name "*mui-formik-textfield*" -o -name "*MuiFormikTextField*" 2>/dev/null | head -10

Repository: fntechgit/summit-admin

Length of output: 124


🏁 Script executed:

#!/bin/bash
# Search for MUI TextField usages with slotProps patterns
rg "slotProps.*htmlInput|slotProps.*input" --type js -B 2 -A 2 | head -100

Repository: fntechgit/summit-admin

Length of output: 657


🏁 Script executed:

#!/bin/bash
# Check the MuiFormikTextField implementation
cat src/components/mui/formik-inputs/mui-formik-textfield.js

Repository: fntechgit/summit-admin

Length of output: 1350


🏁 Script executed:

#!/bin/bash
# Check ItemTableField to compare patterns
cat src/components/mui/FormItemTable/components/ItemTableField.js

Repository: fntechgit/summit-admin

Length of output: 2536


🏁 Script executed:

#!/bin/bash
# Search for htmlInput usage in the codebase
rg "slotProps.*htmlInput" --type js -B 2 -A 2 | head -150

Repository: fntechgit/summit-admin

Length of output: 48


Use slotProps.htmlInput instead of slotProps.input for min, max, and readOnly attributes.

min and max are native HTML input attributes that must reach the <input> element. Similarly, readOnly is typically a native input attribute. These should be passed via slotProps.htmlInput, not slotProps.input. The latter passes props to the Input component itself, which does not apply these HTML attributes to the native element.

Additionally, ItemTableField has the same issue in its Quantity case and should be corrected together.

Suggested fix for GlobalQuantityField:
slotProps={{
  htmlInput: {
    readOnly: isReadOnly,
    min: 0,
    ...(row.quantity_limit_per_sponsor
      ? { max: row.quantity_limit_per_sponsor }
      : {})
  }
}}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/components/GlobalQuantityField.js` around
lines 25 - 32, The slotProps currently use slotProps.input for native input
attributes in GlobalQuantityField (and the Quantity case in ItemTableField);
change those to slotProps.htmlInput so native attributes (readOnly, min, max)
are applied to the underlying <input> element—update the slotProps object in
GlobalQuantityField (and the Quantity branch inside ItemTableField) to move
readOnly, min: 0 and the conditional max (row.quantity_limit_per_sponsor) into
htmlInput instead of input.

Comment on lines +46 to +53
slotProps={{
input: {
min: field.minimum_quantity,
...(field.maximum_quantity > 0
? { max: field.maximum_quantity }
: {})
}
}}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

MUI TextField slotProps.htmlInput vs slotProps.input min max attributes

💡 Result:

In TextField, slotProps.input and slotProps.htmlInput target different layers:

  • slotProps.input → props for the MUI Input component (OutlinedInput / FilledInput / Input), i.e. the wrapper component around the native element. This is where you pass component-level props like startAdornment, endAdornment, sx, etc. (mui.com)
  • slotProps.htmlInput → attributes for the actual native <input> element (the “htmlInput” slot). This is where native constraints like min / max / step / maxLength / etc. belong. (mui.com)

So for min/max, use slotProps.htmlInput:

<TextField
  type="number"
  slotProps={{ htmlInput: { min: 0, max: 100 } }}
/>

This is the v6+ replacement for the deprecated inputProps (native <input> attrs) and InputProps (MUI Input component props):
inputPropsslotProps.htmlInput, and InputPropsslotProps.input. (mui.com)

Citations:


🏁 Script executed:

cat -n src/components/mui/FormItemTable/components/ItemTableField.js | sed -n '40,60p'

Repository: fntechgit/summit-admin

Length of output: 711


Move min/max to slotProps.htmlInput for the native input element to receive these constraints.

In MUI TextField, slotProps.input passes props to the MUI Input component wrapper, while slotProps.htmlInput passes attributes to the actual native <input> element. The min and max attributes must use slotProps.htmlInput to work:

Correct usage:
slotProps={{
  htmlInput: {
    min: field.minimum_quantity,
    ...(field.maximum_quantity > 0
      ? { max: field.maximum_quantity }
      : {})
  }
}}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/components/ItemTableField.js` around lines
46 - 53, Update the TextField's slotProps in ItemTableField.js so the numeric
constraints go to the native input element: move min (field.minimum_quantity)
and conditional max (field.maximum_quantity > 0 ? field.maximum_quantity :
undefined) from slotProps.input to slotProps.htmlInput so the actual <input>
receives these attributes; locate the slotProps object in the ItemTableField
component and replace the input key with htmlInput carrying the min/max values.

Comment on lines 16 to 19
import {
updateCartForm,
getCartForm
} from "../../../../../actions/sponsor-cart-actions";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check exported functions from sponsor-cart-actions
rg -n "^export\s+(const|function|async function)" src/actions/sponsor-cart-actions.js

Repository: fntechgit/summit-admin

Length of output: 965


🏁 Script executed:

#!/bin/bash
# Let me also check what the edit-cart-form.js file actually uses these imports for
sed -n '1,50p' src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-cart-form.js | cat -n

Repository: fntechgit/summit-admin

Length of output: 1539


🏁 Script executed:

#!/bin/bash
# Check if there are any other files trying to import these non-existent actions
rg "updateCartForm|getCartForm" src/ --type js

Repository: fntechgit/summit-admin

Length of output: 871


Replace non-existent imports with correct action creators.

updateCartForm and getCartForm do not exist in sponsor-cart-actions. The file exports getSponsorFormsForCart and saveCartForm instead. Update the imports at lines 16-19 and their usage in the component accordingly.

Additionally, line 30 references undefined variable form_id—should be form.id.

🧰 Tools
🪛 ESLint

[error] 17-17: updateCartForm not found in '../../../../../actions/sponsor-cart-actions'

(import/named)


[error] 18-18: getCartForm not found in '../../../../../actions/sponsor-cart-actions'

(import/named)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-cart-form.js`
around lines 16 - 19, Replace the non-existent imports updateCartForm and
getCartForm with the actual exported action creators getSponsorFormsForCart and
saveCartForm from sponsor-cart-actions, and update all uses in this component to
call saveCartForm instead of updateCartForm and getSponsorFormsForCart instead
of getCartForm; also fix the undefined variable by replacing form_id with
form.id wherever referenced (e.g., in event handlers or payload construction) so
the component uses the correct property names and action creators.


const getForm = () => getCartForm(form.id);

const saveForm = (values) => updateCartForm(form_id, values);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Undefined variable form_id will cause runtime error.

saveForm references form_id which is not defined anywhere in this component. This should likely be form.id.

Proposed fix
-  const saveForm = (values) => updateCartForm(form_id, values);
+  const saveForm = (values) => updateCartForm(form.id, values);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-cart-form.js`
at line 30, The saveForm handler currently references an undefined variable
form_id which will throw at runtime; change the call in saveForm to pass the
correct identifier (use form.id) so it becomes saveForm = (values) =>
updateCartForm(form.id, values), ensuring you update the reference to the
defined prop/object used elsewhere in this component (verify the component
exports/props that provide form and that updateCartForm is the expected
function).

Comment on lines 32 to 34
return (
<EditForm getForm={getForm} saveForm={saveForm} />
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's locate the EditForm component
find . -name "edit-form.js" -type f

Repository: fntechgit/summit-admin

Length of output: 199


🏁 Script executed:

#!/bin/bash
# Let's also check the EditCartForm file to see the full context
cat -n src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-cart-form.js

Repository: fntechgit/summit-admin

Length of output: 1539


🏁 Script executed:

#!/bin/bash
# Search for EditForm component definition to see what props it expects
rg "const EditForm|function EditForm" --max-count=5 -A 10

Repository: fntechgit/summit-admin

Length of output: 1495


🏁 Script executed:

#!/bin/bash
cat -n src/pages/sponsors/sponsor-cart-tab/components/edit-form.js

Repository: fntechgit/summit-admin

Length of output: 269


🏁 Script executed:

#!/bin/bash
# Also get more context from the actual EditForm implementation
cat -n src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-form.js | head -50

Repository: fntechgit/summit-admin

Length of output: 2494


Fix props mismatch between EditCartForm and EditForm.

The EditForm component (in src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-form.js) expects props: form, addOnId, cartFormId, showMetadata, showTimeZone, and saveCartForm. The wrapper passes getForm and saveForm functions which don't match the expected interface. Additionally, line 30 references undefined form_id instead of form.id.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-cart-form.js`
around lines 32 - 34, The wrapper is passing the wrong props to EditForm and
also references form_id incorrectly; update the return to pass the props
EditForm expects: provide form={form} (fix any form_id -> form.id usage),
addOnId={addOnId}, cartFormId={cartFormId}, showMetadata={showMetadata},
showTimeZone={showTimeZone}, and rename saveForm to saveCartForm
(saveCartForm={saveForm}) so the prop names match EditForm’s signature; ensure
any internal references use form.id instead of form_id.

import { useNavigate } from "react-router-dom";
import moment from "moment-timezone";
import { epochToMomentTimeZone } from "openstack-uicore-foundation/lib/utils/methods";
import FormItemTable from "../../../../../components/FormItemTable";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find all FormItemTable files in the repository
fd -t f "FormItemTable" --extension js --extension jsx

Repository: fntechgit/summit-admin

Length of output: 130


🏁 Script executed:

# List all files in the FormItemTable directory
find src/components/mui/FormItemTable -type f

# Also check for the component file more broadly
fd -t f "FormItemTable" --extension js --extension jsx --extension ts --extension tsx

Repository: fntechgit/summit-admin

Length of output: 366


🏁 Script executed:

# Read the edit-form.js file to see the exact import
cat -n src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-form.js | head -30

# Check if there's a FormItemTable at src/components/ (without mui)
find src/components -maxdepth 1 -name "FormItemTable*" -type f
find src/components -maxdepth 1 -name "FormItemTable*" -type d

Repository: fntechgit/summit-admin

Length of output: 1683


🏁 Script executed:

# Check all directories in src/components/ to see the actual structure
ls -la src/components/ | head -20

Repository: fntechgit/summit-admin

Length of output: 1242


🏁 Script executed:

# Continue listing src/components/
ls -la src/components/ | tail -20

Repository: fntechgit/summit-admin

Length of output: 1322


Correct the import path to include the mui directory.

The import path is missing mui. The FormItemTable component is located at src/components/mui/FormItemTable/index.js, so the import should be:

import FormItemTable from "../../../../../components/mui/FormItemTable";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-form.js` at
line 24, The import for FormItemTable is pointing to the wrong directory; update
the import statement that references FormItemTable in the edit-form.js module so
it includes the mui folder (i.e., import the FormItemTable from the
components/mui/FormItemTable location) so the module resolves the component
correctly.

Comment on lines 306 to 316
<NotesModal
item={notesItem}
open={!!notesItem}
onClose={() => setNotesItem(null)}
onSave={formik.handleSubmit}
/>
<ItemSettingsModal
item={settingsItem}
open={!!settingsItem}
onClose={() => setSettingsItem(null)}
/>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

NotesModal and ItemSettingsModal are not imported.

ESLint correctly flags that these components are used but never imported, which will cause a runtime error when the component renders.

Add the missing imports at the top of the file:

import NotesModal from "./NotesModal"; // Adjust path as needed
import ItemSettingsModal from "./ItemSettingsModal"; // Adjust path as needed
🧰 Tools
🪛 ESLint

[error] 306-306: 'NotesModal' is not defined.

(react/jsx-no-undef)


[error] 312-312: 'ItemSettingsModal' is not defined.

(react/jsx-no-undef)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/edit-form.js` around
lines 306 - 316, The file is using NotesModal and ItemSettingsModal in the JSX
but they are not imported; add import statements for NotesModal and
ItemSettingsModal at the top of the module (same module that defines the edit
form) so the components referenced in the JSX (NotesModal, ItemSettingsModal)
are resolved at runtime; ensure the import paths point to the correct files
(e.g., import NotesModal from "./NotesModal" and import ItemSettingsModal from
"./ItemSettingsModal" or the correct relative paths) and save.

Comment on lines +11 to +21
import SelectPageTemplateDialog from "../index";

jest.mock("i18n-react/dist/i18n-react", () => ({
__esModule: true,
default: { translate: (key) => key }
}));

// Mock Redux actions
jest.mock("../../../actions/page-template-actions", () => ({
getPageTemplates: jest.fn(() => () => Promise.resolve())
}));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify what component is exported from select-form-dialog/index.js
echo "=== Checking component export from index.js ==="
cat src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/index.js | head -50

echo ""
echo "=== Checking if SelectPageTemplateDialog exists elsewhere ==="
find . -type f -name "*.js" -o -name "*.jsx" | xargs grep -l "SelectPageTemplateDialog" 2>/dev/null | head -20

echo ""
echo "=== Checking the action imports in the component ==="
rg -n "import.*from.*actions" src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/

Repository: fntechgit/summit-admin

Length of output: 2158


🏁 Script executed:

#!/bin/bash
# Check the full test file to see what's being imported and mocked
echo "=== Full test file content ==="
cat src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/__tests__/select-page-template-dialog.test.js

echo ""
echo "=== Checking the correct test file name (if it exists) ==="
ls -la src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/__tests__/ | grep -E "\.test\.|\.spec\."

Repository: fntechgit/summit-admin

Length of output: 11429


Test file imports and mocks the wrong component.

The test file imports SelectPageTemplateDialog from "../index", but the component exported at that path is SelectFormDialog. The test file also mocks the wrong Redux action (../../../actions/page-template-actions instead of sponsor-cart-actions) and uses the wrong Redux state slice (pageTemplateListState instead of the state structure expected by SelectFormDialog).

This test file appears to be copied from the SelectPageTemplateDialog tests without being properly adapted for SelectFormDialog. It will fail immediately because the component import doesn't exist at the mocked location.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/pages/sponsors/sponsor-cart-tab/components/select-form-dialog/__tests__/select-page-template-dialog.test.js`
around lines 11 - 21, The test imports and mocks refer to the wrong component
and Redux pieces; update the test to import the actual component exported from
the tested module (use SelectFormDialog instead of SelectPageTemplateDialog from
"../index"), replace the mocked action module
"../../../actions/page-template-actions" with the correct actions module for the
form dialog (mock "../../../actions/sponsor-cart-actions" and the specific
action(s) used by SelectFormDialog), and adjust the mocked Redux state to the
slice shape SelectFormDialog expects (replace pageTemplateListState with the
correct state key and structure used by SelectFormDialog, e.g.,
sponsorCart/formTemplate list or whatever prop name SelectFormDialog reads).
Ensure the mocked action names and state keys match the component’s usage so the
test mounts the correct component with the expected props.

Copy link

@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: 12

🧹 Nitpick comments (3)
src/components/mui/ItemSettingsModal/index.js (1)

72-76: Declare timeZone in PropTypes for clarity.

It’s used by ItemTableField, so documenting it avoids silent misuse.

🔧 Suggested fix
 ItemSettingsModal.propTypes = {
   item: PropTypes.object.isRequired,
+  timeZone: PropTypes.string,
   open: PropTypes.bool.isRequired,
   onClose: PropTypes.func.isRequired
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/ItemSettingsModal/index.js` around lines 72 - 76, Add the
missing timeZone PropType to the ItemSettingsModal component: update
ItemSettingsModal.propTypes to include timeZone (e.g.,
PropTypes.string.isRequired or PropTypes.string) since ItemTableField consumes
it; locate the ItemSettingsModal.propTypes block and add the timeZone entry with
the appropriate required/optional setting to match how ItemTableField expects
it.
src/components/mui/FormItemTable/index.js (2)

37-41: Guard against empty data array before accessing data[0].

While data[0]?.meta_fields?.filter handles undefined gracefully, other parts of the component (e.g., data.map on line 131) assume data is a non-empty array. Consider adding an early return or guard clause.

 const FormItemTable = ({
   data,
   rateDates,
   timeZone,
   values,
   onNotesClick,
   onSettingsClick
 }) => {
+  if (!data || data.length === 0) {
+    return null;
+  }
+
   const valuesStr = JSON.stringify(values);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/index.js` around lines 37 - 41, The
component assumes `data` is a non-empty array (e.g., computing
extraColumns/totalColumns and later using data.map in the component) which can
lead to runtime errors; add a guard at the top of the component to handle
empty/undefined `data` (return null/placeholder or an empty table) before
computing valuesStr/extraColumns/fixedColumns/totalColumns and before calling
data.map, or default `data` to an empty array and short-circuit rendering when
data.length === 0 to ensure the rest of the logic (including valuesStr,
extraColumns and the data.map usage) is safe.

86-92: calculateTotal accesses values directly but is not memoized.

This function is called during render (line 98 and 200). While it works correctly because it's inside the component, it would be more consistent to either memoize it or inline the logic where it's used.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/index.js` around lines 86 - 92,
calculateTotal currently closes over values and other props and is re-created on
every render; memoize it to avoid stale closures and unnecessary re-computation
by converting it into a useCallback (or replace with an inline useMemo at call
site) that depends on [values, calculateQuantity, currentApplicableRate]; ensure
the memoized function still accepts row and uses
values[`i-${row.form_item_id}-c-global-f-quantity`] || calculateQuantity(row)
and row.rates[currentApplicableRate], and update any usages (where
calculateTotal is called during render) to call the memoized calculateTotal to
keep behavior identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/mui/formik-inputs/mui-formik-dropdown-checkbox.js`:
- Around line 13-17: Handle undefined options and ensure field.value is an array
in MuiFormikDropdownCheckbox: guard against options being undefined by
defaulting/using a safeOptions (e.g., const safeOptions = options || [])
wherever options is iterated (used for allSelected and maps), and normalize the
selected values coming from useField by coercing field.value to an array (e.g.,
const selected = Array.isArray(field.value) ? field.value : []) before using
.includes or other array methods; update references to options and field.value
(used in allSelected, onChange handlers, and any maps) to use safeOptions and
selected so rendering won’t crash when options are async or field.value is
undefined.

In `@src/components/mui/FormItemTable/components/ItemTableField.js`:
- Around line 1-11: Remove the unused imports T and METAFIELD_TYPES from
ItemTableField.js and reorder the import statements to satisfy ESLint import
ordering (external packages first: react and `@mui/material`, then third-party
packages like i18n-react if used, then local project imports such as
"../../formik-inputs/..." and "../../../../utils/constants"). Specifically,
delete the T and METAFIELD_TYPES import lines, ensure React and MenuItem imports
come before the local MuiFormik* imports, and keep only the imports referenced
by ItemTableField (e.g., MuiFormikCheckbox, MuiFormikDropdownCheckbox,
MuiFormikDropdownRadio, MuiFormikDatepicker, MuiFormikTimepicker,
MuiFormikTextField, MuiFormikSelect) so ESLint no longer reports unused imports
or ordering violations.

In `@src/components/mui/FormItemTable/index.js`:
- Around line 70-84: The calculateQuantity useCallback currently lists only
valuesStr as a dependency but reads extraColumns (and values), so update its
dependency array to include extraColumns (and values if values is mutable) so
the callback recomputes when extraColumns or values change; modify the
dependency array for calculateQuantity to include extraColumns and values (or
valuesStr and extraColumns together) to ensure correct updates.

In `@src/components/mui/NotesModal/index.js`:
- Around line 20-24: handleSave unconditionally calls onSave (and similarly the
handler at lines 64-68 calls onClear/onClose) but onSave/onClear aren't declared
in PropTypes; update the component to either (1) guard the calls by checking if
(onSave) onSave() and if (onClear) onClear() before invoking, and (2) add
PropTypes entries for onSave and onClear (or provide defaultProps with no-op
functions) so callers and linters know these props exist; locate the handlers
handleSave and the handler at lines ~64-68 and the component's PropTypes to make
these changes.
- Around line 1-24: NotesModal keeps a local notes state that isn't updated when
a different item is passed in, causing old notes to appear; update the notes
state whenever the item or the form field value changes by adding a useEffect in
NotesModal that reads field.value (or constructs name) and calls
setNotes(field?.value || "") when item?.form_item_id or field?.value changes, so
the local notes always reflect the current useField value before the modal is
shown; ensure the effect references the existing symbols name, useField (field),
setNotes, and item.

In `@src/components/mui/sponsor-addon-select.js`:
- Around line 15-25: The effect that calls querySponsorAddons should re-run when
sponsor or summitId change and guard against missing data: move the
sponsorshipIds computation into the useEffect (or include sponsorshipIds in the
dependency array) and update the useEffect dependency list to [sponsor?.id,
summitId, /*or sponsorshipIds*/]; ensure you check sponsor and
sponsor.sponsorships exist before calling querySponsorAddons, then call
querySponsorAddons(summitId, sponsor.id, sponsorshipIds, ...) and setOptions as
before so options refresh when props change.
- Around line 27-29: The handleChange handler currently uses ev.target.label
which is undefined for MUI Select; update handleChange (the function named
handleChange) to derive the selected option's name by finding the matching entry
in the options array (the same array used by renderValue) using ev.target.value,
then call onChange with { id: value, name: matchedOption?.label || '' } (or
similar fallback) so the name is populated correctly; ensure you reference the
same options variable used in renderValue when locating the label before
invoking onChange.

In `@src/pages/sponsors/edit-sponsor-page.js`:
- Line 266: The JSX in edit-sponsor-page.js passes an unused history prop to
SponsorCartTab; update the usage or the component: either remove history from
the <SponsorCartTab sponsor={entity} summitId={currentSummit.id}
history={history} /> call, or modify the SponsorCartTab component
(src/pages/sponsors/sponsor-cart-tab/index.js) to accept and use a history prop
(add history to the prop destructuring and implement navigation where needed).
Ensure props remain consistent between the caller (edit-sponsor-page.js) and the
component (SponsorCartTab).

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/index.js`:
- Around line 150-186: The helper buildValidationSchema currently expects a full
form object but the caller passes form?.items, so the function returns an empty
schema; change buildValidationSchema to accept an items array (e.g., rename
parameter to items and use const items = itemsParam || []) and update its
internal references (keep getYupValidation, the acc keys like
i-{item.form_item_id}-c-{...}, and global quantity/notes handling) to operate on
that array; also update every call site (where buildValidationSchema is invoked)
to pass the items array directly (instead of a form) so the schema is
constructed correctly — likewise fix the other occurrence that mirrors this
logic (the similar block around the second build call).
- Around line 218-256: handleSave fails when values contains non-item keys like
discount/discount_type because the key.split("-") path produces invalid indices
and NaN ids; update handleSave to first detect and skip non-item keys (e.g.,
ensure the split produces the expected segments and that parseInt(match[1]) and
parseInt(match[5]) yield valid numbers) before proceeding, and guard lookups on
form.items and meta_fields (ensure metaField exists) before accessing
metaField.type; reference the handleSave reducer, resItem creation, the use of
match[], form.items.find(...).meta_fields.find(...), and the metaField.type
checks to apply these guards.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/new-cart-form.js`:
- Around line 30-32: The useEffect that calls getSponsorForm(formId) currently
has an empty dependency array so it won't re-run when the incoming formId prop
changes; update the effect in the component containing useEffect and
getSponsorForm to include formId in the dependency array (i.e., useEffect(() =>
{ getSponsorForm(formId); }, [formId])) so the form is refetched whenever formId
changes.

In `@src/pages/sponsors/sponsor-cart-tab/index.js`:
- Line 22: The initial state for formEdit is hardcoded to {formId: 19, addon:
null}, causing NewCartForm to render immediately; remove the debug value by
initializing formEdit to a falsy/empty state (e.g., null or {formId: null,
addon: null}) in the useState call and keep using setFormEdit to populate it
when a real edit is triggered so that the component conditionally renders
CartView until a real formEdit exists (refer to the formEdit and setFormEdit
state variables and the NewCartForm/CartView conditional rendering).

---

Duplicate comments:
In `@src/actions/sponsor-cart-actions.js`:
- Around line 248-283: The addCartForm function is using the wrong API base,
omitting the sponsorId, and showing the wrong success message; fix it by reading
currentSponsorState from getState to extract currentSponsor.id (use that as
sponsorId), switch the base URL to window.PURCHASES_API_URL instead of
window.API_BASE_URL, update the endpoint to include the sponsorId (e.g.,
.../api/v2/summits/${currentSummit.id}/sponsors/${sponsorId}/cart/forms), and
replace the snackbar success translation key (currently
"sponsor_list.sponsor_added") with an appropriate cart-form success key (e.g.,
"cart_form.added") so the message matches the operation.

In `@src/components/mui/FormItemTable/components/ItemTableField.js`:
- Around line 45-58: The numeric min/max attributes are being set on
slotProps.input (the MUI Input wrapper) so native constraints never reach the
actual <input>; update the MuiFormikTextField usage to move the min and max into
slotProps.htmlInput instead, using field.minimum_quantity for min and only set
max when field.maximum_quantity > 0 (same conditional), keeping the rest of
props (name, label, type="number", fullWidth, size="small") unchanged; locate
the MuiFormikTextField instance in ItemTableField.js and replace slotProps.input
with slotProps.htmlInput while preserving the conditional max logic.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/index.js`:
- Around line 189-195: The EditForm component exposes props onSaveForm but never
uses it and references undefined variables saveCartForm, formId, and addOnId in
the save handler; update the component to wire handleSave to call the onSaveForm
prop (passing the validated form payload) and stop referencing undefined
identifiers—replace any use of saveCartForm with onSaveForm, ensure handleSave
reads the correct ids from the passed-in form prop (e.g., form.id and
form.addOnId or the prop names present) or from explicit props, and validate
those ids before calling onSaveForm so no undefined values are sent.

---

Nitpick comments:
In `@src/components/mui/FormItemTable/index.js`:
- Around line 37-41: The component assumes `data` is a non-empty array (e.g.,
computing extraColumns/totalColumns and later using data.map in the component)
which can lead to runtime errors; add a guard at the top of the component to
handle empty/undefined `data` (return null/placeholder or an empty table) before
computing valuesStr/extraColumns/fixedColumns/totalColumns and before calling
data.map, or default `data` to an empty array and short-circuit rendering when
data.length === 0 to ensure the rest of the logic (including valuesStr,
extraColumns and the data.map usage) is safe.
- Around line 86-92: calculateTotal currently closes over values and other props
and is re-created on every render; memoize it to avoid stale closures and
unnecessary re-computation by converting it into a useCallback (or replace with
an inline useMemo at call site) that depends on [values, calculateQuantity,
currentApplicableRate]; ensure the memoized function still accepts row and uses
values[`i-${row.form_item_id}-c-global-f-quantity`] || calculateQuantity(row)
and row.rates[currentApplicableRate], and update any usages (where
calculateTotal is called during render) to call the memoized calculateTotal to
keep behavior identical.

In `@src/components/mui/ItemSettingsModal/index.js`:
- Around line 72-76: Add the missing timeZone PropType to the ItemSettingsModal
component: update ItemSettingsModal.propTypes to include timeZone (e.g.,
PropTypes.string.isRequired or PropTypes.string) since ItemTableField consumes
it; locate the ItemSettingsModal.propTypes block and add the timeZone entry with
the appropriate required/optional setting to match how ItemTableField expects
it.

Comment on lines +13 to +17
const MuiFormikDropdownCheckbox = ({ name, options, ...rest }) => {
const [field, meta, helpers] = useField(name);
const allSelected = options.every(({ value }) =>
field.value?.includes(value)
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard against undefined options and normalize selected values.

If options is undefined (e.g., async load), options.every(...) and options.map(...) will throw and crash the render. Defaulting options and normalizing field.value to an array keeps the component safe and controlled.

🛠️ Suggested fix
-const MuiFormikDropdownCheckbox = ({ name, options, ...rest }) => {
+const MuiFormikDropdownCheckbox = ({ name, options = [], ...rest }) => {
   const [field, meta, helpers] = useField(name);
-  const allSelected = options.every(({ value }) =>
-    field.value?.includes(value)
-  );
+  const selectedValues = Array.isArray(field.value) ? field.value : [];
+  const allSelected =
+    options.length > 0 &&
+    options.every(({ value }) => selectedValues.includes(value));
...
-        value={field.value || []}
+        value={selectedValues}
...
-          <MenuItem key={`ckbx-ddl-${value}`} value={value}>
-            <Checkbox checked={field.value?.includes(value)} />
+          <MenuItem key={`ckbx-ddl-${value}`} value={value}>
+            <Checkbox checked={selectedValues.includes(value)} />
             <ListItemText primary={label} />
          </MenuItem>

Also applies to: 40-67

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/formik-inputs/mui-formik-dropdown-checkbox.js` around
lines 13 - 17, Handle undefined options and ensure field.value is an array in
MuiFormikDropdownCheckbox: guard against options being undefined by
defaulting/using a safeOptions (e.g., const safeOptions = options || [])
wherever options is iterated (used for allSelected and maps), and normalize the
selected values coming from useField by coercing field.value to an array (e.g.,
const selected = Array.isArray(field.value) ? field.value : []) before using
.includes or other array methods; update references to options and field.value
(used in allSelected, onChange handlers, and any maps) to use safeOptions and
selected so rendering won’t crash when options are async or field.value is
undefined.

Comment on lines +1 to +11
import React from "react";
import MuiFormikCheckbox from "../../formik-inputs/mui-formik-checkbox";
import MuiFormikDropdownCheckbox from "../../formik-inputs/mui-formik-dropdown-checkbox";
import MuiFormikDropdownRadio from "../../formik-inputs/mui-formik-dropdown-radio";
import MuiFormikDatepicker from "../../formik-inputs/mui-formik-datepicker";
import MuiFormikTimepicker from "../../formik-inputs/mui-formik-timepicker";
import MuiFormikTextField from "../../formik-inputs/mui-formik-textfield";
import MuiFormikSelect from "../../formik-inputs/mui-formik-select";
import T from "i18n-react";
import { METAFIELD_TYPES } from "../../../../utils/constants";
import { MenuItem } from "@mui/material";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove unused imports and fix ESLint import order.

ESLint flags unused T/METAFIELD_TYPES and import ordering violations.

🔧 Suggested fix
-import React from "react";
-import MuiFormikCheckbox from "../../formik-inputs/mui-formik-checkbox";
-import MuiFormikDropdownCheckbox from "../../formik-inputs/mui-formik-dropdown-checkbox";
-import MuiFormikDropdownRadio from "../../formik-inputs/mui-formik-dropdown-radio";
-import MuiFormikDatepicker from "../../formik-inputs/mui-formik-datepicker";
-import MuiFormikTimepicker from "../../formik-inputs/mui-formik-timepicker";
-import MuiFormikTextField from "../../formik-inputs/mui-formik-textfield";
-import MuiFormikSelect from "../../formik-inputs/mui-formik-select";
-import T from "i18n-react";
-import { METAFIELD_TYPES } from "../../../../utils/constants";
-import { MenuItem } from "@mui/material";
+import React from "react";
+import { MenuItem } from "@mui/material";
+import MuiFormikCheckbox from "../../formik-inputs/mui-formik-checkbox";
+import MuiFormikDropdownCheckbox from "../../formik-inputs/mui-formik-dropdown-checkbox";
+import MuiFormikDropdownRadio from "../../formik-inputs/mui-formik-dropdown-radio";
+import MuiFormikDatepicker from "../../formik-inputs/mui-formik-datepicker";
+import MuiFormikTimepicker from "../../formik-inputs/mui-formik-timepicker";
+import MuiFormikTextField from "../../formik-inputs/mui-formik-textfield";
+import MuiFormikSelect from "../../formik-inputs/mui-formik-select";
🧰 Tools
🪛 ESLint

[error] 9-9: i18n-react import should occur before import of ../../formik-inputs/mui-formik-checkbox

(import/order)


[error] 9-9: 'T' is defined but never used.

(unused-imports/no-unused-imports)


[error] 9-9: 'T' is defined but never used.

(no-unused-vars)


[error] 10-10: 'METAFIELD_TYPES' is defined but never used.

(unused-imports/no-unused-imports)


[error] 10-10: 'METAFIELD_TYPES' is defined but never used.

(no-unused-vars)


[error] 11-11: @mui/material import should occur before import of ../../formik-inputs/mui-formik-checkbox

(import/order)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/components/ItemTableField.js` around lines 1
- 11, Remove the unused imports T and METAFIELD_TYPES from ItemTableField.js and
reorder the import statements to satisfy ESLint import ordering (external
packages first: react and `@mui/material`, then third-party packages like
i18n-react if used, then local project imports such as "../../formik-inputs/..."
and "../../../../utils/constants"). Specifically, delete the T and
METAFIELD_TYPES import lines, ensure React and MenuItem imports come before the
local MuiFormik* imports, and keep only the imports referenced by ItemTableField
(e.g., MuiFormikCheckbox, MuiFormikDropdownCheckbox, MuiFormikDropdownRadio,
MuiFormikDatepicker, MuiFormikTimepicker, MuiFormikTextField, MuiFormikSelect)
so ESLint no longer reports unused imports or ordering violations.

Comment on lines +70 to +84
const calculateQuantity = useCallback(
(row) => {
const qtyEXC = extraColumns.filter((exc) => exc.type === "Quantity");
return qtyEXC.reduce((res, exc) => {
const start = res > 0 ? res : 1;
return (
start *
(values?.[
`i-${row.form_item_id}-c-${exc.class_field}-f-${exc.type_id}`
] || 0)
);
}, 0);
},
[valuesStr]
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Dependency on valuesStr instead of extraColumns in calculateQuantity.

The calculateQuantity callback uses extraColumns but only lists valuesStr as a dependency. If extraColumns changes (e.g., different form data loaded), the callback won't update.

   const calculateQuantity = useCallback(
     (row) => {
       const qtyEXC = extraColumns.filter((exc) => exc.type === "Quantity");
       return qtyEXC.reduce((res, exc) => {
         const start = res > 0 ? res : 1;
         return (
           start *
           (values?.[
             `i-${row.form_item_id}-c-${exc.class_field}-f-${exc.type_id}`
           ] || 0)
         );
       }, 0);
     },
-    [valuesStr]
+    [valuesStr, extraColumns]
   );
📝 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
const calculateQuantity = useCallback(
(row) => {
const qtyEXC = extraColumns.filter((exc) => exc.type === "Quantity");
return qtyEXC.reduce((res, exc) => {
const start = res > 0 ? res : 1;
return (
start *
(values?.[
`i-${row.form_item_id}-c-${exc.class_field}-f-${exc.type_id}`
] || 0)
);
}, 0);
},
[valuesStr]
);
const calculateQuantity = useCallback(
(row) => {
const qtyEXC = extraColumns.filter((exc) => exc.type === "Quantity");
return qtyEXC.reduce((res, exc) => {
const start = res > 0 ? res : 1;
return (
start *
(values?.[
`i-${row.form_item_id}-c-${exc.class_field}-f-${exc.type_id}`
] || 0)
);
}, 0);
},
[valuesStr, extraColumns]
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/index.js` around lines 70 - 84, The
calculateQuantity useCallback currently lists only valuesStr as a dependency but
reads extraColumns (and values), so update its dependency array to include
extraColumns (and values if values is mutable) so the callback recomputes when
extraColumns or values change; modify the dependency array for calculateQuantity
to include extraColumns and values (or valuesStr and extraColumns together) to
ensure correct updates.

Comment on lines +1 to +24
import React, { useState } from "react";
import T from "i18n-react/dist/i18n-react";
import PropTypes from "prop-types";
import Button from "@mui/material/Button";
import Dialog from "@mui/material/Dialog";
import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogTitle from "@mui/material/DialogTitle";
import { useField } from "formik";
import { Divider, IconButton, TextField } from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";

const NotesModal = ({ item, open, onClose, onSave }) => {
const name = `i-${item?.form_item_id}-c-global-f-notes`;
// eslint-disable-next-line
const [field, meta, helpers] = useField(name);
const [notes, setNotes] = useState(field?.value || "");

const handleSave = () => {
helpers.setValue(notes);
onClose();
onSave();
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Sync local notes state when the item changes.

As written, opening the modal for a different item can show the previous item’s notes.

🔧 Suggested fix
-import React, { useState } from "react";
+import React, { useEffect, useState } from "react";
 ...
-  const [notes, setNotes] = useState(field?.value || "");
+  const [notes, setNotes] = useState(field?.value || "");
+
+  useEffect(() => {
+    setNotes(field?.value || "");
+  }, [field?.value, item?.form_item_id, open]);
📝 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
import React, { useState } from "react";
import T from "i18n-react/dist/i18n-react";
import PropTypes from "prop-types";
import Button from "@mui/material/Button";
import Dialog from "@mui/material/Dialog";
import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogTitle from "@mui/material/DialogTitle";
import { useField } from "formik";
import { Divider, IconButton, TextField } from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
const NotesModal = ({ item, open, onClose, onSave }) => {
const name = `i-${item?.form_item_id}-c-global-f-notes`;
// eslint-disable-next-line
const [field, meta, helpers] = useField(name);
const [notes, setNotes] = useState(field?.value || "");
const handleSave = () => {
helpers.setValue(notes);
onClose();
onSave();
};
import React, { useEffect, useState } from "react";
import T from "i18n-react/dist/i18n-react";
import PropTypes from "prop-types";
import Button from "@mui/material/Button";
import Dialog from "@mui/material/Dialog";
import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogTitle from "@mui/material/DialogTitle";
import { useField } from "formik";
import { Divider, IconButton, TextField } from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
const NotesModal = ({ item, open, onClose, onSave }) => {
const name = `i-${item?.form_item_id}-c-global-f-notes`;
// eslint-disable-next-line
const [field, meta, helpers] = useField(name);
const [notes, setNotes] = useState(field?.value || "");
useEffect(() => {
setNotes(field?.value || "");
}, [field?.value, item?.form_item_id, open]);
const handleSave = () => {
helpers.setValue(notes);
onClose();
onSave();
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/NotesModal/index.js` around lines 1 - 24, NotesModal keeps
a local notes state that isn't updated when a different item is passed in,
causing old notes to appear; update the notes state whenever the item or the
form field value changes by adding a useEffect in NotesModal that reads
field.value (or constructs name) and calls setNotes(field?.value || "") when
item?.form_item_id or field?.value changes, so the local notes always reflect
the current useField value before the modal is shown; ensure the effect
references the existing symbols name, useField (field), setNotes, and item.

Comment on lines +20 to +24
const handleSave = () => {
helpers.setValue(notes);
onClose();
onSave();
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard or require onSave before invoking.

onSave() is called unconditionally but isn’t defined in PropTypes.

🔧 Suggested fix
   const handleSave = () => {
     helpers.setValue(notes);
     onClose();
-    onSave();
+    if (onSave) onSave();
   };
 ...
 NotesModal.propTypes = {
   item: PropTypes.object.isRequired,
   open: PropTypes.bool.isRequired,
-  onClose: PropTypes.func.isRequired
+  onClose: PropTypes.func.isRequired,
+  onSave: PropTypes.func
 };

Also applies to: 64-68

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/NotesModal/index.js` around lines 20 - 24, handleSave
unconditionally calls onSave (and similarly the handler at lines 64-68 calls
onClear/onClose) but onSave/onClear aren't declared in PropTypes; update the
component to either (1) guard the calls by checking if (onSave) onSave() and if
(onClear) onClear() before invoking, and (2) add PropTypes entries for onSave
and onClear (or provide defaultProps with no-op functions) so callers and
linters know these props exist; locate the handlers handleSave and the handler
at lines ~64-68 and the component's PropTypes to make these changes.

</CustomTabPanel>
<CustomTabPanel value={selectedTab} index={5}>
<SponsorCartTab sponsor={entity} summitId={currentSummit.id} />
<SponsorCartTab sponsor={entity} summitId={currentSummit.id} history={history} />
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unused history prop passed to SponsorCartTab.

Based on the component definition in src/pages/sponsors/sponsor-cart-tab/index.js, SponsorCartTab only accepts sponsor and summitId props. The history prop is not destructured or used.

Either remove the unused prop or update SponsorCartTab to use it if navigation is needed.

-          <SponsorCartTab sponsor={entity} summitId={currentSummit.id} history={history} />
+          <SponsorCartTab sponsor={entity} summitId={currentSummit.id} />
📝 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
<SponsorCartTab sponsor={entity} summitId={currentSummit.id} history={history} />
<SponsorCartTab sponsor={entity} summitId={currentSummit.id} />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/edit-sponsor-page.js` at line 266, The JSX in
edit-sponsor-page.js passes an unused history prop to SponsorCartTab; update the
usage or the component: either remove history from the <SponsorCartTab
sponsor={entity} summitId={currentSummit.id} history={history} /> call, or
modify the SponsorCartTab component
(src/pages/sponsors/sponsor-cart-tab/index.js) to accept and use a history prop
(add history to the prop destructuring and implement navigation where needed).
Ensure props remain consistent between the caller (edit-sponsor-page.js) and the
component (SponsorCartTab).

Comment on lines +150 to +186
const buildValidationSchema = (form) => {
const items = form.items || [];

const schema = items.reduce((acc, item) => {
item.meta_fields
.filter((f) => f.class_field === "Form")
.map((f) => {
acc[`i-${item.form_item_id}-c-${f.class_field}-f-${f.type_id}`] =
getYupValidation(f);
});
// notes
acc[`i-${item.form_item_id}-c-global-f-notes`] = yup.string(
T.translate("validation.string")
);
// validation for the global quantity input
let globalQtySchema = yup
.number(T.translate("validation.number"))
.min(1, `${T.translate("validation.minimum")} 1`);
if (item.quantity_limit_per_sponsor > 0) {
globalQtySchema = globalQtySchema.max(
item.quantity_limit_per_sponsor,
T.translate("validation.maximum", {
maximum: item.quantity_limit_per_sponsor
})
);
}
globalQtySchema = globalQtySchema.required(
T.translate("validation.required")
);
acc[`i-${item.form_item_id}-c-global-f-quantity`] = globalQtySchema;
return acc;
}, {});

schema.discount = yup.number(T.translate("validation.number"))
schema.discount_type = yup.string(T.translate("validation.string")).nullable();

return schema;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validation schema isn’t built because buildValidationSchema receives the wrong argument.

You pass form?.items, but the helper expects a form object, so it returns an empty schema.

🔧 Suggested fix (accept items array)
-const buildValidationSchema = (form) => {
-  const items = form.items || [];
+const buildValidationSchema = (items = []) => {

Also applies to: 261-266

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/index.js` around
lines 150 - 186, The helper buildValidationSchema currently expects a full form
object but the caller passes form?.items, so the function returns an empty
schema; change buildValidationSchema to accept an items array (e.g., rename
parameter to items and use const items = itemsParam || []) and update its
internal references (keep getYupValidation, the acc keys like
i-{item.form_item_id}-c-{...}, and global quantity/notes handling) to operate on
that array; also update every call site (where buildValidationSchema is invoked)
to pass the items array directly (instead of a form) so the schema is
constructed correctly — likewise fix the other occurrence that mirrors this
logic (the similar block around the second build call).

Comment on lines +218 to +256
const handleSave = (values) => {
// re-format form values to match the API format
const items = Object.entries(values).reduce((res, [key, val]) => {
const match = key.split("-");
if (match) {
const formItemId = parseInt(match[1]);
const itemClass = match[3]; // quantity or notes
const itemTypeId = match[5];
const isItemProp = !["quantity", "notes"].includes(itemTypeId);
let current_value = val;

let resItem = res.find((i) => i.form_item_id === formItemId);
if (!resItem) {
resItem = { form_item_id: formItemId, meta_fields: [] };
res.push(resItem);
}
if (isItemProp) {
const metaField = form.items
.find((i) => i.form_item_id === formItemId)
?.meta_fields.find((mf) => mf.type_id === parseInt(itemTypeId));

if (metaField.type === "DateTime") {
current_value = moment(val).unix();
} else if (metaField.type === "Time") {
current_value = moment(val).format("HH:mm");
}

resItem.meta_fields.push({
type_id: parseInt(itemTypeId),
class_field: itemClass,
current_value
});
} else {
resItem[itemTypeId] = current_value;
}
}

return res;
}, []);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

handleSave can throw on non-item keys (discount fields).

values includes discount and discount_type, which produce NaN ids and metaField lookups that will crash. Skip non item keys or handle them separately.

🔧 Suggested fix
-    const items = Object.entries(values).reduce((res, [key, val]) => {
-      const match = key.split("-");
-      if (match) {
+    const items = Object.entries(values).reduce((res, [key, val]) => {
+      if (!key.startsWith("i-")) return res;
+      const match = key.split("-");
+      if (match.length < 6) return res;
         const formItemId = parseInt(match[1]);
         const itemClass = match[3]; // quantity or notes
         const itemTypeId = match[5];
         const isItemProp = !["quantity", "notes"].includes(itemTypeId);
         let current_value = val;
@@
-          if (metaField.type === "DateTime") {
+          if (!metaField) return res;
+          if (metaField.type === "DateTime") {
             current_value = moment(val).unix();
           } else if (metaField.type === "Time") {
             current_value = moment(val).format("HH:mm");
           }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/index.js` around
lines 218 - 256, handleSave fails when values contains non-item keys like
discount/discount_type because the key.split("-") path produces invalid indices
and NaN ids; update handleSave to first detect and skip non-item keys (e.g.,
ensure the split produces the expected segments and that parseInt(match[1]) and
parseInt(match[5]) yield valid numbers) before proceeding, and guard lookups on
form.items and meta_fields (ensure metaField exists) before accessing
metaField.type; reference the handleSave reducer, resItem creation, the use of
match[], form.items.find(...).meta_fields.find(...), and the metaField.type
checks to apply these guards.

Comment on lines +30 to +32
useEffect(() => {
getSponsorForm(formId);
}, []);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check NewCartForm usage in parent components
rg -n --type=js -C5 'NewCartForm' src

Repository: fntechgit/summit-admin

Length of output: 3456


🏁 Script executed:

#!/bin/bash
# Find the parent component that uses NewCartForm
fd -e js sponsor-cart-tab | head -20

Repository: fntechgit/summit-admin

Length of output: 48


🏁 Script executed:

#!/bin/bash
# List the structure of the sponsor-cart-tab directory
find src/pages/sponsors/sponsor-cart-tab -type f -name "*.js" | head -30

Repository: fntechgit/summit-admin

Length of output: 497


🏁 Script executed:

#!/bin/bash
# View the complete new-cart-form.js file
cat -n src/pages/sponsors/sponsor-cart-tab/components/edit-form/new-cart-form.js

Repository: fntechgit/summit-admin

Length of output: 1871


Add formId to the useEffect dependency array to refetch when the form changes.

When the parent component updates formId without remounting this component, the effect won't re-run and stale sponsor form data will be displayed. Add formId to the dependency array to ensure the form is fetched whenever it changes.

🔧 Suggested fix
  useEffect(() => {
-   getSponsorForm(formId);
- }, []);
+   if (formId) {
+     getSponsorForm(formId);
+   }
+ }, [formId, getSponsorForm]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/components/edit-form/new-cart-form.js`
around lines 30 - 32, The useEffect that calls getSponsorForm(formId) currently
has an empty dependency array so it won't re-run when the incoming formId prop
changes; update the effect in the component containing useEffect and
getSponsorForm to include formId in the dependency array (i.e., useEffect(() =>
{ getSponsorForm(formId); }, [formId])) so the form is refetched whenever formId
changes.


const SponsorCartTab = ({ sponsor, summitId }) => {
const [openAddFormDialog, setOpenAddFormDialog] = useState(false);
const [formEdit, setFormEdit] = useState({formId: 19, addon: null});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove hardcoded debug value from initial state.

The formEdit state is initialized with { formId: 19, addon: null }, which causes NewCartForm to render immediately instead of showing CartView. This appears to be leftover debug code.

-  const [formEdit, setFormEdit] = useState({formId: 19, addon: null});
+  const [formEdit, setFormEdit] = useState(null);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/sponsors/sponsor-cart-tab/index.js` at line 22, The initial state
for formEdit is hardcoded to {formId: 19, addon: null}, causing NewCartForm to
render immediately; remove the debug value by initializing formEdit to a
falsy/empty state (e.g., null or {formId: null, addon: null}) in the useState
call and keep using setFormEdit to populate it when a real edit is triggered so
that the component conditionally renders CartView until a real formEdit exists
(refer to the formEdit and setFormEdit state variables and the
NewCartForm/CartView conditional rendering).

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

Comments