@plusscommunities/pluss-feature-builder-web-b 1.0.2-beta.4 → 1.0.2-beta.5
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 +824 -782
- package/package.json +1 -1
- package/src/actions/featureDefinitionsIndex.js +14 -13
- package/src/actions/formActions.js +14 -14
- package/src/actions/listingActions.js +33 -31
- package/src/actions/wizardActions.js +9 -9
- package/src/components/SidebarLayout.jsx +47 -28
- package/src/components/SidebarLayout.module.css +0 -34
- package/src/hooks/useFeatureDefinitionLoader.js +6 -2
- package/src/index.js +6 -6
- package/src/screens/Form.module.css +11 -1
- package/src/screens/FormOverviewStep.jsx +1 -0
- package/src/selectors/featureBuilderSelectors.js +4 -0
package/dist/index.cjs.js
CHANGED
|
@@ -199,6 +199,10 @@ const selectDefinitionError = state => {
|
|
|
199
199
|
const definitionState = selectDefinitionState(state);
|
|
200
200
|
return definitionState && definitionState.error;
|
|
201
201
|
};
|
|
202
|
+
const selectDefinitionMode = state => {
|
|
203
|
+
const definitionState = selectDefinitionState(state);
|
|
204
|
+
return definitionState && definitionState.mode;
|
|
205
|
+
};
|
|
202
206
|
|
|
203
207
|
// Check if we have a definition loaded
|
|
204
208
|
const selectHasDefinition = state => !!selectDefinition(state);
|
|
@@ -2116,816 +2120,846 @@ const Text$8 = Components$4.Text;
|
|
|
2116
2120
|
|
|
2117
2121
|
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; }
|
|
2118
2122
|
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; }
|
|
2119
|
-
const {
|
|
2120
|
-
Helper: Helper$1,
|
|
2121
|
-
Session: Session$1
|
|
2122
|
-
} = PlussCore__namespace;
|
|
2123
|
-
const {
|
|
2124
|
-
getUrl: getUrl$1
|
|
2125
|
-
} = Helper$1;
|
|
2126
|
-
const {
|
|
2127
|
-
authedFunction: authedFunction$1
|
|
2128
|
-
} = Session$1;
|
|
2129
|
-
const featureDefinitionActions = {
|
|
2130
|
-
/**
|
|
2131
|
-
* Get the single feature definition by ID
|
|
2132
|
-
* Path: {id}
|
|
2133
|
-
*/
|
|
2134
|
-
getSingle: async (id, site) => {
|
|
2135
|
-
const query = {
|
|
2136
|
-
id,
|
|
2137
|
-
site
|
|
2138
|
-
};
|
|
2139
|
-
return authedFunction$1({
|
|
2140
|
-
method: "GET",
|
|
2141
|
-
url: getUrl$1("feature-builder", "definition/get/single", query)
|
|
2142
|
-
});
|
|
2143
|
-
},
|
|
2144
|
-
/**
|
|
2145
|
-
* Creates a new feature definition with the provided configuration
|
|
2146
|
-
*
|
|
2147
|
-
* @param {string} id - The unique identifier for the new feature definition
|
|
2148
|
-
* @param {string} site - The site ID where the feature definition will be created
|
|
2149
|
-
* @param {FeatureDefinition} featureDefinition - The feature definition data to create
|
|
2150
|
-
* @returns {Promise<ApiResponse>} Promise resolving to API response with created feature definition
|
|
2151
|
-
* @throws {Error} When creation fails due to validation or API errors
|
|
2152
|
-
*
|
|
2153
|
-
*/
|
|
2154
|
-
create: async (id, site, featureDefinition) => {
|
|
2155
|
-
return authedFunction$1({
|
|
2156
|
-
method: "POST",
|
|
2157
|
-
url: getUrl$1("feature-builder", "definition/update/create"),
|
|
2158
|
-
data: {
|
|
2159
|
-
id,
|
|
2160
|
-
site,
|
|
2161
|
-
featureDefinition
|
|
2162
|
-
}
|
|
2163
|
-
});
|
|
2164
|
-
},
|
|
2165
|
-
/**
|
|
2166
|
-
* Updates an existing feature definition with new configuration
|
|
2167
|
-
*
|
|
2168
|
-
* @param {FeatureDefinition} featureDefinitionData - The updated feature definition data
|
|
2169
|
-
* @param {string} featureDefinitionData.id - The unique identifier of the feature definition to update
|
|
2170
|
-
* @param {string} [featureDefinitionData.displayName] - Updated display name
|
|
2171
|
-
* @param {Field[]} [featureDefinitionData.fields] - Updated field definitions
|
|
2172
|
-
* @param {Object} [featureDefinitionData.layout] - Updated layout configuration
|
|
2173
|
-
* @param {string} site - The site ID where the feature definition exists
|
|
2174
|
-
* @returns {Promise<ApiResponse>} Promise resolving to API response with updated feature definition
|
|
2175
|
-
* @throws {Error} When update fails due to validation or API errors
|
|
2176
|
-
*
|
|
2177
|
-
* @example
|
|
2178
|
-
* try {
|
|
2179
|
-
* const response = await featureDefinitionActions.edit(
|
|
2180
|
-
* {
|
|
2181
|
-
* id: 'feature-123',
|
|
2182
|
-
* displayName: 'Updated Form',
|
|
2183
|
-
* fields: [...]
|
|
2184
|
-
* },
|
|
2185
|
-
* 'site-123'
|
|
2186
|
-
* );
|
|
2187
|
-
*/
|
|
2188
|
-
edit: async (featureDefinitionData, site) => {
|
|
2189
|
-
// Ensure site is included in the request body
|
|
2190
|
-
const dataWithSite = _objectSpread$8({
|
|
2191
|
-
site: site
|
|
2192
|
-
}, featureDefinitionData);
|
|
2193
|
-
return authedFunction$1({
|
|
2194
|
-
method: "POST",
|
|
2195
|
-
url: getUrl$1("feature-builder", "definition/update/edit"),
|
|
2196
|
-
data: dataWithSite
|
|
2197
|
-
});
|
|
2198
|
-
},
|
|
2199
|
-
/**
|
|
2200
|
-
* Soft deletes a feature definition (marks as deleted but doesn't permanently remove)
|
|
2201
|
-
*
|
|
2202
|
-
* @param {string} id - The unique identifier of the feature definition to delete
|
|
2203
|
-
* @param {string} site - The site ID where the feature definition exists
|
|
2204
|
-
* @returns {Promise<ApiResponse>} Promise resolving to API response confirming deletion
|
|
2205
|
-
* @throws {Error} When deletion fails or feature definition is not found
|
|
2206
|
-
*
|
|
2207
|
-
*/
|
|
2208
|
-
delete: async (id, site) => {
|
|
2209
|
-
return authedFunction$1({
|
|
2210
|
-
method: "POST",
|
|
2211
|
-
url: getUrl$1("feature-builder", "definition/update/delete"),
|
|
2212
|
-
data: {
|
|
2213
|
-
id,
|
|
2214
|
-
site
|
|
2215
|
-
}
|
|
2216
|
-
});
|
|
2217
|
-
}
|
|
2218
|
-
};
|
|
2219
|
-
|
|
2220
|
-
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; }
|
|
2221
|
-
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; }
|
|
2222
2123
|
|
|
2223
|
-
//
|
|
2224
|
-
|
|
2225
|
-
const
|
|
2226
|
-
const
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
});
|
|
2240
|
-
dispatch({
|
|
2241
|
-
type: UPDATE_STRINGS,
|
|
2242
|
-
payload: updatedStrings
|
|
2243
|
-
});
|
|
2244
|
-
};
|
|
2245
|
-
const updateFeatureBuilderIcon = icon => (dispatch, getState) => {
|
|
2246
|
-
var _getState$strings2;
|
|
2247
|
-
const currentStrings = ((_getState$strings2 = getState().strings) === null || _getState$strings2 === void 0 ? void 0 : _getState$strings2.config) || {};
|
|
2248
|
-
const updatedStrings = _objectSpread$7(_objectSpread$7({}, currentStrings), {}, {
|
|
2249
|
-
sideNav: _objectSpread$7(_objectSpread$7({}, currentStrings.sideNav), {}, {
|
|
2250
|
-
[values.featureKey + "-icon"]: icon,
|
|
2251
|
-
[values.menuKey + "-icon"]: icon
|
|
2252
|
-
})
|
|
2253
|
-
});
|
|
2254
|
-
dispatch({
|
|
2255
|
-
type: UPDATE_STRINGS,
|
|
2256
|
-
payload: updatedStrings
|
|
2257
|
-
});
|
|
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
|
+
};
|
|
2258
2140
|
};
|
|
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;
|
|
2259
2144
|
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
* @namespace formActions
|
|
2267
|
-
*/
|
|
2268
|
-
|
|
2269
|
-
/**
|
|
2270
|
-
* @typedef {Object} FieldValues
|
|
2271
|
-
* @property {string} [label] - Field label text
|
|
2272
|
-
* @property {string} [placeholder] - Placeholder text for input
|
|
2273
|
-
* @property {boolean} [isRequired] - Whether field is required
|
|
2274
|
-
* @property {string} [helpText] - Help text for field guidance
|
|
2275
|
-
* @property {boolean} [allowCaption] - Whether field allows captions
|
|
2276
|
-
* @property {boolean} [useAsSummary] - Whether field is used as summary
|
|
2277
|
-
*/
|
|
2278
|
-
|
|
2279
|
-
/**
|
|
2280
|
-
* @typedef {Object} FormField
|
|
2281
|
-
* @property {string} id - Unique field identifier
|
|
2282
|
-
* @property {string} type - Field type (text, title, description, image, file, cta, feature-image)
|
|
2283
|
-
* @property {boolean} isMandatory - Whether field is mandatory system field
|
|
2284
|
-
* @property {FieldValues} values - Field configuration values
|
|
2285
|
-
*/
|
|
2286
|
-
|
|
2287
|
-
/**
|
|
2288
|
-
* @typedef {Object} LayoutConfig
|
|
2289
|
-
* @property {string} type - Layout type (round, square, etc.)
|
|
2290
|
-
* @property {string} [gridIcon] - Background image for grid layout
|
|
2291
|
-
*/
|
|
2292
|
-
|
|
2293
|
-
const actionsTypes = {
|
|
2294
|
-
SET_INITIAL_VALUES: "SET_INITIAL_VALUES",
|
|
2295
|
-
SET_TITLE: "SET_TITLE",
|
|
2296
|
-
SET_ICON: "SET_ICON",
|
|
2297
|
-
SET_DISPLAY_NAME: "SET_DISPLAY_NAME",
|
|
2298
|
-
ADD_FIELD: "ADD_FIELD",
|
|
2299
|
-
DELETE_FIELD: "DELETE_FIELD",
|
|
2300
|
-
UPDATE_FIELD: "UPDATE_FIELD",
|
|
2301
|
-
SET_LAYOUT_GRID_ICON: "SET_LAYOUT_GRID_ICON",
|
|
2302
|
-
SET_LAYOUT_TYPE: "SET_LAYOUT_TYPE",
|
|
2303
|
-
SUBMIT_FORM_REQUEST: "SUBMIT_FORM_REQUEST",
|
|
2304
|
-
SUBMIT_FORM_SUCCESS: "SUBMIT_FORM_SUCCESS",
|
|
2305
|
-
SUBMIT_FORM_FAILURE: "SUBMIT_FORM_FAILURE",
|
|
2306
|
-
CLEAR_FORM_SUBMISSION_STATE: "CLEAR_FORM_SUBMISSION_STATE",
|
|
2307
|
-
SET_SUMMARY_FIELD: "SET_SUMMARY_FIELD"
|
|
2145
|
+
// Clear form submission state when changing steps
|
|
2146
|
+
const {
|
|
2147
|
+
clearFormSubmissionState
|
|
2148
|
+
} = require("./formActions");
|
|
2149
|
+
dispatch(clearFormSubmissionState());
|
|
2150
|
+
dispatch(setCurrentStep(step, currentStep));
|
|
2308
2151
|
};
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
* Action creator to set initial form values
|
|
2312
|
-
* Initializes form state with existing feature definition data
|
|
2313
|
-
*
|
|
2314
|
-
* @param {Object} initialValues - Initial form values object
|
|
2315
|
-
* @param {string} initialValues.title - Feature title
|
|
2316
|
-
* @param {string} initialValues.icon - Feature icon
|
|
2317
|
-
* @param {string} initialValues.displayName - Feature display name
|
|
2318
|
-
* @param {LayoutConfig} initialValues.layout - Layout configuration
|
|
2319
|
-
* @param {FormField[]} initialValues.fields - Form fields array
|
|
2320
|
-
* @returns {Object} Redux action object with type and payload
|
|
2321
|
-
*
|
|
2322
|
-
* @example
|
|
2323
|
-
* dispatch(setInitialValues({
|
|
2324
|
-
* title: 'Contact Form',
|
|
2325
|
-
* icon: 'envelope',
|
|
2326
|
-
* fields: []
|
|
2327
|
-
* }));
|
|
2328
|
-
*/
|
|
2329
|
-
const setInitialValues = initialValues => {
|
|
2152
|
+
const updateStepValidation = function (step, isValid) {
|
|
2153
|
+
let errors = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
2330
2154
|
return {
|
|
2331
|
-
type:
|
|
2332
|
-
payload:
|
|
2155
|
+
type: UPDATE_STEP_VALIDATION$1,
|
|
2156
|
+
payload: {
|
|
2157
|
+
step,
|
|
2158
|
+
isValid,
|
|
2159
|
+
errors
|
|
2160
|
+
}
|
|
2333
2161
|
};
|
|
2334
2162
|
};
|
|
2335
|
-
const
|
|
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
|
|
2177
|
+
};
|
|
2178
|
+
const {
|
|
2179
|
+
isValid,
|
|
2180
|
+
errors
|
|
2181
|
+
} = getFormValidation(form, step);
|
|
2182
|
+
dispatch(updateStepValidation(step, isValid, errors));
|
|
2183
|
+
|
|
2184
|
+
// If valid, mark as complete
|
|
2185
|
+
if (isValid) {
|
|
2186
|
+
dispatch({
|
|
2187
|
+
type: MARK_STEP_COMPLETE$1,
|
|
2188
|
+
payload: step
|
|
2189
|
+
});
|
|
2190
|
+
}
|
|
2336
2191
|
return {
|
|
2337
|
-
|
|
2338
|
-
|
|
2192
|
+
isValid,
|
|
2193
|
+
errors
|
|
2339
2194
|
};
|
|
2340
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");
|
|
2341
2251
|
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
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;
|
|
2292
|
+
return dispatch => {
|
|
2293
|
+
dispatch(setCurrentStep(step, previousStep));
|
|
2363
2294
|
};
|
|
2364
2295
|
};
|
|
2365
2296
|
|
|
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
|
+
|
|
2366
2301
|
/**
|
|
2367
|
-
*
|
|
2368
|
-
*
|
|
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
|
|
2369
2305
|
*
|
|
2370
|
-
* @param {
|
|
2371
|
-
* @
|
|
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
|
|
2372
2310
|
*
|
|
2373
2311
|
* @example
|
|
2374
|
-
*
|
|
2312
|
+
* <SidebarLayout history={historyObject}>
|
|
2313
|
+
* <YourMainContent />
|
|
2314
|
+
* </SidebarLayout>
|
|
2375
2315
|
*/
|
|
2376
|
-
const
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2316
|
+
const SideBarInner = props => {
|
|
2317
|
+
const {
|
|
2318
|
+
children,
|
|
2319
|
+
history
|
|
2320
|
+
} = props;
|
|
2321
|
+
const dispatch = reactRedux.useDispatch();
|
|
2380
2322
|
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
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;
|
|
2386
2331
|
};
|
|
2387
|
-
};
|
|
2388
2332
|
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
let fieldType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "text";
|
|
2402
|
-
// Generate a unique ID for the new field
|
|
2403
|
-
const fieldId = "custom-field-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
|
|
2404
|
-
return {
|
|
2405
|
-
type: actionsTypes.ADD_FIELD,
|
|
2406
|
-
payload: {
|
|
2407
|
-
id: fieldId,
|
|
2408
|
-
type: fieldType
|
|
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 "";
|
|
2409
2345
|
}
|
|
2410
2346
|
};
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
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
|
+
});
|
|
2416
2390
|
};
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
payload: {
|
|
2422
|
-
id,
|
|
2423
|
-
updatedField
|
|
2424
|
-
}
|
|
2391
|
+
|
|
2392
|
+
// Determine sidebar title - always use "Build Your Feature" now
|
|
2393
|
+
const getSidebarTitle = () => {
|
|
2394
|
+
return "Build Your Feature";
|
|
2425
2395
|
};
|
|
2426
|
-
};
|
|
2427
2396
|
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
* automatically unsetting all other description fields when a new one is selected
|
|
2432
|
-
*
|
|
2433
|
-
* @param {string} fieldId - ID of the description field to set as summary
|
|
2434
|
-
* @returns {Object} Redux action object for summary field selection
|
|
2435
|
-
*
|
|
2436
|
-
* @example
|
|
2437
|
-
* dispatch(setSummaryField('field-description-123'));
|
|
2438
|
-
*/
|
|
2439
|
-
const setSummaryField = fieldId => {
|
|
2440
|
-
return {
|
|
2441
|
-
type: actionsTypes.SET_SUMMARY_FIELD,
|
|
2442
|
-
payload: fieldId
|
|
2443
|
-
};
|
|
2444
|
-
};
|
|
2445
|
-
const setLayoutType = layoutType => {
|
|
2446
|
-
return {
|
|
2447
|
-
type: actionsTypes.SET_LAYOUT_TYPE,
|
|
2448
|
-
payload: layoutType
|
|
2449
|
-
};
|
|
2450
|
-
};
|
|
2451
|
-
const submitFormRequest = () => {
|
|
2452
|
-
return {
|
|
2453
|
-
type: actionsTypes.SUBMIT_FORM_REQUEST
|
|
2397
|
+
// Simple help text
|
|
2398
|
+
const getHelpText = () => {
|
|
2399
|
+
return "Get help with feature builder";
|
|
2454
2400
|
};
|
|
2401
|
+
|
|
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))));
|
|
2455
2507
|
};
|
|
2456
|
-
const
|
|
2457
|
-
|
|
2458
|
-
type: actionsTypes.SUBMIT_FORM_SUCCESS
|
|
2459
|
-
|
|
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
|
+
}
|
|
2460
2615
|
};
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
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
|
+
});
|
|
2466
2641
|
};
|
|
2467
|
-
const
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
}
|
|
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
|
+
});
|
|
2471
2655
|
};
|
|
2472
2656
|
|
|
2473
2657
|
/**
|
|
2474
|
-
*
|
|
2475
|
-
*
|
|
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
|
|
2476
2662
|
*
|
|
2477
|
-
* @
|
|
2478
|
-
* @throws {Error} When form validation fails or API submission encounters error
|
|
2663
|
+
* @namespace formActions
|
|
2479
2664
|
*/
|
|
2480
|
-
function submitForm() {
|
|
2481
|
-
return async (dispatch, getState) => {
|
|
2482
|
-
const state = getState()[values.reducerKey];
|
|
2483
|
-
const form = state && state.form;
|
|
2484
|
-
if (!form) {
|
|
2485
|
-
dispatch(submitFormFailure(new Error("Form data is missing. Please refresh the page and try again.")));
|
|
2486
|
-
return;
|
|
2487
|
-
}
|
|
2488
|
-
dispatch(submitFormRequest());
|
|
2489
|
-
try {
|
|
2490
|
-
// Get site from auth store
|
|
2491
|
-
const site = getState().auth.site;
|
|
2492
|
-
if (!site) {
|
|
2493
|
-
throw new Error("Authentication error: Site context not found. Please refresh and login again.");
|
|
2494
|
-
}
|
|
2495
2665
|
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
// Include site from auth store
|
|
2506
|
-
featureDefinition: {
|
|
2507
|
-
// Wrap in expected structure for backend
|
|
2508
|
-
title: form.title,
|
|
2509
|
-
icon: form.icon,
|
|
2510
|
-
displayName: form.displayName,
|
|
2511
|
-
layout: form.layout,
|
|
2512
|
-
fields: form.fields
|
|
2513
|
-
}
|
|
2514
|
-
};
|
|
2515
|
-
await featureDefinitionActions.edit(updatedDefinition, site);
|
|
2516
|
-
} else {
|
|
2517
|
-
// Always create when in create mode (or mode is undefined/null)
|
|
2518
|
-
if (!values.featureId || !site) {
|
|
2519
|
-
throw new Error("Authentication error: Missing required context (featureId or site).");
|
|
2520
|
-
}
|
|
2521
|
-
await featureDefinitionActions.create(values.featureId, site,
|
|
2522
|
-
// Use actual site from auth store
|
|
2523
|
-
{
|
|
2524
|
-
title: form.title,
|
|
2525
|
-
icon: form.icon,
|
|
2526
|
-
displayName: form.displayName,
|
|
2527
|
-
layout: form.layout,
|
|
2528
|
-
fields: form.fields
|
|
2529
|
-
});
|
|
2530
|
-
}
|
|
2531
|
-
dispatch(submitFormSuccess());
|
|
2532
|
-
} catch (err) {
|
|
2533
|
-
// Handle different types of errors
|
|
2534
|
-
let errorToDisplay = err;
|
|
2535
|
-
if (err.response) {
|
|
2536
|
-
// API error (400, 401, 404, 500, etc.)
|
|
2537
|
-
const {
|
|
2538
|
-
status,
|
|
2539
|
-
data
|
|
2540
|
-
} = err.response;
|
|
2541
|
-
if (status === 400 && data && data.error) {
|
|
2542
|
-
errorToDisplay = new Error("Validation error: ".concat(data.error));
|
|
2543
|
-
} else if (status === 401) {
|
|
2544
|
-
errorToDisplay = new Error("You are not authorized to perform this action");
|
|
2545
|
-
} else if (status === 404) {
|
|
2546
|
-
errorToDisplay = new Error("Feature definition not found");
|
|
2547
|
-
} else if (status >= 500) {
|
|
2548
|
-
errorToDisplay = new Error("Server error. Please try again later.");
|
|
2549
|
-
} else {
|
|
2550
|
-
errorToDisplay = new Error(data && data.error || "Request failed with status ".concat(status));
|
|
2551
|
-
}
|
|
2552
|
-
} else if (err.request) {
|
|
2553
|
-
// Network error (no response received)
|
|
2554
|
-
errorToDisplay = new Error("Network error. Please check your connection and try again.");
|
|
2555
|
-
} else if (err.message) {
|
|
2556
|
-
// Other JavaScript errors
|
|
2557
|
-
errorToDisplay = err;
|
|
2558
|
-
} else {
|
|
2559
|
-
// Unknown error
|
|
2560
|
-
errorToDisplay = new Error("An unexpected error occurred while saving");
|
|
2561
|
-
}
|
|
2562
|
-
dispatch(submitFormFailure(errorToDisplay));
|
|
2563
|
-
}
|
|
2564
|
-
};
|
|
2565
|
-
}
|
|
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
|
|
2674
|
+
*/
|
|
2566
2675
|
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
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
|
+
*/
|
|
2683
|
+
|
|
2684
|
+
/**
|
|
2685
|
+
* @typedef {Object} LayoutConfig
|
|
2686
|
+
* @property {string} type - Layout type (round, square, etc.)
|
|
2687
|
+
* @property {string} [gridIcon] - Background image for grid layout
|
|
2688
|
+
*/
|
|
2689
|
+
|
|
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")
|
|
2705
|
+
};
|
|
2706
|
+
|
|
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 => {
|
|
2574
2727
|
return {
|
|
2575
|
-
type:
|
|
2576
|
-
payload:
|
|
2577
|
-
currentStep: step,
|
|
2578
|
-
previousStep,
|
|
2579
|
-
canGoBack: step !== "welcome",
|
|
2580
|
-
canGoForward: true
|
|
2581
|
-
}
|
|
2728
|
+
type: actionsTypes.SET_INITIAL_VALUES,
|
|
2729
|
+
payload: initialValues
|
|
2582
2730
|
};
|
|
2583
2731
|
};
|
|
2584
|
-
const
|
|
2585
|
-
const state = getState()[values.reducerKey];
|
|
2586
|
-
const currentStep = state && state.wizard && state.wizard.navigation && state.wizard.navigation.currentStep;
|
|
2587
|
-
|
|
2588
|
-
// Clear form submission state when changing steps
|
|
2589
|
-
dispatch(clearFormSubmissionState());
|
|
2590
|
-
dispatch(setCurrentStep(step, currentStep));
|
|
2591
|
-
};
|
|
2592
|
-
const updateStepValidation = function (step, isValid) {
|
|
2593
|
-
let errors = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
2732
|
+
const setTitle = title => {
|
|
2594
2733
|
return {
|
|
2595
|
-
type:
|
|
2596
|
-
payload:
|
|
2597
|
-
step,
|
|
2598
|
-
isValid,
|
|
2599
|
-
errors
|
|
2600
|
-
}
|
|
2734
|
+
type: actionsTypes.SET_TITLE,
|
|
2735
|
+
payload: title
|
|
2601
2736
|
};
|
|
2602
2737
|
};
|
|
2603
|
-
const validateAndUpdateStep = step => (dispatch, getState) => {
|
|
2604
|
-
// Use existing selectors to get form data
|
|
2605
|
-
const state = getState();
|
|
2606
|
-
const title = selectFormTitle(state);
|
|
2607
|
-
const icon = selectFormIcon(state);
|
|
2608
|
-
const displayName = selectFormDisplayName(state);
|
|
2609
|
-
const layout = selectFormLayout(state);
|
|
2610
|
-
const fields = selectFormFields(state);
|
|
2611
|
-
const form = {
|
|
2612
|
-
title,
|
|
2613
|
-
icon,
|
|
2614
|
-
displayName,
|
|
2615
|
-
layout,
|
|
2616
|
-
fields
|
|
2617
|
-
};
|
|
2618
|
-
const {
|
|
2619
|
-
isValid,
|
|
2620
|
-
errors
|
|
2621
|
-
} = getFormValidation(form, step);
|
|
2622
|
-
dispatch(updateStepValidation(step, isValid, errors));
|
|
2623
2738
|
|
|
2624
|
-
|
|
2625
|
-
|
|
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 => {
|
|
2751
|
+
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
|
|
2626
2756
|
dispatch({
|
|
2627
|
-
type:
|
|
2628
|
-
payload:
|
|
2757
|
+
type: actionsTypes.SET_DISPLAY_NAME,
|
|
2758
|
+
payload: displayName
|
|
2629
2759
|
});
|
|
2630
|
-
}
|
|
2631
|
-
return {
|
|
2632
|
-
isValid,
|
|
2633
|
-
errors
|
|
2634
2760
|
};
|
|
2635
2761
|
};
|
|
2636
|
-
const getFormValidation = (form, step) => {
|
|
2637
|
-
// Return validation results for undefined form (prevent crashes)
|
|
2638
|
-
if (!form) {
|
|
2639
|
-
switch (step) {
|
|
2640
|
-
case "overview":
|
|
2641
|
-
return {
|
|
2642
|
-
isValid: false,
|
|
2643
|
-
errors: {
|
|
2644
|
-
title: "Title is required",
|
|
2645
|
-
displayName: "Display name is required",
|
|
2646
|
-
icon: "Icon is required"
|
|
2647
|
-
}
|
|
2648
|
-
};
|
|
2649
|
-
case "fields":
|
|
2650
|
-
return {
|
|
2651
|
-
isValid: false,
|
|
2652
|
-
errors: {
|
|
2653
|
-
missingTitle: "Title field is required",
|
|
2654
|
-
missingImage: "Feature image field is required",
|
|
2655
|
-
fieldLabels: "Some fields are missing labels"
|
|
2656
|
-
}
|
|
2657
|
-
};
|
|
2658
|
-
case "layout":
|
|
2659
|
-
return {
|
|
2660
|
-
isValid: false,
|
|
2661
|
-
errors: {
|
|
2662
|
-
layoutType: "Layout type is required"
|
|
2663
|
-
}
|
|
2664
|
-
};
|
|
2665
|
-
default:
|
|
2666
|
-
return {
|
|
2667
|
-
isValid: false,
|
|
2668
|
-
errors: {}
|
|
2669
|
-
};
|
|
2670
|
-
}
|
|
2671
|
-
}
|
|
2672
|
-
switch (step) {
|
|
2673
|
-
case "overview":
|
|
2674
|
-
{
|
|
2675
|
-
const hasTitle = form.title && form.title.trim().length > 0;
|
|
2676
|
-
const hasDisplayName = form.displayName && form.displayName.trim().length > 0;
|
|
2677
|
-
const hasIcon = form.icon && form.icon.length > 0;
|
|
2678
|
-
return {
|
|
2679
|
-
isValid: hasTitle && hasDisplayName && hasIcon,
|
|
2680
|
-
errors: {
|
|
2681
|
-
title: !hasTitle ? "Title is required" : null,
|
|
2682
|
-
displayName: !hasDisplayName ? "Display name is required" : null,
|
|
2683
|
-
icon: !hasIcon ? "Icon is required" : null
|
|
2684
|
-
}
|
|
2685
|
-
};
|
|
2686
|
-
}
|
|
2687
|
-
case "fields":
|
|
2688
|
-
{
|
|
2689
|
-
const hasTitleField = form.fields && form.fields.some(field => field.id === "mandatory-title");
|
|
2690
|
-
const hasImageField = form.fields && form.fields.some(field => field.id === "mandatory-feature-image");
|
|
2691
2762
|
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
});
|
|
2704
|
-
}
|
|
2705
|
-
return {
|
|
2706
|
-
isValid: hasTitleField && hasImageField && allFieldsHaveLabels,
|
|
2707
|
-
errors: _objectSpread$6({
|
|
2708
|
-
missingTitle: !hasTitleField ? "Title field is required" : null,
|
|
2709
|
-
missingImage: !hasImageField ? "Feature image field is required" : null
|
|
2710
|
-
}, fieldErrors)
|
|
2711
|
-
};
|
|
2712
|
-
}
|
|
2713
|
-
case "layout":
|
|
2714
|
-
{
|
|
2715
|
-
const hasLayoutType = form.layout && form.layout.type && form.layout.type.length > 0;
|
|
2716
|
-
return {
|
|
2717
|
-
isValid: hasLayoutType,
|
|
2718
|
-
errors: {
|
|
2719
|
-
layoutType: !hasLayoutType ? "Layout type is required" : null
|
|
2720
|
-
}
|
|
2721
|
-
};
|
|
2722
|
-
}
|
|
2723
|
-
default:
|
|
2724
|
-
return {
|
|
2725
|
-
isValid: true,
|
|
2726
|
-
errors: {}
|
|
2727
|
-
};
|
|
2728
|
-
}
|
|
2729
|
-
};
|
|
2730
|
-
const setCurrentStepAndSave = function (step) {
|
|
2731
|
-
let previousStep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
2763
|
+
/**
|
|
2764
|
+
* Action creator to set form icon and update menu
|
|
2765
|
+
* Updates both form state and external menu icon
|
|
2766
|
+
*
|
|
2767
|
+
* @param {string} icon - Icon identifier or FontAwesome icon class
|
|
2768
|
+
* @returns {Function} Thunk function for Redux
|
|
2769
|
+
*
|
|
2770
|
+
* @example
|
|
2771
|
+
* dispatch(setIcon('fa-user'));
|
|
2772
|
+
*/
|
|
2773
|
+
const setIcon = icon => {
|
|
2732
2774
|
return dispatch => {
|
|
2733
|
-
|
|
2775
|
+
// Update menu icon when icon changes
|
|
2776
|
+
dispatch(updateFeatureBuilderIcon(icon));
|
|
2777
|
+
|
|
2778
|
+
// Dispatch the actual action
|
|
2779
|
+
dispatch({
|
|
2780
|
+
type: actionsTypes.SET_ICON,
|
|
2781
|
+
payload: icon
|
|
2782
|
+
});
|
|
2734
2783
|
};
|
|
2735
2784
|
};
|
|
2736
2785
|
|
|
2737
|
-
var css$d = ".SidebarLayout_module_fullWidthContent__ba777567 {\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__ba777567 {\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__ba777567 {\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__ba777567{\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__ba777567 {\n\t\tpadding: 1.5rem 1.5rem 2.5rem 1.5rem; /* Slightly reduced but still adequate */\n\t}\n\t.SidebarLayout_module_container__ba777567 {\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__ba777567 {\n\t\tpadding: 1rem 1rem 2rem 1rem; /* Maintain padding on small screens */\n\t}\n\t.SidebarLayout_module_container__ba777567 {\n\t\tpadding: 1rem 1rem 2rem 1rem; /* Legacy container support */\n\t}\n}\n\n/* Enhanced sidebar navigation for progress indication */\n.hub-sideBar {\n\t/* Make sidebar more prominent during creation mode */\n}\n\n.sideNav-item.isCurrent {\n\tbackground: var(--colour-purple, #6e79c5) !important;\n\tcolor: var(--colour-white, #ffffff) !important;\n\tfont-weight: 600 !important;\n\tborder-left: 4px solid var(--colour-branding-dark, #364196) !important;\n}\n\n.sideNav-item.isCurrent i {\n\tcolor: var(--colour-white, #ffffff) !important;\n}\n\n.sideNav-item.isCompleted {\n\tcolor: var(--colour-branding-dark, #364196) !important;\n\tposition: relative;\n}\n\n.sideNav-item.isCompleted::after {\n\tcontent: \"✓\";\n\tposition: absolute;\n\tright: 1rem;\n\ttop: 50%;\n\ttransform: translateY(-50%);\n\tcolor: var(--colour-branding-dark, #364196);\n\tfont-weight: bold;\n}\n\n.sideNav-item.isDisabled {\n\topacity: 0.4;\n\tcursor: not-allowed;\n}\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";
|
|
2738
|
-
var modules_d5b6badf = {"fullWidthContent":"SidebarLayout_module_fullWidthContent__ba777567","fullWidthContainer":"SidebarLayout_module_fullWidthContainer__ba777567","contentContainer":"SidebarLayout_module_contentContainer__ba777567","container":"SidebarLayout_module_container__ba777567"};
|
|
2739
|
-
n(css$d,{});
|
|
2740
|
-
|
|
2741
2786
|
/**
|
|
2742
|
-
*
|
|
2743
|
-
*
|
|
2744
|
-
* Manages step accessibility based on wizard mode and validation state
|
|
2787
|
+
* Action creator to add a new field to the form
|
|
2788
|
+
* Generates unique ID and supports custom field types
|
|
2745
2789
|
*
|
|
2746
|
-
* @param {
|
|
2747
|
-
* @
|
|
2748
|
-
* @param {Object} props.history - React Router history object for navigation
|
|
2749
|
-
* @returns {React.ReactElement} Layout component with sidebar navigation
|
|
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
|
|
2750
2792
|
*
|
|
2751
2793
|
* @example
|
|
2752
|
-
*
|
|
2753
|
-
*
|
|
2754
|
-
* </SidebarLayout>
|
|
2794
|
+
* dispatch(addField('text'));
|
|
2795
|
+
* dispatch(addField('image'));
|
|
2755
2796
|
*/
|
|
2756
|
-
const
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
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
|
|
2806
|
+
}
|
|
2807
|
+
};
|
|
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
|
+
}
|
|
2822
|
+
};
|
|
2823
|
+
};
|
|
2762
2824
|
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
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
|
|
2771
2840
|
};
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2841
|
+
};
|
|
2842
|
+
const setLayoutType = layoutType => {
|
|
2843
|
+
return {
|
|
2844
|
+
type: actionsTypes.SET_LAYOUT_TYPE,
|
|
2845
|
+
payload: layoutType
|
|
2777
2846
|
};
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
url: getStepUrl("overview")
|
|
2783
|
-
}, {
|
|
2784
|
-
key: "fields",
|
|
2785
|
-
text: "Configure Fields",
|
|
2786
|
-
icon: "edit",
|
|
2787
|
-
url: getStepUrl("fields")
|
|
2788
|
-
}, {
|
|
2789
|
-
key: "layout",
|
|
2790
|
-
text: "Choose Layout",
|
|
2791
|
-
icon: "columns",
|
|
2792
|
-
url: getStepUrl("layout")
|
|
2793
|
-
}];
|
|
2794
|
-
|
|
2795
|
-
// Build sidebar items based on mode
|
|
2796
|
-
const buildSidebarItems = () => {
|
|
2797
|
-
return steps.map((step, index) => {
|
|
2798
|
-
const isCompleted = selectIsStepComplete(step.key);
|
|
2799
|
-
const isAccessible = selectIsStepAccessible(step.key);
|
|
2800
|
-
|
|
2801
|
-
// Add step number to text for better clarity
|
|
2802
|
-
const stepText = "".concat(index + 1, ". ").concat(step.text);
|
|
2803
|
-
const itemProps = {
|
|
2804
|
-
type: "navItem",
|
|
2805
|
-
text: stepText,
|
|
2806
|
-
icon: step.icon,
|
|
2807
|
-
selected: isSelected(step.url),
|
|
2808
|
-
onclick: isAccessible ? () => {
|
|
2809
|
-
goTo(step.url);
|
|
2810
|
-
dispatch(goToStep(step.key));
|
|
2811
|
-
} : null,
|
|
2812
|
-
isFontAwesome: true,
|
|
2813
|
-
// Enhanced completion indicator
|
|
2814
|
-
completed: isCompleted,
|
|
2815
|
-
// Allow navigation to completed steps even in create mode
|
|
2816
|
-
disabled: mode === "create" && !isAccessible
|
|
2817
|
-
};
|
|
2818
|
-
return itemProps;
|
|
2819
|
-
});
|
|
2847
|
+
};
|
|
2848
|
+
const submitFormRequest = () => {
|
|
2849
|
+
return {
|
|
2850
|
+
type: actionsTypes.SUBMIT_FORM_REQUEST
|
|
2820
2851
|
};
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2852
|
+
};
|
|
2853
|
+
const submitFormSuccess = () => {
|
|
2854
|
+
return {
|
|
2855
|
+
type: actionsTypes.SUBMIT_FORM_SUCCESS
|
|
2825
2856
|
};
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2857
|
+
};
|
|
2858
|
+
const submitFormFailure = error => {
|
|
2859
|
+
return {
|
|
2860
|
+
type: actionsTypes.SUBMIT_FORM_FAILURE,
|
|
2861
|
+
payload: error
|
|
2830
2862
|
};
|
|
2863
|
+
};
|
|
2864
|
+
const clearFormSubmissionState = () => {
|
|
2865
|
+
return {
|
|
2866
|
+
type: actionsTypes.CLEAR_FORM_SUBMISSION_STATE
|
|
2867
|
+
};
|
|
2868
|
+
};
|
|
2831
2869
|
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
// Remove any existing click listeners
|
|
2855
|
-
navItem.onclick = null;
|
|
2856
|
-
|
|
2857
|
-
// Check if this step is accessible
|
|
2858
|
-
const isAccessible = selectIsStepAccessible(step.key)({
|
|
2859
|
-
[values.reducerKey]: {
|
|
2860
|
-
wizard: {
|
|
2861
|
-
mode: mode,
|
|
2862
|
-
navigation: {
|
|
2863
|
-
currentStep: currentStep
|
|
2864
|
-
}
|
|
2865
|
-
}
|
|
2866
|
-
}
|
|
2867
|
-
});
|
|
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
|
+
}
|
|
2868
2892
|
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
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
|
|
2877
2910
|
}
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
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).");
|
|
2883
2917
|
}
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
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
|
+
}
|
|
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));
|
|
2915
2960
|
}
|
|
2916
|
-
}
|
|
2917
|
-
|
|
2918
|
-
}, /*#__PURE__*/React__default["default"].createElement("div", {
|
|
2919
|
-
className: modules_d5b6badf.fullWidthContainer
|
|
2920
|
-
}, /*#__PURE__*/React__default["default"].createElement("div", {
|
|
2921
|
-
className: modules_d5b6badf.contentContainer
|
|
2922
|
-
}, children))));
|
|
2923
|
-
};
|
|
2924
|
-
const SidebarLayout = reactRouter.withRouter(SideBarInner);
|
|
2925
|
-
|
|
2926
|
-
var css$c = ".Form_module_content__dfb952c8 {\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__dfb952c8 {\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__dfb952c8 {\n\t\tpadding: 3rem 0;\n\t}\n}\n\n/* Form container styling when using CenteredContainer */\n.Form_module_formContainer__dfb952c8 {\n\tbackground-color: var(--bg-white);\n}\n\n/* Section styling */\n.Form_module_section__dfb952c8 {\n\tmargin-bottom: 2rem;\n\t\tpadding: 0 0 2em;\n}\n\n.Form_module_section_NoBorder__dfb952c8 {\n\t\tborder-bottom: none;\n}\n\n.Form_module_subtitle__dfb952c8 {\n\tcolor: var(--text-bluegrey, #6c7a90);\n}\n\n.Form_module_sectionHeader__dfb952c8 {\n\t\tdisplay: flex;\n\t\tjustify-content: space-between;\n}\n\n/* Add Field Button styling */\n.Form_module_addFieldButton__dfb952c8 {\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__dfb952c8: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__dfb952c8:focus {\n\toutline: 2px solid var(--colour-branding-action, #5c90df);\n\toutline-offset: 2px;\n}\n\n.Form_module_addFieldButton__dfb952c8:active {\n\ttransform: translateY(0);\n}\n\n/* Refresh button styling */\n.Form_module_refreshButton__dfb952c8 {\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__dfb952c8:hover {\n\tbackground: var(--colour-dusk-hover, #485968);\n}\n\n/* Error message container */\n.Form_module_errorMessageContainer__dfb952c8 {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.5rem;\n}\n\n/* Add Field Container - matches field structure */\n.Form_module_addFieldContainer__dfb952c8 {\n\tdisplay: flex;\n\tmargin-top: 32px;\n}\n\n.Form_module_fieldNumberContainer__dfb952c8 {\n\tdisplay: flex;\n\twidth: 40px;\n}\n\n/* Add Field Section */\n.Form_module_addFieldSection__dfb952c8 {\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__dfb952c8 {\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__dfb952c8 {\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__dfb952c8 {\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__dfb952c8 {\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__dfb952c8 {\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__dfb952c8 {\n\t\tgap: 1.5rem; /* Slightly larger gap on desktop */\n\t}\n}\n\n.Form_module_fieldTypeCard__dfb952c8 {\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__dfb952c8: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__dfb952c8:focus {\n\toutline: 2px solid var(--text-light);\n\toutline-offset: 2px;\n}\n\n.Form_module_fieldTypeCard__dfb952c8:active {\n\ttransform: scale(0.98);\n\ttransition: transform 0.1s ease;\n}\n\n.Form_module_fieldTypeCardIcon__dfb952c8 {\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__dfb952c8 {\n\tflex: 1;\n\twidth: 100%;\n\tmin-width: 0; /* Prevent content from overflowing */\n}\n\n.Form_module_fieldTypeCardTitle__dfb952c8 {\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__dfb952c8 {\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__dfb952c8 {\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__dfb952c8> 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__dfb952c8 {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: flex-end;\n}\n\n/* Empty State */\n.Form_module_emptyState__dfb952c8 {\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__dfb952c8 {\n\tcolor: var(--text-bluegrey, #6c7a90);\n\tfont-style: italic;\n}\n\n.Form_module_fieldTypeSelector__dfb952c8 {\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__dfb952c8 {\n\t\talign-items: stretch;\n\t}\n\t\n\t.Form_module_fieldTypeSelector__dfb952c8 {\n\t\tmax-width: none;\n\t}\n}\n\n.Form_module_grid__four__dfb952c8 {\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__dfb952c8 {\n\t\tgrid-template-columns: 1fr;\n\t\tgap: 2rem;\n\t}\n}\n\n/* Navigation styles */\n.Form_module_navigation__dfb952c8 {\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__dfb952c8> :only-child {\n\tmargin-left: auto;\n\tmargin-right: 0;\n}\n\n/* Two button alignment - one left, one right */\n.Form_module_navigation__dfb952c8> :first-child:not(:only-child) {\n\tmargin-right: auto;\n}\n\n.Form_module_navigation__dfb952c8> :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__dfb952c8 .Form_module_navigation__dfb952c8> :only-child {\n\tmargin-left: auto;\n\tmargin-right: 0;\n}\n\n.Form_module_previousButton__dfb952c8 {\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__dfb952c8:hover {\n\tbackground: #5a6268;\n}\n\n.Form_module_saveButton__dfb952c8 {\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__dfb952c8: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__dfb952c8:focus {\n\toutline: 2px solid var(--colour-purple, #6e79c5);\n\toutline-offset: 2px;\n}\n\n.Form_module_saveButton__dfb952c8: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__dfb952c8 {\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__dfb952c8: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__dfb952c8: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__dfb952c8 {\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__dfb952c8 {\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}\n\n.Form_module_layoutOptionImage__dfb952c8 {\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__dfb952c8.Form_module_selected__dfb952c8 .Form_module_layoutOptionImage__dfb952c8 {\n\tborder-color: var(--border-line-grey, #dbddf1);\n\tbox-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n}\n\n.Form_module_layoutOptionImg__dfb952c8 {\n\twidth: 100%;\n\theight: 100%;\n\tobject-fit: cover;\n}\n\n.Form_module_layoutOptionContent__dfb952c8 {\n\tmax-width: 250px;\n}\n\n.Form_module_layoutOptionTitle__dfb952c8 {\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__dfb952c8 {\n\tfont-size: 1.2rem;\n\tmargin: 0;\n\tline-height: 1.3;\n\tcolor: #6c757d;\n}\n\n.Form_module_layoutOption__dfb952c8.Form_module_hasError__dfb952c8 .Form_module_layoutOptionImage__dfb952c8 {\n\tborder-color: var(--colour-red, #dc3545);\n}\n\n/* Field error styles */\n.Form_module_fieldError__dfb952c8 {\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__dfb952c8 {\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__dfb952c8 {\n\t0%, 100% { transform: translateX(0); }\n\t25% { transform: translateX(-3px); }\n\t75% { transform: translateX(3px); }\n}\n\n@keyframes Form_module_errorPulse__dfb952c8 {\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__dfb952c8 {\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__dfb952c8 {\n\tcolor: var(--colour-purple, #6e79c5);\n}\n\n.Form_module_editMode__dfb952c8 {\n\tcolor: var(--colour-branding-dark, #364196);\n}\n\n/* Responsive Design */\n@media (max-width: 768px) {\n\t.Form_module_content__dfb952c8 {\n\t\tpadding: 1.5rem 0 2.5rem 0; /* Maintain proper padding on mobile */\n\t}\n\t\n\t.Form_module_section__dfb952c8 {\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__dfb952c8 {\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__dfb952c8 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__dfb952c8 {\n\t\talign-items: stretch;\n\t\tjustify-content: stretch;\n\t\tmin-height: auto;\n\t}\n\t\n\t.Form_module_navigation__dfb952c8 {\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__dfb952c8> :only-child {\n\t\tmargin-left: auto;\n\t\tmargin-right: 0;\n\t}\n\t\n\t.Form_module_navigation__dfb952c8> :first-child:not(:only-child),\n\t.Form_module_navigation__dfb952c8> :last-child:not(:only-child) {\n\t\tmargin-left: 0;\n\t\tmargin-right: 0;\n\t}\n\t\n\t.Form_module_previousButton__dfb952c8,\n\t.Form_module_nextButton__dfb952c8,\n\t.Form_module_saveButton__dfb952c8 {\n\t\twidth: 100%;\n\t\tpadding: 1rem;\n\t}\n}\n\n@media (max-width: 480px) {\n\t.Form_module_content__dfb952c8 {\n\t\tpadding: 1rem 0 2rem 0; /* Still maintain padding on small screens */\n\t}\n\t\n\t.Form_module_section__dfb952c8 {\n\t\tmargin-bottom: 1rem;\n\t}\n\t\n\t.Form_module_navigation__dfb952c8 {\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__dfb952c8> :only-child {\n\t\tmargin-left: auto;\n\t\tmargin-right: 0;\n\t}\n\t\n\t.Form_module_navigation__dfb952c8> :first-child:not(:only-child),\n\t.Form_module_navigation__dfb952c8> :last-child:not(:only-child) {\n\t\tmargin-left: 0;\n\t\tmargin-right: 0;\n\t}\n\t\n\t.Form_module_errorMessageContainer__dfb952c8 {\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__dfb952c8 {\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__dfb952c8 {\n flex-flow: column;\n}\n\n/* Validation error message - displayed at top of form */\n.Form_module_validationErrorMessage__dfb952c8 {\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__dfb952c8::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__dfb952c8 {\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__dfb952c8 {\n\ttext-align: center;\n\tpadding: 60px 20px;\n}\n\n/* Help note styling */\n.Form_module_helpNote__dfb952c8 {\n\tfont-size: 13px;\n\tcolor: #6c757d;\n}\n\n/* Loading container for overview */\n.Form_module_overviewLoadingContainer__dfb952c8 {\n\ttext-align: center;\n\tpadding: 60px 20px;\n}\n\n/* Form layout header */\n.Form_module_formLayoutHeader__dfb952c8 {\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__dfb952c8 {\n\tmargin-bottom: 3rem;\n}\n\n.Form_module_layoutSection__dfb952c8 {\n\tmargin-bottom: 2rem;\n}\n\n/* Grid icon loading state */\n.Form_module_gridIconLoading__dfb952c8 {\n\tgrid-column: 1 / -1;\n}\n\n/* Hide upload button in grid icon section */\n.Form_module_gridIconSection__dfb952c8 .iconLoader__buttonOverlay button:first-child {\n\tdisplay: none !important;\n}\n";
|
|
2927
|
-
var modules_cd65a764 = {"content":"Form_module_content__dfb952c8","pageWrapper":"Form_module_pageWrapper__dfb952c8","formContainer":"Form_module_formContainer__dfb952c8","section":"Form_module_section__dfb952c8","section--no-border":"Form_module_section_NoBorder__dfb952c8","subtitle":"Form_module_subtitle__dfb952c8","sectionHeader":"Form_module_sectionHeader__dfb952c8","addFieldButton":"Form_module_addFieldButton__dfb952c8","refreshButton":"Form_module_refreshButton__dfb952c8","errorMessageContainer":"Form_module_errorMessageContainer__dfb952c8","addFieldContainer":"Form_module_addFieldContainer__dfb952c8","fieldNumberContainer":"Form_module_fieldNumberContainer__dfb952c8","addFieldSection":"Form_module_addFieldSection__dfb952c8","helpSection":"Form_module_helpSection__dfb952c8","helpTitle":"Form_module_helpTitle__dfb952c8","helpText":"Form_module_helpText__dfb952c8","fieldTypeCards":"Form_module_fieldTypeCards__dfb952c8","fieldTypeCard":"Form_module_fieldTypeCard__dfb952c8","fieldTypeCardIcon":"Form_module_fieldTypeCardIcon__dfb952c8","fieldTypeCardContent":"Form_module_fieldTypeCardContent__dfb952c8","fieldTypeCardTitle":"Form_module_fieldTypeCardTitle__dfb952c8","fieldTypeCardDescription":"Form_module_fieldTypeCardDescription__dfb952c8","fieldTypeCardUseCase":"Form_module_fieldTypeCardUseCase__dfb952c8","addFieldButtonContainer":"Form_module_addFieldButtonContainer__dfb952c8","emptyState":"Form_module_emptyState__dfb952c8","emptyStateText":"Form_module_emptyStateText__dfb952c8","fieldTypeSelector":"Form_module_fieldTypeSelector__dfb952c8","grid__four":"Form_module_grid__four__dfb952c8","navigation":"Form_module_navigation__dfb952c8","overviewStep":"Form_module_overviewStep__dfb952c8","previousButton":"Form_module_previousButton__dfb952c8","saveButton":"Form_module_saveButton__dfb952c8","nextButton":"Form_module_nextButton__dfb952c8","errorMessage":"Form_module_errorMessage__dfb952c8","layoutOption":"Form_module_layoutOption__dfb952c8","layoutOptionImage":"Form_module_layoutOptionImage__dfb952c8","selected":"Form_module_selected__dfb952c8","layoutOptionImg":"Form_module_layoutOptionImg__dfb952c8","layoutOptionContent":"Form_module_layoutOptionContent__dfb952c8","layoutOptionTitle":"Form_module_layoutOptionTitle__dfb952c8","layoutOptionDescription":"Form_module_layoutOptionDescription__dfb952c8","hasError":"Form_module_hasError__dfb952c8","fieldError":"Form_module_fieldError__dfb952c8","errorIcon":"Form_module_errorIcon__dfb952c8","successMessage":"Form_module_successMessage__dfb952c8","createMode":"Form_module_createMode__dfb952c8","editMode":"Form_module_editMode__dfb952c8","hub-contentWrapper--col":"Form_module_hubContentWrapper_Col__dfb952c8","validationErrorMessage":"Form_module_validationErrorMessage__dfb952c8","formHeader":"Form_module_formHeader__dfb952c8","fieldsLoadingContainer":"Form_module_fieldsLoadingContainer__dfb952c8","helpNote":"Form_module_helpNote__dfb952c8","overviewLoadingContainer":"Form_module_overviewLoadingContainer__dfb952c8","formLayoutHeader":"Form_module_formLayoutHeader__dfb952c8","gridIconSection":"Form_module_gridIconSection__dfb952c8","layoutSection":"Form_module_layoutSection__dfb952c8","gridIconLoading":"Form_module_gridIconLoading__dfb952c8","errorShake":"Form_module_errorShake__dfb952c8","errorPulse":"Form_module_errorPulse__dfb952c8"};
|
|
2928
|
-
n(css$c,{});
|
|
2961
|
+
};
|
|
2962
|
+
}
|
|
2929
2963
|
|
|
2930
2964
|
/*
|
|
2931
2965
|
* Icon categories and definitions for the feature builder
|
|
@@ -3249,6 +3283,9 @@ const FormOverviewStepInner = props => {
|
|
|
3249
3283
|
|
|
3250
3284
|
// Clear submission state after showing toast (only for non-edit cases)
|
|
3251
3285
|
if (!isEditMode) {
|
|
3286
|
+
const {
|
|
3287
|
+
clearFormSubmissionState
|
|
3288
|
+
} = require("../actions/formActions");
|
|
3252
3289
|
dispatch(clearFormSubmissionState());
|
|
3253
3290
|
}
|
|
3254
3291
|
}
|
|
@@ -3864,21 +3901,22 @@ const FileField = props => {
|
|
|
3864
3901
|
});
|
|
3865
3902
|
};
|
|
3866
3903
|
|
|
3867
|
-
const
|
|
3868
|
-
const
|
|
3869
|
-
const
|
|
3870
|
-
const
|
|
3871
|
-
const
|
|
3872
|
-
const
|
|
3873
|
-
const
|
|
3874
|
-
const
|
|
3875
|
-
const
|
|
3876
|
-
const
|
|
3877
|
-
const
|
|
3904
|
+
const REDUCER_PREFIX$1 = values.reducerKey.toUpperCase();
|
|
3905
|
+
const FETCH_FEATURES_REQUEST = "".concat(REDUCER_PREFIX$1, "_FETCH_FEATURES_REQUEST");
|
|
3906
|
+
const FETCH_FEATURES_SUCCESS = "".concat(REDUCER_PREFIX$1, "_FETCH_FEATURES_SUCCESS");
|
|
3907
|
+
const FETCH_FEATURES_FAILURE = "".concat(REDUCER_PREFIX$1, "_FETCH_FEATURES_FAILURE");
|
|
3908
|
+
const FEATURE_CREATE_REQUEST = "".concat(REDUCER_PREFIX$1, "_FEATURE_CREATE_REQUEST");
|
|
3909
|
+
const FEATURE_CREATE_SUCCESS = "".concat(REDUCER_PREFIX$1, "_FEATURE_CREATE_SUCCESS");
|
|
3910
|
+
const FEATURE_CREATE_FAILURE = "".concat(REDUCER_PREFIX$1, "_FEATURE_CREATE_FAILURE");
|
|
3911
|
+
const FEATURE_EDIT_REQUEST = "".concat(REDUCER_PREFIX$1, "_FEATURE_EDIT_REQUEST");
|
|
3912
|
+
const FEATURE_EDIT_SUCCESS = "".concat(REDUCER_PREFIX$1, "_FEATURE_EDIT_SUCCESS");
|
|
3913
|
+
const FEATURE_EDIT_FAILURE = "".concat(REDUCER_PREFIX$1, "_FEATURE_EDIT_FAILURE");
|
|
3914
|
+
const FEATURE_DELETE_REQUEST = "".concat(REDUCER_PREFIX$1, "_FEATURE_DELETE_REQUEST");
|
|
3915
|
+
const FEATURE_DELETE_FAILURE = "".concat(REDUCER_PREFIX$1, "_FEATURE_DELETE_FAILURE");
|
|
3878
3916
|
|
|
3879
3917
|
// Wizard synchronization action types
|
|
3880
|
-
const SYNC_WIZARD_MODE_FROM_DEFINITION = "
|
|
3881
|
-
const SET_WIZARD_MODE = "
|
|
3918
|
+
const SYNC_WIZARD_MODE_FROM_DEFINITION = "".concat(REDUCER_PREFIX$1, "_SYNC_WIZARD_MODE_FROM_DEFINITION");
|
|
3919
|
+
const SET_WIZARD_MODE = "".concat(REDUCER_PREFIX$1, "_SET_WIZARD_MODE");
|
|
3882
3920
|
function fetchFeaturesRequest() {
|
|
3883
3921
|
return {
|
|
3884
3922
|
type: FETCH_FEATURES_REQUEST
|
|
@@ -3990,9 +4028,12 @@ const useFeatureDefinitionLoader = function () {
|
|
|
3990
4028
|
const definition = reactRedux.useSelector(selectDefinition);
|
|
3991
4029
|
const isLoading = reactRedux.useSelector(selectDefinitionIsLoading);
|
|
3992
4030
|
const error = reactRedux.useSelector(selectDefinitionError);
|
|
4031
|
+
const mode = reactRedux.useSelector(selectDefinitionMode);
|
|
3993
4032
|
|
|
3994
4033
|
// Determine if we need to load the definition
|
|
3995
|
-
|
|
4034
|
+
// Only load if: definition is missing AND mode is not yet set (meaning we haven't tried to fetch yet)
|
|
4035
|
+
// OR forceReload is true
|
|
4036
|
+
const shouldLoadDefinition = !definition && !mode || forceReload;
|
|
3996
4037
|
|
|
3997
4038
|
// Function to manually reload definition
|
|
3998
4039
|
const reloadDefinition = () => {
|
|
@@ -5058,28 +5099,29 @@ const listingActions = {
|
|
|
5058
5099
|
// Legacy exports have been removed as Redux actions now use the new listingActions object
|
|
5059
5100
|
|
|
5060
5101
|
// Action Types
|
|
5061
|
-
const
|
|
5062
|
-
const
|
|
5063
|
-
const
|
|
5064
|
-
const
|
|
5065
|
-
const
|
|
5066
|
-
const
|
|
5067
|
-
const
|
|
5068
|
-
const
|
|
5069
|
-
const
|
|
5070
|
-
const
|
|
5071
|
-
const
|
|
5072
|
-
const
|
|
5073
|
-
const
|
|
5074
|
-
const
|
|
5075
|
-
const
|
|
5076
|
-
const
|
|
5077
|
-
const
|
|
5078
|
-
const
|
|
5079
|
-
const
|
|
5080
|
-
const
|
|
5081
|
-
const
|
|
5082
|
-
const
|
|
5102
|
+
const REDUCER_PREFIX = values.reducerKey.toUpperCase();
|
|
5103
|
+
const FETCH_LISTING_REQUEST = "".concat(REDUCER_PREFIX, "_FETCH_LISTING_REQUEST");
|
|
5104
|
+
const FETCH_LISTING_SUCCESS = "".concat(REDUCER_PREFIX, "_FETCH_LISTING_SUCCESS");
|
|
5105
|
+
const FETCH_LISTING_FAILURE = "".concat(REDUCER_PREFIX, "_FETCH_LISTING_FAILURE");
|
|
5106
|
+
const FETCH_LISTING_SILENT_SUCCESS = "".concat(REDUCER_PREFIX, "_FETCH_LISTING_SILENT_SUCCESS");
|
|
5107
|
+
const FETCH_LISTING_SILENT_FAILURE = "".concat(REDUCER_PREFIX, "_FETCH_LISTING_SILENT_FAILURE");
|
|
5108
|
+
const REORDER_LISTING_SUCCESS = "".concat(REDUCER_PREFIX, "_REORDER_LISTING_SUCCESS");
|
|
5109
|
+
const DELETE_LISTING_REQUEST = "".concat(REDUCER_PREFIX, "_DELETE_LISTING_REQUEST");
|
|
5110
|
+
const DELETE_LISTING_SUCCESS = "".concat(REDUCER_PREFIX, "_DELETE_LISTING_SUCCESS");
|
|
5111
|
+
const DELETE_LISTING_FAILURE = "".concat(REDUCER_PREFIX, "_DELETE_LISTING_FAILURE");
|
|
5112
|
+
const UNDELETE_LISTING_REQUEST = "".concat(REDUCER_PREFIX, "_UNDELETE_LISTING_REQUEST");
|
|
5113
|
+
const UNDELETE_LISTING_SUCCESS = "".concat(REDUCER_PREFIX, "_UNDELETE_LISTING_SUCCESS");
|
|
5114
|
+
const UNDELETE_LISTING_FAILURE = "".concat(REDUCER_PREFIX, "_UNDELETE_LISTING_FAILURE");
|
|
5115
|
+
const CREATE_LISTING_REQUEST = "".concat(REDUCER_PREFIX, "_CREATE_LISTING_REQUEST");
|
|
5116
|
+
const CREATE_LISTING_SUCCESS = "".concat(REDUCER_PREFIX, "_CREATE_LISTING_SUCCESS");
|
|
5117
|
+
const CREATE_LISTING_FAILURE = "".concat(REDUCER_PREFIX, "_CREATE_LISTING_FAILURE");
|
|
5118
|
+
const EDIT_LISTING_REQUEST = "".concat(REDUCER_PREFIX, "_EDIT_LISTING_REQUEST");
|
|
5119
|
+
const EDIT_LISTING_SUCCESS = "".concat(REDUCER_PREFIX, "_EDIT_LISTING_SUCCESS");
|
|
5120
|
+
const EDIT_LISTING_FAILURE = "".concat(REDUCER_PREFIX, "_EDIT_LISTING_FAILURE");
|
|
5121
|
+
const TOGGLE_LISTING_SUCCESS = "".concat(REDUCER_PREFIX, "_TOGGLE_LISTING_SUCCESS");
|
|
5122
|
+
const TOGGLE_LISTING_FAILURE = "".concat(REDUCER_PREFIX, "_TOGGLE_LISTING_FAILURE");
|
|
5123
|
+
const SET_SORT_BY = "".concat(REDUCER_PREFIX, "_SET_SORT_BY");
|
|
5124
|
+
const SET_SHOW_DELETED = "".concat(REDUCER_PREFIX, "_SET_SHOW_DELETED");
|
|
5083
5125
|
const fetchListingRequest = () => ({
|
|
5084
5126
|
type: FETCH_LISTING_REQUEST
|
|
5085
5127
|
});
|
|
@@ -7718,12 +7760,12 @@ const Reducers = (() => {
|
|
|
7718
7760
|
})();
|
|
7719
7761
|
const Screens = (() => {
|
|
7720
7762
|
const screens = {};
|
|
7721
|
-
screens[
|
|
7722
|
-
screens[
|
|
7723
|
-
screens[
|
|
7724
|
-
screens[
|
|
7725
|
-
screens[
|
|
7726
|
-
screens[
|
|
7763
|
+
screens["FormOverviewStep"] = FormOverviewStep;
|
|
7764
|
+
screens["FormFieldsStep"] = FormFieldsStep;
|
|
7765
|
+
screens["FormLayoutStep"] = FormLayoutStep;
|
|
7766
|
+
screens["ListingScreen"] = ListingScreen$1;
|
|
7767
|
+
screens["CreateListingPage"] = CreateListingPage;
|
|
7768
|
+
screens["EditListingPage"] = EditListingPage;
|
|
7727
7769
|
return screens;
|
|
7728
7770
|
})();
|
|
7729
7771
|
|