@plusscommunities/pluss-feature-builder-web-d 1.0.7 → 1.0.9-beta.3

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.
Files changed (119) hide show
  1. package/dist/{index.cjs.js → index.js} +3803 -3504
  2. package/dist/index.js.map +1 -0
  3. package/package.json +20 -27
  4. package/.babelrc +0 -4
  5. package/rollup.config.js +0 -69
  6. package/src/actions/featureBuilderStringsActions.js +0 -88
  7. package/src/actions/featureDefinitionsIndex.js +0 -258
  8. package/src/actions/formActions.js +0 -301
  9. package/src/actions/index.js +0 -12
  10. package/src/actions/listingActions.js +0 -352
  11. package/src/actions/wizardActions.js +0 -228
  12. package/src/components/ActivityCardExample.jsx +0 -86
  13. package/src/components/ActivityCardExample.module.css +0 -130
  14. package/src/components/BackgroundLoader.jsx +0 -33
  15. package/src/components/BackgroundLoader.module.css +0 -46
  16. package/src/components/BaseFieldConfig.jsx +0 -305
  17. package/src/components/BaseFieldConfig.module.css +0 -42
  18. package/src/components/CenteredContainer.jsx +0 -29
  19. package/src/components/CenteredContainer.module.css +0 -171
  20. package/src/components/DeleteConfirmationPopup.jsx +0 -95
  21. package/src/components/DeleteConfirmationPopup.module.css +0 -12
  22. package/src/components/ErrorBoundary.jsx +0 -134
  23. package/src/components/ErrorBoundary.module.css +0 -77
  24. package/src/components/ErrorMessage.jsx +0 -85
  25. package/src/components/ErrorMessage.module.css +0 -116
  26. package/src/components/ExampleDisplay.jsx +0 -26
  27. package/src/components/ExampleDisplay.module.css +0 -3
  28. package/src/components/FeatureBuilderSidebar.jsx +0 -84
  29. package/src/components/FeatureBuilderSuccessPopup.jsx +0 -49
  30. package/src/components/FeatureBuilderSuccessPopup.module.css +0 -41
  31. package/src/components/FeatureBuilderWelcomePopup.jsx +0 -51
  32. package/src/components/FeatureBuilderWelcomePopup.module.css +0 -21
  33. package/src/components/FeatureListingCard.jsx +0 -104
  34. package/src/components/FeatureListingCard.module.css +0 -62
  35. package/src/components/Fields.jsx +0 -423
  36. package/src/components/Fields.module.css +0 -159
  37. package/src/components/IconLoader.jsx +0 -153
  38. package/src/components/IconLoader.module.css +0 -92
  39. package/src/components/IconSelector.jsx +0 -111
  40. package/src/components/IconSelector.module.css +0 -197
  41. package/src/components/ListingEditor.jsx +0 -405
  42. package/src/components/ListingEditor.module.css +0 -14
  43. package/src/components/ListingSuccessPopup.jsx +0 -52
  44. package/src/components/LoadingScreen.jsx +0 -54
  45. package/src/components/LoadingScreen.module.css +0 -103
  46. package/src/components/LoadingState.jsx +0 -40
  47. package/src/components/LoadingState.module.css +0 -18
  48. package/src/components/PreviewFull.js +0 -24
  49. package/src/components/PreviewFull.module.css +0 -11
  50. package/src/components/PreviewGrid.js +0 -14
  51. package/src/components/PreviewWidget.js +0 -27
  52. package/src/components/PreviewWidget.module.css +0 -15
  53. package/src/components/SidebarLayout.jsx +0 -252
  54. package/src/components/SidebarLayout.module.css +0 -71
  55. package/src/components/SkeletonLoader.jsx +0 -128
  56. package/src/components/SkeletonLoader.module.css +0 -295
  57. package/src/components/SortButtonGroup.jsx +0 -34
  58. package/src/components/SortButtonGroup.module.css +0 -51
  59. package/src/components/ToastContainer.jsx +0 -98
  60. package/src/components/ToastContainer.module.css +0 -156
  61. package/src/components/ToggleSwitch.js +0 -40
  62. package/src/components/ToggleSwitch.module.css +0 -48
  63. package/src/components/TwoColumnInput.jsx +0 -29
  64. package/src/components/TwoColumnInput.module.css +0 -32
  65. package/src/components/ViewFull.js +0 -139
  66. package/src/components/ViewFull.module.css +0 -71
  67. package/src/components/ViewWidget.js +0 -62
  68. package/src/components/ViewWidget.module.css +0 -28
  69. package/src/components/iconCategories.js +0 -135
  70. package/src/components/iconImports.js +0 -409
  71. package/src/components/index.js +0 -59
  72. package/src/components/listing/FileListItem.jsx +0 -86
  73. package/src/components/listing/GalleryDisplay.jsx +0 -330
  74. package/src/components/listing/GalleryDisplay.module.css +0 -309
  75. package/src/components/listing/ListingCTAInput.jsx +0 -82
  76. package/src/components/listing/ListingDescriptionInput.jsx +0 -73
  77. package/src/components/listing/ListingField.jsx +0 -101
  78. package/src/components/listing/ListingField.module.css +0 -106
  79. package/src/components/listing/ListingFileInput.jsx +0 -273
  80. package/src/components/listing/ListingFileInput.module.css +0 -189
  81. package/src/components/listing/ListingForm.jsx +0 -90
  82. package/src/components/listing/ListingForm.module.css +0 -38
  83. package/src/components/listing/ListingGalleryInput.jsx +0 -239
  84. package/src/components/listing/ListingGalleryInput.module.css +0 -132
  85. package/src/components/listing/ListingImageInput.jsx +0 -153
  86. package/src/components/listing/ListingTextInput.jsx +0 -72
  87. package/src/feature.config.js +0 -130
  88. package/src/helper/index.js +0 -135
  89. package/src/hooks/useFeatureDefinitionLoader.js +0 -66
  90. package/src/images/full.png +0 -0
  91. package/src/images/fullNoTitle.png +0 -0
  92. package/src/images/previewWidget.png +0 -0
  93. package/src/images/widget.png +0 -0
  94. package/src/index.js +0 -38
  95. package/src/pages/CreateListingPage.jsx +0 -49
  96. package/src/pages/EditListingPage.jsx +0 -58
  97. package/src/reducers/featureBuilderReducer.js +0 -739
  98. package/src/screens/CreateListing.module.css +0 -45
  99. package/src/screens/Form.module.css +0 -744
  100. package/src/screens/FormFieldsStep.jsx +0 -626
  101. package/src/screens/FormLayoutStep.jsx +0 -405
  102. package/src/screens/FormOverviewStep.jsx +0 -389
  103. package/src/screens/ListingScreen.jsx +0 -477
  104. package/src/screens/ListingScreen.module.css +0 -333
  105. package/src/selectors/featureBuilderSelectors.js +0 -533
  106. package/src/types/index.js +0 -91
  107. package/src/utils/textUtils.js +0 -89
  108. package/src/validators/galleryValidators.js +0 -345
  109. package/src/values.config.a.js +0 -49
  110. package/src/values.config.b.js +0 -49
  111. package/src/values.config.c.js +0 -49
  112. package/src/values.config.d.js +0 -49
  113. package/src/values.config.default.js +0 -49
  114. package/src/values.config.js +0 -49
  115. package/src/webapi/featureDefinitionActions.js +0 -0
  116. package/src/webapi/featuresActions.js +0 -90
  117. package/src/webapi/helper.js +0 -4
  118. package/src/webapi/index.js +0 -12
  119. package/src/webapi/listingActions.js +0 -176
@@ -1,533 +0,0 @@
1
- import { values } from "../values.config";
2
-
3
- /**
4
- * Retrieves the feature builder state from the Redux store
5
- *
6
- * @param {Object} state - The Redux store state
7
- * @returns {Object} The feature builder state or empty object if not found
8
- */
9
- export const getFeatureBuilderState = (state) => state[values.reducerKey] || {};
10
-
11
- // ============ FORM SELECTORS ============
12
-
13
- /**
14
- * Retrieves the form state from the feature builder state
15
- *
16
- * @param {Object} state - The Redux store state
17
- * @returns {Object} The form state object or undefined
18
- */
19
- export const selectFormState = (state) => getFeatureBuilderState(state).form;
20
-
21
- /**
22
- * Retrieves the form title from the form state
23
- *
24
- * @param {Object} state - The Redux store state
25
- * @returns {string|undefined} The form title or undefined if not set
26
- */
27
- export const selectFormTitle = (state) => {
28
- const formState = selectFormState(state);
29
- return formState?.title;
30
- };
31
-
32
- /**
33
- * Retrieves the form icon from the form state
34
- *
35
- * @param {Object} state - The Redux store state
36
- * @returns {string|undefined} The form icon identifier or undefined if not set
37
- */
38
- export const selectFormIcon = (state) => {
39
- const formState = selectFormState(state);
40
- return formState?.icon;
41
- };
42
-
43
- /**
44
- * Retrieves the form display name from the form state
45
- *
46
- * @param {Object} state - The Redux store state
47
- * @returns {string|undefined} The form display name or undefined if not set
48
- */
49
- export const selectFormDisplayName = (state) => {
50
- const formState = selectFormState(state);
51
- return formState?.displayName;
52
- };
53
-
54
- /**
55
- * Retrieves the form layout from the form state
56
- *
57
- * @param {Object} state - The Redux store state
58
- * @returns {Object|undefined} The form layout object or undefined if not set
59
- */
60
- export const selectFormLayout = (state) => {
61
- const formState = selectFormState(state);
62
- return formState?.layout;
63
- };
64
-
65
- /**
66
- * Retrieves the form fields from the form state
67
- *
68
- * @param {Object} state - The Redux store state
69
- * @returns {Array} Array of field definitions or empty array if not set
70
- */
71
- export const selectFormFields = (state) => {
72
- const formState = selectFormState(state);
73
- return formState?.fields || [];
74
- };
75
-
76
- export const selectFormField = (fieldId) => (state) =>
77
- selectFormFields(state).find((field) => field.id === fieldId);
78
-
79
- export const selectFormIsInitial = (state) => {
80
- const formState = selectFormState(state);
81
- return formState?._isInitial;
82
- };
83
- export const selectFormIsSubmitting = (state) => {
84
- const formState = selectFormState(state);
85
- return formState?._isSubmitting;
86
- };
87
-
88
- export const selectFormSubmitError = (state) => {
89
- const formState = selectFormState(state);
90
- return formState?._submitError;
91
- };
92
-
93
- export const selectFormSubmitSuccess = (state) => {
94
- const formState = selectFormState(state);
95
- return formState?._submitSuccess;
96
- };
97
-
98
- // ============ DEFINITION SELECTORS ============
99
-
100
- export const selectDefinitionState = (state) =>
101
- getFeatureBuilderState(state).definition;
102
-
103
- export const selectDefinition = (state) => {
104
- const definitionState = selectDefinitionState(state);
105
- return definitionState?.definition;
106
- };
107
- export const selectDefinitionId = (state) => {
108
- const definitionState = selectDefinitionState(state);
109
- return definitionState?.id;
110
- };
111
- export const selectDefinitionIsLoading = (state) => {
112
- const definitionState = selectDefinitionState(state);
113
- return definitionState?.isLoading;
114
- };
115
- export const selectDefinitionError = (state) => {
116
- const definitionState = selectDefinitionState(state);
117
- return definitionState?.error;
118
- };
119
- export const selectDefinitionIsCreating = (state) => {
120
- const definitionState = selectDefinitionState(state);
121
- return definitionState?.isCreating;
122
- };
123
- export const selectDefinitionIsEditing = (state) => {
124
- const definitionState = selectDefinitionState(state);
125
- return definitionState?.isEditing;
126
- };
127
- export const selectDefinitionMode = (state) => {
128
- const definitionState = selectDefinitionState(state);
129
- return definitionState?.mode;
130
- };
131
-
132
- // Check if we have a definition loaded or if we've determined the mode
133
- // This is used by hiddenFromFeaturePicker to determine if feature should be shown
134
- export const selectHasDefinition = (state) => {
135
- const definition = selectDefinition(state);
136
- return !!definition;
137
- };
138
-
139
- // ============ LISTINGS SELECTORS ============
140
-
141
- export const selectListingsState = (state) =>
142
- getFeatureBuilderState(state).listings;
143
-
144
- export const selectListings = (state) => {
145
- const listingsState = selectListingsState(state);
146
- return listingsState?.listings || [];
147
- };
148
- export const selectListingsIsLoading = (state) => {
149
- const listingsState = selectListingsState(state);
150
- return listingsState?.isLoading;
151
- };
152
- export const selectListingsError = (state) => {
153
- const listingsState = selectListingsState(state);
154
- return listingsState?.error;
155
- };
156
- export const selectListingsIsCreating = (state) => {
157
- const listingsState = selectListingsState(state);
158
- return listingsState?.isCreating;
159
- };
160
- export const selectListingsIsEditing = (state) => {
161
- const listingsState = selectListingsState(state);
162
- return listingsState?.isEditing;
163
- };
164
- export const selectListingsIsDeleting = (state) => {
165
- const listingsState = selectListingsState(state);
166
- return listingsState?.isDeleting;
167
- };
168
- export const selectListingsIsRestoring = (state) => {
169
- const listingsState = selectListingsState(state);
170
- return listingsState?.isRestoring;
171
- };
172
- export const selectListingsIsInitiallyLoaded = (state) => {
173
- const listingsState = selectListingsState(state);
174
- return listingsState?.isInitiallyLoaded;
175
- };
176
-
177
- // Get a specific listing by ID
178
- export const selectListingById = (listingId) => (state) => {
179
- const listings = selectListings(state);
180
-
181
- if (!listingId) {
182
- return null;
183
- }
184
-
185
- const found = listings.find((listing) => {
186
- const id = listing.id || listing._id;
187
- return id === listingId;
188
- });
189
-
190
- return found;
191
- };
192
-
193
- // ============ SOFT DELETE SELECTORS ============
194
-
195
- // Get active (non-deleted) listings
196
- export const selectActiveListings = (state) => {
197
- return selectListings(state).filter((listing) => !listing.deletedAt);
198
- };
199
-
200
- // Get deleted listings
201
- export const selectDeletedListings = (state) => {
202
- return selectListings(state).filter((listing) => listing.deletedAt);
203
- };
204
-
205
- // Check if there are any deleted listings
206
- export const selectHasDeletedListings = (state) => {
207
- return selectDeletedListings(state).length > 0;
208
- };
209
-
210
- // Check if there are any active listings
211
- export const selectHasActiveListings = (state) => {
212
- return selectActiveListings(state).length > 0;
213
- };
214
-
215
- // Get count of deleted listings
216
- export const selectDeletedListingsCount = (state) => {
217
- return selectDeletedListings(state).length;
218
- };
219
-
220
- // ============ COMBINED SELECTORS ============
221
-
222
- // Get the current feature definition ID (either from definition or fallback to config)
223
- export const selectCurrentFeatureDefinitionId = (state) =>
224
- selectDefinitionId(state) || values.featureId;
225
-
226
- // Check if there are any unsaved changes in the form
227
- export const selectHasUnsavedChanges = (state) => {
228
- const definition = selectDefinition(state);
229
- const formTitle = selectFormTitle(state);
230
- const formIcon = selectFormIcon(state);
231
- const formDisplayName = selectFormDisplayName(state);
232
- const formLayout = selectFormLayout(state);
233
-
234
- if (!definition) return false;
235
-
236
- return (
237
- definition.title !== formTitle ||
238
- definition.icon !== formIcon ||
239
- definition.displayName !== formDisplayName ||
240
- JSON.stringify(definition.layout) !== JSON.stringify(formLayout)
241
- );
242
- };
243
-
244
- // Get validation state for the form
245
- export const selectFormValidation = (state) => {
246
- const formFields = selectFormFields(state);
247
- const title = selectFormTitle(state);
248
- const displayName = selectFormDisplayName(state);
249
- const icon = selectFormIcon(state);
250
-
251
- const hasTitle = title && title.trim().length > 0;
252
- const hasDisplayName = displayName && displayName.trim().length > 0;
253
- const hasIcon = icon && icon.length > 0;
254
- const hasValidFields = formFields.every((field) => {
255
- if (
256
- field.isMandatory &&
257
- (field.type === "text" ||
258
- field.type === "description" ||
259
- field.type === "title" ||
260
- field.type === "image" ||
261
- field.type === "feature-image" ||
262
- field.type === "file" ||
263
- field.type === "cta")
264
- ) {
265
- return field.values.label && field.values.label.trim().length > 0;
266
- }
267
- return true;
268
- });
269
-
270
- // Check summary field validation
271
- const descriptionFields = formFields.filter(
272
- (field) => field.type === "description",
273
- );
274
- const summaryFields = descriptionFields.filter(
275
- (field) => field.values && field.values.useAsSummary === true,
276
- );
277
- const hasValidSummaryFields = summaryFields.length <= 1; // At most one summary field allowed
278
-
279
- return {
280
- isValid:
281
- hasTitle &&
282
- hasDisplayName &&
283
- hasIcon &&
284
- hasValidFields &&
285
- hasValidSummaryFields,
286
- hasTitle,
287
- hasDisplayName,
288
- hasIcon,
289
- hasValidFields,
290
- hasValidSummaryFields,
291
- errors: {
292
- title: !hasTitle ? "Title is required" : null,
293
- displayName: !hasDisplayName ? "Display name is required" : null,
294
- icon: !hasIcon ? "Icon is required" : null,
295
- fields: !hasValidFields ? "Some required fields are missing" : null,
296
- summary: !hasValidSummaryFields
297
- ? "Only one description field can be used as preview text"
298
- : null,
299
- },
300
- };
301
- };
302
-
303
- // ============ WIZARD SELECTORS ============
304
-
305
- export const selectWizardState = (state) =>
306
- getFeatureBuilderState(state).wizard;
307
-
308
- export const selectWizardMode = (state) => {
309
- const wizardState = selectWizardState(state);
310
- return wizardState?.mode;
311
- };
312
-
313
- // Mode detection selectors - wizard mode is the SINGLE SOURCE OF TRUTH for create/edit mode
314
- // Wizard mode is automatically synchronized with definition state through dispatched actions
315
- export const selectIsCreateMode = (state) =>
316
- selectWizardMode(state) === "create";
317
-
318
- export const selectIsEditMode = (state) => selectWizardMode(state) === "edit";
319
-
320
- export const selectNavigationState = (state) => {
321
- const wizardState = selectWizardState(state);
322
- return wizardState?.navigation;
323
- };
324
-
325
- export const selectCurrentStep = (state) => {
326
- const navigationState = selectNavigationState(state);
327
- return navigationState?.currentStep;
328
- };
329
-
330
- export const selectCanGoBack = (state) => {
331
- const navigationState = selectNavigationState(state);
332
- return navigationState?.canGoBack;
333
- };
334
-
335
- export const selectPreviousStep = (state) => {
336
- const navigationState = selectNavigationState(state);
337
- return navigationState?.previousStep;
338
- };
339
-
340
- export const selectCanGoForward = (state) => {
341
- const navigationState = selectNavigationState(state);
342
- return navigationState?.canGoForward;
343
- };
344
-
345
- export const selectStepValidation = (state) => {
346
- const wizardState = selectWizardState(state);
347
- return wizardState?.stepValidation;
348
- };
349
-
350
- export const selectStepValidationState = (step) => (state) => {
351
- const stepValidation = selectStepValidation(state);
352
- return stepValidation?.[step];
353
- };
354
-
355
- export const selectIsStepValid = (step) => (state) => {
356
- const stepValidationState = selectStepValidationState(step)(state);
357
- return stepValidationState?.isValid;
358
- };
359
-
360
- export const selectStepErrors = (step) => (state) => {
361
- const stepValidationState = selectStepValidationState(step)(state);
362
- return stepValidationState?.errors || {};
363
- };
364
-
365
- export const selectStepCompletion = (state) => {
366
- const wizardState = selectWizardState(state);
367
- return wizardState?.stepCompletion;
368
- };
369
-
370
- export const selectIsStepComplete = (step) => (state) => {
371
- const stepCompletion = selectStepCompletion(state);
372
- return stepCompletion?.[step];
373
- };
374
-
375
- export const selectAllStepsComplete = (state) => {
376
- const stepCompletion = selectStepCompletion(state);
377
- if (!stepCompletion) return false;
378
- return (
379
- stepCompletion.overview && stepCompletion.fields && stepCompletion.layout
380
- );
381
- };
382
-
383
- export const selectStepProgress = (state) => {
384
- const stepCompletion = selectStepCompletion(state);
385
- if (!stepCompletion) return { completed: 0, total: 3, percentage: 0 };
386
-
387
- const completed = Object.values(stepCompletion).filter(Boolean).length;
388
- const total = Object.keys(stepCompletion).length;
389
- const percentage = Math.round((completed / total) * 100);
390
-
391
- return { completed, total, percentage };
392
- };
393
-
394
- // Determine initial wizard mode based on definition existence
395
- export const selectInitialWizardMode = (state) => {
396
- const hasDefinition = selectHasDefinition(state);
397
- return hasDefinition ? "edit" : "create";
398
- };
399
-
400
- // Check if current step should be accessible in current mode
401
- export const selectIsStepAccessible = (step) => (state) => {
402
- const mode = selectWizardMode(state);
403
- const currentStep = selectCurrentStep(state);
404
-
405
- if (mode === "edit") {
406
- // In edit mode, all steps are accessible
407
- return true;
408
- }
409
-
410
- // In create mode, check if we can access this step
411
- switch (step) {
412
- case "welcome":
413
- return !selectHasDefinition(state);
414
- case "overview":
415
- case "fields":
416
- case "layout":
417
- // In create mode, can only access if we're not on welcome screen
418
- return currentStep !== "welcome";
419
- default:
420
- return false;
421
- }
422
- };
423
-
424
- // ============ LISTING UI SELECTORS ============
425
-
426
- // Get current sort method
427
- export const selectSortBy = (state) => {
428
- const listingsState = selectListingsState(state);
429
- return listingsState?.sortBy || "newest";
430
- };
431
-
432
- // Get show deleted toggle state
433
- export const selectShowDeleted = (state) => {
434
- const listingsState = selectListingsState(state);
435
- return listingsState?.showDeleted || false;
436
- };
437
-
438
- // Get sorted and filtered listings
439
- export const selectSortedListings = (state) => {
440
- const showDeleted = selectShowDeleted(state);
441
- const sortBy = selectSortBy(state);
442
- const activeListings = selectActiveListings(state);
443
- const deletedListings = selectDeletedListings(state);
444
-
445
- // Determine which listings to include
446
- let listingsToShow = activeListings;
447
- if (showDeleted) {
448
- listingsToShow = [...activeListings, ...deletedListings];
449
- }
450
-
451
- // Sort the listings
452
- switch (sortBy) {
453
- case "newest":
454
- return [...listingsToShow].sort((a, b) => {
455
- const dateA = a.createdAt || a.order;
456
- const dateB = b.createdAt || b.order;
457
- return new Date(dateB) - new Date(dateA);
458
- });
459
- case "oldest":
460
- return [...listingsToShow].sort((a, b) => {
461
- const dateA = a.createdAt || a.order;
462
- const dateB = b.createdAt || b.order;
463
- return new Date(dateA) - new Date(dateB);
464
- });
465
- case "az":
466
- return [...listingsToShow].sort((a, b) => {
467
- const titleA = (a.fields && a.fields["mandatory-title"]) || "";
468
- const titleB = (b.fields && b.fields["mandatory-title"]) || "";
469
- return titleA.localeCompare(titleB);
470
- });
471
- case "za":
472
- return [...listingsToShow].sort((a, b) => {
473
- const titleA = (a.fields && a.fields["mandatory-title"]) || "";
474
- const titleB = (b.fields && b.fields["mandatory-title"]) || "";
475
- return titleB.localeCompare(titleA);
476
- });
477
- default:
478
- return listingsToShow;
479
- }
480
- };
481
-
482
- // ============ SUMMARY FIELD SELECTORS ============
483
-
484
- /**
485
- * Get the description field that is marked as summary field
486
- *
487
- * @param {Object} state - The Redux store state
488
- * @returns {Object|null} The field object marked as summary, or null if none found
489
- */
490
- export const selectSummaryDescriptionField = (state) => {
491
- const fields = selectFormFields(state);
492
- return (
493
- fields.find(
494
- (field) =>
495
- field.type === "description" &&
496
- field.values &&
497
- field.values.useAsSummary === true,
498
- ) || null
499
- );
500
- };
501
-
502
- /**
503
- * Get the field ID of the description field marked as summary
504
- *
505
- * @param {Object} state - The Redux store state
506
- * @returns {string|null} The field ID marked as summary, or null if none found
507
- */
508
- export const selectSummaryDescriptionFieldId = (state) => {
509
- const summaryField = selectSummaryDescriptionField(state);
510
- return summaryField ? summaryField.id : null;
511
- };
512
-
513
- /**
514
- * Extract summary content from listing data based on the summary field configuration
515
- *
516
- * @param {Object} state - The Redux store state
517
- * @param {Object} listing - The listing object containing field values
518
- * @returns {string} The summary content or empty string if not found
519
- */
520
- export const getSummaryDescriptionFromListing = (state, listing) => {
521
- if (!listing || !listing.fields) {
522
- return "";
523
- }
524
-
525
- const summaryField = selectSummaryDescriptionField(state);
526
- if (!summaryField) {
527
- // If no summary field is configured, return empty string
528
- return "";
529
- }
530
-
531
- // Get the value from the listing's fields using the summary field's ID
532
- return listing.fields[summaryField.id] || "";
533
- };
@@ -1,91 +0,0 @@
1
- /**
2
- * Core type definitions for the Feature Builder
3
- * This file contains JSDoc type definitions for all major entities
4
- */
5
-
6
- /**
7
- * @typedef {Object} Field
8
- * @property {string} id - Unique identifier for the field
9
- * @property {string} type - Field type (text, title, description, image, file, cta, feature-image, gallery)
10
- * @property {string} label - Display label for the field
11
- * @property {boolean} required - Whether the field is required
12
- * @property {string} [placeholder] - Placeholder text for input fields
13
- * @property {string} [helpText] - Help text displayed below the field
14
- * @property {Object} [validation] - Validation rules for the field
15
- * @property {Object} [options] - Additional options specific to field type
16
- * @property {number} [order] - Display order of the field
17
- */
18
-
19
- /**
20
- * @typedef {Object} FormState
21
- * @property {string} id - Feature definition ID
22
- * @property {string} displayName - Display name for the feature
23
- * @property {string} [description] - Description of the feature
24
- * @property {string} icon - Icon identifier for the feature
25
- * @property {Field[]} fields - Array of field definitions
26
- * @property {Object} layout - Layout configuration
27
- * @property {boolean} isInitial - Whether this is the initial state
28
- * @property {boolean} isDirty - Whether the form has unsaved changes
29
- * @property {Object} validation - Form validation state
30
- */
31
-
32
- /**
33
- * @typedef {Object} Listing
34
- * @property {string} id - Unique identifier for the listing
35
- * @property {string} featureDefinitionId - ID of the feature definition this belongs to
36
- * @property {string} siteId - Site ID where this listing belongs
37
- * @property {string} [title] - Listing title
38
- * @property {string} [description] - Listing description
39
- * @property {Object} [fieldValues] - Key-value pairs of field data
40
- * @property {boolean} isActive - Whether the listing is active
41
- * @property {boolean} isDeleted - Whether the listing is soft-deleted
42
- * @property {string} [createdBy] - User ID who created this listing
43
- * @property {string} [updatedBy] - User ID who last updated this listing
44
- * @property {string} createdAt - Creation timestamp
45
- * @property {string} updatedAt - Last update timestamp
46
- */
47
-
48
- /**
49
- * @typedef {Object} FeatureDefinition
50
- * @property {string} id - Unique identifier for the feature definition
51
- * @property {string} displayName - Human-readable name for the feature
52
- * @property {string} [description] - Description of what the feature does
53
- * @property {string} icon - Icon identifier
54
- * @property {Field[]} fields - Array of field definitions
55
- * @property {Object} layout - Layout configuration
56
- * @property {boolean} isActive - Whether the feature definition is active
57
- * @property {string} [createdBy] - User ID who created this feature definition
58
- * @property {string} createdAt - Creation timestamp
59
- * @property {string} updatedAt - Last update timestamp
60
- */
61
-
62
- /**
63
- * @typedef {Object} WizardState
64
- * @property {string} mode - Current wizard mode ('create' | 'edit')
65
- * @property {number} currentStep - Current step index
66
- * @property {Object} validation - Validation state for each step
67
- * @property {boolean} canProceed - Whether user can proceed to next step
68
- * @property {boolean} isComplete - Whether wizard is complete
69
- */
70
-
71
- /**
72
- * @typedef {Object} ApiResponse
73
- * @property {boolean} success - Whether the API call was successful
74
- * @property {*} data - Response data payload
75
- * @property {string} [message] - Optional message from the server
76
- * @property {string} [error] - Error message if the call failed
77
- */
78
-
79
- /**
80
- * @typedef {Object} SortConfig
81
- * @property {string} field - Field to sort by
82
- * @property {string} direction - Sort direction ('asc' | 'desc')
83
- */
84
-
85
- /**
86
- * @typedef {Object} FilterConfig
87
- * @property {string} [search] - Search term
88
- * @property {boolean} [showDeleted] - Whether to include deleted items
89
- * @property {Object} [fieldFilters] - Additional field-based filters
90
- */
91
-
@@ -1,89 +0,0 @@
1
- /**
2
- * Text utility functions for consistent formatting throughout the application
3
- */
4
-
5
- /**
6
- * Converts a string to Title Case (first letter of each word capitalized)
7
- * Handles null, undefined, and empty string cases safely
8
- *
9
- * @param {string} text - The text to convert to Title Case
10
- * @param {string} [fallback=""] - Fallback text if input is null/undefined
11
- * @returns {string} - Title Cased text or fallback
12
- *
13
- * @example
14
- * toTitleCase("hello world") // returns "Hello World"
15
- * toTitleCase("feature builder") // returns "Feature Builder"
16
- * toTitleCase("") // returns ""
17
- * toTitleCase(null) // returns ""
18
- * toTitleCase(undefined, "Default") // returns "Default"
19
- */
20
- export const toTitleCase = (text, fallback = "") => {
21
- if (text === null || text === undefined) {
22
- return fallback;
23
- }
24
-
25
- if (typeof text !== "string") {
26
- return fallback;
27
- }
28
-
29
- if (text.length === 0) {
30
- return fallback;
31
- }
32
-
33
- return text
34
- .toLowerCase()
35
- .split(" ")
36
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
37
- .join(" ");
38
- };
39
-
40
- /**
41
- * Capitalizes the first character of a string while preserving the rest
42
- * Handles null, undefined, and empty string cases safely
43
- *
44
- * @param {string} text - The text to capitalize
45
- * @param {string} [fallback=""] - Fallback text if input is null/undefined
46
- * @returns {string} - Capitalized text or fallback
47
- *
48
- * @example
49
- * capitalizeText("hello") // returns "Hello"
50
- * capitalizeText("WORLD") // returns "WORLD"
51
- * capitalizeText("") // returns ""
52
- * capitalizeText(null) // returns ""
53
- * capitalizeText(undefined, "item") // returns "item"
54
- */
55
- export const capitalizeText = (text, fallback = "") => {
56
- if (text === null || text === undefined) {
57
- return fallback;
58
- }
59
-
60
- if (typeof text !== "string") {
61
- return fallback;
62
- }
63
-
64
- if (text.length === 0) {
65
- return fallback;
66
- }
67
-
68
- return text.charAt(0).toUpperCase() + text.slice(1);
69
- };
70
-
71
- /**
72
- * Capitalizes text and ensures it's not empty by providing a fallback
73
- *
74
- * @param {string} text - The text to capitalize
75
- * @param {string} fallback - Fallback text if input is empty/null/undefined
76
- * @returns {string} - Capitalized text or fallback
77
- *
78
- * @example
79
- * capitalizeTextWithFallback("hello", "Item") // returns "Hello"
80
- * capitalizeTextWithFallback("", "Item") // returns "Item"
81
- * capitalizeTextWithFallback(null, "Item") // returns "Item"
82
- */
83
- export const capitalizeTextWithFallback = (text, fallback) => {
84
- if (!text || (typeof text === "string" && text.trim().length === 0)) {
85
- return capitalizeText(fallback, "");
86
- }
87
-
88
- return capitalizeText(text, fallback);
89
- };