@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,405 +0,0 @@
1
- import React, { useEffect } from "react";
2
- import { SidebarLayout } from "../components/SidebarLayout.jsx";
3
- import { values } from "../values.config.js";
4
- import { PlussCore } from "../feature.config";
5
- import styles from "./Form.module.css";
6
- import {
7
- Text,
8
- Button,
9
- LoadingState,
10
- IconLoader,
11
- ErrorBoundary,
12
- FeatureBuilderSuccessPopup,
13
- } from "../components";
14
- import ToastContainer from "../components/ToastContainer.jsx";
15
- import { useDispatch, useSelector } from "react-redux";
16
- import {
17
- setLayoutType,
18
- setGridLayoutIcon,
19
- submitForm,
20
- clearFormSubmissionState,
21
- setInitialValues,
22
- } from "../actions/formActions";
23
- import {
24
- selectFormLayout,
25
- selectFormIcon,
26
- selectIsCreateMode,
27
- selectIsEditMode,
28
- selectIsStepValid,
29
- selectStepErrors,
30
- selectFormIsSubmitting,
31
- selectFormSubmitError,
32
- selectFormSubmitSuccess,
33
- selectFormDisplayName,
34
- selectFormTitle,
35
- selectDefinitionId,
36
- selectFormIsInitial,
37
- } from "../selectors/featureBuilderSelectors";
38
- import { useFeatureDefinitionLoader } from "../hooks/useFeatureDefinitionLoader";
39
- import {
40
- validateAndUpdateStep,
41
- setCurrentStepAndSave,
42
- } from "../actions/wizardActions";
43
- import { withRouter } from "react-router-dom";
44
-
45
- const FormLayoutStepInner = (props) => {
46
- const { history } = props;
47
- const dispatch = useDispatch();
48
- const auth = useSelector((state) => state.auth);
49
- const layout = useSelector(selectFormLayout);
50
- const displayName = useSelector(selectFormDisplayName);
51
- const featureFormName = useSelector(selectFormTitle);
52
- const overviewIcon = useSelector(selectFormIcon);
53
- const definitionId = useSelector(selectDefinitionId);
54
- const layoutType = layout?.type || "round";
55
- const isCreateMode = useSelector(selectIsCreateMode);
56
- const isEditMode = useSelector(selectIsEditMode);
57
- const { definition, definitionIsLoading } = useFeatureDefinitionLoader();
58
-
59
- // Get form initialization state
60
- const isFormInitial = useSelector(selectFormIsInitial);
61
-
62
- // Get validation state
63
- const isStepValid = useSelector(selectIsStepValid("layout"));
64
- const stepErrors = useSelector(selectStepErrors("layout"));
65
-
66
- // Get submission state
67
- const isSubmitting = useSelector(selectFormIsSubmitting);
68
- const submitError = useSelector(selectFormSubmitError);
69
- const submitSuccess = useSelector(selectFormSubmitSuccess);
70
-
71
- const [toasts, setToasts] = React.useState([]);
72
- const [showSuccessPopup, setShowSuccessPopup] = React.useState(false);
73
-
74
- const addToast = (type, message) => {
75
- const id = Date.now();
76
- setToasts((prev) => [...prev, { id, type, message, isVisible: true }]);
77
- };
78
-
79
- const removeToast = (id) => {
80
- setToasts((prev) => prev.filter((toast) => toast.id !== id));
81
- };
82
-
83
- const handleSuccessPopupClose = () => {
84
- setShowSuccessPopup(false);
85
- dispatch(clearFormSubmissionState());
86
- window.location.replace(values.routeFormOverviewStep);
87
- };
88
-
89
- useEffect(() => {
90
- if (submitSuccess && !isSubmitting) {
91
- if (isEditMode) {
92
- addToast("success", "Changes saved");
93
- dispatch(clearFormSubmissionState());
94
- } else {
95
- setShowSuccessPopup(true);
96
- }
97
- }
98
- }, [submitSuccess, isEditMode, isSubmitting, dispatch]);
99
-
100
- useEffect(() => {
101
- if (submitError) {
102
- addToast("error", "It didn't work. Please try again.");
103
- setTimeout(() => {
104
- window.location.reload();
105
- }, 1000);
106
- }
107
- }, [submitError]);
108
-
109
- const handleRefresh = () => {
110
- dispatch(validateAndUpdateStep("layout"));
111
- };
112
-
113
- const layoutOptions = [
114
- {
115
- value: "round",
116
- title: "Round Images",
117
- description: "Round photos in a grid",
118
- image:
119
- "https://pluss-prd-uploads.s3.ap-southeast-2.amazonaws.com/uploads/users/ap-southeast-2:b5bebf26-ee4c-c29c-88c8-ec859245e17b/public/b8156f584c92a0edbe13a8e05d/fblayoutround.png",
120
- },
121
- {
122
- value: "condensed",
123
- title: "Compact List",
124
- description: "Small photos in a list",
125
- image:
126
- "https://pluss-prd-uploads.s3.ap-southeast-2.amazonaws.com/uploads/users/ap-southeast-2:b5bebf26-ee4c-c29c-88c8-ec859245e17b/public/dfec30d342249a4073e5ffc6b8/fblayoutcompact.png",
127
- },
128
- {
129
- value: "square",
130
- title: "Square Images",
131
- description: "Square photos in a grid",
132
- image:
133
- "https://pluss-prd-uploads.s3.ap-southeast-2.amazonaws.com/uploads/users/ap-southeast-2:b5bebf26-ee4c-c29c-88c8-ec859245e17b/public/771e4626462a93041746a746c8/fblayoutsquare.png",
134
- },
135
- {
136
- value: "feature",
137
- title: "Large Photos",
138
- description: "Big photos with details",
139
- image:
140
- "https://pluss-prd-uploads.s3.ap-southeast-2.amazonaws.com/uploads/users/ap-southeast-2:b5bebf26-ee4c-c29c-88c8-ec859245e17b/public/f48acc614508ba246186b12845/fblayoutcardslarge.png",
141
- },
142
- ];
143
-
144
- useEffect(() => {
145
- // Set current step when component mounts
146
- dispatch(setCurrentStepAndSave("layout"));
147
- }, [dispatch]);
148
-
149
- // ADD THIS EFFECT: Hydrate form data from definition on refresh
150
- useEffect(() => {
151
- if (definition && !definitionIsLoading && isFormInitial) {
152
- dispatch(setInitialValues(definition));
153
-
154
- // In edit mode, trigger validation after setting initial values
155
- if (isEditMode) {
156
- setTimeout(() => {
157
- dispatch(validateAndUpdateStep("layout"));
158
- }, 100);
159
- }
160
- }
161
- }, [definition, definitionIsLoading, isFormInitial, isEditMode, dispatch]);
162
-
163
- useEffect(() => {
164
- // In edit mode, trigger validation when definition is available
165
- // Note: The new effect above handles data population, this handles re-validation
166
- if (isEditMode && definition && !definitionIsLoading && !isFormInitial) {
167
- // Only validate if form is NOT initial (meaning it has data)
168
- setTimeout(() => {
169
- dispatch(validateAndUpdateStep("layout"));
170
- }, 100);
171
- }
172
- }, [definition, definitionIsLoading, isEditMode, isFormInitial, dispatch]);
173
-
174
- function handleSelectLayout(layoutType) {
175
- dispatch(setLayoutType(layoutType));
176
- }
177
-
178
- function handlePrevious() {
179
- dispatch(clearFormSubmissionState());
180
-
181
- if (isCreateMode) {
182
- history.push(values.routeFormFieldsStep);
183
- } else {
184
- history.push(values.routeFormFieldsStep);
185
- }
186
- }
187
-
188
- function handleNext() {
189
- if (isSubmitting) {
190
- return;
191
- }
192
- const validationResult = dispatch(validateAndUpdateStep("layout"));
193
- if (validationResult?.isValid) {
194
- if (isCreateMode) {
195
- dispatch(submitForm());
196
- } else {
197
- // In edit mode, just save changes
198
- dispatch(submitForm());
199
- }
200
- }
201
- // If validation fails, validation errors will be displayed
202
- }
203
-
204
- function handleSaveStep() {
205
- // Validate before saving in edit mode
206
- const validationResult = dispatch(validateAndUpdateStep("layout"));
207
-
208
- // If validation passes, proceed with saving
209
- if (validationResult?.isValid) {
210
- dispatch(submitForm());
211
- }
212
- }
213
-
214
- // Check for definition management permission
215
- if (
216
- !PlussCore.Session.validateAccess(
217
- auth.site,
218
- values.permissionFeatureBuilderDefinition,
219
- auth,
220
- )
221
- ) {
222
- return (
223
- <div className="hub-wrapperContainer">
224
- <div className="hub-contentWrapper">
225
- <div className={styles.welcomeContainer}>
226
- <div className={styles.welcomeHeader}>
227
- <Text type="h1" className={styles.welcomeTitle}>
228
- Access Restricted
229
- </Text>
230
- <Text type="body" className={styles.welcomeSubtitle}>
231
- You don't have permission to manage feature definitions. Please
232
- contact your administrator if you need access.
233
- </Text>
234
- </div>
235
- </div>
236
- </div>
237
- </div>
238
- );
239
- }
240
-
241
- return (
242
- <ErrorBoundary
243
- title="Unable to load layout design"
244
- message="If you continue to experience issues with the layout design, please try refreshing the page or contact support."
245
- onRetry={handleRefresh}
246
- >
247
- <SidebarLayout>
248
- <div className={styles.formLayoutHeader}>
249
- <Text
250
- type="formTitleLarge"
251
- className={`${isEditMode ? styles.editMode : styles.createMode}`}
252
- >
253
- {isEditMode ? "In-App Design" : "In-App Design"}
254
- </Text>
255
- </div>
256
- <Text type="body" className="paddingBottom-16">
257
- {isCreateMode
258
- ? "Pick how your feature looks. Choose a layout and add a grid icon if you want."
259
- : "Change how your feature looks. You can update the layout and grid icon anytime."}
260
- </Text>
261
-
262
- {/* Grid Icon Section */}
263
- <div className={styles.gridIconSection}>
264
- <Text type="formTitleSmall" className="">
265
- Grid Icon (Optional)
266
- </Text>
267
- <Text type="body" color="#6c757d" className="paddingBottom-16">
268
- Upload a grid icon for your feature. If you don't upload one, we'll
269
- use your main icon.
270
- </Text>
271
-
272
- <IconLoader
273
- value={layout?.gridIcon}
274
- defaultValue={overviewIcon}
275
- onChange={() => {}} // Disabled
276
- onRemove={() => {}} // Disabled
277
- featureId={definitionId || "new"}
278
- />
279
-
280
- <Text type="help" color="#6c757d" className="marginTop-16">
281
- We're working on bringing the ability to use custom grid icons
282
- </Text>
283
- </div>
284
-
285
- {/* Layout Selection Section */}
286
- <div className={styles.layoutSection}>
287
- <Text type="formTitleSmall">In-App Layout</Text>
288
- <Text type="body" color="#6c757d" className="paddingBottom-16">
289
- Select how your feature content will be displayed in the app
290
- </Text>
291
- <div className={styles.grid__four}>
292
- {definitionIsLoading ? (
293
- <div className={styles.gridIconLoading}>
294
- <LoadingState message="Loading layout options..." />
295
- </div>
296
- ) : (
297
- layoutOptions.map((option) => {
298
- const hasError =
299
- !isStepValid && stepErrors && stepErrors.layoutType;
300
- const isSelected = layoutType === option.value;
301
-
302
- return (
303
- <div
304
- key={option.value}
305
- className={`${styles.layoutOption} ${
306
- hasError ? styles.hasError : ""
307
- } ${isSelected ? styles.selected : ""}`}
308
- onClick={() => handleSelectLayout(option.value)}
309
- >
310
- <div className={styles.layoutOptionImage}>
311
- <img
312
- src={option.image}
313
- alt={option.title}
314
- className={styles.layoutOptionImg}
315
- />
316
- </div>
317
- <div className={styles.layoutOptionContent}>
318
- <div className={styles.layoutOptionTitle}>
319
- {option.title}
320
- </div>
321
- <div className={styles.layoutOptionDescription}>
322
- {option.description}
323
- </div>
324
- </div>
325
- {hasError && (
326
- <div className={styles.fieldError}>
327
- <span className={styles.errorIcon}>!</span>
328
- Layout selection is required
329
- </div>
330
- )}
331
- </div>
332
- );
333
- })
334
- )}
335
- </div>
336
- </div>
337
-
338
- {/* Top-level validation message - positioned above action buttons */}
339
- {!isStepValid && Object.keys(stepErrors).length > 0 && (
340
- <div
341
- className={styles.validationErrorMessage}
342
- role="alert"
343
- aria-live="polite"
344
- >
345
- {Object.keys(stepErrors).length}{" "}
346
- {Object.keys(stepErrors).length === 1
347
- ? "field needs"
348
- : "fields need"}{" "}
349
- attention before proceeding
350
- </div>
351
- )}
352
-
353
- {/* Mode-aware navigation buttons */}
354
- <div className={styles.navigation}>
355
- {isCreateMode ? (
356
- <>
357
- <Button
358
- buttonType="secondary"
359
- isActive
360
- onClick={handlePrevious}
361
- leftIcon="arrow-left"
362
- >
363
- Previous step: Choose Layout
364
- </Button>
365
- <Button
366
- buttonType="primary"
367
- isActive
368
- onClick={handleNext}
369
- leftIcon="check"
370
- disabled={isSubmitting}
371
- loading={isSubmitting}
372
- >
373
- {isSubmitting ? "Creating..." : "Complete Feature"}
374
- </Button>
375
- </>
376
- ) : (
377
- <Button
378
- buttonType="primary"
379
- isActive
380
- onClick={handleSaveStep}
381
- disabled={!isStepValid || isSubmitting}
382
- leftIcon={isSubmitting ? "sync" : "save"}
383
- loading={isSubmitting}
384
- >
385
- {isSubmitting ? "Saving..." : "Save"}
386
- </Button>
387
- )}
388
- </div>
389
- </SidebarLayout>
390
-
391
- {/* Success Popup */}
392
- <FeatureBuilderSuccessPopup
393
- isOpen={showSuccessPopup}
394
- onClose={handleSuccessPopupClose}
395
- featureName={featureFormName}
396
- displayName={displayName}
397
- />
398
-
399
- {/* Toast Container for Notifications */}
400
- <ToastContainer toasts={toasts} onDismiss={removeToast} />
401
- </ErrorBoundary>
402
- );
403
- };
404
-
405
- export const FormLayoutStep = withRouter(FormLayoutStepInner);