@plusscommunities/pluss-feature-builder-web-d 1.0.2-beta.0
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/.babelrc +4 -0
- package/dist/index.cjs.js +7792 -0
- package/package.json +54 -0
- package/rollup.config.js +68 -0
- package/src/actions/featureBuilderStringsActions.js +88 -0
- package/src/actions/featureDefinitionsIndex.js +258 -0
- package/src/actions/formActions.js +311 -0
- package/src/actions/index.js +12 -0
- package/src/actions/listingActions.js +350 -0
- package/src/actions/wizardActions.js +240 -0
- package/src/components/ActivityCardExample.jsx +86 -0
- package/src/components/ActivityCardExample.module.css +130 -0
- package/src/components/BackgroundLoader.jsx +33 -0
- package/src/components/BackgroundLoader.module.css +46 -0
- package/src/components/BaseFieldConfig.jsx +305 -0
- package/src/components/BaseFieldConfig.module.css +42 -0
- package/src/components/CenteredContainer.jsx +29 -0
- package/src/components/CenteredContainer.module.css +171 -0
- package/src/components/DeleteConfirmationPopup.jsx +95 -0
- package/src/components/DeleteConfirmationPopup.module.css +12 -0
- package/src/components/ErrorBoundary.jsx +134 -0
- package/src/components/ErrorBoundary.module.css +77 -0
- package/src/components/ErrorMessage.jsx +85 -0
- package/src/components/ErrorMessage.module.css +116 -0
- package/src/components/ExampleDisplay.jsx +26 -0
- package/src/components/ExampleDisplay.module.css +3 -0
- package/src/components/FeatureBuilderSidebar.jsx +84 -0
- package/src/components/FeatureBuilderSuccessPopup.jsx +55 -0
- package/src/components/FeatureBuilderSuccessPopup.module.css +43 -0
- package/src/components/FeatureBuilderWelcomePopup.jsx +51 -0
- package/src/components/FeatureBuilderWelcomePopup.module.css +21 -0
- package/src/components/FeatureListingCard.jsx +104 -0
- package/src/components/FeatureListingCard.module.css +62 -0
- package/src/components/Fields.jsx +460 -0
- package/src/components/Fields.module.css +159 -0
- package/src/components/IconLoader.jsx +153 -0
- package/src/components/IconLoader.module.css +92 -0
- package/src/components/IconSelector.jsx +112 -0
- package/src/components/IconSelector.module.css +197 -0
- package/src/components/ListingEditor.jsx +406 -0
- package/src/components/ListingEditor.module.css +14 -0
- package/src/components/ListingSuccessPopup.jsx +52 -0
- package/src/components/LoadingScreen.jsx +54 -0
- package/src/components/LoadingScreen.module.css +103 -0
- package/src/components/LoadingState.jsx +40 -0
- package/src/components/LoadingState.module.css +18 -0
- package/src/components/PreviewFull.js +24 -0
- package/src/components/PreviewFull.module.css +11 -0
- package/src/components/PreviewGrid.js +14 -0
- package/src/components/PreviewWidget.js +27 -0
- package/src/components/PreviewWidget.module.css +15 -0
- package/src/components/SidebarLayout.jsx +292 -0
- package/src/components/SidebarLayout.module.css +145 -0
- package/src/components/SkeletonLoader.jsx +128 -0
- package/src/components/SkeletonLoader.module.css +295 -0
- package/src/components/SortButtonGroup.jsx +34 -0
- package/src/components/SortButtonGroup.module.css +51 -0
- package/src/components/ToastContainer.jsx +98 -0
- package/src/components/ToastContainer.module.css +156 -0
- package/src/components/ToggleSwitch.js +40 -0
- package/src/components/ToggleSwitch.module.css +48 -0
- package/src/components/TwoColumnInput.jsx +29 -0
- package/src/components/TwoColumnInput.module.css +32 -0
- package/src/components/ViewFull.js +139 -0
- package/src/components/ViewFull.module.css +71 -0
- package/src/components/ViewWidget.js +62 -0
- package/src/components/ViewWidget.module.css +28 -0
- package/src/components/iconCategories.js +135 -0
- package/src/components/iconImports.js +409 -0
- package/src/components/index.js +61 -0
- package/src/components/listing/FileListItem.jsx +86 -0
- package/src/components/listing/GalleryDisplay.jsx +331 -0
- package/src/components/listing/GalleryDisplay.module.css +309 -0
- package/src/components/listing/ListingCTAInput.jsx +82 -0
- package/src/components/listing/ListingDescriptionInput.jsx +73 -0
- package/src/components/listing/ListingField.jsx +101 -0
- package/src/components/listing/ListingField.module.css +106 -0
- package/src/components/listing/ListingFileInput.jsx +255 -0
- package/src/components/listing/ListingFileInput.module.css +192 -0
- package/src/components/listing/ListingForm.jsx +90 -0
- package/src/components/listing/ListingForm.module.css +38 -0
- package/src/components/listing/ListingGalleryInput.jsx +236 -0
- package/src/components/listing/ListingGalleryInput.module.css +131 -0
- package/src/components/listing/ListingImageInput.jsx +153 -0
- package/src/components/listing/ListingTextInput.jsx +72 -0
- package/src/feature.config.js +130 -0
- package/src/helper/index.js +135 -0
- package/src/hooks/useFeatureDefinitionLoader.js +62 -0
- package/src/images/full.png +0 -0
- package/src/images/fullNoTitle.png +0 -0
- package/src/images/previewWidget.png +0 -0
- package/src/images/widget.png +0 -0
- package/src/index.js +38 -0
- package/src/pages/CreateListingPage.jsx +49 -0
- package/src/pages/EditListingPage.jsx +58 -0
- package/src/reducers/featureBuilderReducer.js +744 -0
- package/src/screens/CreateListing.module.css +45 -0
- package/src/screens/Form.module.css +734 -0
- package/src/screens/FormFieldsStep.jsx +689 -0
- package/src/screens/FormLayoutStep.jsx +445 -0
- package/src/screens/FormOverviewStep.jsx +396 -0
- package/src/screens/ListingScreen.jsx +478 -0
- package/src/screens/ListingScreen.module.css +333 -0
- package/src/selectors/featureBuilderSelectors.js +529 -0
- package/src/types/index.js +91 -0
- package/src/utils/textUtils.js +89 -0
- package/src/validators/galleryValidators.js +345 -0
- package/src/values.config.a.js +49 -0
- package/src/values.config.b.js +49 -0
- package/src/values.config.c.js +49 -0
- package/src/values.config.d.js +49 -0
- package/src/values.config.js +49 -0
- package/src/webapi/featureDefinitionActions.js +0 -0
- package/src/webapi/featuresActions.js +90 -0
- package/src/webapi/helper.js +4 -0
- package/src/webapi/index.js +12 -0
- package/src/webapi/listingActions.js +176 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useState } from "react";
|
|
2
|
+
import { SidebarLayout } from "../components/SidebarLayout.jsx";
|
|
3
|
+
import {
|
|
4
|
+
GenericInput,
|
|
5
|
+
Text,
|
|
6
|
+
Button,
|
|
7
|
+
LoadingState,
|
|
8
|
+
SkeletonLoader,
|
|
9
|
+
ErrorBoundary,
|
|
10
|
+
FeatureBuilderWelcomePopup,
|
|
11
|
+
CenteredContainer,
|
|
12
|
+
} from "../components";
|
|
13
|
+
import ToastContainer from "../components/ToastContainer.jsx";
|
|
14
|
+
import { values } from "../values.config.js";
|
|
15
|
+
import { PlussCore } from "../feature.config";
|
|
16
|
+
import { capitalizeTextWithFallback } from "../utils/textUtils";
|
|
17
|
+
import styles from "./Form.module.css";
|
|
18
|
+
import { withRouter } from "react-router-dom";
|
|
19
|
+
|
|
20
|
+
import { useDispatch, useSelector } from "react-redux";
|
|
21
|
+
import {
|
|
22
|
+
setDisplayName,
|
|
23
|
+
setIcon,
|
|
24
|
+
setInitialValues,
|
|
25
|
+
setTitle,
|
|
26
|
+
submitForm,
|
|
27
|
+
clearFormSubmissionState,
|
|
28
|
+
} from "../actions/formActions";
|
|
29
|
+
import {
|
|
30
|
+
selectFormIcon,
|
|
31
|
+
selectFormDisplayName,
|
|
32
|
+
selectFormTitle,
|
|
33
|
+
selectDefinition,
|
|
34
|
+
selectDefinitionIsLoading,
|
|
35
|
+
selectIsCreateMode,
|
|
36
|
+
selectIsEditMode,
|
|
37
|
+
selectIsStepValid,
|
|
38
|
+
selectStepErrors,
|
|
39
|
+
selectWizardMode,
|
|
40
|
+
selectFormIsSubmitting,
|
|
41
|
+
selectFormSubmitError,
|
|
42
|
+
selectFormSubmitSuccess,
|
|
43
|
+
} from "../selectors/featureBuilderSelectors";
|
|
44
|
+
import {
|
|
45
|
+
validateAndUpdateStep,
|
|
46
|
+
setCurrentStepAndSave,
|
|
47
|
+
} from "../actions/wizardActions";
|
|
48
|
+
import IconSelector from "../components/IconSelector.jsx";
|
|
49
|
+
import ExampleDisplay from "../components/ExampleDisplay.jsx";
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Form Overview Step screen component for feature builder wizard
|
|
53
|
+
* Handles feature configuration including title, display name, and icon selection
|
|
54
|
+
* Manages validation, submission, and error handling for overview step
|
|
55
|
+
* Supports both create and edit modes with different behaviors
|
|
56
|
+
*
|
|
57
|
+
* @typedef {Object} FormOverviewStepProps
|
|
58
|
+
* @property {Object} history - React Router history object for navigation
|
|
59
|
+
* @property {Object} location - React Router location object
|
|
60
|
+
*
|
|
61
|
+
* @param {FormOverviewStepProps} props - Component props
|
|
62
|
+
* @returns {React.ReactElement} Form overview step interface
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* <FormOverviewStep history={historyObject} location={locationObject} />
|
|
66
|
+
*/
|
|
67
|
+
const FormOverviewStepInner = (props) => {
|
|
68
|
+
const { history, location } = props;
|
|
69
|
+
const dispatch = useDispatch();
|
|
70
|
+
const auth = useSelector((state) => state.auth);
|
|
71
|
+
|
|
72
|
+
// Get wizard state
|
|
73
|
+
const isCreateMode = useSelector(selectIsCreateMode);
|
|
74
|
+
const isEditMode = useSelector(selectIsEditMode);
|
|
75
|
+
const definition = useSelector(selectDefinition);
|
|
76
|
+
const definitionIsLoading = useSelector(selectDefinitionIsLoading);
|
|
77
|
+
|
|
78
|
+
// Get form state
|
|
79
|
+
const selectedIcon = useSelector(selectFormIcon);
|
|
80
|
+
const title = useSelector(selectFormTitle);
|
|
81
|
+
const displayName = useSelector(selectFormDisplayName);
|
|
82
|
+
|
|
83
|
+
// Get validation state
|
|
84
|
+
const isStepValid = useSelector(selectIsStepValid("overview"));
|
|
85
|
+
const stepErrors = useSelector(selectStepErrors("overview"));
|
|
86
|
+
|
|
87
|
+
// Get submission state
|
|
88
|
+
const isSubmitting = useSelector(selectFormIsSubmitting);
|
|
89
|
+
const submitError = useSelector(selectFormSubmitError);
|
|
90
|
+
const submitSuccess = useSelector(selectFormSubmitSuccess);
|
|
91
|
+
|
|
92
|
+
// State for welcome popup (only show in create mode)
|
|
93
|
+
const [showWelcomePopup, setShowWelcomePopup] = useState(false);
|
|
94
|
+
|
|
95
|
+
// Toast state
|
|
96
|
+
const [toasts, setToasts] = React.useState([]);
|
|
97
|
+
|
|
98
|
+
// Toast management functions
|
|
99
|
+
const addToast = (type, message) => {
|
|
100
|
+
const id = Date.now();
|
|
101
|
+
setToasts((prev) => [...prev, { id, type, message, isVisible: true }]);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const removeToast = (id) => {
|
|
105
|
+
setToasts((prev) => prev.filter((toast) => toast.id !== id));
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Handle redirect after successful save in edit mode
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (submitSuccess && isEditMode && !isSubmitting) {
|
|
111
|
+
// Show toast notification
|
|
112
|
+
addToast("success", "Changes saved");
|
|
113
|
+
|
|
114
|
+
// Clear the success state after a short delay and redirect to overview
|
|
115
|
+
const timer = setTimeout(() => {
|
|
116
|
+
dispatch(clearFormSubmissionState());
|
|
117
|
+
history.push(values.routeFormOverviewStep);
|
|
118
|
+
}, 1500); // Show success message for 1.5 seconds before redirect
|
|
119
|
+
|
|
120
|
+
return () => clearTimeout(timer);
|
|
121
|
+
}
|
|
122
|
+
}, [submitSuccess, isEditMode, isSubmitting, dispatch, history]);
|
|
123
|
+
|
|
124
|
+
// Show toast notification for general success cases
|
|
125
|
+
React.useEffect(() => {
|
|
126
|
+
if (submitSuccess) {
|
|
127
|
+
if (!isEditMode) {
|
|
128
|
+
addToast("success", "Step saved");
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Clear submission state after showing toast (only for non-edit cases)
|
|
132
|
+
if (!isEditMode) {
|
|
133
|
+
const { clearFormSubmissionState } = require("../actions/formActions");
|
|
134
|
+
dispatch(clearFormSubmissionState());
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}, [submitSuccess, isEditMode, dispatch]);
|
|
138
|
+
|
|
139
|
+
// Handle submit error
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
if (submitError) {
|
|
142
|
+
addToast("error", "It didn't work. Please try again.");
|
|
143
|
+
setTimeout(() => {
|
|
144
|
+
window.location.reload();
|
|
145
|
+
}, 1000);
|
|
146
|
+
}
|
|
147
|
+
}, [submitError]);
|
|
148
|
+
|
|
149
|
+
// Error boundary handlers
|
|
150
|
+
const handleRefresh = () => {
|
|
151
|
+
// Refresh current step data
|
|
152
|
+
dispatch(validateAndUpdateStep("overview"));
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const handleBack = () => {
|
|
156
|
+
// Always go to listing screen when going back
|
|
157
|
+
history.push(values.routeListingScreen);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
// Check if we should populate the form from definition
|
|
162
|
+
// Primary condition: edit mode with definition available
|
|
163
|
+
// Fallback condition: definition exists regardless of mode (handles timing issues)
|
|
164
|
+
const shouldPopulateForm =
|
|
165
|
+
definition &&
|
|
166
|
+
!definitionIsLoading &&
|
|
167
|
+
(isEditMode || (definition && !isCreateMode)); // Fallback: if definition exists and we're not in create mode
|
|
168
|
+
|
|
169
|
+
if (shouldPopulateForm) {
|
|
170
|
+
dispatch(setInitialValues(definition));
|
|
171
|
+
|
|
172
|
+
// In edit mode, trigger validation after setting initial values to enable save button
|
|
173
|
+
if (isEditMode) {
|
|
174
|
+
setTimeout(() => {
|
|
175
|
+
dispatch(validateAndUpdateStep("overview"));
|
|
176
|
+
}, 100); // Small delay to ensure state is updated
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}, [definition, definitionIsLoading, isEditMode, isCreateMode, dispatch]);
|
|
180
|
+
|
|
181
|
+
// Show welcome popup on component mount for create mode
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
if (isCreateMode && !definitionIsLoading && !definition) {
|
|
184
|
+
setShowWelcomePopup(true);
|
|
185
|
+
}
|
|
186
|
+
}, [isCreateMode, definitionIsLoading, definition]);
|
|
187
|
+
|
|
188
|
+
// Handle welcome popup close
|
|
189
|
+
const handleWelcomePopupClose = () => {
|
|
190
|
+
setShowWelcomePopup(false);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
function handleNext() {
|
|
194
|
+
// Validate before proceeding - validation will update Redux state
|
|
195
|
+
const validationResult = dispatch(validateAndUpdateStep("overview"));
|
|
196
|
+
|
|
197
|
+
// If validation passes, navigate to next step
|
|
198
|
+
if (validationResult && validationResult.isValid) {
|
|
199
|
+
// Clear form submission state when changing steps
|
|
200
|
+
dispatch(clearFormSubmissionState());
|
|
201
|
+
|
|
202
|
+
if (isCreateMode) {
|
|
203
|
+
history.push(values.routeFormFieldsStep);
|
|
204
|
+
} else {
|
|
205
|
+
// In edit mode, navigate directly
|
|
206
|
+
history.push(values.routeFormFieldsStep);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// If validation fails, the validation errors will be displayed and user can fix them
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function handlePrevious() {
|
|
213
|
+
// Clear form submission state when changing steps
|
|
214
|
+
dispatch(clearFormSubmissionState());
|
|
215
|
+
|
|
216
|
+
// Always go to listing screen after completion
|
|
217
|
+
history.push(values.routeListingScreen);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function handleSaveStep() {
|
|
221
|
+
// Validate before saving in edit mode
|
|
222
|
+
const validationResult = dispatch(validateAndUpdateStep("overview"));
|
|
223
|
+
|
|
224
|
+
// If validation passes, save the entire form
|
|
225
|
+
if (validationResult && validationResult.isValid) {
|
|
226
|
+
dispatch(submitForm());
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function handleTitleChange(ev) {
|
|
231
|
+
dispatch(setTitle(ev.target.value));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function handleSelectIcon(icon) {
|
|
235
|
+
dispatch(setIcon(icon));
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function handleDisplayNameChange(ev) {
|
|
239
|
+
dispatch(setDisplayName(ev.target.value));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Check for definition management permission
|
|
243
|
+
if (
|
|
244
|
+
!PlussCore.Session.validateAccess(
|
|
245
|
+
auth.site,
|
|
246
|
+
values.permissionFeatureBuilderDefinition,
|
|
247
|
+
auth,
|
|
248
|
+
)
|
|
249
|
+
) {
|
|
250
|
+
return (
|
|
251
|
+
<div className="hub-wrapperContainer">
|
|
252
|
+
<div className="hub-contentWrapper">
|
|
253
|
+
<div className={styles.welcomeContainer}>
|
|
254
|
+
<div className={styles.welcomeHeader}>
|
|
255
|
+
<Text type="h1" className={styles.welcomeTitle}>
|
|
256
|
+
Access Restricted
|
|
257
|
+
</Text>
|
|
258
|
+
<Text type="body" className={styles.welcomeSubtitle}>
|
|
259
|
+
You don't have permission to manage feature definitions. Please
|
|
260
|
+
contact your administrator if you need access.
|
|
261
|
+
</Text>
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
</div>
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return (
|
|
270
|
+
<ErrorBoundary
|
|
271
|
+
title="Unable to load overview"
|
|
272
|
+
message="If you continue to experience issues with the overview step, please try refreshing the page or contact support."
|
|
273
|
+
onRetry={handleRefresh}
|
|
274
|
+
>
|
|
275
|
+
<SidebarLayout>
|
|
276
|
+
<Text
|
|
277
|
+
type="formTitleLarge"
|
|
278
|
+
className={`${isEditMode ? styles.editMode : styles.createMode}`}
|
|
279
|
+
>
|
|
280
|
+
{definitionIsLoading
|
|
281
|
+
? "Loading..."
|
|
282
|
+
: isEditMode
|
|
283
|
+
? `Edit Feature: ${capitalizeTextWithFallback(title, "Unnamed")}`
|
|
284
|
+
: "Create New Feature"}
|
|
285
|
+
</Text>
|
|
286
|
+
{definitionIsLoading ? (
|
|
287
|
+
<div className={styles.overviewLoadingContainer}>
|
|
288
|
+
<LoadingState message="Loading feature..." size={48} />
|
|
289
|
+
</div>
|
|
290
|
+
) : (
|
|
291
|
+
<>
|
|
292
|
+
<GenericInput
|
|
293
|
+
label="Feature Name"
|
|
294
|
+
help="Name your feature as it should appear in the Community Manager and the app"
|
|
295
|
+
isRequired
|
|
296
|
+
type="text"
|
|
297
|
+
onChange={handleTitleChange}
|
|
298
|
+
value={title}
|
|
299
|
+
className="mt-8"
|
|
300
|
+
showError={() => {
|
|
301
|
+
return !isStepValid && stepErrors && stepErrors.title;
|
|
302
|
+
}}
|
|
303
|
+
errorMessage="Title is required"
|
|
304
|
+
isValid={() => {
|
|
305
|
+
return title && title.trim().length > 0;
|
|
306
|
+
}}
|
|
307
|
+
/>
|
|
308
|
+
|
|
309
|
+
<IconSelector
|
|
310
|
+
selectedIcon={selectedIcon}
|
|
311
|
+
onIconSelect={handleSelectIcon}
|
|
312
|
+
className=""
|
|
313
|
+
stepErrors={stepErrors}
|
|
314
|
+
showError={() => {
|
|
315
|
+
return !isStepValid && stepErrors && stepErrors.icon;
|
|
316
|
+
}}
|
|
317
|
+
/>
|
|
318
|
+
|
|
319
|
+
<GenericInput
|
|
320
|
+
label="Display Name"
|
|
321
|
+
help="Display name for this feature (used in buttons, notifications, and activity feeds)"
|
|
322
|
+
isRequired
|
|
323
|
+
type="text"
|
|
324
|
+
onChange={handleDisplayNameChange}
|
|
325
|
+
value={displayName}
|
|
326
|
+
className="mt-8"
|
|
327
|
+
showError={() => {
|
|
328
|
+
return !isStepValid && stepErrors && stepErrors.displayName;
|
|
329
|
+
}}
|
|
330
|
+
errorMessage="Display name is required"
|
|
331
|
+
isValid={() => {
|
|
332
|
+
return displayName && displayName.trim().length > 0;
|
|
333
|
+
}}
|
|
334
|
+
/>
|
|
335
|
+
|
|
336
|
+
{/* Examples Display */}
|
|
337
|
+
<ExampleDisplay displayName={displayName} />
|
|
338
|
+
</>
|
|
339
|
+
)}
|
|
340
|
+
|
|
341
|
+
{/* Top-level validation message - positioned above action buttons */}
|
|
342
|
+
{!isStepValid && Object.keys(stepErrors).length > 0 && (
|
|
343
|
+
<div
|
|
344
|
+
className={styles.validationErrorMessage}
|
|
345
|
+
role="alert"
|
|
346
|
+
aria-live="polite"
|
|
347
|
+
>
|
|
348
|
+
{Object.keys(stepErrors).length}{" "}
|
|
349
|
+
{Object.keys(stepErrors).length === 1
|
|
350
|
+
? "field needs"
|
|
351
|
+
: "fields need"}{" "}
|
|
352
|
+
attention before proceeding
|
|
353
|
+
</div>
|
|
354
|
+
)}
|
|
355
|
+
|
|
356
|
+
{/* Mode-aware navigation buttons */}
|
|
357
|
+
<div className={styles.navigation}>
|
|
358
|
+
{isCreateMode ? (
|
|
359
|
+
<Button
|
|
360
|
+
buttonType="primary"
|
|
361
|
+
isActive
|
|
362
|
+
onClick={handleNext}
|
|
363
|
+
leftIcon="arrow-right"
|
|
364
|
+
>
|
|
365
|
+
Next step: Configure Fields
|
|
366
|
+
</Button>
|
|
367
|
+
) : (
|
|
368
|
+
<Button
|
|
369
|
+
buttonType="primary"
|
|
370
|
+
isActive
|
|
371
|
+
onClick={handleSaveStep}
|
|
372
|
+
disabled={!isStepValid || isSubmitting}
|
|
373
|
+
leftIcon={isSubmitting ? "sync" : "save"}
|
|
374
|
+
loading={isSubmitting}
|
|
375
|
+
>
|
|
376
|
+
{isSubmitting ? "Saving..." : "Save"}
|
|
377
|
+
</Button>
|
|
378
|
+
)}
|
|
379
|
+
</div>
|
|
380
|
+
|
|
381
|
+
{/* Submission feedback */}
|
|
382
|
+
</SidebarLayout>
|
|
383
|
+
|
|
384
|
+
{/* Welcome popup for create mode */}
|
|
385
|
+
<FeatureBuilderWelcomePopup
|
|
386
|
+
isOpen={showWelcomePopup}
|
|
387
|
+
onClose={handleWelcomePopupClose}
|
|
388
|
+
/>
|
|
389
|
+
|
|
390
|
+
{/* Toast Container for Notifications */}
|
|
391
|
+
<ToastContainer toasts={toasts} onDismiss={removeToast} />
|
|
392
|
+
</ErrorBoundary>
|
|
393
|
+
);
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
export const FormOverviewStep = withRouter(FormOverviewStepInner);
|