Conversation
📝 WalkthroughWalkthroughThis 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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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 | 🟡 MinorRefetch 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
sponsororsummitIdwon't trigger a refetch. Additionally, accessingsponsor.sponsorshipswithout 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 | 🟡 MinorAdd
summitIdto 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
summitIdprop changes, the component will display stale addon options. AddsummitIdas 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 | 🟡 MinorRemove or convert debug
console.logstatements.Multiple handlers contain placeholder
console.logstatements 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 | 🟡 MinorMissing default case in switch statement.
The switch statement doesn't handle unknown
field.typevalues, causing the function to implicitly returnundefined. 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 | 🟡 MinorEdge case:
allSelectedis true whenoptionsis empty.
Array.every()returnstruefor an empty array. Ifoptionsis empty,allSelectedwill betrue, causing the "All" checkbox to appear checked andrenderValueto 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 | 🟡 MinorPlaceholder file with unused imports should be removed or repurposed.
This file defines an
EditFormcomponent that returnsnulland imports unusedReactandT. Meanwhile, the actualEditFormimplementation exists atsrc/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 | 🟡 MinorMissing
helpersin useEffect dependency array.The effect uses
helpers.setValueandhelpers.setTouchedbut doesn't includehelpersin the dependency array. This could cause stale closure issues. Additionally, unconditionally settingtouched: trueon 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 | 🟡 MinorHardcoded English string breaks internationalization.
The text
"forms in Cart"is hardcoded while the rest of the component usesT.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 | 🟡 MinorState not reset when dialog closes via backdrop/escape.
The Dialog's
onCloseprop callsonClosedirectly (Line 111), bypassinghandleClosewhich resetsselectedRows. Additionally,selectedAddonis 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 | 🟡 MinorProperty name mismatch in test mock data.
The test uses
class: "Form"but theItemTableFieldcomponent constructs the field name usingfield.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 | 🟡 MinorProperty name mismatch in MOCK_RATE_DATES.
The mock uses
onsite_end_datebut theFormItemTablecomponent expectsonsite_price_end_datebased 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 | 🟡 MinorIncorrect property name used in rate highlighting tests.
The tests use
MOCK_RATE_DATES.early_bird_rateandMOCK_RATE_DATES.standard_rate, butMOCK_RATE_DATESis defined withearly_bird_end_dateandstandard_price_end_dateproperties. This will result in accessingundefinedvalues, 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:calculateTotalis not memoized, causing potential performance issues.
calculateTotalis a regular function that gets recreated on every render and is used intotalAmountuseMemo. 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:calculateQuantitydependency onvaluesStrmay cause stale closures.The
useCallbackdepends onvaluesStr(stringified values) but referencesextraColumnsdirectly. IfextraColumnschanges withoutvaluesStrchanging, the callback will use staleextraColumns. 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)}toFormControl, which sets error styling, but doesn't render the actual error message. Other similar components (e.g.,MuiFormikCheckbox) include aFormHelperTextto 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: MissinggetSponsorCartin useEffect dependency array.The effect calls
getSponsorCart()but doesn't include it in the dependency array. While this works due to howconnectworks, 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, andgetSponsorFormsForCart. 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
getSponsorFormsForCartfunction 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
formEditback tonullafter editing is complete or cancelled. TheEditFormcomponent's cancel button callsnavigate(-1)(based on relevant snippet), which navigates away rather than returning to the cart view within this tab.♻️ Suggested approach
Consider adding an
onCanceloronCompletecallback toEditFormthat resetsformEdit:+ 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.
src/actions/sponsor-cart-actions.js
Outdated
| 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 |
There was a problem hiding this comment.
🧩 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 3Repository: 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 5Repository: 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 1Repository: 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 fromcurrentSponsorStatelike 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_addedis 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.
| slotProps={{ | ||
| input: { | ||
| readOnly: isReadOnly, | ||
| min: 0, | ||
| ...(row.quantity_limit_per_sponsor | ||
| ? { max: row.quantity_limit_per_sponsor } | ||
| : {}) | ||
| } |
There was a problem hiding this comment.
🧩 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 -20Repository: 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 -10Repository: 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 -100Repository: fntechgit/summit-admin
Length of output: 657
🏁 Script executed:
#!/bin/bash
# Check the MuiFormikTextField implementation
cat src/components/mui/formik-inputs/mui-formik-textfield.jsRepository: fntechgit/summit-admin
Length of output: 1350
🏁 Script executed:
#!/bin/bash
# Check ItemTableField to compare patterns
cat src/components/mui/FormItemTable/components/ItemTableField.jsRepository: 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 -150Repository: 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.
| slotProps={{ | ||
| input: { | ||
| min: field.minimum_quantity, | ||
| ...(field.maximum_quantity > 0 | ||
| ? { max: field.maximum_quantity } | ||
| : {}) | ||
| } | ||
| }} |
There was a problem hiding this comment.
🧩 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 likestartAdornment,endAdornment,sx, etc. (mui.com)slotProps.htmlInput→ attributes for the actual native<input>element (the “htmlInput” slot). This is where native constraints likemin/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):
inputProps → slotProps.htmlInput, and InputProps → slotProps.input. (mui.com)
Citations:
- 1: https://mui.com/api/text-field/?utm_source=openai
- 2: https://mui.com/api/text-field/?utm_source=openai
- 3: https://mui.com/material-ui/migration/migrating-from-deprecated-apis/?utm_source=openai
🏁 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.
| import { | ||
| updateCartForm, | ||
| getCartForm | ||
| } from "../../../../../actions/sponsor-cart-actions"; |
There was a problem hiding this comment.
🧩 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.jsRepository: 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 -nRepository: 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 jsRepository: 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); |
There was a problem hiding this comment.
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).
| return ( | ||
| <EditForm getForm={getForm} saveForm={saveForm} /> | ||
| ); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, let's locate the EditForm component
find . -name "edit-form.js" -type fRepository: 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.jsRepository: 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 10Repository: fntechgit/summit-admin
Length of output: 1495
🏁 Script executed:
#!/bin/bash
cat -n src/pages/sponsors/sponsor-cart-tab/components/edit-form.jsRepository: 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 -50Repository: 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"; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find all FormItemTable files in the repository
fd -t f "FormItemTable" --extension js --extension jsxRepository: 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 tsxRepository: 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 dRepository: 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 -20Repository: fntechgit/summit-admin
Length of output: 1242
🏁 Script executed:
# Continue listing src/components/
ls -la src/components/ | tail -20Repository: 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.
| <NotesModal | ||
| item={notesItem} | ||
| open={!!notesItem} | ||
| onClose={() => setNotesItem(null)} | ||
| onSave={formik.handleSubmit} | ||
| /> | ||
| <ItemSettingsModal | ||
| item={settingsItem} | ||
| open={!!settingsItem} | ||
| onClose={() => setSettingsItem(null)} | ||
| /> |
There was a problem hiding this comment.
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.
| 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()) | ||
| })); |
There was a problem hiding this comment.
🧩 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.
There was a problem hiding this comment.
Actionable comments posted: 12
🧹 Nitpick comments (3)
src/components/mui/ItemSettingsModal/index.js (1)
72-76: DeclaretimeZonein 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 emptydataarray before accessingdata[0].While
data[0]?.meta_fields?.filterhandles undefined gracefully, other parts of the component (e.g.,data.mapon line 131) assumedatais 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:calculateTotalaccessesvaluesdirectly 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.
| const MuiFormikDropdownCheckbox = ({ name, options, ...rest }) => { | ||
| const [field, meta, helpers] = useField(name); | ||
| const allSelected = options.every(({ value }) => | ||
| field.value?.includes(value) | ||
| ); |
There was a problem hiding this comment.
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.
| 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"; |
There was a problem hiding this comment.
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.
| 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] | ||
| ); |
There was a problem hiding this comment.
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.
| 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.
| 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(); | ||
| }; |
There was a problem hiding this comment.
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.
| 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.
| const handleSave = () => { | ||
| helpers.setValue(notes); | ||
| onClose(); | ||
| onSave(); | ||
| }; |
There was a problem hiding this comment.
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} /> |
There was a problem hiding this comment.
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.
| <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).
| 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; |
There was a problem hiding this comment.
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).
| 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; | ||
| }, []); |
There was a problem hiding this comment.
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.
| useEffect(() => { | ||
| getSponsorForm(formId); | ||
| }, []); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check NewCartForm usage in parent components
rg -n --type=js -C5 'NewCartForm' srcRepository: 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 -20Repository: 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 -30Repository: 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.jsRepository: 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}); |
There was a problem hiding this comment.
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).
https://app.clickup.com/t/86b66n5kf
Summary by CodeRabbit
New Features
Tests