@plusscommunities/pluss-feature-builder-web-b 1.0.2-beta.5 → 1.0.2-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -116,7 +116,7 @@ const selectFormState = state => getFeatureBuilderState(state).form;
116
116
  */
117
117
  const selectFormTitle = state => {
118
118
  const formState = selectFormState(state);
119
- return formState && formState.title;
119
+ return formState === null || formState === void 0 ? void 0 : formState.title;
120
120
  };
121
121
 
122
122
  /**
@@ -127,7 +127,7 @@ const selectFormTitle = state => {
127
127
  */
128
128
  const selectFormIcon = state => {
129
129
  const formState = selectFormState(state);
130
- return formState && formState.icon;
130
+ return formState === null || formState === void 0 ? void 0 : formState.icon;
131
131
  };
132
132
 
133
133
  /**
@@ -138,7 +138,7 @@ const selectFormIcon = state => {
138
138
  */
139
139
  const selectFormDisplayName = state => {
140
140
  const formState = selectFormState(state);
141
- return formState && formState.displayName;
141
+ return formState === null || formState === void 0 ? void 0 : formState.displayName;
142
142
  };
143
143
 
144
144
  /**
@@ -149,7 +149,7 @@ const selectFormDisplayName = state => {
149
149
  */
150
150
  const selectFormLayout = state => {
151
151
  const formState = selectFormState(state);
152
- return formState && formState.layout;
152
+ return formState === null || formState === void 0 ? void 0 : formState.layout;
153
153
  };
154
154
 
155
155
  /**
@@ -160,24 +160,24 @@ const selectFormLayout = state => {
160
160
  */
161
161
  const selectFormFields = state => {
162
162
  const formState = selectFormState(state);
163
- return formState && formState.fields || [];
163
+ return (formState === null || formState === void 0 ? void 0 : formState.fields) || [];
164
164
  };
165
165
  const selectFormField = fieldId => state => selectFormFields(state).find(field => field.id === fieldId);
166
166
  const selectFormIsInitial = state => {
167
167
  const formState = selectFormState(state);
168
- return formState && formState._isInitial;
168
+ return formState === null || formState === void 0 ? void 0 : formState._isInitial;
169
169
  };
170
170
  const selectFormIsSubmitting = state => {
171
171
  const formState = selectFormState(state);
172
- return formState && formState._isSubmitting;
172
+ return formState === null || formState === void 0 ? void 0 : formState._isSubmitting;
173
173
  };
174
174
  const selectFormSubmitError = state => {
175
175
  const formState = selectFormState(state);
176
- return formState && formState._submitError;
176
+ return formState === null || formState === void 0 ? void 0 : formState._submitError;
177
177
  };
178
178
  const selectFormSubmitSuccess = state => {
179
179
  const formState = selectFormState(state);
180
- return formState && formState._submitSuccess;
180
+ return formState === null || formState === void 0 ? void 0 : formState._submitSuccess;
181
181
  };
182
182
 
183
183
  // ============ DEFINITION SELECTORS ============
@@ -185,50 +185,59 @@ const selectFormSubmitSuccess = state => {
185
185
  const selectDefinitionState = state => getFeatureBuilderState(state).definition;
186
186
  const selectDefinition = state => {
187
187
  const definitionState = selectDefinitionState(state);
188
- return definitionState && definitionState.definition;
188
+ return definitionState === null || definitionState === void 0 ? void 0 : definitionState.definition;
189
189
  };
190
190
  const selectDefinitionId = state => {
191
191
  const definitionState = selectDefinitionState(state);
192
- return definitionState && definitionState.id;
192
+ return definitionState === null || definitionState === void 0 ? void 0 : definitionState.id;
193
193
  };
194
194
  const selectDefinitionIsLoading = state => {
195
195
  const definitionState = selectDefinitionState(state);
196
- return definitionState && definitionState.isLoading;
196
+ return definitionState === null || definitionState === void 0 ? void 0 : definitionState.isLoading;
197
197
  };
198
198
  const selectDefinitionError = state => {
199
199
  const definitionState = selectDefinitionState(state);
200
- return definitionState && definitionState.error;
200
+ return definitionState === null || definitionState === void 0 ? void 0 : definitionState.error;
201
201
  };
202
202
  const selectDefinitionMode = state => {
203
203
  const definitionState = selectDefinitionState(state);
204
- return definitionState && definitionState.mode;
204
+ return definitionState === null || definitionState === void 0 ? void 0 : definitionState.mode;
205
205
  };
206
206
 
207
- // Check if we have a definition loaded
208
- const selectHasDefinition = state => !!selectDefinition(state);
207
+ // Check if we have a definition loaded or if we've determined the mode
208
+ // This is used by hiddenFromFeaturePicker to determine if feature should be shown
209
+ // When mode is "create", definition is null but we've determined the feature doesn't exist
210
+ // When mode is "edit", definition exists and we've determined the feature exists
211
+ const selectHasDefinition = state => {
212
+ const definition = selectDefinition(state);
213
+ const mode = selectDefinitionMode(state);
214
+ // Consider feature "loaded" if definition exists OR mode is set
215
+ // Mode being set means we've successfully fetched and determined the state
216
+ return !!definition || !!mode;
217
+ };
209
218
 
210
219
  // ============ LISTINGS SELECTORS ============
211
220
 
212
221
  const selectListingsState = state => getFeatureBuilderState(state).listings;
213
222
  const selectListings = state => {
214
223
  const listingsState = selectListingsState(state);
215
- return listingsState && listingsState.listings || [];
224
+ return (listingsState === null || listingsState === void 0 ? void 0 : listingsState.listings) || [];
216
225
  };
217
226
  const selectListingsIsLoading = state => {
218
227
  const listingsState = selectListingsState(state);
219
- return listingsState && listingsState.isLoading;
228
+ return listingsState === null || listingsState === void 0 ? void 0 : listingsState.isLoading;
220
229
  };
221
230
  const selectListingsError = state => {
222
231
  const listingsState = selectListingsState(state);
223
- return listingsState && listingsState.error;
232
+ return listingsState === null || listingsState === void 0 ? void 0 : listingsState.error;
224
233
  };
225
234
  const selectListingsIsRestoring = state => {
226
235
  const listingsState = selectListingsState(state);
227
- return listingsState && listingsState.isRestoring;
236
+ return listingsState === null || listingsState === void 0 ? void 0 : listingsState.isRestoring;
228
237
  };
229
238
  const selectListingsIsInitiallyLoaded = state => {
230
239
  const listingsState = selectListingsState(state);
231
- return listingsState && listingsState.isInitiallyLoaded;
240
+ return listingsState === null || listingsState === void 0 ? void 0 : listingsState.isInitiallyLoaded;
232
241
  };
233
242
 
234
243
  // Get a specific listing by ID
@@ -261,7 +270,7 @@ const selectDeletedListings = state => {
261
270
  const selectWizardState = state => getFeatureBuilderState(state).wizard;
262
271
  const selectWizardMode = state => {
263
272
  const wizardState = selectWizardState(state);
264
- return wizardState && wizardState.mode;
273
+ return wizardState === null || wizardState === void 0 ? void 0 : wizardState.mode;
265
274
  };
266
275
 
267
276
  // Mode detection selectors - wizard mode is the SINGLE SOURCE OF TRUTH for create/edit mode
@@ -270,35 +279,35 @@ const selectIsCreateMode = state => selectWizardMode(state) === "create";
270
279
  const selectIsEditMode = state => selectWizardMode(state) === "edit";
271
280
  const selectNavigationState = state => {
272
281
  const wizardState = selectWizardState(state);
273
- return wizardState && wizardState.navigation;
282
+ return wizardState === null || wizardState === void 0 ? void 0 : wizardState.navigation;
274
283
  };
275
284
  const selectCurrentStep = state => {
276
285
  const navigationState = selectNavigationState(state);
277
- return navigationState && navigationState.currentStep;
286
+ return navigationState === null || navigationState === void 0 ? void 0 : navigationState.currentStep;
278
287
  };
279
288
  const selectStepValidation = state => {
280
289
  const wizardState = selectWizardState(state);
281
- return wizardState && wizardState.stepValidation;
290
+ return wizardState === null || wizardState === void 0 ? void 0 : wizardState.stepValidation;
282
291
  };
283
292
  const selectStepValidationState = step => state => {
284
293
  const stepValidation = selectStepValidation(state);
285
- return stepValidation && stepValidation[step];
294
+ return stepValidation === null || stepValidation === void 0 ? void 0 : stepValidation[step];
286
295
  };
287
296
  const selectIsStepValid = step => state => {
288
297
  const stepValidationState = selectStepValidationState(step)(state);
289
- return stepValidationState && stepValidationState.isValid;
298
+ return stepValidationState === null || stepValidationState === void 0 ? void 0 : stepValidationState.isValid;
290
299
  };
291
300
  const selectStepErrors = step => state => {
292
301
  const stepValidationState = selectStepValidationState(step)(state);
293
- return stepValidationState ? stepValidationState.errors : {};
302
+ return (stepValidationState === null || stepValidationState === void 0 ? void 0 : stepValidationState.errors) || {};
294
303
  };
295
304
  const selectStepCompletion = state => {
296
305
  const wizardState = selectWizardState(state);
297
- return wizardState && wizardState.stepCompletion;
306
+ return wizardState === null || wizardState === void 0 ? void 0 : wizardState.stepCompletion;
298
307
  };
299
308
  const selectIsStepComplete = step => state => {
300
309
  const stepCompletion = selectStepCompletion(state);
301
- return stepCompletion && stepCompletion[step];
310
+ return stepCompletion === null || stepCompletion === void 0 ? void 0 : stepCompletion[step];
302
311
  };
303
312
 
304
313
  // Check if current step should be accessible in current mode
@@ -328,14 +337,16 @@ const selectIsStepAccessible = step => state => {
328
337
 
329
338
  // Get current sort method
330
339
  const selectSortBy = state => {
340
+ var _listingsState$sortBy;
331
341
  const listingsState = selectListingsState(state);
332
- return listingsState && listingsState.sortBy ? listingsState.sortBy : "newest";
342
+ return (_listingsState$sortBy = listingsState === null || listingsState === void 0 ? void 0 : listingsState.sortBy) !== null && _listingsState$sortBy !== void 0 ? _listingsState$sortBy : "newest";
333
343
  };
334
344
 
335
345
  // Get show deleted toggle state
336
346
  const selectShowDeleted = state => {
347
+ var _listingsState$showDe;
337
348
  const listingsState = selectListingsState(state);
338
- return listingsState && listingsState.showDeleted ? listingsState.showDeleted : false;
349
+ return (_listingsState$showDe = listingsState === null || listingsState === void 0 ? void 0 : listingsState.showDeleted) !== null && _listingsState$showDe !== void 0 ? _listingsState$showDe : false;
339
350
  };
340
351
 
341
352
  // Get sorted and filtered listings
@@ -2120,846 +2131,838 @@ const Text$8 = Components$4.Text;
2120
2131
 
2121
2132
  function ownKeys$8(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2122
2133
  function _objectSpread$8(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$8(Object(t), !0).forEach(function (r) { _defineProperty__default["default"](e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$8(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
2134
+ const {
2135
+ Helper: Helper$1,
2136
+ Session: Session$1
2137
+ } = PlussCore__namespace;
2138
+ const {
2139
+ getUrl: getUrl$1
2140
+ } = Helper$1;
2141
+ const {
2142
+ authedFunction: authedFunction$1
2143
+ } = Session$1;
2144
+ const featureDefinitionActions = {
2145
+ /**
2146
+ * Get the single feature definition by ID
2147
+ * Path: {id}
2148
+ */
2149
+ getSingle: async (id, site) => {
2150
+ const query = {
2151
+ id,
2152
+ site
2153
+ };
2154
+ return authedFunction$1({
2155
+ method: "GET",
2156
+ url: getUrl$1("feature-builder", "definition/get/single", query)
2157
+ });
2158
+ },
2159
+ /**
2160
+ * Creates a new feature definition with the provided configuration
2161
+ *
2162
+ * @param {string} id - The unique identifier for the new feature definition
2163
+ * @param {string} site - The site ID where the feature definition will be created
2164
+ * @param {FeatureDefinition} featureDefinition - The feature definition data to create
2165
+ * @returns {Promise<ApiResponse>} Promise resolving to API response with created feature definition
2166
+ * @throws {Error} When creation fails due to validation or API errors
2167
+ *
2168
+ */
2169
+ create: async (id, site, featureDefinition) => {
2170
+ return authedFunction$1({
2171
+ method: "POST",
2172
+ url: getUrl$1("feature-builder", "definition/update/create"),
2173
+ data: {
2174
+ id,
2175
+ site,
2176
+ featureDefinition
2177
+ }
2178
+ });
2179
+ },
2180
+ /**
2181
+ * Updates an existing feature definition with new configuration
2182
+ *
2183
+ * @param {FeatureDefinition} featureDefinitionData - The updated feature definition data
2184
+ * @param {string} featureDefinitionData.id - The unique identifier of the feature definition to update
2185
+ * @param {string} [featureDefinitionData.displayName] - Updated display name
2186
+ * @param {Field[]} [featureDefinitionData.fields] - Updated field definitions
2187
+ * @param {Object} [featureDefinitionData.layout] - Updated layout configuration
2188
+ * @param {string} site - The site ID where the feature definition exists
2189
+ * @returns {Promise<ApiResponse>} Promise resolving to API response with updated feature definition
2190
+ * @throws {Error} When update fails due to validation or API errors
2191
+ *
2192
+ * @example
2193
+ * try {
2194
+ * const response = await featureDefinitionActions.edit(
2195
+ * {
2196
+ * id: 'feature-123',
2197
+ * displayName: 'Updated Form',
2198
+ * fields: [...]
2199
+ * },
2200
+ * 'site-123'
2201
+ * );
2202
+ */
2203
+ edit: async (featureDefinitionData, site) => {
2204
+ // Ensure site is included in the request body
2205
+ const dataWithSite = _objectSpread$8({
2206
+ site: site
2207
+ }, featureDefinitionData);
2208
+ return authedFunction$1({
2209
+ method: "POST",
2210
+ url: getUrl$1("feature-builder", "definition/update/edit"),
2211
+ data: dataWithSite
2212
+ });
2213
+ },
2214
+ /**
2215
+ * Soft deletes a feature definition (marks as deleted but doesn't permanently remove)
2216
+ *
2217
+ * @param {string} id - The unique identifier of the feature definition to delete
2218
+ * @param {string} site - The site ID where the feature definition exists
2219
+ * @returns {Promise<ApiResponse>} Promise resolving to API response confirming deletion
2220
+ * @throws {Error} When deletion fails or feature definition is not found
2221
+ *
2222
+ */
2223
+ delete: async (id, site) => {
2224
+ return authedFunction$1({
2225
+ method: "POST",
2226
+ url: getUrl$1("feature-builder", "definition/update/delete"),
2227
+ data: {
2228
+ id,
2229
+ site
2230
+ }
2231
+ });
2232
+ }
2233
+ };
2123
2234
 
2124
- // Wizard action types
2125
- const REDUCER_PREFIX$2 = values.reducerKey.toUpperCase();
2126
- const SET_NAVIGATION_STATE$1 = "".concat(REDUCER_PREFIX$2, "_SET_NAVIGATION_STATE");
2127
- const UPDATE_STEP_VALIDATION$1 = "".concat(REDUCER_PREFIX$2, "_UPDATE_STEP_VALIDATION");
2128
- const MARK_STEP_COMPLETE$1 = "".concat(REDUCER_PREFIX$2, "_MARK_STEP_COMPLETE");
2129
- const setCurrentStep = function (step) {
2130
- let previousStep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
2131
- return {
2132
- type: SET_NAVIGATION_STATE$1,
2133
- payload: {
2134
- currentStep: step,
2135
- previousStep,
2136
- canGoBack: step !== "welcome",
2137
- canGoForward: true
2138
- }
2139
- };
2235
+ function ownKeys$7(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2236
+ function _objectSpread$7(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$7(Object(t), !0).forEach(function (r) { _defineProperty__default["default"](e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$7(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
2237
+
2238
+ // IMPORTANT: Using local UPDATE_STRINGS action type to make extension self-contained
2239
+ // The main app's StringsReducer will handle this action type the same way
2240
+ const UPDATE_STRINGS = "UPDATE_STRINGS";
2241
+ const updateFeatureBuilderString = title => (dispatch, getState) => {
2242
+ var _getState$strings;
2243
+ const currentStrings = ((_getState$strings = getState().strings) === null || _getState$strings === void 0 ? void 0 : _getState$strings.config) || {};
2244
+ const titleCased = toTitleCase(title) || values.textMenuTitle;
2245
+ const updatedStrings = _objectSpread$7(_objectSpread$7({}, currentStrings), {}, {
2246
+ sideNav: _objectSpread$7(_objectSpread$7({}, currentStrings.sideNav), {}, {
2247
+ [values.featureKey]: titleCased,
2248
+ [values.menuKey]: "Manage ".concat(titleCased)
2249
+ }),
2250
+ permission: _objectSpread$7(_objectSpread$7({}, currentStrings.permission), {}, {
2251
+ [values.permissionFeatureBuilderDefinition]: "Manage custom feature ".concat(titleCased),
2252
+ [values.permissionFeatureBuilderContent]: "Manage ".concat(titleCased, " content")
2253
+ })
2254
+ });
2255
+ dispatch({
2256
+ type: UPDATE_STRINGS,
2257
+ payload: updatedStrings
2258
+ });
2259
+ };
2260
+ const updateFeatureBuilderIcon = icon => (dispatch, getState) => {
2261
+ var _getState$strings2;
2262
+ const currentStrings = ((_getState$strings2 = getState().strings) === null || _getState$strings2 === void 0 ? void 0 : _getState$strings2.config) || {};
2263
+ const updatedStrings = _objectSpread$7(_objectSpread$7({}, currentStrings), {}, {
2264
+ sideNav: _objectSpread$7(_objectSpread$7({}, currentStrings.sideNav), {}, {
2265
+ [values.featureKey + "-icon"]: icon,
2266
+ [values.menuKey + "-icon"]: icon
2267
+ })
2268
+ });
2269
+ dispatch({
2270
+ type: UPDATE_STRINGS,
2271
+ payload: updatedStrings
2272
+ });
2140
2273
  };
2141
- const goToStep = step => (dispatch, getState) => {
2142
- const state = getState()[require("../values.config").reducerKey];
2143
- const currentStep = state && state.wizard && state.wizard.navigation && state.wizard.navigation.currentStep;
2144
2274
 
2145
- // Clear form submission state when changing steps
2146
- const {
2147
- clearFormSubmissionState
2148
- } = require("./formActions");
2149
- dispatch(clearFormSubmissionState());
2150
- dispatch(setCurrentStep(step, currentStep));
2275
+ /**
2276
+ * @typedef {Object} FieldValues
2277
+ * @property {string} [label] - Field label text
2278
+ * @property {string} [placeholder] - Placeholder text for input
2279
+ * @property {boolean} [isRequired] - Whether field is required
2280
+ * @property {string} [helpText] - Help text for field guidance
2281
+ * @property {boolean} [allowCaption] - Whether field allows captions
2282
+ * @property {boolean} [useAsSummary] - Whether field is used as summary
2283
+ */
2284
+
2285
+ /**
2286
+ * @typedef {Object} FormField
2287
+ * @property {string} id - Unique field identifier
2288
+ * @property {string} type - Field type (text, title, description, image, file, cta, feature-image)
2289
+ * @property {boolean} isMandatory - Whether field is mandatory system field
2290
+ * @property {FieldValues} values - Field configuration values
2291
+ */
2292
+
2293
+ /**
2294
+ * @typedef {Object} LayoutConfig
2295
+ * @property {string} type - Layout type (round, square, etc.)
2296
+ * @property {string} [gridIcon] - Background image for grid layout
2297
+ */
2298
+
2299
+ const actionsTypes = {
2300
+ SET_INITIAL_VALUES: "".concat(values.reducerKey.toUpperCase(), "_SET_INITIAL_VALUES"),
2301
+ SET_TITLE: "".concat(values.reducerKey.toUpperCase(), "_SET_TITLE"),
2302
+ SET_ICON: "".concat(values.reducerKey.toUpperCase(), "_SET_ICON"),
2303
+ SET_DISPLAY_NAME: "".concat(values.reducerKey.toUpperCase(), "_SET_DISPLAY_NAME"),
2304
+ ADD_FIELD: "".concat(values.reducerKey.toUpperCase(), "_ADD_FIELD"),
2305
+ DELETE_FIELD: "".concat(values.reducerKey.toUpperCase(), "_DELETE_FIELD"),
2306
+ UPDATE_FIELD: "".concat(values.reducerKey.toUpperCase(), "_UPDATE_FIELD"),
2307
+ SET_LAYOUT_GRID_ICON: "".concat(values.reducerKey.toUpperCase(), "_SET_LAYOUT_GRID_ICON"),
2308
+ SET_LAYOUT_TYPE: "".concat(values.reducerKey.toUpperCase(), "_SET_LAYOUT_TYPE"),
2309
+ SUBMIT_FORM_REQUEST: "".concat(values.reducerKey.toUpperCase(), "_SUBMIT_FORM_REQUEST"),
2310
+ SUBMIT_FORM_SUCCESS: "".concat(values.reducerKey.toUpperCase(), "_SUBMIT_FORM_SUCCESS"),
2311
+ SUBMIT_FORM_FAILURE: "".concat(values.reducerKey.toUpperCase(), "_SUBMIT_FORM_FAILURE"),
2312
+ CLEAR_FORM_SUBMISSION_STATE: "".concat(values.reducerKey.toUpperCase(), "_CLEAR_FORM_SUBMISSION_STATE"),
2313
+ SET_SUMMARY_FIELD: "".concat(values.reducerKey.toUpperCase(), "_SET_SUMMARY_FIELD")
2151
2314
  };
2152
- const updateStepValidation = function (step, isValid) {
2153
- let errors = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
2315
+
2316
+ /**
2317
+ * Action creator to set initial form values
2318
+ * Initializes form state with existing feature definition data
2319
+ *
2320
+ * @param {Object} initialValues - Initial form values object
2321
+ * @param {string} initialValues.title - Feature title
2322
+ * @param {string} initialValues.icon - Feature icon
2323
+ * @param {string} initialValues.displayName - Feature display name
2324
+ * @param {LayoutConfig} initialValues.layout - Layout configuration
2325
+ * @param {FormField[]} initialValues.fields - Form fields array
2326
+ * @returns {Object} Redux action object with type and payload
2327
+ *
2328
+ * @example
2329
+ * dispatch(setInitialValues({
2330
+ * title: 'Contact Form',
2331
+ * icon: 'envelope',
2332
+ * fields: []
2333
+ * }));
2334
+ */
2335
+ const setInitialValues = initialValues => {
2154
2336
  return {
2155
- type: UPDATE_STEP_VALIDATION$1,
2156
- payload: {
2157
- step,
2158
- isValid,
2159
- errors
2160
- }
2337
+ type: actionsTypes.SET_INITIAL_VALUES,
2338
+ payload: initialValues
2161
2339
  };
2162
2340
  };
2163
- const validateAndUpdateStep = step => (dispatch, getState) => {
2164
- // Use existing selectors to get form data
2165
- const state = getState();
2166
- const title = selectFormTitle(state);
2167
- const icon = selectFormIcon(state);
2168
- const displayName = selectFormDisplayName(state);
2169
- const layout = selectFormLayout(state);
2170
- const fields = selectFormFields(state);
2171
- const form = {
2172
- title,
2173
- icon,
2174
- displayName,
2175
- layout,
2176
- fields
2341
+ const setTitle = title => {
2342
+ return {
2343
+ type: actionsTypes.SET_TITLE,
2344
+ payload: title
2177
2345
  };
2178
- const {
2179
- isValid,
2180
- errors
2181
- } = getFormValidation(form, step);
2182
- dispatch(updateStepValidation(step, isValid, errors));
2346
+ };
2183
2347
 
2184
- // If valid, mark as complete
2185
- if (isValid) {
2186
- dispatch({
2187
- type: MARK_STEP_COMPLETE$1,
2188
- payload: step
2189
- });
2190
- }
2191
- return {
2192
- isValid,
2193
- errors
2194
- };
2195
- };
2196
- const getFormValidation = (form, step) => {
2197
- // Return validation results for undefined form (prevent crashes)
2198
- if (!form) {
2199
- switch (step) {
2200
- case "overview":
2201
- return {
2202
- isValid: false,
2203
- errors: {
2204
- title: "Title is required",
2205
- displayName: "Display name is required",
2206
- icon: "Icon is required"
2207
- }
2208
- };
2209
- case "fields":
2210
- return {
2211
- isValid: false,
2212
- errors: {
2213
- missingTitle: "Title field is required",
2214
- missingImage: "Feature image field is required",
2215
- fieldLabels: "Some fields are missing labels"
2216
- }
2217
- };
2218
- case "layout":
2219
- return {
2220
- isValid: false,
2221
- errors: {
2222
- layoutType: "Layout type is required"
2223
- }
2224
- };
2225
- default:
2226
- return {
2227
- isValid: false,
2228
- errors: {}
2229
- };
2230
- }
2231
- }
2232
- switch (step) {
2233
- case "overview":
2234
- {
2235
- const hasTitle = form.title && form.title.trim().length > 0;
2236
- const hasDisplayName = form.displayName && form.displayName.trim().length > 0;
2237
- const hasIcon = form.icon && form.icon.length > 0;
2238
- return {
2239
- isValid: hasTitle && hasDisplayName && hasIcon,
2240
- errors: {
2241
- title: !hasTitle ? "Title is required" : null,
2242
- displayName: !hasDisplayName ? "Display name is required" : null,
2243
- icon: !hasIcon ? "Icon is required" : null
2244
- }
2245
- };
2246
- }
2247
- case "fields":
2248
- {
2249
- const hasTitleField = form.fields && form.fields.some(field => field.id === "mandatory-title");
2250
- const hasImageField = form.fields && form.fields.some(field => field.id === "mandatory-feature-image");
2251
-
2252
- // Check each field for missing labels and create field-specific errors
2253
- const fieldErrors = {};
2254
- let allFieldsHaveLabels = true;
2255
- if (form.fields) {
2256
- form.fields.forEach(field => {
2257
- if ((field.type === "text" || field.type === "description" || field.type === "title" || field.type === "image" || field.type === "gallery" || field.type === "feature-image" || field.type === "file" || field.type === "cta") && field.values) {
2258
- if (!field.values.label || field.values.label.trim().length === 0) {
2259
- fieldErrors[field.id] = "Field label is required";
2260
- allFieldsHaveLabels = false;
2261
- }
2262
- }
2263
- });
2264
- }
2265
- return {
2266
- isValid: hasTitleField && hasImageField && allFieldsHaveLabels,
2267
- errors: _objectSpread$8({
2268
- missingTitle: !hasTitleField ? "Title field is required" : null,
2269
- missingImage: !hasImageField ? "Feature image field is required" : null
2270
- }, fieldErrors)
2271
- };
2272
- }
2273
- case "layout":
2274
- {
2275
- const hasLayoutType = form.layout && form.layout.type && form.layout.type.length > 0;
2276
- return {
2277
- isValid: hasLayoutType,
2278
- errors: {
2279
- layoutType: !hasLayoutType ? "Layout type is required" : null
2280
- }
2281
- };
2282
- }
2283
- default:
2284
- return {
2285
- isValid: true,
2286
- errors: {}
2287
- };
2288
- }
2289
- };
2290
- const setCurrentStepAndSave = function (step) {
2291
- let previousStep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
2348
+ /**
2349
+ * Action creator to set form display name and update menu
2350
+ * Updates both form state and external menu string
2351
+ * Title cases the display name before updating the strings store
2352
+ *
2353
+ * @param {string} displayName - New display name for form
2354
+ * @returns {Function} Thunk function for Redux
2355
+ *
2356
+ * @example
2357
+ * dispatch(setDisplayName('Contact Information'));
2358
+ */
2359
+ const setDisplayName = displayName => {
2292
2360
  return dispatch => {
2293
- dispatch(setCurrentStep(step, previousStep));
2361
+ // Update menu string when display name changes (will be title cased in updateFeatureBuilderString)
2362
+ dispatch(updateFeatureBuilderString(displayName));
2363
+
2364
+ // Dispatch the actual action
2365
+ dispatch({
2366
+ type: actionsTypes.SET_DISPLAY_NAME,
2367
+ payload: displayName
2368
+ });
2294
2369
  };
2295
2370
  };
2296
2371
 
2297
- var css$d = ".SidebarLayout_module_fullWidthContent__0d6658dd {\n\tmax-width: 100%;\n\tmargin-left: auto;\n\tmargin-right: auto;\n\tpadding: 2rem 2rem 3rem 2rem; /* Add extra bottom padding */\n}\n\n/* Full-width container that allows scrollbar at edge */\n.SidebarLayout_module_fullWidthContainer__0d6658dd {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1;\n\tmin-height: 0; /* Allow content to determine height */\n\twidth: 100%; /* Take full width to ensure scrollbar is at edge */\n}\n\n/* Content container to keep content centered */\n.SidebarLayout_module_contentContainer__0d6658dd {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1;\n\tmin-height: 0;\n\tmax-width: 960px;\n\tmargin: 0 auto;\n\tpadding: 64px 32px;\n\twidth: 100%;\n\tbox-sizing: border-box;\n}\n\n/* Legacy container class for backward compatibility */\n.SidebarLayout_module_container__0d6658dd{\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1;\n\tmin-height: 0; /* Allow content to determine height */\n max-width: 960px;\n margin: 0 auto;\n padding: 64px 32px;\n}\n\n/* Responsive adjustments for content container */\n@media (max-width: 768px) {\n\t.SidebarLayout_module_contentContainer__0d6658dd {\n\t\tpadding: 1.5rem 1.5rem 2.5rem 1.5rem; /* Slightly reduced but still adequate */\n\t}\n\t.SidebarLayout_module_container__0d6658dd {\n\t\tpadding: 1.5rem 1.5rem 2.5rem 1.5rem; /* Legacy container support */\n\t}\n}\n\n@media (max-width: 480px) {\n\t.SidebarLayout_module_contentContainer__0d6658dd {\n\t\tpadding: 1rem 1rem 2rem 1rem; /* Maintain padding on small screens */\n\t}\n\t.SidebarLayout_module_container__0d6658dd {\n\t\tpadding: 1rem 1rem 2rem 1rem; /* Legacy container support */\n\t}\n}\n\n/* Enhanced sidebar navigation for progress indication */\n\n/* Enhanced progress section */\n.hub-sideBar-section {\n\tborder-bottom: 2px solid var(--colour-branding-main-fade, rgba(74, 87, 183, 0.15));\n\tpadding-bottom: 1rem;\n\tmargin-bottom: 1rem;\n}\n\n.hub-sideBar-section:last-child {\n\tborder-bottom: none;\n}\n";
2298
- var modules_d5b6badf = {"fullWidthContent":"SidebarLayout_module_fullWidthContent__0d6658dd","fullWidthContainer":"SidebarLayout_module_fullWidthContainer__0d6658dd","contentContainer":"SidebarLayout_module_contentContainer__0d6658dd","container":"SidebarLayout_module_container__0d6658dd"};
2299
- n(css$d,{});
2300
-
2301
2372
  /**
2302
- * Sidebar Layout component for feature builder wizard
2303
- * Provides navigation sidebar with step progression, completion tracking
2304
- * Manages step accessibility based on wizard mode and validation state
2373
+ * Action creator to set form icon and update menu
2374
+ * Updates both form state and external menu icon
2305
2375
  *
2306
- * @param {Object} props - Component props
2307
- * @param {React.ReactNode} props.children - Child components to render in main content area
2308
- * @param {Object} props.history - React Router history object for navigation
2309
- * @returns {React.ReactElement} Layout component with sidebar navigation
2376
+ * @param {string} icon - Icon identifier or FontAwesome icon class
2377
+ * @returns {Function} Thunk function for Redux
2310
2378
  *
2311
2379
  * @example
2312
- * <SidebarLayout history={historyObject}>
2313
- * <YourMainContent />
2314
- * </SidebarLayout>
2380
+ * dispatch(setIcon('fa-user'));
2315
2381
  */
2316
- const SideBarInner = props => {
2317
- const {
2318
- children,
2319
- history
2320
- } = props;
2321
- const dispatch = reactRedux.useDispatch();
2382
+ const setIcon = icon => {
2383
+ return dispatch => {
2384
+ // Update menu icon when icon changes
2385
+ dispatch(updateFeatureBuilderIcon(icon));
2322
2386
 
2323
- // Get wizard state
2324
- const mode = reactRedux.useSelector(selectWizardMode);
2325
- const isEditMode = reactRedux.useSelector(selectIsEditMode);
2326
- const isCreateMode = reactRedux.useSelector(selectIsCreateMode);
2327
- const currentStep = reactRedux.useSelector(selectCurrentStep);
2328
- const goTo = url => history.push(url);
2329
- const isSelected = url => {
2330
- return history.location.pathname === url;
2387
+ // Dispatch the actual action
2388
+ dispatch({
2389
+ type: actionsTypes.SET_ICON,
2390
+ payload: icon
2391
+ });
2331
2392
  };
2393
+ };
2332
2394
 
2333
- // Define step configuration with dynamic URL based on mode
2334
- const getStepUrl = stepKey => {
2335
- // Use routes from values.config to support different variants (-a, -b, -c, -d)
2336
- switch (stepKey) {
2337
- case "overview":
2338
- return values.routeFormOverviewStep;
2339
- case "fields":
2340
- return values.routeFormFieldsStep;
2341
- case "layout":
2342
- return values.routeFormLayoutStep;
2343
- default:
2344
- return "";
2395
+ /**
2396
+ * Action creator to add a new field to the form
2397
+ * Generates unique ID and supports custom field types
2398
+ *
2399
+ * @param {string} [fieldType="text"] - Type of field to add (text, title, description, image, gallery, file, cta, feature-image)
2400
+ * @returns {Object} Redux action object with field ID and type
2401
+ *
2402
+ * @example
2403
+ * dispatch(addField('text'));
2404
+ * dispatch(addField('image'));
2405
+ */
2406
+ const addField = function () {
2407
+ let fieldType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "text";
2408
+ // Generate a unique ID for the new field
2409
+ const fieldId = "custom-field-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
2410
+ return {
2411
+ type: actionsTypes.ADD_FIELD,
2412
+ payload: {
2413
+ id: fieldId,
2414
+ type: fieldType
2345
2415
  }
2346
2416
  };
2347
- const steps = [{
2348
- key: "overview",
2349
- text: "Feature Overview",
2350
- icon: "info-circle",
2351
- url: getStepUrl("overview")
2352
- }, {
2353
- key: "fields",
2354
- text: "Configure Fields",
2355
- icon: "edit",
2356
- url: getStepUrl("fields")
2357
- }, {
2358
- key: "layout",
2359
- text: "Choose Layout",
2360
- icon: "columns",
2361
- url: getStepUrl("layout")
2362
- }];
2363
-
2364
- // Build sidebar items based on mode
2365
- const buildSidebarItems = () => {
2366
- const isWizardMode = mode === "create" || mode === "edit";
2367
- return steps.map((step, index) => {
2368
- const isCompleted = selectIsStepComplete(step.key);
2369
- const isAccessible = selectIsStepAccessible(step.key);
2370
-
2371
- // Add step number to text for better clarity
2372
- const stepText = "".concat(index + 1, ". ").concat(step.text);
2373
- const itemProps = {
2374
- type: "navItem",
2375
- text: stepText,
2376
- icon: step.icon,
2377
- selected: isSelected(step.url),
2378
- onclick: isWizardMode ? null : isAccessible ? () => {
2379
- goTo(step.url);
2380
- dispatch(goToStep(step.key));
2381
- } : null,
2382
- isFontAwesome: true,
2383
- // Enhanced completion indicator
2384
- completed: isCompleted,
2385
- // Disable all navigation in wizard mode
2386
- disabled: isWizardMode || mode === "create" && !isAccessible
2387
- };
2388
- return itemProps;
2389
- });
2390
- };
2391
-
2392
- // Determine sidebar title - always use "Build Your Feature" now
2393
- const getSidebarTitle = () => {
2394
- return "Build Your Feature";
2417
+ };
2418
+ const deleteField = id => {
2419
+ return {
2420
+ type: actionsTypes.DELETE_FIELD,
2421
+ payload: id
2395
2422
  };
2396
-
2397
- // Simple help text
2398
- const getHelpText = () => {
2399
- return "Get help with feature builder";
2423
+ };
2424
+ const updateFieldById = (id, updatedField) => {
2425
+ return {
2426
+ type: actionsTypes.UPDATE_FIELD,
2427
+ payload: {
2428
+ id,
2429
+ updatedField
2430
+ }
2400
2431
  };
2432
+ };
2401
2433
 
2402
- // Build sidebar sections - simplified without progress section
2403
- const sidebarSections = [{
2404
- title: getSidebarTitle(),
2405
- items: buildSidebarItems()
2406
- }];
2407
-
2408
- // Add effect to manually attach click handlers since HubSidebar might not use onclick properly
2409
- React.useEffect(() => {
2410
- const isWizardMode = mode === "create" || mode === "edit";
2411
- const attachClickHandlers = () => {
2412
- const stepsWithUrls = [{
2413
- key: "overview",
2414
- url: getStepUrl("overview")
2415
- }, {
2416
- key: "fields",
2417
- url: getStepUrl("fields")
2418
- }, {
2419
- key: "layout",
2420
- url: getStepUrl("layout")
2421
- }];
2422
- stepsWithUrls.forEach((step, index) => {
2423
- const navItem = Array.from(document.querySelectorAll(".hub-wrapperContainer .sideNav-item")).find(item => item.textContent && item.textContent.includes("".concat(index + 1, ".")));
2424
- if (navItem) {
2425
- // Remove any existing click listeners
2426
- navItem.onclick = null;
2427
-
2428
- // Check if this step is accessible
2429
- const isAccessible = selectIsStepAccessible(step.key)({
2430
- [values.reducerKey]: {
2431
- wizard: {
2432
- mode: mode,
2433
- navigation: {
2434
- currentStep: currentStep
2435
- }
2436
- }
2437
- }
2438
- });
2439
-
2440
- // Check if this is the current step (selected)
2441
- const isCurrentStep = isSelected(step.url);
2442
-
2443
- // In wizard mode, don't attach any click handlers
2444
- // Only attach click handler if not in wizard mode AND accessible
2445
- if (!isWizardMode && isAccessible) {
2446
- navItem.onclick = event => {
2447
- event.preventDefault();
2448
- event.stopPropagation();
2449
- history.push(step.url);
2450
- dispatch(goToStep(step.key));
2451
- };
2452
- }
2453
-
2454
- // Make sure it's styled appropriately
2455
- // In wizard mode: block clicks, but keep current step visible
2456
- navItem.style.pointerEvents = isWizardMode ? "none" : "auto";
2457
- if (isWizardMode) {
2458
- // Current step: full opacity, not-allowed cursor
2459
- // Other steps: reduced opacity
2460
- navItem.style.opacity = isCurrentStep ? "1" : "0.4";
2461
- navItem.style.cursor = "not-allowed";
2462
- } else {
2463
- // Not in wizard mode: normal styling based on accessibility
2464
- navItem.style.cursor = isAccessible ? "pointer" : "not-allowed";
2465
- navItem.style.opacity = isAccessible ? "1" : "0.5";
2466
- }
2467
- }
2468
- });
2469
- };
2470
-
2471
- // Initial attachment
2472
- attachClickHandlers();
2473
-
2474
- // Re-attach after a short delay to ensure HubSidebar has rendered
2475
- const timeoutId = setTimeout(attachClickHandlers, 100);
2476
-
2477
- // Also try to re-attach when DOM changes (observe for mutations)
2478
- const observer = new MutationObserver(() => {
2479
- setTimeout(attachClickHandlers, 50);
2480
- });
2481
-
2482
- // Start observing the document body for changes
2483
- observer.observe(document.body, {
2484
- childList: true,
2485
- subtree: true
2486
- });
2487
- return () => {
2488
- clearTimeout(timeoutId);
2489
- observer.disconnect();
2490
- };
2491
- }, [history, dispatch, isEditMode, isCreateMode, currentStep]);
2492
- return /*#__PURE__*/React__default["default"].createElement("div", {
2493
- className: "hub-wrapperContainer"
2494
- }, /*#__PURE__*/React__default["default"].createElement(HubSidebar, {
2495
- sections: sidebarSections,
2496
- helpGuide: {
2497
- text: getHelpText(),
2498
- url: "https://www.plusscommunities.com/user-guide"
2499
- }
2500
- }), /*#__PURE__*/React__default["default"].createElement("div", {
2501
- className: "hub-contentWrapper"
2502
- }, /*#__PURE__*/React__default["default"].createElement("div", {
2503
- className: modules_d5b6badf.fullWidthContainer
2504
- }, /*#__PURE__*/React__default["default"].createElement("div", {
2505
- className: modules_d5b6badf.contentContainer
2506
- }, children))));
2434
+ /**
2435
+ * Action creator to set a description field as the summary field
2436
+ * Ensures only one description field can be marked as summary by
2437
+ * automatically unsetting all other description fields when a new one is selected
2438
+ *
2439
+ * @param {string} fieldId - ID of the description field to set as summary
2440
+ * @returns {Object} Redux action object for summary field selection
2441
+ *
2442
+ * @example
2443
+ * dispatch(setSummaryField('field-description-123'));
2444
+ */
2445
+ const setSummaryField = fieldId => {
2446
+ return {
2447
+ type: actionsTypes.SET_SUMMARY_FIELD,
2448
+ payload: fieldId
2449
+ };
2507
2450
  };
2508
- const SidebarLayout = reactRouter.withRouter(SideBarInner);
2509
-
2510
- var css$c = ".Form_module_content__d62303b4 {\n\tflex: 1 1 auto;\n\tdisplay: flex;\n\tflex-flow: column nowrap;\n\tpadding: 2rem 0 3rem 0; /* Add proper top/bottom padding */\n\tmin-height: 100%; /* Ensure full height for proper spacing */\n}\n\n/* New page wrapper for centered container approach */\n.Form_module_pageWrapper__d62303b4 {\n\tpadding: 2rem 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tjustify-content: flex-start;\n}\n\n@media (min-width: 768px) {\n\t.Form_module_pageWrapper__d62303b4 {\n\t\tpadding: 3rem 0;\n\t}\n}\n\n/* Form container styling when using CenteredContainer */\n.Form_module_formContainer__d62303b4 {\n\tbackground-color: var(--bg-white);\n}\n\n/* Section styling */\n.Form_module_section__d62303b4 {\n\tmargin-bottom: 2rem;\n\t\tpadding: 0 0 2em;\n}\n\n.Form_module_section_NoBorder__d62303b4 {\n\t\tborder-bottom: none;\n}\n\n.Form_module_subtitle__d62303b4 {\n\tcolor: var(--text-bluegrey, #6c7a90);\n}\n\n.Form_module_sectionHeader__d62303b4 {\n\t\tdisplay: flex;\n\t\tjustify-content: space-between;\n}\n\n/* Add Field Button styling */\n.Form_module_addFieldButton__d62303b4 {\n\tbackground: var(--colour-branding-action, #5c90df);\n\tcolor: white;\n\tborder: none;\n\tpadding: 0.75rem 1.5rem;\n\tborder-radius: 6px;\n\tfont-size: 1rem;\n\tcursor: pointer;\n\tmargin-bottom: 2rem;\n\ttransition: all 0.2s ease;\n}\n\n.Form_module_addFieldButton__d62303b4:hover {\n\tbackground: var(--colour-branding-action-hover, #364196);\n\ttransform: translateY(-1px);\n\tbox-shadow: 0 2px 4px rgba(92, 144, 223, 0.3);\n}\n\n.Form_module_addFieldButton__d62303b4:focus {\n\toutline: 2px solid var(--colour-branding-action, #5c90df);\n\toutline-offset: 2px;\n}\n\n.Form_module_addFieldButton__d62303b4:active {\n\ttransform: translateY(0);\n}\n\n/* Refresh button styling */\n.Form_module_refreshButton__d62303b4 {\n\tmargin-left: 10px;\n\tpadding: 2px 8px;\n\tfont-size: 12px;\n\tbackground: var(--colour-dusk, #536280);\n\tcolor: white;\n\tborder: none;\n\tborder-radius: 4px;\n\tcursor: pointer;\n\ttransition: background-color 0.2s ease;\n}\n\n.Form_module_refreshButton__d62303b4:hover {\n\tbackground: var(--colour-dusk-hover, #485968);\n}\n\n/* Error message container */\n.Form_module_errorMessageContainer__d62303b4 {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.5rem;\n}\n\n/* Add Field Container - matches field structure */\n.Form_module_addFieldContainer__d62303b4 {\n\tdisplay: flex;\n\tmargin-top: 32px;\n}\n\n.Form_module_fieldNumberContainer__d62303b4 {\n\tdisplay: flex;\n\twidth: 40px;\n}\n\n/* Add Field Section */\n.Form_module_addFieldSection__d62303b4 {\n\tdisplay: flex;\n\tgap: 1rem;\n\talign-items: center;\n\tjustify-content: flex-start; /* Align to start to match field content */\n\tmargin-top: 0; /* Remove top margin since it's in the container */\n}\n\n/* Desktop: horizontal layout for field selector and button */\n@media (min-width: 769px) {\n\t.Form_module_addFieldSection__d62303b4 {\n\t\tflex-direction: row;\n\t\talign-items: baseline;\n\t\tgap: 2rem;\n\t\talign-items: flex-start;\n\t\tjustify-content: flex-start; /* Align to start to match field content */\n\t}\n}\n\n/* Help Section for Popup */\n.Form_module_helpSection__d62303b4 {\n\tbackground-color: var(--colour-branding-action-superlight);\n\tborder: 1px solid var(--colour-branding-inactive);\n\tborder-radius: 8px;\n\tpadding: 1.5rem;\n\tmargin-bottom: 1.5rem;\n}\n\n.Form_module_helpTitle__d62303b4 {\n\tcolor: var(--text-dark);\n\tfont-weight: 600;\n\tmargin-bottom: 0.75rem;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.5rem;\n\tfont-size: 1.25rem;\n}\n\n.Form_module_helpText__d62303b4 {\n\tcolor: var(--colour-branding-action);\n\tline-height: 1.6;\n\tfont-size: 1.25rem;\n}\n\n/* Field Type Cards for Popup */\n.Form_module_fieldTypeCards__d62303b4 {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 1rem; /* Spacing between vertical cards */\n\tpadding: 1rem 0;\n}\n\n/* Responsive layout: maintain vertical layout on all screen sizes */\n@media (min-width: 768px) {\n\t.Form_module_fieldTypeCards__d62303b4 {\n\t\tgap: 1.5rem; /* Slightly larger gap on desktop */\n\t}\n}\n\n.Form_module_fieldTypeCard__d62303b4 {\n\tdisplay: flex;\n\tflex-direction: row;\n\talign-items: flex-start;\n\tpadding: 1.75rem 1.25rem; /* More vertical padding */\n\tborder: 1px solid var(--border-line-grey);\n\tborder-radius: 8px;\n\tbackground-color: var(--bg-white);\n\tcursor: pointer;\n\ttransition: all 0.2s ease;\n\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n\tmin-height: 120px; /* Adjust height for horizontal layout */\n\tgap: 1rem; /* Space between icon and content */\n}\n\n.Form_module_fieldTypeCard__d62303b4:hover {\n\tborder-color: var(--text-light);\n\tbackground-color: var(--bg-bluegrey);\n\tbox-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n}\n\n.Form_module_fieldTypeCard__d62303b4:focus {\n\toutline: 2px solid var(--text-light);\n\toutline-offset: 2px;\n}\n\n.Form_module_fieldTypeCard__d62303b4:active {\n\ttransform: scale(0.98);\n\ttransition: transform 0.1s ease;\n}\n\n.Form_module_fieldTypeCardIcon__d62303b4 {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 48px;\n\theight: 48px;\n\tmargin-bottom: 0; /* Remove bottom margin for horizontal layout */\n\tfont-size: 20px;\n\tflex-shrink: 0;\n\tborder: 1px solid var(--border-line-grey); /* Subtle border */\n\tborder-radius: 8px;\n\tbackground-color: var(--bg-bluegrey);\n\tpadding: 8px;\n}\n\n\n.Form_module_fieldTypeCardContent__d62303b4 {\n\tflex: 1;\n\twidth: 100%;\n\tmin-width: 0; /* Prevent content from overflowing */\n}\n\n.Form_module_fieldTypeCardTitle__d62303b4 {\n\tmargin: 0 0 0.25rem 0;\n\tfont-weight: 600;\n\tfont-size: 1.4rem; /* Increased for better readability */\n}\n\n.Form_module_fieldTypeCardDescription__d62303b4 {\n\tmargin: 0 0 0.75rem 0;\n\tfont-size: 1.6rem; /* Increased for better readability */\n\tline-height: 1.5; /* Improved line height for better readability */\n}\n\n.Form_module_fieldTypeCardUseCase__d62303b4 {\n\tmargin: 0;\n\tfont-size: 1.4rem;\n\tfont-style: italic;\n\tcolor: var(--text-light);\n\tpadding-top: 0.5rem;\n\tborder-top: 1px solid var(--border-line-grey);\n}\n\n/* Field selector and button container - horizontal layout */\n.Form_module_addFieldSection__d62303b4> div:first-child {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 0.5rem;\n\tflex: 1;\n}\n\n/* Container for add field button alignment */\n.Form_module_addFieldButtonContainer__d62303b4 {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: flex-end;\n}\n\n/* Empty State */\n.Form_module_emptyState__d62303b4 {\n\tpadding: 2rem;\n\ttext-align: center;\n\tbackground-color: var(--bg-bluegrey, #f4f7f9);\n\tborder-radius: 8px;\n\tborder: 1px dashed var(--border-line-grey, #dbddf1);\n\tmargin-bottom: 1rem;\n}\n\n.Form_module_emptyStateText__d62303b4 {\n\tcolor: var(--text-bluegrey, #6c7a90);\n\tfont-style: italic;\n}\n\n.Form_module_fieldTypeSelector__d62303b4 {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmax-width: 500px; /* Increased from 300px to accommodate longer text */\n\twidth: 100%;\n}\n\n@media (max-width: 768px) {\n\t.Form_module_addFieldSection__d62303b4 {\n\t\talign-items: stretch;\n\t}\n\t\n\t.Form_module_fieldTypeSelector__d62303b4 {\n\t\tmax-width: none;\n\t}\n}\n\n.Form_module_grid__four__d62303b4 {\n max-width: 1200px;\n\tdisplay: grid;\n\tgrid-template-columns: repeat(2, minmax(250px, 1fr));\n margin: 2rem 0;\n\tgap: 2rem;\n\tjustify-items: center;\n}\n\n@media (max-width: 768px) {\n\t.Form_module_grid__four__d62303b4 {\n\t\tgrid-template-columns: 1fr;\n\t\tgap: 2rem;\n\t}\n}\n\n/* Navigation styles */\n.Form_module_navigation__d62303b4 {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\tgap: 1rem;\n\tmargin-top: 3rem; /* Increase from 2rem */\n\tpadding-top: 2rem;\n\tpadding-bottom: 2rem; /* Add bottom padding */\n\tborder-top: 1px solid #e9ecef;\n}\n\n/* Single button alignment - align to right for overview step save button */\n.Form_module_navigation__d62303b4> :only-child {\n\tmargin-left: auto;\n\tmargin-right: 0;\n}\n\n/* Two button alignment - one left, one right */\n.Form_module_navigation__d62303b4> :first-child:not(:only-child) {\n\tmargin-right: auto;\n}\n\n.Form_module_navigation__d62303b4> :last-child:not(:only-child) {\n\tmargin-left: auto;\n}\n\n/* Special case for overview step - align save button to right */\n.Form_module_overviewStep__d62303b4 .Form_module_navigation__d62303b4> :only-child {\n\tmargin-left: auto;\n\tmargin-right: 0;\n}\n\n.Form_module_previousButton__d62303b4 {\n\tbackground: #6c757d;\n\tcolor: white;\n\tborder: none;\n\tpadding: 0.75rem 1.5rem;\n\tborder-radius: 6px;\n\tfont-size: 1rem;\n\tcursor: pointer;\n\ttransition: all 0.2s ease;\n}\n\n.Form_module_previousButton__d62303b4:hover {\n\tbackground: #5a6268;\n}\n\n.Form_module_saveButton__d62303b4 {\n\tbackground: var(--colour-purple, #6e79c5);\n\tcolor: white;\n\tborder: none;\n\tpadding: 0.75rem 2rem;\n\tborder-radius: 6px;\n\tfont-size: 1rem;\n\tfont-weight: 500;\n\tcursor: pointer;\n\ttransition: all 0.2s ease;\n}\n\n.Form_module_saveButton__d62303b4:hover:not(:disabled) {\n\tbackground: var(--colour-purple-hover, #5a66b3);\n\ttransform: translateY(-1px);\n\tbox-shadow: 0 2px 4px rgba(110, 121, 197, 0.3);\n}\n\n.Form_module_saveButton__d62303b4:focus {\n\toutline: 2px solid var(--colour-purple, #6e79c5);\n\toutline-offset: 2px;\n}\n\n.Form_module_saveButton__d62303b4:disabled {\n\tbackground: #6c757d;\n\tcursor: not-allowed;\n\topacity: 0.65;\n\ttransform: none;\n\tbox-shadow: none;\n}\n\n.Form_module_nextButton__d62303b4 {\n\tbackground: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n\tcolor: white;\n\tborder: none;\n\tpadding: 0.75rem 2rem;\n\tborder-radius: 6px;\n\tfont-size: 1rem;\n\tfont-weight: 500;\n\tcursor: pointer;\n\ttransition: all 0.2s ease;\n}\n\n.Form_module_nextButton__d62303b4:hover:not(:disabled) {\n\ttransform: translateY(-2px);\n\tbox-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);\n}\n\n.Form_module_nextButton__d62303b4:disabled {\n\tbackground: #6c757d;\n\tcursor: not-allowed;\n\topacity: 0.65;\n\ttransform: none;\n\tbox-shadow: none;\n}\n\n\n\n.Form_module_errorMessage__d62303b4 {\n\tcolor: var(--colour-red);\n\tmargin: 0.25rem 0;\n\tpadding: 0.25rem 0;\n\tfont-size: 0.875rem;\n\tline-height: 1.4;\n}\n\n/* Layout option styles */\n.Form_module_layoutOption__d62303b4 {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\ttext-align: center;\n\tcursor: pointer;\n\ttransition: all 0.2s ease;\n\tbackground-color: transparent;\n\topacity: 0.6;\n}\n\n.Form_module_layoutOption__d62303b4:hover {\n\topacity: 1;\n}\n\n.Form_module_layoutOptionImage__d62303b4 {\n\twidth: 250px;\n\theight: 250px;\n\tborder-radius: 12px;\n\toverflow: hidden;\n\tmargin-bottom: 1rem;\n\tborder: 2px solid var(--border-line-grey, #dbddf1);\n\ttransition: all 0.2s ease;\n}\n\n.Form_module_layoutOption__d62303b4.Form_module_selected__d62303b4 .Form_module_layoutOptionImage__d62303b4 {\n\tborder-color: var(--colour-purple, #6e79c5);\n\tbox-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n}\n\n.Form_module_layoutOption__d62303b4.Form_module_selected__d62303b4 {\n\topacity: 1;\n}\n\n.Form_module_layoutOptionImg__d62303b4 {\n\twidth: 100%;\n\theight: 100%;\n\tobject-fit: cover;\n}\n\n.Form_module_layoutOptionContent__d62303b4 {\n\tmax-width: 250px;\n\tmargin-bottom: 0.5rem;\n}\n\n.Form_module_layoutOptionTitle__d62303b4 {\n\tfont-size: 1.6rem;\n\tfont-weight: 600;\n\tmargin: 0 0 0.5rem 0;\n\tline-height: 1.3;\n\tcolor: #333;\n}\n\n.Form_module_layoutOptionDescription__d62303b4 {\n\tfont-size: 1.2rem;\n\tmargin: 0;\n\tline-height: 1.3;\n\tcolor: #6c757d;\n}\n\n.Form_module_layoutOption__d62303b4.Form_module_hasError__d62303b4 .Form_module_layoutOptionImage__d62303b4 {\n\tborder-color: var(--colour-red, #dc3545);\n}\n\n/* Field error styles */\n.Form_module_fieldError__d62303b4 {\n\tcolor: #dc3545;\n\tfont-size: 1.6rem;\n\tfont-weight: 500;\n\tmargin-top: 0.5rem;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.25rem;\n}\n\n.Form_module_errorIcon__d62303b4 {\n\tfont-size: 1rem;\n}\n\n/* Field wrapper styles are now handled in Fields.module.css */\n\n/* Field type indicator styles are now handled in Fields.module.css */\n\n@keyframes Form_module_errorShake__d62303b4 {\n\t0%, 100% { transform: translateX(0); }\n\t25% { transform: translateX(-3px); }\n\t75% { transform: translateX(3px); }\n}\n\n@keyframes Form_module_errorPulse__d62303b4 {\n\t0% { \n\t\tbox-shadow: 0 1px 3px rgba(192, 39, 67, 0.1), 0 1px 2px rgba(192, 39, 67, 0.08);\n\t}\n\t50% { \n\t\tbox-shadow: 0 2px 6px rgba(192, 39, 67, 0.2), 0 1px 3px rgba(192, 39, 67, 0.15);\n\t}\n\t100% { \n\t\tbox-shadow: 0 1px 3px rgba(192, 39, 67, 0.1), 0 1px 2px rgba(192, 39, 67, 0.08);\n\t}\n}\n\n.Form_module_successMessage__d62303b4 {\n\tbackground: var(--colour-branding-secondary-light);\n\tborder: 1px solid var(--colour-branding-secondary);\n\tborder-radius: 8px;\n\tpadding: 1rem;\n\tmargin-top: 1rem;\n\tcolor: var(--colour-green);\n\tfont-weight: 500;\n}\n\n/* Mode-aware styling */\n.Form_module_createMode__d62303b4 {\n\tcolor: var(--colour-purple, #6e79c5);\n}\n\n.Form_module_editMode__d62303b4 {\n\tcolor: var(--colour-branding-dark, #364196);\n}\n\n/* Responsive Design */\n@media (max-width: 768px) {\n\t.Form_module_content__d62303b4 {\n\t\tpadding: 1.5rem 0 2.5rem 0; /* Maintain proper padding on mobile */\n\t}\n\t\n\t.Form_module_section__d62303b4 {\n\t\tmargin-bottom: 1.5rem;\n\t}\n\t\n\t/* Mobile: vertical layout for field selector and button */\n\t.Form_module_addFieldSection__d62303b4 {\n\t\tflex-direction: column;\n\t\talign-items: stretch; /* Stretch to fill available space */\n\t}\n\t\n\t/* Button should not be full width on mobile */\n\t.Form_module_addFieldSection__d62303b4 Button {\n\t\twidth: auto; /* Let button use its natural width */\n\t\tpadding: 1rem 1.5rem; /* Keep proper padding but not full width */\n\t}\n\t\n\t.Form_module_addFieldButtonContainer__d62303b4 {\n\t\talign-items: stretch;\n\t\tjustify-content: stretch;\n\t\tmin-height: auto;\n\t}\n\t\n\t.Form_module_navigation__d62303b4 {\n\t\tflex-direction: column;\n\t\tgap: 0.75rem;\n\t\tjustify-content: flex-start; /* Align to start on mobile */\n\t\tmargin-top: 2rem; /* Slightly reduce on mobile */\n\t\tpadding-top: 1.5rem;\n\t\tpadding-bottom: 1.5rem; /* Maintain bottom padding */\n\t}\n\t\n\t/* Mobile button alignment - single button aligns right, two buttons stack */\n\t.Form_module_navigation__d62303b4> :only-child {\n\t\tmargin-left: auto;\n\t\tmargin-right: 0;\n\t}\n\t\n\t.Form_module_navigation__d62303b4> :first-child:not(:only-child),\n\t.Form_module_navigation__d62303b4> :last-child:not(:only-child) {\n\t\tmargin-left: 0;\n\t\tmargin-right: 0;\n\t}\n\t\n\t.Form_module_previousButton__d62303b4,\n\t.Form_module_nextButton__d62303b4,\n\t.Form_module_saveButton__d62303b4 {\n\t\twidth: 100%;\n\t\tpadding: 1rem;\n\t}\n}\n\n@media (max-width: 480px) {\n\t.Form_module_content__d62303b4 {\n\t\tpadding: 1rem 0 2rem 0; /* Still maintain padding on small screens */\n\t}\n\t\n\t.Form_module_section__d62303b4 {\n\t\tmargin-bottom: 1rem;\n\t}\n\t\n\t.Form_module_navigation__d62303b4 {\n\t\tmargin-top: 1.5rem; /* Further reduce on very small screens */\n\t\tpadding-top: 1rem;\n\t\tpadding-bottom: 1.5rem;\n\t\tjustify-content: flex-start; /* Align to start on small screens */\n\t}\n\t\n\t/* Small screen button alignment */\n\t.Form_module_navigation__d62303b4> :only-child {\n\t\tmargin-left: auto;\n\t\tmargin-right: 0;\n\t}\n\t\n\t.Form_module_navigation__d62303b4> :first-child:not(:only-child),\n\t.Form_module_navigation__d62303b4> :last-child:not(:only-child) {\n\t\tmargin-left: 0;\n\t\tmargin-right: 0;\n\t}\n\t\n\t.Form_module_errorMessageContainer__d62303b4 {\n\t\tflex-direction: column;\n\t\talign-items: flex-start;\n\t\tgap: 0.75rem;\n\t}\n\t\n\t.Form_module_refreshButton__d62303b4 {\n\t\talign-self: flex-end;\n\t}\n}\n\n/* Full width content when sidebar is hidden */\n.hub-contentWrapper.fullWidthContent {\n\tmax-width: 1000px;\n\tmargin: 0 auto;\n\tpadding: 2rem;\n}\n\n.Form_module_hubContentWrapper_Col__d62303b4 {\n flex-flow: column;\n}\n\n/* Validation error message - displayed at top of form */\n.Form_module_validationErrorMessage__d62303b4 {\n\tbackground-color: var(--colour-branding-secondary-light);\n\tborder: 1px solid var(--colour-branding-secondary);\n\tborder-radius: 6px;\n\tcolor: var(--colour-red);\n\tpadding: 12px 16px;\n\tfont-weight: 500;\n\tfont-size: 14px;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\t\tmargin: 24px 32px;\n}\n\n.Form_module_validationErrorMessage__d62303b4::before {\n\tcontent: \"⚠\";\n\tfont-size: 16px;\n\tcolor: var(--colour-red);\n}\n\n/* Loading overlay for forms - deprecated, use SkeletonLoader instead */\n/*\n.loadingOverlay {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tbackground: rgba(255, 255, 255, 0.95);\n\tbackdrop-filter: blur(2px);\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tz-index: 10;\n\tborder-radius: 8px;\n\tanimation: fadeIn 0.2s ease-in-out;\n}\n\n@keyframes fadeIn {\n\tfrom { opacity: 0; }\n\tto { opacity: 1; }\n}\n*/\n\n/* Form header with buttons */\n.Form_module_formHeader__d62303b4 {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: flex-start;\n\tmargin-bottom: 16px;\n}\n\n/* Loading container for fields */\n.Form_module_fieldsLoadingContainer__d62303b4 {\n\ttext-align: center;\n\tpadding: 60px 20px;\n}\n\n/* Help note styling */\n.Form_module_helpNote__d62303b4 {\n\tfont-size: 13px;\n\tcolor: #6c757d;\n}\n\n/* Loading container for overview */\n.Form_module_overviewLoadingContainer__d62303b4 {\n\ttext-align: center;\n\tpadding: 60px 20px;\n}\n\n/* Form layout header */\n.Form_module_formLayoutHeader__d62303b4 {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: flex-start;\n\tmargin-bottom: 16px;\n}\n\n/* Section margins */\n.Form_module_gridIconSection__d62303b4 {\n\tmargin-bottom: 3rem;\n}\n\n.Form_module_layoutSection__d62303b4 {\n\tmargin-bottom: 2rem;\n}\n\n/* Grid icon loading state */\n.Form_module_gridIconLoading__d62303b4 {\n\tgrid-column: 1 / -1;\n}\n\n/* Hide upload button in grid icon section */\n.Form_module_gridIconSection__d62303b4 .iconLoader__buttonOverlay button:first-child {\n\tdisplay: none !important;\n}\n";
2511
- var modules_cd65a764 = {"content":"Form_module_content__d62303b4","pageWrapper":"Form_module_pageWrapper__d62303b4","formContainer":"Form_module_formContainer__d62303b4","section":"Form_module_section__d62303b4","section--no-border":"Form_module_section_NoBorder__d62303b4","subtitle":"Form_module_subtitle__d62303b4","sectionHeader":"Form_module_sectionHeader__d62303b4","addFieldButton":"Form_module_addFieldButton__d62303b4","refreshButton":"Form_module_refreshButton__d62303b4","errorMessageContainer":"Form_module_errorMessageContainer__d62303b4","addFieldContainer":"Form_module_addFieldContainer__d62303b4","fieldNumberContainer":"Form_module_fieldNumberContainer__d62303b4","addFieldSection":"Form_module_addFieldSection__d62303b4","helpSection":"Form_module_helpSection__d62303b4","helpTitle":"Form_module_helpTitle__d62303b4","helpText":"Form_module_helpText__d62303b4","fieldTypeCards":"Form_module_fieldTypeCards__d62303b4","fieldTypeCard":"Form_module_fieldTypeCard__d62303b4","fieldTypeCardIcon":"Form_module_fieldTypeCardIcon__d62303b4","fieldTypeCardContent":"Form_module_fieldTypeCardContent__d62303b4","fieldTypeCardTitle":"Form_module_fieldTypeCardTitle__d62303b4","fieldTypeCardDescription":"Form_module_fieldTypeCardDescription__d62303b4","fieldTypeCardUseCase":"Form_module_fieldTypeCardUseCase__d62303b4","addFieldButtonContainer":"Form_module_addFieldButtonContainer__d62303b4","emptyState":"Form_module_emptyState__d62303b4","emptyStateText":"Form_module_emptyStateText__d62303b4","fieldTypeSelector":"Form_module_fieldTypeSelector__d62303b4","grid__four":"Form_module_grid__four__d62303b4","navigation":"Form_module_navigation__d62303b4","overviewStep":"Form_module_overviewStep__d62303b4","previousButton":"Form_module_previousButton__d62303b4","saveButton":"Form_module_saveButton__d62303b4","nextButton":"Form_module_nextButton__d62303b4","errorMessage":"Form_module_errorMessage__d62303b4","layoutOption":"Form_module_layoutOption__d62303b4","layoutOptionImage":"Form_module_layoutOptionImage__d62303b4","selected":"Form_module_selected__d62303b4","layoutOptionImg":"Form_module_layoutOptionImg__d62303b4","layoutOptionContent":"Form_module_layoutOptionContent__d62303b4","layoutOptionTitle":"Form_module_layoutOptionTitle__d62303b4","layoutOptionDescription":"Form_module_layoutOptionDescription__d62303b4","hasError":"Form_module_hasError__d62303b4","fieldError":"Form_module_fieldError__d62303b4","errorIcon":"Form_module_errorIcon__d62303b4","successMessage":"Form_module_successMessage__d62303b4","createMode":"Form_module_createMode__d62303b4","editMode":"Form_module_editMode__d62303b4","hub-contentWrapper--col":"Form_module_hubContentWrapper_Col__d62303b4","validationErrorMessage":"Form_module_validationErrorMessage__d62303b4","formHeader":"Form_module_formHeader__d62303b4","fieldsLoadingContainer":"Form_module_fieldsLoadingContainer__d62303b4","helpNote":"Form_module_helpNote__d62303b4","overviewLoadingContainer":"Form_module_overviewLoadingContainer__d62303b4","formLayoutHeader":"Form_module_formLayoutHeader__d62303b4","gridIconSection":"Form_module_gridIconSection__d62303b4","layoutSection":"Form_module_layoutSection__d62303b4","gridIconLoading":"Form_module_gridIconLoading__d62303b4","errorShake":"Form_module_errorShake__d62303b4","errorPulse":"Form_module_errorPulse__d62303b4"};
2512
- n(css$c,{});
2513
-
2514
- function ownKeys$7(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2515
- function _objectSpread$7(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$7(Object(t), !0).forEach(function (r) { _defineProperty__default["default"](e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$7(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
2516
- const {
2517
- Helper: Helper$1,
2518
- Session: Session$1
2519
- } = PlussCore__namespace;
2520
- const {
2521
- getUrl: getUrl$1
2522
- } = Helper$1;
2523
- const {
2524
- authedFunction: authedFunction$1
2525
- } = Session$1;
2526
- const featureDefinitionActions = {
2527
- /**
2528
- * Get the single feature definition by ID
2529
- * Path: {id}
2530
- */
2531
- getSingle: async (id, site) => {
2532
- const query = {
2533
- id,
2534
- site
2535
- };
2536
- return authedFunction$1({
2537
- method: "GET",
2538
- url: getUrl$1("feature-builder", "definition/get/single", query)
2539
- });
2540
- },
2541
- /**
2542
- * Creates a new feature definition with the provided configuration
2543
- *
2544
- * @param {string} id - The unique identifier for the new feature definition
2545
- * @param {string} site - The site ID where the feature definition will be created
2546
- * @param {FeatureDefinition} featureDefinition - The feature definition data to create
2547
- * @returns {Promise<ApiResponse>} Promise resolving to API response with created feature definition
2548
- * @throws {Error} When creation fails due to validation or API errors
2549
- *
2550
- */
2551
- create: async (id, site, featureDefinition) => {
2552
- return authedFunction$1({
2553
- method: "POST",
2554
- url: getUrl$1("feature-builder", "definition/update/create"),
2555
- data: {
2556
- id,
2557
- site,
2558
- featureDefinition
2559
- }
2560
- });
2561
- },
2562
- /**
2563
- * Updates an existing feature definition with new configuration
2564
- *
2565
- * @param {FeatureDefinition} featureDefinitionData - The updated feature definition data
2566
- * @param {string} featureDefinitionData.id - The unique identifier of the feature definition to update
2567
- * @param {string} [featureDefinitionData.displayName] - Updated display name
2568
- * @param {Field[]} [featureDefinitionData.fields] - Updated field definitions
2569
- * @param {Object} [featureDefinitionData.layout] - Updated layout configuration
2570
- * @param {string} site - The site ID where the feature definition exists
2571
- * @returns {Promise<ApiResponse>} Promise resolving to API response with updated feature definition
2572
- * @throws {Error} When update fails due to validation or API errors
2573
- *
2574
- * @example
2575
- * try {
2576
- * const response = await featureDefinitionActions.edit(
2577
- * {
2578
- * id: 'feature-123',
2579
- * displayName: 'Updated Form',
2580
- * fields: [...]
2581
- * },
2582
- * 'site-123'
2583
- * );
2584
- */
2585
- edit: async (featureDefinitionData, site) => {
2586
- // Ensure site is included in the request body
2587
- const dataWithSite = _objectSpread$7({
2588
- site: site
2589
- }, featureDefinitionData);
2590
- return authedFunction$1({
2591
- method: "POST",
2592
- url: getUrl$1("feature-builder", "definition/update/edit"),
2593
- data: dataWithSite
2594
- });
2595
- },
2596
- /**
2597
- * Soft deletes a feature definition (marks as deleted but doesn't permanently remove)
2598
- *
2599
- * @param {string} id - The unique identifier of the feature definition to delete
2600
- * @param {string} site - The site ID where the feature definition exists
2601
- * @returns {Promise<ApiResponse>} Promise resolving to API response confirming deletion
2602
- * @throws {Error} When deletion fails or feature definition is not found
2603
- *
2604
- */
2605
- delete: async (id, site) => {
2606
- return authedFunction$1({
2607
- method: "POST",
2608
- url: getUrl$1("feature-builder", "definition/update/delete"),
2609
- data: {
2610
- id,
2611
- site
2612
- }
2613
- });
2614
- }
2451
+ const setLayoutType = layoutType => {
2452
+ return {
2453
+ type: actionsTypes.SET_LAYOUT_TYPE,
2454
+ payload: layoutType
2455
+ };
2615
2456
  };
2616
-
2617
- function ownKeys$6(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2618
- function _objectSpread$6(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$6(Object(t), !0).forEach(function (r) { _defineProperty__default["default"](e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$6(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
2619
-
2620
- // IMPORTANT: Using local UPDATE_STRINGS action type to make extension self-contained
2621
- // The main app's StringsReducer will handle this action type the same way
2622
- const UPDATE_STRINGS = "UPDATE_STRINGS";
2623
- const updateFeatureBuilderString = title => (dispatch, getState) => {
2624
- var _getState$strings;
2625
- const currentStrings = ((_getState$strings = getState().strings) === null || _getState$strings === void 0 ? void 0 : _getState$strings.config) || {};
2626
- const titleCased = toTitleCase(title) || values.textMenuTitle;
2627
- const updatedStrings = _objectSpread$6(_objectSpread$6({}, currentStrings), {}, {
2628
- sideNav: _objectSpread$6(_objectSpread$6({}, currentStrings.sideNav), {}, {
2629
- [values.featureKey]: titleCased,
2630
- [values.menuKey]: "Manage ".concat(titleCased)
2631
- }),
2632
- permission: _objectSpread$6(_objectSpread$6({}, currentStrings.permission), {}, {
2633
- [values.permissionFeatureBuilderDefinition]: "Manage custom feature ".concat(titleCased),
2634
- [values.permissionFeatureBuilderContent]: "Manage ".concat(titleCased, " content")
2635
- })
2636
- });
2637
- dispatch({
2638
- type: UPDATE_STRINGS,
2639
- payload: updatedStrings
2640
- });
2457
+ const submitFormRequest = () => {
2458
+ return {
2459
+ type: actionsTypes.SUBMIT_FORM_REQUEST
2460
+ };
2641
2461
  };
2642
- const updateFeatureBuilderIcon = icon => (dispatch, getState) => {
2643
- var _getState$strings2;
2644
- const currentStrings = ((_getState$strings2 = getState().strings) === null || _getState$strings2 === void 0 ? void 0 : _getState$strings2.config) || {};
2645
- const updatedStrings = _objectSpread$6(_objectSpread$6({}, currentStrings), {}, {
2646
- sideNav: _objectSpread$6(_objectSpread$6({}, currentStrings.sideNav), {}, {
2647
- [values.featureKey + "-icon"]: icon,
2648
- [values.menuKey + "-icon"]: icon
2649
- })
2650
- });
2651
- dispatch({
2652
- type: UPDATE_STRINGS,
2653
- payload: updatedStrings
2654
- });
2462
+ const submitFormSuccess = () => {
2463
+ return {
2464
+ type: actionsTypes.SUBMIT_FORM_SUCCESS
2465
+ };
2466
+ };
2467
+ const submitFormFailure = error => {
2468
+ return {
2469
+ type: actionsTypes.SUBMIT_FORM_FAILURE,
2470
+ payload: error
2471
+ };
2472
+ };
2473
+ const clearFormSubmissionState = () => {
2474
+ return {
2475
+ type: actionsTypes.CLEAR_FORM_SUBMISSION_STATE
2476
+ };
2655
2477
  };
2656
2478
 
2657
2479
  /**
2658
- * Form Actions for Feature Builder
2659
- * Manages form state including title, icon, fields, layout, and submission
2660
- * Handles CRUD operations for form fields and layout configuration
2661
- * Coordinates with external menu updates and feature definition actions
2480
+ * Submits the complete feature form to the server
2481
+ * Handles form validation, API submission, and error handling
2662
2482
  *
2663
- * @namespace formActions
2664
- */
2665
-
2666
- /**
2667
- * @typedef {Object} FieldValues
2668
- * @property {string} [label] - Field label text
2669
- * @property {string} [placeholder] - Placeholder text for input
2670
- * @property {boolean} [isRequired] - Whether field is required
2671
- * @property {string} [helpText] - Help text for field guidance
2672
- * @property {boolean} [allowCaption] - Whether field allows captions
2673
- * @property {boolean} [useAsSummary] - Whether field is used as summary
2483
+ * @returns {Function} Async thunk function for Redux
2484
+ * @throws {Error} When form validation fails or API submission encounters error
2674
2485
  */
2486
+ function submitForm() {
2487
+ return async (dispatch, getState) => {
2488
+ const state = getState()[values.reducerKey];
2489
+ const form = state === null || state === void 0 ? void 0 : state.form;
2490
+ if (!form) {
2491
+ dispatch(submitFormFailure(new Error("Form data is missing. Please refresh the page and try again.")));
2492
+ return;
2493
+ }
2494
+ dispatch(submitFormRequest());
2495
+ try {
2496
+ // Get site from auth store
2497
+ const site = getState().auth.site;
2498
+ if (!site) {
2499
+ throw new Error("Authentication error: Site context not found. Please refresh and login again.");
2500
+ }
2675
2501
 
2676
- /**
2677
- * @typedef {Object} FormField
2678
- * @property {string} id - Unique field identifier
2679
- * @property {string} type - Field type (text, title, description, image, file, cta, feature-image)
2680
- * @property {boolean} isMandatory - Whether field is mandatory system field
2681
- * @property {FieldValues} values - Field configuration values
2682
- */
2502
+ // Use mode from fetch instead of checking definition ID
2503
+ const definitionState = state === null || state === void 0 ? void 0 : state.definition;
2504
+ const mode = definitionState === null || definitionState === void 0 ? void 0 : definitionState.mode; // Use stored mode from fetch
2505
+ const definitionId = definitionState === null || definitionState === void 0 ? void 0 : definitionState.id;
2506
+ if (mode === "edit") {
2507
+ // Always update when in edit mode
2508
+ const updatedDefinition = {
2509
+ id: definitionId,
2510
+ site: site,
2511
+ // Include site from auth store
2512
+ featureDefinition: {
2513
+ // Wrap in expected structure for backend
2514
+ title: form.title,
2515
+ icon: form.icon,
2516
+ displayName: form.displayName,
2517
+ layout: form.layout,
2518
+ fields: form.fields
2519
+ }
2520
+ };
2521
+ await featureDefinitionActions.edit(updatedDefinition, site);
2522
+ } else {
2523
+ // Always create when in create mode (or mode is undefined/null)
2524
+ if (!values.featureId || !site) {
2525
+ throw new Error("Authentication error: Missing required context (featureId or site).");
2526
+ }
2527
+ await featureDefinitionActions.create(values.featureId, site,
2528
+ // Use actual site from auth store
2529
+ {
2530
+ title: form.title,
2531
+ icon: form.icon,
2532
+ displayName: form.displayName,
2533
+ layout: form.layout,
2534
+ fields: form.fields
2535
+ });
2536
+ }
2537
+ dispatch(submitFormSuccess());
2538
+ } catch (err) {
2539
+ // Handle different types of errors
2540
+ let errorToDisplay = err;
2541
+ if (err.response) {
2542
+ // API error (400, 401, 404, 500, etc.)
2543
+ const {
2544
+ status,
2545
+ data
2546
+ } = err.response;
2547
+ if (status === 400 && data !== null && data !== void 0 && data.error) {
2548
+ errorToDisplay = new Error("Validation error: ".concat(data.error));
2549
+ } else if (status === 401) {
2550
+ errorToDisplay = new Error("You are not authorized to perform this action");
2551
+ } else if (status === 404) {
2552
+ errorToDisplay = new Error("Feature definition not found");
2553
+ } else if (status >= 500) {
2554
+ errorToDisplay = new Error("Server error. Please try again later.");
2555
+ } else {
2556
+ errorToDisplay = new Error((data === null || data === void 0 ? void 0 : data.error) || "Request failed with status ".concat(status));
2557
+ }
2558
+ } else if (err.request) {
2559
+ // Network error (no response received)
2560
+ errorToDisplay = new Error("Network error. Please check your connection and try again.");
2561
+ } else if (err.message) {
2562
+ // Other JavaScript errors
2563
+ errorToDisplay = err;
2564
+ } else {
2565
+ // Unknown error
2566
+ errorToDisplay = new Error("An unexpected error occurred while saving");
2567
+ }
2568
+ dispatch(submitFormFailure(errorToDisplay));
2569
+ }
2570
+ };
2571
+ }
2683
2572
 
2684
- /**
2685
- * @typedef {Object} LayoutConfig
2686
- * @property {string} type - Layout type (round, square, etc.)
2687
- * @property {string} [gridIcon] - Background image for grid layout
2688
- */
2573
+ function ownKeys$6(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2574
+ function _objectSpread$6(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$6(Object(t), !0).forEach(function (r) { _defineProperty__default["default"](e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$6(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
2689
2575
 
2690
- const actionsTypes = {
2691
- SET_INITIAL_VALUES: "".concat(values.reducerKey.toUpperCase(), "_SET_INITIAL_VALUES"),
2692
- SET_TITLE: "".concat(values.reducerKey.toUpperCase(), "_SET_TITLE"),
2693
- SET_ICON: "".concat(values.reducerKey.toUpperCase(), "_SET_ICON"),
2694
- SET_DISPLAY_NAME: "".concat(values.reducerKey.toUpperCase(), "_SET_DISPLAY_NAME"),
2695
- ADD_FIELD: "".concat(values.reducerKey.toUpperCase(), "_ADD_FIELD"),
2696
- DELETE_FIELD: "".concat(values.reducerKey.toUpperCase(), "_DELETE_FIELD"),
2697
- UPDATE_FIELD: "".concat(values.reducerKey.toUpperCase(), "_UPDATE_FIELD"),
2698
- SET_LAYOUT_GRID_ICON: "".concat(values.reducerKey.toUpperCase(), "_SET_LAYOUT_GRID_ICON"),
2699
- SET_LAYOUT_TYPE: "".concat(values.reducerKey.toUpperCase(), "_SET_LAYOUT_TYPE"),
2700
- SUBMIT_FORM_REQUEST: "".concat(values.reducerKey.toUpperCase(), "_SUBMIT_FORM_REQUEST"),
2701
- SUBMIT_FORM_SUCCESS: "".concat(values.reducerKey.toUpperCase(), "_SUBMIT_FORM_SUCCESS"),
2702
- SUBMIT_FORM_FAILURE: "".concat(values.reducerKey.toUpperCase(), "_SUBMIT_FORM_FAILURE"),
2703
- CLEAR_FORM_SUBMISSION_STATE: "".concat(values.reducerKey.toUpperCase(), "_CLEAR_FORM_SUBMISSION_STATE"),
2704
- SET_SUMMARY_FIELD: "".concat(values.reducerKey.toUpperCase(), "_SET_SUMMARY_FIELD")
2576
+ // Wizard action types
2577
+ const REDUCER_PREFIX$2 = values.reducerKey.toUpperCase();
2578
+ const SET_NAVIGATION_STATE$1 = "".concat(REDUCER_PREFIX$2, "_SET_NAVIGATION_STATE");
2579
+ const UPDATE_STEP_VALIDATION$1 = "".concat(REDUCER_PREFIX$2, "_UPDATE_STEP_VALIDATION");
2580
+ const MARK_STEP_COMPLETE$1 = "".concat(REDUCER_PREFIX$2, "_MARK_STEP_COMPLETE");
2581
+ const setCurrentStep = function (step) {
2582
+ let previousStep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
2583
+ return {
2584
+ type: SET_NAVIGATION_STATE$1,
2585
+ payload: {
2586
+ currentStep: step,
2587
+ previousStep,
2588
+ canGoBack: step !== "welcome",
2589
+ canGoForward: true
2590
+ }
2591
+ };
2705
2592
  };
2593
+ const goToStep = step => (dispatch, getState) => {
2594
+ var _state$wizard;
2595
+ const state = getState()[values.reducerKey];
2596
+ const currentStep = state === null || state === void 0 || (_state$wizard = state.wizard) === null || _state$wizard === void 0 || (_state$wizard = _state$wizard.navigation) === null || _state$wizard === void 0 ? void 0 : _state$wizard.currentStep;
2706
2597
 
2707
- /**
2708
- * Action creator to set initial form values
2709
- * Initializes form state with existing feature definition data
2710
- *
2711
- * @param {Object} initialValues - Initial form values object
2712
- * @param {string} initialValues.title - Feature title
2713
- * @param {string} initialValues.icon - Feature icon
2714
- * @param {string} initialValues.displayName - Feature display name
2715
- * @param {LayoutConfig} initialValues.layout - Layout configuration
2716
- * @param {FormField[]} initialValues.fields - Form fields array
2717
- * @returns {Object} Redux action object with type and payload
2718
- *
2719
- * @example
2720
- * dispatch(setInitialValues({
2721
- * title: 'Contact Form',
2722
- * icon: 'envelope',
2723
- * fields: []
2724
- * }));
2725
- */
2726
- const setInitialValues = initialValues => {
2598
+ // Clear form submission state when changing steps
2599
+ dispatch(clearFormSubmissionState());
2600
+ dispatch(setCurrentStep(step, currentStep));
2601
+ };
2602
+ const updateStepValidation = function (step, isValid) {
2603
+ let errors = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
2727
2604
  return {
2728
- type: actionsTypes.SET_INITIAL_VALUES,
2729
- payload: initialValues
2605
+ type: UPDATE_STEP_VALIDATION$1,
2606
+ payload: {
2607
+ step,
2608
+ isValid,
2609
+ errors
2610
+ }
2611
+ };
2612
+ };
2613
+ const validateAndUpdateStep = step => (dispatch, getState) => {
2614
+ // Use existing selectors to get form data
2615
+ const state = getState();
2616
+ const title = selectFormTitle(state);
2617
+ const icon = selectFormIcon(state);
2618
+ const displayName = selectFormDisplayName(state);
2619
+ const layout = selectFormLayout(state);
2620
+ const fields = selectFormFields(state);
2621
+ const form = {
2622
+ title,
2623
+ icon,
2624
+ displayName,
2625
+ layout,
2626
+ fields
2730
2627
  };
2731
- };
2732
- const setTitle = title => {
2628
+ const {
2629
+ isValid,
2630
+ errors
2631
+ } = getFormValidation(form, step);
2632
+ dispatch(updateStepValidation(step, isValid, errors));
2633
+
2634
+ // If valid, mark as complete
2635
+ if (isValid) {
2636
+ dispatch({
2637
+ type: MARK_STEP_COMPLETE$1,
2638
+ payload: step
2639
+ });
2640
+ }
2733
2641
  return {
2734
- type: actionsTypes.SET_TITLE,
2735
- payload: title
2642
+ isValid,
2643
+ errors
2736
2644
  };
2737
2645
  };
2646
+ const getFormValidation = (form, step) => {
2647
+ // Return validation results for undefined form (prevent crashes)
2648
+ if (!form) {
2649
+ switch (step) {
2650
+ case "overview":
2651
+ return {
2652
+ isValid: false,
2653
+ errors: {
2654
+ title: "Title is required",
2655
+ displayName: "Display name is required",
2656
+ icon: "Icon is required"
2657
+ }
2658
+ };
2659
+ case "fields":
2660
+ return {
2661
+ isValid: false,
2662
+ errors: {
2663
+ missingTitle: "Title field is required",
2664
+ missingImage: "Feature image field is required",
2665
+ fieldLabels: "Some fields are missing labels"
2666
+ }
2667
+ };
2668
+ case "layout":
2669
+ return {
2670
+ isValid: false,
2671
+ errors: {
2672
+ layoutType: "Layout type is required"
2673
+ }
2674
+ };
2675
+ default:
2676
+ return {
2677
+ isValid: false,
2678
+ errors: {}
2679
+ };
2680
+ }
2681
+ }
2682
+ switch (step) {
2683
+ case "overview":
2684
+ {
2685
+ var _form$title, _form$displayName, _form$icon;
2686
+ const hasTitle = ((_form$title = form.title) === null || _form$title === void 0 ? void 0 : _form$title.trim().length) > 0;
2687
+ const hasDisplayName = ((_form$displayName = form.displayName) === null || _form$displayName === void 0 ? void 0 : _form$displayName.trim().length) > 0;
2688
+ const hasIcon = ((_form$icon = form.icon) === null || _form$icon === void 0 ? void 0 : _form$icon.length) > 0;
2689
+ return {
2690
+ isValid: hasTitle && hasDisplayName && hasIcon,
2691
+ errors: {
2692
+ title: !hasTitle ? "Title is required" : null,
2693
+ displayName: !hasDisplayName ? "Display name is required" : null,
2694
+ icon: !hasIcon ? "Icon is required" : null
2695
+ }
2696
+ };
2697
+ }
2698
+ case "fields":
2699
+ {
2700
+ var _form$fields, _form$fields2;
2701
+ const hasTitleField = (_form$fields = form.fields) === null || _form$fields === void 0 ? void 0 : _form$fields.some(field => field.id === "mandatory-title");
2702
+ const hasImageField = (_form$fields2 = form.fields) === null || _form$fields2 === void 0 ? void 0 : _form$fields2.some(field => field.id === "mandatory-feature-image");
2738
2703
 
2739
- /**
2740
- * Action creator to set form display name and update menu
2741
- * Updates both form state and external menu string
2742
- * Title cases the display name before updating the strings store
2743
- *
2744
- * @param {string} displayName - New display name for form
2745
- * @returns {Function} Thunk function for Redux
2746
- *
2747
- * @example
2748
- * dispatch(setDisplayName('Contact Information'));
2749
- */
2750
- const setDisplayName = displayName => {
2704
+ // Check each field for missing labels and create field-specific errors
2705
+ const fieldErrors = {};
2706
+ let allFieldsHaveLabels = true;
2707
+ if (form.fields) {
2708
+ form.fields.forEach(field => {
2709
+ if ((field.type === "text" || field.type === "description" || field.type === "title" || field.type === "image" || field.type === "gallery" || field.type === "feature-image" || field.type === "file" || field.type === "cta") && field.values) {
2710
+ if (!field.values.label || field.values.label.trim().length === 0) {
2711
+ fieldErrors[field.id] = "Field label is required";
2712
+ allFieldsHaveLabels = false;
2713
+ }
2714
+ }
2715
+ });
2716
+ }
2717
+ return {
2718
+ isValid: hasTitleField && hasImageField && allFieldsHaveLabels,
2719
+ errors: _objectSpread$6({
2720
+ missingTitle: !hasTitleField ? "Title field is required" : null,
2721
+ missingImage: !hasImageField ? "Feature image field is required" : null
2722
+ }, fieldErrors)
2723
+ };
2724
+ }
2725
+ case "layout":
2726
+ {
2727
+ var _form$layout;
2728
+ const hasLayoutType = ((_form$layout = form.layout) === null || _form$layout === void 0 || (_form$layout = _form$layout.type) === null || _form$layout === void 0 ? void 0 : _form$layout.length) > 0;
2729
+ return {
2730
+ isValid: hasLayoutType,
2731
+ errors: {
2732
+ layoutType: !hasLayoutType ? "Layout type is required" : null
2733
+ }
2734
+ };
2735
+ }
2736
+ default:
2737
+ return {
2738
+ isValid: true,
2739
+ errors: {}
2740
+ };
2741
+ }
2742
+ };
2743
+ const setCurrentStepAndSave = function (step) {
2744
+ let previousStep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
2751
2745
  return dispatch => {
2752
- // Update menu string when display name changes (will be title cased in updateFeatureBuilderString)
2753
- dispatch(updateFeatureBuilderString(displayName));
2754
-
2755
- // Dispatch the actual action
2756
- dispatch({
2757
- type: actionsTypes.SET_DISPLAY_NAME,
2758
- payload: displayName
2759
- });
2746
+ dispatch(setCurrentStep(step, previousStep));
2760
2747
  };
2761
2748
  };
2762
2749
 
2750
+ var css$d = ".SidebarLayout_module_fullWidthContent__0d6658dd {\n\tmax-width: 100%;\n\tmargin-left: auto;\n\tmargin-right: auto;\n\tpadding: 2rem 2rem 3rem 2rem; /* Add extra bottom padding */\n}\n\n/* Full-width container that allows scrollbar at edge */\n.SidebarLayout_module_fullWidthContainer__0d6658dd {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1;\n\tmin-height: 0; /* Allow content to determine height */\n\twidth: 100%; /* Take full width to ensure scrollbar is at edge */\n}\n\n/* Content container to keep content centered */\n.SidebarLayout_module_contentContainer__0d6658dd {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1;\n\tmin-height: 0;\n\tmax-width: 960px;\n\tmargin: 0 auto;\n\tpadding: 64px 32px;\n\twidth: 100%;\n\tbox-sizing: border-box;\n}\n\n/* Legacy container class for backward compatibility */\n.SidebarLayout_module_container__0d6658dd{\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1;\n\tmin-height: 0; /* Allow content to determine height */\n max-width: 960px;\n margin: 0 auto;\n padding: 64px 32px;\n}\n\n/* Responsive adjustments for content container */\n@media (max-width: 768px) {\n\t.SidebarLayout_module_contentContainer__0d6658dd {\n\t\tpadding: 1.5rem 1.5rem 2.5rem 1.5rem; /* Slightly reduced but still adequate */\n\t}\n\t.SidebarLayout_module_container__0d6658dd {\n\t\tpadding: 1.5rem 1.5rem 2.5rem 1.5rem; /* Legacy container support */\n\t}\n}\n\n@media (max-width: 480px) {\n\t.SidebarLayout_module_contentContainer__0d6658dd {\n\t\tpadding: 1rem 1rem 2rem 1rem; /* Maintain padding on small screens */\n\t}\n\t.SidebarLayout_module_container__0d6658dd {\n\t\tpadding: 1rem 1rem 2rem 1rem; /* Legacy container support */\n\t}\n}\n\n/* Enhanced sidebar navigation for progress indication */\n\n/* Enhanced progress section */\n.hub-sideBar-section {\n\tborder-bottom: 2px solid var(--colour-branding-main-fade, rgba(74, 87, 183, 0.15));\n\tpadding-bottom: 1rem;\n\tmargin-bottom: 1rem;\n}\n\n.hub-sideBar-section:last-child {\n\tborder-bottom: none;\n}\n";
2751
+ var modules_d5b6badf = {"fullWidthContent":"SidebarLayout_module_fullWidthContent__0d6658dd","fullWidthContainer":"SidebarLayout_module_fullWidthContainer__0d6658dd","contentContainer":"SidebarLayout_module_contentContainer__0d6658dd","container":"SidebarLayout_module_container__0d6658dd"};
2752
+ n(css$d,{});
2753
+
2763
2754
  /**
2764
- * Action creator to set form icon and update menu
2765
- * Updates both form state and external menu icon
2755
+ * Sidebar Layout component for feature builder wizard
2756
+ * Provides navigation sidebar with step progression, completion tracking
2757
+ * Manages step accessibility based on wizard mode and validation state
2766
2758
  *
2767
- * @param {string} icon - Icon identifier or FontAwesome icon class
2768
- * @returns {Function} Thunk function for Redux
2759
+ * @param {Object} props - Component props
2760
+ * @param {React.ReactNode} props.children - Child components to render in main content area
2761
+ * @param {Object} props.history - React Router history object for navigation
2762
+ * @returns {React.ReactElement} Layout component with sidebar navigation
2769
2763
  *
2770
2764
  * @example
2771
- * dispatch(setIcon('fa-user'));
2765
+ * <SidebarLayout history={historyObject}>
2766
+ * <YourMainContent />
2767
+ * </SidebarLayout>
2772
2768
  */
2773
- const setIcon = icon => {
2774
- return dispatch => {
2775
- // Update menu icon when icon changes
2776
- dispatch(updateFeatureBuilderIcon(icon));
2769
+ const SideBarInner = props => {
2770
+ const {
2771
+ children,
2772
+ history
2773
+ } = props;
2774
+ const dispatch = reactRedux.useDispatch();
2777
2775
 
2778
- // Dispatch the actual action
2779
- dispatch({
2780
- type: actionsTypes.SET_ICON,
2781
- payload: icon
2782
- });
2776
+ // Get wizard state
2777
+ const mode = reactRedux.useSelector(selectWizardMode);
2778
+ const isEditMode = reactRedux.useSelector(selectIsEditMode);
2779
+ const isCreateMode = reactRedux.useSelector(selectIsCreateMode);
2780
+ const currentStep = reactRedux.useSelector(selectCurrentStep);
2781
+ const goTo = url => history.push(url);
2782
+ const isSelected = url => {
2783
+ return history.location.pathname === url;
2783
2784
  };
2784
- };
2785
2785
 
2786
- /**
2787
- * Action creator to add a new field to the form
2788
- * Generates unique ID and supports custom field types
2789
- *
2790
- * @param {string} [fieldType="text"] - Type of field to add (text, title, description, image, gallery, file, cta, feature-image)
2791
- * @returns {Object} Redux action object with field ID and type
2792
- *
2793
- * @example
2794
- * dispatch(addField('text'));
2795
- * dispatch(addField('image'));
2796
- */
2797
- const addField = function () {
2798
- let fieldType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "text";
2799
- // Generate a unique ID for the new field
2800
- const fieldId = "custom-field-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
2801
- return {
2802
- type: actionsTypes.ADD_FIELD,
2803
- payload: {
2804
- id: fieldId,
2805
- type: fieldType
2786
+ // Define step configuration with dynamic URL based on mode
2787
+ const getStepUrl = stepKey => {
2788
+ // Use routes from values.config to support different variants (-a, -b, -c, -d)
2789
+ switch (stepKey) {
2790
+ case "overview":
2791
+ return values.routeFormOverviewStep;
2792
+ case "fields":
2793
+ return values.routeFormFieldsStep;
2794
+ case "layout":
2795
+ return values.routeFormLayoutStep;
2796
+ default:
2797
+ return "";
2806
2798
  }
2807
2799
  };
2808
- };
2809
- const deleteField = id => {
2810
- return {
2811
- type: actionsTypes.DELETE_FIELD,
2812
- payload: id
2813
- };
2814
- };
2815
- const updateFieldById = (id, updatedField) => {
2816
- return {
2817
- type: actionsTypes.UPDATE_FIELD,
2818
- payload: {
2819
- id,
2820
- updatedField
2821
- }
2800
+ const steps = [{
2801
+ key: "overview",
2802
+ text: "Feature Overview",
2803
+ icon: "info-circle",
2804
+ url: getStepUrl("overview")
2805
+ }, {
2806
+ key: "fields",
2807
+ text: "Configure Fields",
2808
+ icon: "edit",
2809
+ url: getStepUrl("fields")
2810
+ }, {
2811
+ key: "layout",
2812
+ text: "Choose Layout",
2813
+ icon: "columns",
2814
+ url: getStepUrl("layout")
2815
+ }];
2816
+
2817
+ // Build sidebar items based on mode
2818
+ const buildSidebarItems = () => {
2819
+ const isWizardMode = mode === "create" || mode === "edit";
2820
+ return steps.map((step, index) => {
2821
+ const isCompleted = selectIsStepComplete(step.key);
2822
+ const isAccessible = selectIsStepAccessible(step.key);
2823
+
2824
+ // Add step number to text for better clarity
2825
+ const stepText = "".concat(index + 1, ". ").concat(step.text);
2826
+ const itemProps = {
2827
+ type: "navItem",
2828
+ text: stepText,
2829
+ icon: step.icon,
2830
+ selected: isSelected(step.url),
2831
+ onclick: isWizardMode ? null : isAccessible ? () => {
2832
+ goTo(step.url);
2833
+ dispatch(goToStep(step.key));
2834
+ } : null,
2835
+ isFontAwesome: true,
2836
+ // Enhanced completion indicator
2837
+ completed: isCompleted,
2838
+ // Disable all navigation in wizard mode
2839
+ disabled: isWizardMode || mode === "create" && !isAccessible
2840
+ };
2841
+ return itemProps;
2842
+ });
2822
2843
  };
2823
- };
2824
2844
 
2825
- /**
2826
- * Action creator to set a description field as the summary field
2827
- * Ensures only one description field can be marked as summary by
2828
- * automatically unsetting all other description fields when a new one is selected
2829
- *
2830
- * @param {string} fieldId - ID of the description field to set as summary
2831
- * @returns {Object} Redux action object for summary field selection
2832
- *
2833
- * @example
2834
- * dispatch(setSummaryField('field-description-123'));
2835
- */
2836
- const setSummaryField = fieldId => {
2837
- return {
2838
- type: actionsTypes.SET_SUMMARY_FIELD,
2839
- payload: fieldId
2840
- };
2841
- };
2842
- const setLayoutType = layoutType => {
2843
- return {
2844
- type: actionsTypes.SET_LAYOUT_TYPE,
2845
- payload: layoutType
2846
- };
2847
- };
2848
- const submitFormRequest = () => {
2849
- return {
2850
- type: actionsTypes.SUBMIT_FORM_REQUEST
2851
- };
2852
- };
2853
- const submitFormSuccess = () => {
2854
- return {
2855
- type: actionsTypes.SUBMIT_FORM_SUCCESS
2856
- };
2857
- };
2858
- const submitFormFailure = error => {
2859
- return {
2860
- type: actionsTypes.SUBMIT_FORM_FAILURE,
2861
- payload: error
2845
+ // Determine sidebar title - always use "Build Your Feature" now
2846
+ const getSidebarTitle = () => {
2847
+ return "Build Your Feature";
2862
2848
  };
2863
- };
2864
- const clearFormSubmissionState = () => {
2865
- return {
2866
- type: actionsTypes.CLEAR_FORM_SUBMISSION_STATE
2849
+
2850
+ // Simple help text
2851
+ const getHelpText = () => {
2852
+ return "Get help with feature builder";
2867
2853
  };
2868
- };
2869
2854
 
2870
- /**
2871
- * Submits the complete feature form to the server
2872
- * Handles form validation, API submission, and error handling
2873
- *
2874
- * @returns {Function} Async thunk function for Redux
2875
- * @throws {Error} When form validation fails or API submission encounters error
2876
- */
2877
- function submitForm() {
2878
- return async (dispatch, getState) => {
2879
- const state = getState()[values.reducerKey];
2880
- const form = state && state.form;
2881
- if (!form) {
2882
- dispatch(submitFormFailure(new Error("Form data is missing. Please refresh the page and try again.")));
2883
- return;
2884
- }
2885
- dispatch(submitFormRequest());
2886
- try {
2887
- // Get site from auth store
2888
- const site = getState().auth.site;
2889
- if (!site) {
2890
- throw new Error("Authentication error: Site context not found. Please refresh and login again.");
2891
- }
2855
+ // Build sidebar sections - simplified without progress section
2856
+ const sidebarSections = [{
2857
+ title: getSidebarTitle(),
2858
+ items: buildSidebarItems()
2859
+ }];
2892
2860
 
2893
- // Use mode from fetch instead of checking definition ID
2894
- const definitionState = state && state.definition;
2895
- const mode = definitionState && definitionState.mode; // Use stored mode from fetch
2896
- const definitionId = definitionState && definitionState.id;
2897
- if (mode === "edit") {
2898
- // Always update when in edit mode
2899
- const updatedDefinition = {
2900
- id: definitionId,
2901
- site: site,
2902
- // Include site from auth store
2903
- featureDefinition: {
2904
- // Wrap in expected structure for backend
2905
- title: form.title,
2906
- icon: form.icon,
2907
- displayName: form.displayName,
2908
- layout: form.layout,
2909
- fields: form.fields
2861
+ // Add effect to manually attach click handlers since HubSidebar might not use onclick properly
2862
+ React.useEffect(() => {
2863
+ const isWizardMode = mode === "create" || mode === "edit";
2864
+ const attachClickHandlers = () => {
2865
+ const stepsWithUrls = [{
2866
+ key: "overview",
2867
+ url: getStepUrl("overview")
2868
+ }, {
2869
+ key: "fields",
2870
+ url: getStepUrl("fields")
2871
+ }, {
2872
+ key: "layout",
2873
+ url: getStepUrl("layout")
2874
+ }];
2875
+ stepsWithUrls.forEach((step, index) => {
2876
+ const navItem = Array.from(document.querySelectorAll(".hub-wrapperContainer .sideNav-item")).find(item => item.textContent && item.textContent.includes("".concat(index + 1, ".")));
2877
+ if (navItem) {
2878
+ // Remove any existing click listeners
2879
+ navItem.onclick = null;
2880
+
2881
+ // Check if this step is accessible
2882
+ const isAccessible = selectIsStepAccessible(step.key)({
2883
+ [values.reducerKey]: {
2884
+ wizard: {
2885
+ mode: mode,
2886
+ navigation: {
2887
+ currentStep: currentStep
2888
+ }
2889
+ }
2890
+ }
2891
+ });
2892
+
2893
+ // Check if this is the current step (selected)
2894
+ const isCurrentStep = isSelected(step.url);
2895
+
2896
+ // In wizard mode, don't attach any click handlers
2897
+ // Only attach click handler if not in wizard mode AND accessible
2898
+ if (!isWizardMode && isAccessible) {
2899
+ navItem.onclick = event => {
2900
+ event.preventDefault();
2901
+ event.stopPropagation();
2902
+ history.push(step.url);
2903
+ dispatch(goToStep(step.key));
2904
+ };
2905
+ }
2906
+
2907
+ // Make sure it's styled appropriately
2908
+ // In wizard mode: block clicks, but keep current step visible
2909
+ navItem.style.pointerEvents = isWizardMode ? "none" : "auto";
2910
+ if (isWizardMode) {
2911
+ // Current step: full opacity, not-allowed cursor
2912
+ // Other steps: reduced opacity
2913
+ navItem.style.opacity = isCurrentStep ? "1" : "0.4";
2914
+ navItem.style.cursor = "not-allowed";
2915
+ } else {
2916
+ // Not in wizard mode: normal styling based on accessibility
2917
+ navItem.style.cursor = isAccessible ? "pointer" : "not-allowed";
2918
+ navItem.style.opacity = isAccessible ? "1" : "0.5";
2910
2919
  }
2911
- };
2912
- await featureDefinitionActions.edit(updatedDefinition, site);
2913
- } else {
2914
- // Always create when in create mode (or mode is undefined/null)
2915
- if (!values.featureId || !site) {
2916
- throw new Error("Authentication error: Missing required context (featureId or site).");
2917
- }
2918
- await featureDefinitionActions.create(values.featureId, site,
2919
- // Use actual site from auth store
2920
- {
2921
- title: form.title,
2922
- icon: form.icon,
2923
- displayName: form.displayName,
2924
- layout: form.layout,
2925
- fields: form.fields
2926
- });
2927
- }
2928
- dispatch(submitFormSuccess());
2929
- } catch (err) {
2930
- // Handle different types of errors
2931
- let errorToDisplay = err;
2932
- if (err.response) {
2933
- // API error (400, 401, 404, 500, etc.)
2934
- const {
2935
- status,
2936
- data
2937
- } = err.response;
2938
- if (status === 400 && data && data.error) {
2939
- errorToDisplay = new Error("Validation error: ".concat(data.error));
2940
- } else if (status === 401) {
2941
- errorToDisplay = new Error("You are not authorized to perform this action");
2942
- } else if (status === 404) {
2943
- errorToDisplay = new Error("Feature definition not found");
2944
- } else if (status >= 500) {
2945
- errorToDisplay = new Error("Server error. Please try again later.");
2946
- } else {
2947
- errorToDisplay = new Error(data && data.error || "Request failed with status ".concat(status));
2948
2920
  }
2949
- } else if (err.request) {
2950
- // Network error (no response received)
2951
- errorToDisplay = new Error("Network error. Please check your connection and try again.");
2952
- } else if (err.message) {
2953
- // Other JavaScript errors
2954
- errorToDisplay = err;
2955
- } else {
2956
- // Unknown error
2957
- errorToDisplay = new Error("An unexpected error occurred while saving");
2958
- }
2959
- dispatch(submitFormFailure(errorToDisplay));
2921
+ });
2922
+ };
2923
+
2924
+ // Initial attachment
2925
+ attachClickHandlers();
2926
+
2927
+ // Re-attach after a short delay to ensure HubSidebar has rendered
2928
+ const timeoutId = setTimeout(attachClickHandlers, 100);
2929
+
2930
+ // Also try to re-attach when DOM changes (observe for mutations)
2931
+ const observer = new MutationObserver(() => {
2932
+ setTimeout(attachClickHandlers, 50);
2933
+ });
2934
+
2935
+ // Start observing the document body for changes
2936
+ observer.observe(document.body, {
2937
+ childList: true,
2938
+ subtree: true
2939
+ });
2940
+ return () => {
2941
+ clearTimeout(timeoutId);
2942
+ observer.disconnect();
2943
+ };
2944
+ }, [history, dispatch, isEditMode, isCreateMode, currentStep]);
2945
+ return /*#__PURE__*/React__default["default"].createElement("div", {
2946
+ className: "hub-wrapperContainer"
2947
+ }, /*#__PURE__*/React__default["default"].createElement(HubSidebar, {
2948
+ sections: sidebarSections,
2949
+ helpGuide: {
2950
+ text: getHelpText(),
2951
+ url: "https://www.plusscommunities.com/user-guide"
2960
2952
  }
2961
- };
2962
- }
2953
+ }), /*#__PURE__*/React__default["default"].createElement("div", {
2954
+ className: "hub-contentWrapper"
2955
+ }, /*#__PURE__*/React__default["default"].createElement("div", {
2956
+ className: modules_d5b6badf.fullWidthContainer
2957
+ }, /*#__PURE__*/React__default["default"].createElement("div", {
2958
+ className: modules_d5b6badf.contentContainer
2959
+ }, children))));
2960
+ };
2961
+ const SidebarLayout = reactRouter.withRouter(SideBarInner);
2962
+
2963
+ var css$c = ".Form_module_content__d62303b4 {\n\tflex: 1 1 auto;\n\tdisplay: flex;\n\tflex-flow: column nowrap;\n\tpadding: 2rem 0 3rem 0; /* Add proper top/bottom padding */\n\tmin-height: 100%; /* Ensure full height for proper spacing */\n}\n\n/* New page wrapper for centered container approach */\n.Form_module_pageWrapper__d62303b4 {\n\tpadding: 2rem 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tjustify-content: flex-start;\n}\n\n@media (min-width: 768px) {\n\t.Form_module_pageWrapper__d62303b4 {\n\t\tpadding: 3rem 0;\n\t}\n}\n\n/* Form container styling when using CenteredContainer */\n.Form_module_formContainer__d62303b4 {\n\tbackground-color: var(--bg-white);\n}\n\n/* Section styling */\n.Form_module_section__d62303b4 {\n\tmargin-bottom: 2rem;\n\t\tpadding: 0 0 2em;\n}\n\n.Form_module_section_NoBorder__d62303b4 {\n\t\tborder-bottom: none;\n}\n\n.Form_module_subtitle__d62303b4 {\n\tcolor: var(--text-bluegrey, #6c7a90);\n}\n\n.Form_module_sectionHeader__d62303b4 {\n\t\tdisplay: flex;\n\t\tjustify-content: space-between;\n}\n\n/* Add Field Button styling */\n.Form_module_addFieldButton__d62303b4 {\n\tbackground: var(--colour-branding-action, #5c90df);\n\tcolor: white;\n\tborder: none;\n\tpadding: 0.75rem 1.5rem;\n\tborder-radius: 6px;\n\tfont-size: 1rem;\n\tcursor: pointer;\n\tmargin-bottom: 2rem;\n\ttransition: all 0.2s ease;\n}\n\n.Form_module_addFieldButton__d62303b4:hover {\n\tbackground: var(--colour-branding-action-hover, #364196);\n\ttransform: translateY(-1px);\n\tbox-shadow: 0 2px 4px rgba(92, 144, 223, 0.3);\n}\n\n.Form_module_addFieldButton__d62303b4:focus {\n\toutline: 2px solid var(--colour-branding-action, #5c90df);\n\toutline-offset: 2px;\n}\n\n.Form_module_addFieldButton__d62303b4:active {\n\ttransform: translateY(0);\n}\n\n/* Refresh button styling */\n.Form_module_refreshButton__d62303b4 {\n\tmargin-left: 10px;\n\tpadding: 2px 8px;\n\tfont-size: 12px;\n\tbackground: var(--colour-dusk, #536280);\n\tcolor: white;\n\tborder: none;\n\tborder-radius: 4px;\n\tcursor: pointer;\n\ttransition: background-color 0.2s ease;\n}\n\n.Form_module_refreshButton__d62303b4:hover {\n\tbackground: var(--colour-dusk-hover, #485968);\n}\n\n/* Error message container */\n.Form_module_errorMessageContainer__d62303b4 {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.5rem;\n}\n\n/* Add Field Container - matches field structure */\n.Form_module_addFieldContainer__d62303b4 {\n\tdisplay: flex;\n\tmargin-top: 32px;\n}\n\n.Form_module_fieldNumberContainer__d62303b4 {\n\tdisplay: flex;\n\twidth: 40px;\n}\n\n/* Add Field Section */\n.Form_module_addFieldSection__d62303b4 {\n\tdisplay: flex;\n\tgap: 1rem;\n\talign-items: center;\n\tjustify-content: flex-start; /* Align to start to match field content */\n\tmargin-top: 0; /* Remove top margin since it's in the container */\n}\n\n/* Desktop: horizontal layout for field selector and button */\n@media (min-width: 769px) {\n\t.Form_module_addFieldSection__d62303b4 {\n\t\tflex-direction: row;\n\t\talign-items: baseline;\n\t\tgap: 2rem;\n\t\talign-items: flex-start;\n\t\tjustify-content: flex-start; /* Align to start to match field content */\n\t}\n}\n\n/* Help Section for Popup */\n.Form_module_helpSection__d62303b4 {\n\tbackground-color: var(--colour-branding-action-superlight);\n\tborder: 1px solid var(--colour-branding-inactive);\n\tborder-radius: 8px;\n\tpadding: 1.5rem;\n\tmargin-bottom: 1.5rem;\n}\n\n.Form_module_helpTitle__d62303b4 {\n\tcolor: var(--text-dark);\n\tfont-weight: 600;\n\tmargin-bottom: 0.75rem;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.5rem;\n\tfont-size: 1.25rem;\n}\n\n.Form_module_helpText__d62303b4 {\n\tcolor: var(--colour-branding-action);\n\tline-height: 1.6;\n\tfont-size: 1.25rem;\n}\n\n/* Field Type Cards for Popup */\n.Form_module_fieldTypeCards__d62303b4 {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 1rem; /* Spacing between vertical cards */\n\tpadding: 1rem 0;\n}\n\n/* Responsive layout: maintain vertical layout on all screen sizes */\n@media (min-width: 768px) {\n\t.Form_module_fieldTypeCards__d62303b4 {\n\t\tgap: 1.5rem; /* Slightly larger gap on desktop */\n\t}\n}\n\n.Form_module_fieldTypeCard__d62303b4 {\n\tdisplay: flex;\n\tflex-direction: row;\n\talign-items: flex-start;\n\tpadding: 1.75rem 1.25rem; /* More vertical padding */\n\tborder: 1px solid var(--border-line-grey);\n\tborder-radius: 8px;\n\tbackground-color: var(--bg-white);\n\tcursor: pointer;\n\ttransition: all 0.2s ease;\n\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n\tmin-height: 120px; /* Adjust height for horizontal layout */\n\tgap: 1rem; /* Space between icon and content */\n}\n\n.Form_module_fieldTypeCard__d62303b4:hover {\n\tborder-color: var(--text-light);\n\tbackground-color: var(--bg-bluegrey);\n\tbox-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n}\n\n.Form_module_fieldTypeCard__d62303b4:focus {\n\toutline: 2px solid var(--text-light);\n\toutline-offset: 2px;\n}\n\n.Form_module_fieldTypeCard__d62303b4:active {\n\ttransform: scale(0.98);\n\ttransition: transform 0.1s ease;\n}\n\n.Form_module_fieldTypeCardIcon__d62303b4 {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 48px;\n\theight: 48px;\n\tmargin-bottom: 0; /* Remove bottom margin for horizontal layout */\n\tfont-size: 20px;\n\tflex-shrink: 0;\n\tborder: 1px solid var(--border-line-grey); /* Subtle border */\n\tborder-radius: 8px;\n\tbackground-color: var(--bg-bluegrey);\n\tpadding: 8px;\n}\n\n\n.Form_module_fieldTypeCardContent__d62303b4 {\n\tflex: 1;\n\twidth: 100%;\n\tmin-width: 0; /* Prevent content from overflowing */\n}\n\n.Form_module_fieldTypeCardTitle__d62303b4 {\n\tmargin: 0 0 0.25rem 0;\n\tfont-weight: 600;\n\tfont-size: 1.4rem; /* Increased for better readability */\n}\n\n.Form_module_fieldTypeCardDescription__d62303b4 {\n\tmargin: 0 0 0.75rem 0;\n\tfont-size: 1.6rem; /* Increased for better readability */\n\tline-height: 1.5; /* Improved line height for better readability */\n}\n\n.Form_module_fieldTypeCardUseCase__d62303b4 {\n\tmargin: 0;\n\tfont-size: 1.4rem;\n\tfont-style: italic;\n\tcolor: var(--text-light);\n\tpadding-top: 0.5rem;\n\tborder-top: 1px solid var(--border-line-grey);\n}\n\n/* Field selector and button container - horizontal layout */\n.Form_module_addFieldSection__d62303b4> div:first-child {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 0.5rem;\n\tflex: 1;\n}\n\n/* Container for add field button alignment */\n.Form_module_addFieldButtonContainer__d62303b4 {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: flex-end;\n}\n\n/* Empty State */\n.Form_module_emptyState__d62303b4 {\n\tpadding: 2rem;\n\ttext-align: center;\n\tbackground-color: var(--bg-bluegrey, #f4f7f9);\n\tborder-radius: 8px;\n\tborder: 1px dashed var(--border-line-grey, #dbddf1);\n\tmargin-bottom: 1rem;\n}\n\n.Form_module_emptyStateText__d62303b4 {\n\tcolor: var(--text-bluegrey, #6c7a90);\n\tfont-style: italic;\n}\n\n.Form_module_fieldTypeSelector__d62303b4 {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmax-width: 500px; /* Increased from 300px to accommodate longer text */\n\twidth: 100%;\n}\n\n@media (max-width: 768px) {\n\t.Form_module_addFieldSection__d62303b4 {\n\t\talign-items: stretch;\n\t}\n\t\n\t.Form_module_fieldTypeSelector__d62303b4 {\n\t\tmax-width: none;\n\t}\n}\n\n.Form_module_grid__four__d62303b4 {\n max-width: 1200px;\n\tdisplay: grid;\n\tgrid-template-columns: repeat(2, minmax(250px, 1fr));\n margin: 2rem 0;\n\tgap: 2rem;\n\tjustify-items: center;\n}\n\n@media (max-width: 768px) {\n\t.Form_module_grid__four__d62303b4 {\n\t\tgrid-template-columns: 1fr;\n\t\tgap: 2rem;\n\t}\n}\n\n/* Navigation styles */\n.Form_module_navigation__d62303b4 {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\tgap: 1rem;\n\tmargin-top: 3rem; /* Increase from 2rem */\n\tpadding-top: 2rem;\n\tpadding-bottom: 2rem; /* Add bottom padding */\n\tborder-top: 1px solid #e9ecef;\n}\n\n/* Single button alignment - align to right for overview step save button */\n.Form_module_navigation__d62303b4> :only-child {\n\tmargin-left: auto;\n\tmargin-right: 0;\n}\n\n/* Two button alignment - one left, one right */\n.Form_module_navigation__d62303b4> :first-child:not(:only-child) {\n\tmargin-right: auto;\n}\n\n.Form_module_navigation__d62303b4> :last-child:not(:only-child) {\n\tmargin-left: auto;\n}\n\n/* Special case for overview step - align save button to right */\n.Form_module_overviewStep__d62303b4 .Form_module_navigation__d62303b4> :only-child {\n\tmargin-left: auto;\n\tmargin-right: 0;\n}\n\n.Form_module_previousButton__d62303b4 {\n\tbackground: #6c757d;\n\tcolor: white;\n\tborder: none;\n\tpadding: 0.75rem 1.5rem;\n\tborder-radius: 6px;\n\tfont-size: 1rem;\n\tcursor: pointer;\n\ttransition: all 0.2s ease;\n}\n\n.Form_module_previousButton__d62303b4:hover {\n\tbackground: #5a6268;\n}\n\n.Form_module_saveButton__d62303b4 {\n\tbackground: var(--colour-purple, #6e79c5);\n\tcolor: white;\n\tborder: none;\n\tpadding: 0.75rem 2rem;\n\tborder-radius: 6px;\n\tfont-size: 1rem;\n\tfont-weight: 500;\n\tcursor: pointer;\n\ttransition: all 0.2s ease;\n}\n\n.Form_module_saveButton__d62303b4:hover:not(:disabled) {\n\tbackground: var(--colour-purple-hover, #5a66b3);\n\ttransform: translateY(-1px);\n\tbox-shadow: 0 2px 4px rgba(110, 121, 197, 0.3);\n}\n\n.Form_module_saveButton__d62303b4:focus {\n\toutline: 2px solid var(--colour-purple, #6e79c5);\n\toutline-offset: 2px;\n}\n\n.Form_module_saveButton__d62303b4:disabled {\n\tbackground: #6c757d;\n\tcursor: not-allowed;\n\topacity: 0.65;\n\ttransform: none;\n\tbox-shadow: none;\n}\n\n.Form_module_nextButton__d62303b4 {\n\tbackground: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n\tcolor: white;\n\tborder: none;\n\tpadding: 0.75rem 2rem;\n\tborder-radius: 6px;\n\tfont-size: 1rem;\n\tfont-weight: 500;\n\tcursor: pointer;\n\ttransition: all 0.2s ease;\n}\n\n.Form_module_nextButton__d62303b4:hover:not(:disabled) {\n\ttransform: translateY(-2px);\n\tbox-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);\n}\n\n.Form_module_nextButton__d62303b4:disabled {\n\tbackground: #6c757d;\n\tcursor: not-allowed;\n\topacity: 0.65;\n\ttransform: none;\n\tbox-shadow: none;\n}\n\n\n\n.Form_module_errorMessage__d62303b4 {\n\tcolor: var(--colour-red);\n\tmargin: 0.25rem 0;\n\tpadding: 0.25rem 0;\n\tfont-size: 0.875rem;\n\tline-height: 1.4;\n}\n\n/* Layout option styles */\n.Form_module_layoutOption__d62303b4 {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\ttext-align: center;\n\tcursor: pointer;\n\ttransition: all 0.2s ease;\n\tbackground-color: transparent;\n\topacity: 0.6;\n}\n\n.Form_module_layoutOption__d62303b4:hover {\n\topacity: 1;\n}\n\n.Form_module_layoutOptionImage__d62303b4 {\n\twidth: 250px;\n\theight: 250px;\n\tborder-radius: 12px;\n\toverflow: hidden;\n\tmargin-bottom: 1rem;\n\tborder: 2px solid var(--border-line-grey, #dbddf1);\n\ttransition: all 0.2s ease;\n}\n\n.Form_module_layoutOption__d62303b4.Form_module_selected__d62303b4 .Form_module_layoutOptionImage__d62303b4 {\n\tborder-color: var(--colour-purple, #6e79c5);\n\tbox-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n}\n\n.Form_module_layoutOption__d62303b4.Form_module_selected__d62303b4 {\n\topacity: 1;\n}\n\n.Form_module_layoutOptionImg__d62303b4 {\n\twidth: 100%;\n\theight: 100%;\n\tobject-fit: cover;\n}\n\n.Form_module_layoutOptionContent__d62303b4 {\n\tmax-width: 250px;\n\tmargin-bottom: 0.5rem;\n}\n\n.Form_module_layoutOptionTitle__d62303b4 {\n\tfont-size: 1.6rem;\n\tfont-weight: 600;\n\tmargin: 0 0 0.5rem 0;\n\tline-height: 1.3;\n\tcolor: #333;\n}\n\n.Form_module_layoutOptionDescription__d62303b4 {\n\tfont-size: 1.2rem;\n\tmargin: 0;\n\tline-height: 1.3;\n\tcolor: #6c757d;\n}\n\n.Form_module_layoutOption__d62303b4.Form_module_hasError__d62303b4 .Form_module_layoutOptionImage__d62303b4 {\n\tborder-color: var(--colour-red, #dc3545);\n}\n\n/* Field error styles */\n.Form_module_fieldError__d62303b4 {\n\tcolor: #dc3545;\n\tfont-size: 1.6rem;\n\tfont-weight: 500;\n\tmargin-top: 0.5rem;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.25rem;\n}\n\n.Form_module_errorIcon__d62303b4 {\n\tfont-size: 1rem;\n}\n\n/* Field wrapper styles are now handled in Fields.module.css */\n\n/* Field type indicator styles are now handled in Fields.module.css */\n\n@keyframes Form_module_errorShake__d62303b4 {\n\t0%, 100% { transform: translateX(0); }\n\t25% { transform: translateX(-3px); }\n\t75% { transform: translateX(3px); }\n}\n\n@keyframes Form_module_errorPulse__d62303b4 {\n\t0% { \n\t\tbox-shadow: 0 1px 3px rgba(192, 39, 67, 0.1), 0 1px 2px rgba(192, 39, 67, 0.08);\n\t}\n\t50% { \n\t\tbox-shadow: 0 2px 6px rgba(192, 39, 67, 0.2), 0 1px 3px rgba(192, 39, 67, 0.15);\n\t}\n\t100% { \n\t\tbox-shadow: 0 1px 3px rgba(192, 39, 67, 0.1), 0 1px 2px rgba(192, 39, 67, 0.08);\n\t}\n}\n\n.Form_module_successMessage__d62303b4 {\n\tbackground: var(--colour-branding-secondary-light);\n\tborder: 1px solid var(--colour-branding-secondary);\n\tborder-radius: 8px;\n\tpadding: 1rem;\n\tmargin-top: 1rem;\n\tcolor: var(--colour-green);\n\tfont-weight: 500;\n}\n\n/* Mode-aware styling */\n.Form_module_createMode__d62303b4 {\n\tcolor: var(--colour-purple, #6e79c5);\n}\n\n.Form_module_editMode__d62303b4 {\n\tcolor: var(--colour-branding-dark, #364196);\n}\n\n/* Responsive Design */\n@media (max-width: 768px) {\n\t.Form_module_content__d62303b4 {\n\t\tpadding: 1.5rem 0 2.5rem 0; /* Maintain proper padding on mobile */\n\t}\n\t\n\t.Form_module_section__d62303b4 {\n\t\tmargin-bottom: 1.5rem;\n\t}\n\t\n\t/* Mobile: vertical layout for field selector and button */\n\t.Form_module_addFieldSection__d62303b4 {\n\t\tflex-direction: column;\n\t\talign-items: stretch; /* Stretch to fill available space */\n\t}\n\t\n\t/* Button should not be full width on mobile */\n\t.Form_module_addFieldSection__d62303b4 Button {\n\t\twidth: auto; /* Let button use its natural width */\n\t\tpadding: 1rem 1.5rem; /* Keep proper padding but not full width */\n\t}\n\t\n\t.Form_module_addFieldButtonContainer__d62303b4 {\n\t\talign-items: stretch;\n\t\tjustify-content: stretch;\n\t\tmin-height: auto;\n\t}\n\t\n\t.Form_module_navigation__d62303b4 {\n\t\tflex-direction: column;\n\t\tgap: 0.75rem;\n\t\tjustify-content: flex-start; /* Align to start on mobile */\n\t\tmargin-top: 2rem; /* Slightly reduce on mobile */\n\t\tpadding-top: 1.5rem;\n\t\tpadding-bottom: 1.5rem; /* Maintain bottom padding */\n\t}\n\t\n\t/* Mobile button alignment - single button aligns right, two buttons stack */\n\t.Form_module_navigation__d62303b4> :only-child {\n\t\tmargin-left: auto;\n\t\tmargin-right: 0;\n\t}\n\t\n\t.Form_module_navigation__d62303b4> :first-child:not(:only-child),\n\t.Form_module_navigation__d62303b4> :last-child:not(:only-child) {\n\t\tmargin-left: 0;\n\t\tmargin-right: 0;\n\t}\n\t\n\t.Form_module_previousButton__d62303b4,\n\t.Form_module_nextButton__d62303b4,\n\t.Form_module_saveButton__d62303b4 {\n\t\twidth: 100%;\n\t\tpadding: 1rem;\n\t}\n}\n\n@media (max-width: 480px) {\n\t.Form_module_content__d62303b4 {\n\t\tpadding: 1rem 0 2rem 0; /* Still maintain padding on small screens */\n\t}\n\t\n\t.Form_module_section__d62303b4 {\n\t\tmargin-bottom: 1rem;\n\t}\n\t\n\t.Form_module_navigation__d62303b4 {\n\t\tmargin-top: 1.5rem; /* Further reduce on very small screens */\n\t\tpadding-top: 1rem;\n\t\tpadding-bottom: 1.5rem;\n\t\tjustify-content: flex-start; /* Align to start on small screens */\n\t}\n\t\n\t/* Small screen button alignment */\n\t.Form_module_navigation__d62303b4> :only-child {\n\t\tmargin-left: auto;\n\t\tmargin-right: 0;\n\t}\n\t\n\t.Form_module_navigation__d62303b4> :first-child:not(:only-child),\n\t.Form_module_navigation__d62303b4> :last-child:not(:only-child) {\n\t\tmargin-left: 0;\n\t\tmargin-right: 0;\n\t}\n\t\n\t.Form_module_errorMessageContainer__d62303b4 {\n\t\tflex-direction: column;\n\t\talign-items: flex-start;\n\t\tgap: 0.75rem;\n\t}\n\t\n\t.Form_module_refreshButton__d62303b4 {\n\t\talign-self: flex-end;\n\t}\n}\n\n/* Full width content when sidebar is hidden */\n.hub-contentWrapper.fullWidthContent {\n\tmax-width: 1000px;\n\tmargin: 0 auto;\n\tpadding: 2rem;\n}\n\n.Form_module_hubContentWrapper_Col__d62303b4 {\n flex-flow: column;\n}\n\n/* Validation error message - displayed at top of form */\n.Form_module_validationErrorMessage__d62303b4 {\n\tbackground-color: var(--colour-branding-secondary-light);\n\tborder: 1px solid var(--colour-branding-secondary);\n\tborder-radius: 6px;\n\tcolor: var(--colour-red);\n\tpadding: 12px 16px;\n\tfont-weight: 500;\n\tfont-size: 14px;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\t\tmargin: 24px 32px;\n}\n\n.Form_module_validationErrorMessage__d62303b4::before {\n\tcontent: \"⚠\";\n\tfont-size: 16px;\n\tcolor: var(--colour-red);\n}\n\n/* Loading overlay for forms - deprecated, use SkeletonLoader instead */\n/*\n.loadingOverlay {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tbackground: rgba(255, 255, 255, 0.95);\n\tbackdrop-filter: blur(2px);\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tz-index: 10;\n\tborder-radius: 8px;\n\tanimation: fadeIn 0.2s ease-in-out;\n}\n\n@keyframes fadeIn {\n\tfrom { opacity: 0; }\n\tto { opacity: 1; }\n}\n*/\n\n/* Form header with buttons */\n.Form_module_formHeader__d62303b4 {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: flex-start;\n\tmargin-bottom: 16px;\n}\n\n/* Loading container for fields */\n.Form_module_fieldsLoadingContainer__d62303b4 {\n\ttext-align: center;\n\tpadding: 60px 20px;\n}\n\n/* Help note styling */\n.Form_module_helpNote__d62303b4 {\n\tfont-size: 13px;\n\tcolor: #6c757d;\n}\n\n/* Loading container for overview */\n.Form_module_overviewLoadingContainer__d62303b4 {\n\ttext-align: center;\n\tpadding: 60px 20px;\n}\n\n/* Form layout header */\n.Form_module_formLayoutHeader__d62303b4 {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: flex-start;\n\tmargin-bottom: 16px;\n}\n\n/* Section margins */\n.Form_module_gridIconSection__d62303b4 {\n\tmargin-bottom: 3rem;\n}\n\n.Form_module_layoutSection__d62303b4 {\n\tmargin-bottom: 2rem;\n}\n\n/* Grid icon loading state */\n.Form_module_gridIconLoading__d62303b4 {\n\tgrid-column: 1 / -1;\n}\n\n/* Hide upload button in grid icon section */\n.Form_module_gridIconSection__d62303b4 .iconLoader__buttonOverlay button:first-child {\n\tdisplay: none !important;\n}\n";
2964
+ var modules_cd65a764 = {"content":"Form_module_content__d62303b4","pageWrapper":"Form_module_pageWrapper__d62303b4","formContainer":"Form_module_formContainer__d62303b4","section":"Form_module_section__d62303b4","section--no-border":"Form_module_section_NoBorder__d62303b4","subtitle":"Form_module_subtitle__d62303b4","sectionHeader":"Form_module_sectionHeader__d62303b4","addFieldButton":"Form_module_addFieldButton__d62303b4","refreshButton":"Form_module_refreshButton__d62303b4","errorMessageContainer":"Form_module_errorMessageContainer__d62303b4","addFieldContainer":"Form_module_addFieldContainer__d62303b4","fieldNumberContainer":"Form_module_fieldNumberContainer__d62303b4","addFieldSection":"Form_module_addFieldSection__d62303b4","helpSection":"Form_module_helpSection__d62303b4","helpTitle":"Form_module_helpTitle__d62303b4","helpText":"Form_module_helpText__d62303b4","fieldTypeCards":"Form_module_fieldTypeCards__d62303b4","fieldTypeCard":"Form_module_fieldTypeCard__d62303b4","fieldTypeCardIcon":"Form_module_fieldTypeCardIcon__d62303b4","fieldTypeCardContent":"Form_module_fieldTypeCardContent__d62303b4","fieldTypeCardTitle":"Form_module_fieldTypeCardTitle__d62303b4","fieldTypeCardDescription":"Form_module_fieldTypeCardDescription__d62303b4","fieldTypeCardUseCase":"Form_module_fieldTypeCardUseCase__d62303b4","addFieldButtonContainer":"Form_module_addFieldButtonContainer__d62303b4","emptyState":"Form_module_emptyState__d62303b4","emptyStateText":"Form_module_emptyStateText__d62303b4","fieldTypeSelector":"Form_module_fieldTypeSelector__d62303b4","grid__four":"Form_module_grid__four__d62303b4","navigation":"Form_module_navigation__d62303b4","overviewStep":"Form_module_overviewStep__d62303b4","previousButton":"Form_module_previousButton__d62303b4","saveButton":"Form_module_saveButton__d62303b4","nextButton":"Form_module_nextButton__d62303b4","errorMessage":"Form_module_errorMessage__d62303b4","layoutOption":"Form_module_layoutOption__d62303b4","layoutOptionImage":"Form_module_layoutOptionImage__d62303b4","selected":"Form_module_selected__d62303b4","layoutOptionImg":"Form_module_layoutOptionImg__d62303b4","layoutOptionContent":"Form_module_layoutOptionContent__d62303b4","layoutOptionTitle":"Form_module_layoutOptionTitle__d62303b4","layoutOptionDescription":"Form_module_layoutOptionDescription__d62303b4","hasError":"Form_module_hasError__d62303b4","fieldError":"Form_module_fieldError__d62303b4","errorIcon":"Form_module_errorIcon__d62303b4","successMessage":"Form_module_successMessage__d62303b4","createMode":"Form_module_createMode__d62303b4","editMode":"Form_module_editMode__d62303b4","hub-contentWrapper--col":"Form_module_hubContentWrapper_Col__d62303b4","validationErrorMessage":"Form_module_validationErrorMessage__d62303b4","formHeader":"Form_module_formHeader__d62303b4","fieldsLoadingContainer":"Form_module_fieldsLoadingContainer__d62303b4","helpNote":"Form_module_helpNote__d62303b4","overviewLoadingContainer":"Form_module_overviewLoadingContainer__d62303b4","formLayoutHeader":"Form_module_formLayoutHeader__d62303b4","gridIconSection":"Form_module_gridIconSection__d62303b4","layoutSection":"Form_module_layoutSection__d62303b4","gridIconLoading":"Form_module_gridIconLoading__d62303b4","errorShake":"Form_module_errorShake__d62303b4","errorPulse":"Form_module_errorPulse__d62303b4"};
2965
+ n(css$c,{});
2963
2966
 
2964
2967
  /*
2965
2968
  * Icon categories and definitions for the feature builder
@@ -3283,9 +3286,6 @@ const FormOverviewStepInner = props => {
3283
3286
 
3284
3287
  // Clear submission state after showing toast (only for non-edit cases)
3285
3288
  if (!isEditMode) {
3286
- const {
3287
- clearFormSubmissionState
3288
- } = require("../actions/formActions");
3289
3289
  dispatch(clearFormSubmissionState());
3290
3290
  }
3291
3291
  }
@@ -3979,8 +3979,9 @@ function fetchFeatureDefinitions() {
3979
3979
  dispatch(fetchFeaturesFailure(new Error("Unexpected response status: ".concat(response.status))));
3980
3980
  }
3981
3981
  } catch (err) {
3982
+ var _err$response;
3982
3983
  // Check if it's a 404 (feature doesn't exist)
3983
- if (err.response && err.response.status === 404) {
3984
+ if (((_err$response = err.response) === null || _err$response === void 0 ? void 0 : _err$response.status) === 404) {
3984
3985
  // 404: Feature doesn't exist → create mode
3985
3986
  dispatch(fetchFeaturesSuccess(null, "create"));
3986
3987
 
@@ -4636,8 +4637,7 @@ const FormLayoutStepInner = props => {
4636
4637
  // Use custom hook to handle definition loading
4637
4638
  const {
4638
4639
  definition,
4639
- definitionIsLoading,
4640
- reloadDefinition
4640
+ definitionIsLoading
4641
4641
  } = useFeatureDefinitionLoader();
4642
4642
 
4643
4643
  // Get form initialization state
@@ -5249,7 +5249,7 @@ const undeleteListing = id => {
5249
5249
  const response = await listingActions.undelete(id, site);
5250
5250
  // If API returns the restored listing, use it; otherwise we'll need to refetch
5251
5251
  const restoredListing = response.data;
5252
- if (restoredListing && restoredListing.id) {
5252
+ if (restoredListing !== null && restoredListing !== void 0 && restoredListing.id) {
5253
5253
  dispatch(undeleteListingSuccess(restoredListing));
5254
5254
  } else {
5255
5255
  // Trigger a refetch by dispatching the success with just ID, then fetch updated listings
@@ -5565,20 +5565,21 @@ const formReducer = function () {
5565
5565
  switch (type) {
5566
5566
  case actionsTypes.SET_INITIAL_VALUES:
5567
5567
  {
5568
+ var _payload$featureDefin, _definitionWrapper$de;
5568
5569
  // The actual definition data is in payload.featureDefinition.definition
5569
- const definitionWrapper = payload && payload.featureDefinition ? payload.featureDefinition : payload;
5570
- const definition = definitionWrapper && definitionWrapper.definition ? definitionWrapper.definition : definitionWrapper;
5570
+ const definitionWrapper = (_payload$featureDefin = payload === null || payload === void 0 ? void 0 : payload.featureDefinition) !== null && _payload$featureDefin !== void 0 ? _payload$featureDefin : payload;
5571
+ const definition = (_definitionWrapper$de = definitionWrapper === null || definitionWrapper === void 0 ? void 0 : definitionWrapper.definition) !== null && _definitionWrapper$de !== void 0 ? _definitionWrapper$de : definitionWrapper;
5571
5572
 
5572
5573
  // Validate and map definition data to form state structure
5573
5574
  const mappedValues = {
5574
- title: definition && definition.title || "",
5575
- icon: definition && definition.icon || "star",
5576
- displayName: definition && definition.displayName || "",
5577
- layout: definition && definition.layout || {
5575
+ title: (definition === null || definition === void 0 ? void 0 : definition.title) || "",
5576
+ icon: (definition === null || definition === void 0 ? void 0 : definition.icon) || "star",
5577
+ displayName: (definition === null || definition === void 0 ? void 0 : definition.displayName) || "",
5578
+ layout: (definition === null || definition === void 0 ? void 0 : definition.layout) || {
5578
5579
  gridIcon: undefined,
5579
5580
  type: "round"
5580
5581
  },
5581
- fields: definition && Array.isArray(definition.fields) ? definition.fields : state.fields
5582
+ fields: Array.isArray(definition === null || definition === void 0 ? void 0 : definition.fields) ? definition.fields : state.fields
5582
5583
  };
5583
5584
  const newState = _objectSpread$3(_objectSpread$3(_objectSpread$3({}, state), mappedValues), {}, {
5584
5585
  _isInitial: false
@@ -5783,14 +5784,15 @@ const definitionReducer = function () {
5783
5784
  let definitionId = values.featureId; // Always use hardcoded ID
5784
5785
 
5785
5786
  if (mode === "edit" && data) {
5787
+ var _data$featureDefiniti, _featureDefinitionWra, _featureDefinitionWra2, _definition;
5786
5788
  // Extract from API response for edit mode
5787
5789
  // Handle nested structure: data.featureDefinition.definition
5788
- const featureDefinitionWrapper = data && data.featureDefinition ? data.featureDefinition : data;
5789
- definition = featureDefinitionWrapper && featureDefinitionWrapper.definition ? featureDefinitionWrapper.definition : featureDefinitionWrapper;
5790
- definitionId = featureDefinitionWrapper && featureDefinitionWrapper.id || values.featureId;
5790
+ const featureDefinitionWrapper = (_data$featureDefiniti = data === null || data === void 0 ? void 0 : data.featureDefinition) !== null && _data$featureDefiniti !== void 0 ? _data$featureDefiniti : data;
5791
+ definition = (_featureDefinitionWra = featureDefinitionWrapper === null || featureDefinitionWrapper === void 0 ? void 0 : featureDefinitionWrapper.definition) !== null && _featureDefinitionWra !== void 0 ? _featureDefinitionWra : featureDefinitionWrapper;
5792
+ definitionId = (_featureDefinitionWra2 = featureDefinitionWrapper === null || featureDefinitionWrapper === void 0 ? void 0 : featureDefinitionWrapper.id) !== null && _featureDefinitionWra2 !== void 0 ? _featureDefinitionWra2 : values.featureId;
5791
5793
 
5792
5794
  // Ensure fields array exists and preserves order property
5793
- if (definition && definition.fields) {
5795
+ if ((_definition = definition) !== null && _definition !== void 0 && _definition.fields) {
5794
5796
  // Create a new array to ensure we preserve all field properties including order
5795
5797
  definition.fields = definition.fields.map(field => _objectSpread$3(_objectSpread$3({}, field), {}, {
5796
5798
  // Ensure order property exists, fallback to array index if missing
@@ -5829,7 +5831,7 @@ const definitionReducer = function () {
5829
5831
  // Optimistically update with new definition
5830
5832
  mode: "edit" // Switch to edit mode immediately
5831
5833
  }),
5832
- id: payload && payload.id,
5834
+ id: payload === null || payload === void 0 ? void 0 : payload.id,
5833
5835
  error: null
5834
5836
  });
5835
5837
  case FEATURE_EDIT_REQUEST: