diff --git a/src/components/mui/__tests__/additional-input-list.test.js b/src/components/mui/__tests__/additional-input-list.test.js index 923a7bd37..46b922d73 100644 --- a/src/components/mui/__tests__/additional-input-list.test.js +++ b/src/components/mui/__tests__/additional-input-list.test.js @@ -97,12 +97,13 @@ describe("AdditionalInputList", () => { expect(screen.getByTestId("item-name-2")).toHaveTextContent("Field 3"); }); - test("renders nothing when meta_fields is empty", () => { + test("renders a default metafield when meta_fields is empty", () => { renderWithFormik(defaultProps, { meta_fields: [] }); - expect( - screen.queryByTestId("additional-input-0") - ).not.toBeInTheDocument(); + // Should render one default empty field + expect(screen.getByTestId("additional-input-0")).toBeInTheDocument(); + expect(screen.getByTestId("item-name-0")).toHaveTextContent(""); + expect(screen.getByTestId("item-type-0")).toHaveTextContent(""); }); }); diff --git a/src/components/mui/formik-inputs/additional-input/additional-input-list.js b/src/components/mui/formik-inputs/additional-input/additional-input-list.js index 541732502..2fbe1bbbf 100644 --- a/src/components/mui/formik-inputs/additional-input/additional-input-list.js +++ b/src/components/mui/formik-inputs/additional-input/additional-input-list.js @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect } from "react"; import { useFormikContext, getIn } from "formik"; import T from "i18n-react"; import AdditionalInput from "./additional-input"; @@ -19,8 +19,19 @@ const AdditionalInputList = ({ name, onDelete, onDeleteValue, entityId }) => { const metaFields = values[name] || []; + useEffect(() => { + if (metaFields.length === 0) { + setFieldValue(name, [ + { ...DEFAULT_META_FIELD, _key: `draft_${Date.now()}` } + ]); + } + }, [metaFields.length]); + const handleAddItem = () => { - setFieldValue(name, [...metaFields, { ...DEFAULT_META_FIELD }]); + setFieldValue(name, [ + ...metaFields, + { ...DEFAULT_META_FIELD, _key: `draft_${Date.now()}` } + ]); }; const handleRemove = async (item, index) => { @@ -39,7 +50,7 @@ const AdditionalInputList = ({ name, onDelete, onDeleteValue, entityId }) => { const removeFromUI = () => { const newValues = metaFields.filter((_, idx) => idx !== index); if (newValues.length === 0) { - newValues.push({ ...DEFAULT_META_FIELD }); + newValues.push({ ...DEFAULT_META_FIELD, _key: `draft_${Date.now()}` }); } setFieldValue(name, newValues); }; @@ -80,7 +91,7 @@ const AdditionalInputList = ({ name, onDelete, onDeleteValue, entityId }) => { <> {metaFields.map((item, itemIdx) => ( - + {T.translate("additional_inputs.meta_field_title")} diff --git a/src/pages/sponsors-global/form-templates/form-template-popup.js b/src/pages/sponsors-global/form-templates/form-template-popup.js index ab8807838..1b76af376 100644 --- a/src/pages/sponsors-global/form-templates/form-template-popup.js +++ b/src/pages/sponsors-global/form-templates/form-template-popup.js @@ -39,16 +39,7 @@ const FormTemplateDialog = ({ ...initialEntity, meta_fields: initialEntity?.meta_fields?.length ? initialEntity.meta_fields - : [ - { - name: "", - type: "Text", - is_required: false, - minimum_quantity: 0, - maximum_quantity: 0, - values: [] - } - ] + : [] }, validationSchema: yup.object().shape({ code: requiredStringValidation(), diff --git a/src/pages/sponsors-global/form-templates/sponsor-inventory-popup.js b/src/pages/sponsors-global/form-templates/sponsor-inventory-popup.js index f66bfd749..6d357d45d 100644 --- a/src/pages/sponsors-global/form-templates/sponsor-inventory-popup.js +++ b/src/pages/sponsors-global/form-templates/sponsor-inventory-popup.js @@ -51,16 +51,7 @@ const SponsorItemDialog = ({ ...initialEntity, meta_fields: initialEntity?.meta_fields?.length ? initialEntity.meta_fields - : [ - { - name: "", - type: "Text", - is_required: false, - minimum_quantity: 0, - maximum_quantity: 0, - values: [] - } - ], + : [], images: initialEntity?.images ?? [] }, validationSchema: yup.object().shape({ diff --git a/src/reducers/sponsors/__tests__/sponsor-form-items-list-reducer.test.js b/src/reducers/sponsors/__tests__/sponsor-form-items-list-reducer.test.js index 31e2ac275..562a7f486 100644 --- a/src/reducers/sponsors/__tests__/sponsor-form-items-list-reducer.test.js +++ b/src/reducers/sponsors/__tests__/sponsor-form-items-list-reducer.test.js @@ -32,14 +32,7 @@ function createDefaultState() { quantity_limit_per_sponsor: "", default_quantity: "", images: [], - meta_fields: [ - { - name: "", - type: "Text", - is_required: false, - values: [] - } - ] + meta_fields: [] } }; } @@ -193,14 +186,7 @@ describe("SponsorFormItemsListReducer", () => { early_bird_rate: "1.00", standard_rate: "1.00", onsite_rate: "1.00", - meta_fields: [ - { - name: "", - type: "Text", - is_required: false, - values: [] - } - ] + meta_fields: [] } }); }); diff --git a/src/reducers/sponsors/sponsor-customized-form-items-list-reducer.js b/src/reducers/sponsors/sponsor-customized-form-items-list-reducer.js index a1f436f84..2bb0d7c57 100644 --- a/src/reducers/sponsors/sponsor-customized-form-items-list-reducer.js +++ b/src/reducers/sponsors/sponsor-customized-form-items-list-reducer.js @@ -40,14 +40,7 @@ const DEFAULT_ITEM_ENTITY = { quantity_limit_per_sponsor: 0, default_quantity: 0, images: [], - meta_fields: [ - { - name: "", - type: "Text", - is_required: false, - values: [] - } - ] + meta_fields: [] }; const DEFAULT_STATE = { @@ -123,17 +116,7 @@ const sponsorCustomizedFormItemsListReducer = ( early_bird_rate: amountFromCents(item.early_bird_rate), standard_rate: amountFromCents(item.standard_rate), onsite_rate: amountFromCents(item.onsite_rate), - meta_fields: - item.meta_fields.length > 0 - ? item.meta_fields - : [ - { - name: "", - type: "Text", - is_required: false, - values: [] - } - ] + meta_fields: item.meta_fields.length > 0 ? item.meta_fields : [] }; return { ...state, currentItem }; } diff --git a/src/reducers/sponsors/sponsor-customized-form-reducer.js b/src/reducers/sponsors/sponsor-customized-form-reducer.js index 576e96f70..9a2d22a36 100644 --- a/src/reducers/sponsors/sponsor-customized-form-reducer.js +++ b/src/reducers/sponsors/sponsor-customized-form-reducer.js @@ -26,16 +26,7 @@ const DEFAULT_ENTITY = { opens_at: "", expires_at: "", instructions: "", - meta_fields: [ - { - name: "", - type: "Text", - is_required: false, - minimum_quantity: 0, - maximum_quantity: 0, - values: [] - } - ] + meta_fields: [] }; const DEFAULT_STATE = { diff --git a/src/reducers/sponsors/sponsor-form-items-list-reducer.js b/src/reducers/sponsors/sponsor-form-items-list-reducer.js index 67829092a..e15f1dcff 100644 --- a/src/reducers/sponsors/sponsor-form-items-list-reducer.js +++ b/src/reducers/sponsors/sponsor-form-items-list-reducer.js @@ -44,14 +44,7 @@ const DEFAULT_STATE = { quantity_limit_per_sponsor: "", default_quantity: "", images: [], - meta_fields: [ - { - name: "", - type: "Text", - is_required: false, - values: [] - } - ] + meta_fields: [] } }; @@ -110,17 +103,7 @@ const sponsorFormItemsListReducer = (state = DEFAULT_STATE, action) => { early_bird_rate: amountFromCents(item.early_bird_rate), standard_rate: amountFromCents(item.standard_rate), onsite_rate: amountFromCents(item.onsite_rate), - meta_fields: - item.meta_fields.length > 0 - ? item.meta_fields - : [ - { - name: "", - type: "Text", - is_required: false, - values: [] - } - ] + meta_fields: item.meta_fields.length > 0 ? item.meta_fields : [] }; return { ...state, currentItem }; diff --git a/src/reducers/sponsors/sponsor-forms-list-reducer.js b/src/reducers/sponsors/sponsor-forms-list-reducer.js index 151b82a5a..d78a0d4c8 100644 --- a/src/reducers/sponsors/sponsor-forms-list-reducer.js +++ b/src/reducers/sponsors/sponsor-forms-list-reducer.js @@ -58,14 +58,7 @@ const DEFAULT_STATE = { opens_at: null, expires_at: null, instructions: "", - meta_fields: [ - { - name: "", - type: "Text", - is_required: false, - values: [] - } - ] + meta_fields: [] } }; @@ -131,17 +124,7 @@ const sponsorFormsListReducer = (state = DEFAULT_STATE, action) => { opens_at: form.opens_at, expires_at: form.expires_at, instructions: form.instructions, - meta_fields: - form.meta_fields.length > 0 - ? form.meta_fields - : [ - { - name: "", - type: "Text", - is_required: false, - values: [] - } - ] + meta_fields: form.meta_fields.length > 0 ? form.meta_fields : [] }; return { ...state, formTemplate }; diff --git a/src/utils/yup.js b/src/utils/yup.js index d350ad232..f5390bb34 100644 --- a/src/utils/yup.js +++ b/src/utils/yup.js @@ -111,22 +111,16 @@ export const formMetafieldsValidation = () => }), type: yup.string().oneOf(METAFIELD_TYPES), is_required: yup.boolean(), - minimum_quantity: yup - .number() - .nullable() - .when("type", { - is: (type) => type === "Quantity", - then: (schema) => schema.required(T.translate("validation.required")), - otherwise: (schema) => schema - }), - maximum_quantity: yup - .number() - .nullable() - .when("type", { - is: (type) => type === "Quantity", - then: (schema) => schema.required(T.translate("validation.required")), - otherwise: (schema) => schema - }), + minimum_quantity: positiveNumberValidation().when("type", { + is: (type) => type === "Quantity", + then: (schema) => schema.required(T.translate("validation.required")), + otherwise: (schema) => schema + }), + maximum_quantity: positiveNumberValidation().when("type", { + is: (type) => type === "Quantity", + then: (schema) => schema.required(T.translate("validation.required")), + otherwise: (schema) => schema + }), values: yup.array().when("type", { is: (type) => fieldTypesWithOptions.includes(type), then: (schema) =>