@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,73 +0,0 @@
1
- import React from "react";
2
- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3
- import { GenericInput, Text } from "../index.js";
4
- import { iconImports } from "../iconImports.js";
5
- import styles from "./ListingField.module.css";
6
-
7
- const ListingDescriptionInput = ({
8
- field,
9
- value,
10
- onChange,
11
- showError,
12
- errorMessage,
13
- }) => {
14
- const { label, placeholder, isRequired, helpText } = field.values;
15
-
16
- const handleChange = (e) => {
17
- onChange(field.id, e.target.value);
18
- };
19
-
20
- const isValid = () => {
21
- if (isRequired) {
22
- const isEmpty =
23
- !value || (typeof value === "string" && value.trim() === "");
24
- return !isEmpty;
25
- }
26
- return true;
27
- };
28
-
29
- const displayLabel = (
30
- <>
31
- {label}
32
- {isRequired && <span className={styles.requiredAsterisk}>*</span>}
33
- </>
34
- );
35
-
36
- return (
37
- <>
38
- {/* Field header with icon and description */}
39
- <div className={styles.listingField__header}>
40
- <div className={styles.listingField__icon}>
41
- <FontAwesomeIcon icon={iconImports.alignLeft} />
42
- </div>
43
- <div className={styles.listingField__content}>
44
- <h3 className={styles.listingField__title}>Description</h3>
45
- <p className={styles.listingField__description}>
46
- Longer text area for detailed information or stories
47
- </p>
48
- </div>
49
- </div>
50
-
51
- <GenericInput
52
- type="textarea"
53
- label={displayLabel}
54
- placeholder={placeholder || ""}
55
- value={value || ""}
56
- onChange={handleChange}
57
- isRequired={isRequired}
58
- showError={!!showError}
59
- errorMessage={errorMessage}
60
- isValid={isValid()}
61
- alwaysShowLabel
62
- style={{ resize: "vertical" }}
63
- />
64
- {helpText && (
65
- <div style={{ marginTop: "8px", color: "#6c7a90", fontSize: "14px" }}>
66
- {helpText}
67
- </div>
68
- )}
69
- </>
70
- );
71
- };
72
-
73
- export default ListingDescriptionInput;
@@ -1,101 +0,0 @@
1
- import React from "react";
2
- import ListingTextInput from "./ListingTextInput.jsx";
3
- import ListingDescriptionInput from "./ListingDescriptionInput.jsx";
4
- import ListingImageInput from "./ListingImageInput.jsx";
5
- import ListingGalleryInput from "./ListingGalleryInput.jsx";
6
- import ListingCTAInput from "./ListingCTAInput.jsx";
7
- import ListingFileInput from "./ListingFileInput.jsx";
8
- import styles from "./ListingField.module.css";
9
-
10
- const ListingField = ({
11
- field,
12
- value,
13
- onChange,
14
- showError,
15
- errorMessage,
16
- isActive,
17
- }) => {
18
- const fieldClassName =
19
- showError || isActive
20
- ? `${styles.listingField} ${styles.hasError}`
21
- : styles.listingField;
22
-
23
- const renderField = () => {
24
- switch (field.type) {
25
- case "title":
26
- return (
27
- <ListingTextInput
28
- field={field}
29
- value={value}
30
- onChange={onChange}
31
- showError={showError}
32
- errorMessage={errorMessage}
33
- />
34
- );
35
- case "description":
36
- return (
37
- <ListingDescriptionInput
38
- field={field}
39
- value={value}
40
- onChange={onChange}
41
- showError={showError}
42
- errorMessage={errorMessage}
43
- />
44
- );
45
- case "image":
46
- case "feature-image":
47
- return (
48
- <ListingImageInput
49
- field={field}
50
- value={value}
51
- onChange={onChange}
52
- showError={showError}
53
- errorMessage={errorMessage}
54
- />
55
- );
56
- case "gallery":
57
- return (
58
- <ListingGalleryInput
59
- field={field}
60
- value={value}
61
- onChange={onChange}
62
- showError={showError}
63
- errorMessage={errorMessage}
64
- />
65
- );
66
- case "cta":
67
- return (
68
- <ListingCTAInput
69
- field={field}
70
- value={value}
71
- onChange={onChange}
72
- showError={showError}
73
- errorMessage={errorMessage}
74
- />
75
- );
76
- case "file":
77
- return (
78
- <ListingFileInput
79
- field={field}
80
- value={value}
81
- onChange={onChange}
82
- showError={showError}
83
- errorMessage={errorMessage}
84
- />
85
- );
86
- default:
87
- return <div>Field type {field.type} not implemented</div>;
88
- }
89
- };
90
-
91
- return (
92
- <div className={fieldClassName} data-field-id={field.id}>
93
- {renderField()}
94
- {showError && errorMessage && (
95
- <div className={styles.listingField__error}>{errorMessage}</div>
96
- )}
97
- </div>
98
- );
99
- };
100
-
101
- export default ListingField;
@@ -1,106 +0,0 @@
1
- /* Simple listing field styling - clean vertical layout */
2
-
3
- .listingField {
4
- padding: 0.5rem 0.8rem 0.6rem;
5
- border-radius: var(--border-radius-xl);
6
- background: var(--bg-white);
7
- transition: box-shadow var(--transition-base) ease;
8
- }
9
-
10
- /* Field header with icon and description */
11
- .listingField__header {
12
- display: flex;
13
- display: none;
14
- align-items: flex-start;
15
- gap: 0.3rem;
16
-
17
- padding: 0 0.6rem 0.3rem;
18
- border-bottom: 1px solid var(--border-line-grey);
19
- margin: 0 calc(-1 * 0.7rem);
20
- margin-bottom: 0.5rem;
21
- }
22
-
23
- .listingField__icon {
24
- color: var(--text-bluegrey);
25
- font-size: var(--font-size-base);
26
- flex-shrink: 0;
27
- }
28
-
29
- .listingField__content {
30
- flex: 1;
31
- }
32
-
33
- .listingField__title {
34
- margin: 0 0 0.1rem 0;
35
- font-weight: var(--font-weight-semibold);
36
- font-size: var(--font-size-base);
37
- color: var(--text-dark);
38
- line-height: var(--line-height-snug);
39
- }
40
-
41
- .listingField__description {
42
- margin: 0;
43
- font-size: var(--font-size-xs);
44
- color: var(--text-bluegrey);
45
- line-height: var(--line-height-relaxed);
46
- }
47
-
48
- .listingField:last-child {
49
- margin-bottom: 0;
50
- }
51
-
52
- /* Error state styling */
53
- .listingField--error {
54
- border-color: var(--colour-red);
55
- }
56
-
57
- /* Required field asterisk */
58
- .requiredAsterisk {
59
- color: var(--colour-red);
60
- margin-left: 0.1rem;
61
- font-weight: var(--font-weight-bold);
62
- }
63
-
64
- /* Error message styling */
65
- .listingField__error {
66
- margin-top: 0.1rem;
67
- color: var(--colour-red);
68
- font-size: var(--font-size-xs);
69
- font-weight: var(--font-weight-normal);
70
- line-height: var(--line-height-relaxed);
71
- display: flex;
72
- align-items: center;
73
- gap: 0.1rem;
74
- }
75
-
76
- .listingField__error::before {
77
- content: "⚠";
78
- font-size: var(--font-size-sm);
79
- flex-shrink: 0;
80
- }
81
-
82
- /* Make error more visible */
83
- .listingField.hasError {
84
- position: relative;
85
- }
86
-
87
- .listingField.hasError input,
88
- .listingField.hasError textarea,
89
- .listingField.hasError select,
90
- .listingField.hasError .genericInput,
91
- .listingField.hasError .genericInput input,
92
- .listingField.hasError .genericInput textarea,
93
- .listingField.hasError .imageInputOuter-single,
94
- .listingField.hasError .imageInputOuter-grid,
95
- .listingField.hasError .FileInput,
96
- .listingField.hasError .imageInput,
97
- .listingField.hasError input[type="file"],
98
- .listingField.hasError .file-input,
99
- .listingField.hasError div[class*="imageInput"],
100
- .listingField.hasError div[class*="file-input"],
101
- .listingField.hasError .image-container,
102
- .listingField.hasError .image-grid,
103
- .listingField.hasError img {
104
- }
105
-
106
- /* Hover effect for better interactivity */
@@ -1,273 +0,0 @@
1
- import React, { useRef, useState, useEffect } from "react";
2
- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3
- import { FileInput, Text, Button } from "../../components";
4
- import { iconImports } from "../../components/iconImports.js";
5
- import FileListItem from "./FileListItem.jsx";
6
- import listingFieldStyles from "./ListingField.module.css";
7
- import styles from "./ListingFileInput.module.css";
8
-
9
- const ListingFileInput = ({
10
- field,
11
- value,
12
- onChange,
13
- showError,
14
- errorMessage,
15
- disabled = false,
16
- }) => {
17
- const [inputs, setInputs] = useState([{ id: 0, fileUrl: null }]);
18
- const nextIdRef = useRef(1);
19
-
20
- // Initialize inputs from value prop - map each existing file to an input
21
- useEffect(() => {
22
- if (value) {
23
- let fileData = [];
24
-
25
- // Handle multiple files - could be array of URLs or array of file objects
26
- if (Array.isArray(value)) {
27
- fileData = value
28
- .map((file) => {
29
- if (typeof file === "string") {
30
- const fileName = file.split("/").pop() || "Unknown File";
31
- return {
32
- url: file,
33
- name: fileName.replace(/\.[^/.]+$/, ""),
34
- originalName: fileName,
35
- };
36
- } else if (file && typeof file === "object" && file.url) {
37
- return {
38
- url: file.url,
39
- name: file.name || file.originalName || "Unknown File",
40
- originalName:
41
- file.originalName ||
42
- file.url.split("/").pop() ||
43
- "Unknown File",
44
- };
45
- }
46
- return null;
47
- })
48
- .filter(Boolean);
49
- } else {
50
- // Handle single file values
51
- let singleFile = null;
52
- if (typeof value === "string") {
53
- const fileName = value.split("/").pop() || "Unknown File";
54
- singleFile = {
55
- url: value,
56
- name: fileName.replace(/\.[^/.]+$/, ""),
57
- originalName: fileName,
58
- };
59
- } else if (value && typeof value === "object" && value.url) {
60
- singleFile = {
61
- url: value.url,
62
- name:
63
- value.name !== undefined
64
- ? value.name
65
- : value.originalName || "Unknown File",
66
- originalName:
67
- value.originalName ||
68
- value.url.split("/").pop() ||
69
- "Unknown File",
70
- };
71
- }
72
- fileData = singleFile ? [singleFile] : [];
73
- }
74
-
75
- // Create inputs for each existing file
76
- const existingInputs = fileData.map((file, index) => ({
77
- id: index,
78
- fileUrl: file.url,
79
- name: file.name,
80
- originalName: file.originalName,
81
- }));
82
- // Add one empty input at the end
83
- nextIdRef.current = fileData.length;
84
- setInputs([...existingInputs, { id: nextIdRef.current, fileUrl: null }]);
85
- nextIdRef.current++;
86
- } else {
87
- setInputs([{ id: 0, fileUrl: null }]);
88
- }
89
- }, [value]);
90
-
91
- // Handle new file upload from FileInput component
92
- const handleFileUpload = (inputId, uploadedUrl) => {
93
- if (!uploadedUrl) {
94
- return;
95
- }
96
-
97
- const fileName = uploadedUrl.split("/").pop() || "Unknown File";
98
-
99
- // Find the input that triggered this upload and update it
100
- setInputs((prevInputs) => {
101
- const updatedInputs = prevInputs.map((input) => {
102
- if (input.id === inputId) {
103
- return {
104
- ...input,
105
- fileUrl: uploadedUrl,
106
- name: "",
107
- originalName: fileName,
108
- };
109
- }
110
- return input;
111
- });
112
-
113
- // Add a new empty input for the next upload
114
- updatedInputs.push({ id: nextIdRef.current, fileUrl: null });
115
- nextIdRef.current++;
116
-
117
- return updatedInputs;
118
- });
119
- };
120
-
121
- // Handle file name change
122
- const handleNameChange = (url, newName) => {
123
- setInputs((prevInputs) =>
124
- prevInputs.map((input) =>
125
- input.fileUrl === url ? { ...input, name: newName } : input,
126
- ),
127
- );
128
- };
129
-
130
- // Handle file removal
131
- const handleFileRemove = (url) => {
132
- setInputs((prevInputs) => {
133
- return prevInputs.map((input) => {
134
- if (input.fileUrl === url) {
135
- return { ...input, fileUrl: null };
136
- }
137
- return input;
138
- });
139
- });
140
- };
141
-
142
- // Get all uploaded files from inputs
143
- const getUploadedFiles = () => {
144
- return inputs
145
- .filter((input) => input.fileUrl !== null)
146
- .map((input) => ({
147
- url: input.fileUrl,
148
- name: input.name,
149
- originalName: input.originalName,
150
- }));
151
- };
152
-
153
- // Track previous uploaded files to prevent infinite loops
154
- const prevFilesRef = useRef([]);
155
-
156
- // Sync with parent when uploaded files actually change
157
- useEffect(() => {
158
- const files = getUploadedFiles();
159
- const currentUrls = files.map((f) => f.url).join(",");
160
- const prevUrls = prevFilesRef.current.map((f) => f.url).join(",");
161
-
162
- // Only call onChange if the file list actually changed
163
- if (currentUrls !== prevUrls && onChange) {
164
- prevFilesRef.current = files;
165
- onChange(field.id, files);
166
- }
167
- }, [inputs]);
168
-
169
- // Define acceptable file types for documents and common formats
170
- const acceptTypes = {
171
- "application/pdf": [".pdf"],
172
- "application/msword": [".doc"],
173
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document": [
174
- ".docx",
175
- ],
176
- "application/vnd.ms-excel": [".xls"],
177
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": [
178
- ".xlsx",
179
- ],
180
- "text/plain": [".txt"],
181
- "text/csv": [".csv"],
182
- "image/jpeg": [".jpg", ".jpeg"],
183
- "image/png": [".png"],
184
- };
185
-
186
- // Get the last empty input (the one to show)
187
- const emptyInput = inputs.find((input) => input.fileUrl === null);
188
-
189
- // Get uploaded files for display
190
- const uploadedFiles = getUploadedFiles();
191
-
192
- return (
193
- <div className={styles.listingFileInput}>
194
- {/* Field header with icon and description */}
195
- <div className={listingFieldStyles.listingField__header}>
196
- <div className={listingFieldStyles.listingField__icon}>
197
- <FontAwesomeIcon icon={iconImports.file} />
198
- </div>
199
- <div className={listingFieldStyles.listingField__content}>
200
- <h3 className={listingFieldStyles.listingField__title}>File</h3>
201
- <p className={listingFieldStyles.listingField__description}>
202
- Attach documents, PDFs, or other files
203
- </p>
204
- </div>
205
- </div>
206
-
207
- <Text type="formLabel" style={{ display: "block", marginBottom: "8px" }}>
208
- {field.values.label}
209
- {field.values.isRequired && (
210
- <span className={listingFieldStyles.requiredAsterisk}>*</span>
211
- )}
212
- </Text>
213
-
214
- {/* Drop zone - always show exactly one empty input */}
215
- <div
216
- className={`${styles.listingFileInput__dropZone} ${showError ? styles["listingFileInput__dropZone--error"] : ""}`}
217
- >
218
- {emptyInput && (
219
- <FileInput
220
- key={emptyInput.id}
221
- refreshCallback={(url) => handleFileUpload(emptyInput.id, url)}
222
- hasDefault={null}
223
- accept={acceptTypes}
224
- multiple={false}
225
- disabled={disabled}
226
- />
227
- )}
228
- </div>
229
-
230
- {/* File list */}
231
- {uploadedFiles.length > 0 && (
232
- <div className={styles.listingFileInput__fileList}>
233
- {uploadedFiles.map((file) => (
234
- <FileListItem
235
- key={file.url}
236
- file={file}
237
- onNameChange={handleNameChange}
238
- onRemove={handleFileRemove}
239
- disabled={disabled}
240
- />
241
- ))}
242
- </div>
243
- )}
244
-
245
- {showError && errorMessage && (
246
- <Text
247
- type="help"
248
- style={{
249
- color: "var(--colour-red)",
250
- marginTop: "8px",
251
- display: "block",
252
- }}
253
- >
254
- {errorMessage}
255
- </Text>
256
- )}
257
- {field.values.helpText && (
258
- <Text
259
- type="help"
260
- style={{
261
- color: "var(--text-bluegrey)",
262
- marginTop: "8px",
263
- display: "block",
264
- }}
265
- >
266
- {field.values.helpText}
267
- </Text>
268
- )}
269
- </div>
270
- );
271
- };
272
-
273
- export default ListingFileInput;