@plusscommunities/pluss-feature-builder-web-a 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.
Files changed (117) hide show
  1. package/.babelrc +4 -0
  2. package/dist/index.cjs.js +7792 -0
  3. package/package.json +54 -0
  4. package/rollup.config.js +68 -0
  5. package/src/actions/featureBuilderStringsActions.js +88 -0
  6. package/src/actions/featureDefinitionsIndex.js +258 -0
  7. package/src/actions/formActions.js +311 -0
  8. package/src/actions/index.js +12 -0
  9. package/src/actions/listingActions.js +350 -0
  10. package/src/actions/wizardActions.js +240 -0
  11. package/src/components/ActivityCardExample.jsx +86 -0
  12. package/src/components/ActivityCardExample.module.css +130 -0
  13. package/src/components/BackgroundLoader.jsx +33 -0
  14. package/src/components/BackgroundLoader.module.css +46 -0
  15. package/src/components/BaseFieldConfig.jsx +305 -0
  16. package/src/components/BaseFieldConfig.module.css +42 -0
  17. package/src/components/CenteredContainer.jsx +29 -0
  18. package/src/components/CenteredContainer.module.css +171 -0
  19. package/src/components/DeleteConfirmationPopup.jsx +95 -0
  20. package/src/components/DeleteConfirmationPopup.module.css +12 -0
  21. package/src/components/ErrorBoundary.jsx +134 -0
  22. package/src/components/ErrorBoundary.module.css +77 -0
  23. package/src/components/ErrorMessage.jsx +85 -0
  24. package/src/components/ErrorMessage.module.css +116 -0
  25. package/src/components/ExampleDisplay.jsx +26 -0
  26. package/src/components/ExampleDisplay.module.css +3 -0
  27. package/src/components/FeatureBuilderSidebar.jsx +84 -0
  28. package/src/components/FeatureBuilderSuccessPopup.jsx +55 -0
  29. package/src/components/FeatureBuilderSuccessPopup.module.css +43 -0
  30. package/src/components/FeatureBuilderWelcomePopup.jsx +51 -0
  31. package/src/components/FeatureBuilderWelcomePopup.module.css +21 -0
  32. package/src/components/FeatureListingCard.jsx +104 -0
  33. package/src/components/FeatureListingCard.module.css +62 -0
  34. package/src/components/Fields.jsx +460 -0
  35. package/src/components/Fields.module.css +159 -0
  36. package/src/components/IconLoader.jsx +153 -0
  37. package/src/components/IconLoader.module.css +92 -0
  38. package/src/components/IconSelector.jsx +112 -0
  39. package/src/components/IconSelector.module.css +197 -0
  40. package/src/components/ListingEditor.jsx +406 -0
  41. package/src/components/ListingEditor.module.css +14 -0
  42. package/src/components/ListingSuccessPopup.jsx +52 -0
  43. package/src/components/LoadingScreen.jsx +54 -0
  44. package/src/components/LoadingScreen.module.css +103 -0
  45. package/src/components/LoadingState.jsx +40 -0
  46. package/src/components/LoadingState.module.css +18 -0
  47. package/src/components/PreviewFull.js +24 -0
  48. package/src/components/PreviewFull.module.css +11 -0
  49. package/src/components/PreviewGrid.js +14 -0
  50. package/src/components/PreviewWidget.js +27 -0
  51. package/src/components/PreviewWidget.module.css +15 -0
  52. package/src/components/SidebarLayout.jsx +292 -0
  53. package/src/components/SidebarLayout.module.css +145 -0
  54. package/src/components/SkeletonLoader.jsx +128 -0
  55. package/src/components/SkeletonLoader.module.css +295 -0
  56. package/src/components/SortButtonGroup.jsx +34 -0
  57. package/src/components/SortButtonGroup.module.css +51 -0
  58. package/src/components/ToastContainer.jsx +98 -0
  59. package/src/components/ToastContainer.module.css +156 -0
  60. package/src/components/ToggleSwitch.js +40 -0
  61. package/src/components/ToggleSwitch.module.css +48 -0
  62. package/src/components/TwoColumnInput.jsx +29 -0
  63. package/src/components/TwoColumnInput.module.css +32 -0
  64. package/src/components/ViewFull.js +139 -0
  65. package/src/components/ViewFull.module.css +71 -0
  66. package/src/components/ViewWidget.js +62 -0
  67. package/src/components/ViewWidget.module.css +28 -0
  68. package/src/components/iconCategories.js +135 -0
  69. package/src/components/iconImports.js +409 -0
  70. package/src/components/index.js +61 -0
  71. package/src/components/listing/FileListItem.jsx +86 -0
  72. package/src/components/listing/GalleryDisplay.jsx +331 -0
  73. package/src/components/listing/GalleryDisplay.module.css +309 -0
  74. package/src/components/listing/ListingCTAInput.jsx +82 -0
  75. package/src/components/listing/ListingDescriptionInput.jsx +73 -0
  76. package/src/components/listing/ListingField.jsx +101 -0
  77. package/src/components/listing/ListingField.module.css +106 -0
  78. package/src/components/listing/ListingFileInput.jsx +255 -0
  79. package/src/components/listing/ListingFileInput.module.css +192 -0
  80. package/src/components/listing/ListingForm.jsx +90 -0
  81. package/src/components/listing/ListingForm.module.css +38 -0
  82. package/src/components/listing/ListingGalleryInput.jsx +236 -0
  83. package/src/components/listing/ListingGalleryInput.module.css +131 -0
  84. package/src/components/listing/ListingImageInput.jsx +153 -0
  85. package/src/components/listing/ListingTextInput.jsx +72 -0
  86. package/src/feature.config.js +130 -0
  87. package/src/helper/index.js +135 -0
  88. package/src/hooks/useFeatureDefinitionLoader.js +62 -0
  89. package/src/images/full.png +0 -0
  90. package/src/images/fullNoTitle.png +0 -0
  91. package/src/images/previewWidget.png +0 -0
  92. package/src/images/widget.png +0 -0
  93. package/src/index.js +38 -0
  94. package/src/pages/CreateListingPage.jsx +49 -0
  95. package/src/pages/EditListingPage.jsx +58 -0
  96. package/src/reducers/featureBuilderReducer.js +744 -0
  97. package/src/screens/CreateListing.module.css +45 -0
  98. package/src/screens/Form.module.css +734 -0
  99. package/src/screens/FormFieldsStep.jsx +689 -0
  100. package/src/screens/FormLayoutStep.jsx +445 -0
  101. package/src/screens/FormOverviewStep.jsx +396 -0
  102. package/src/screens/ListingScreen.jsx +478 -0
  103. package/src/screens/ListingScreen.module.css +333 -0
  104. package/src/selectors/featureBuilderSelectors.js +529 -0
  105. package/src/types/index.js +91 -0
  106. package/src/utils/textUtils.js +89 -0
  107. package/src/validators/galleryValidators.js +345 -0
  108. package/src/values.config.a.js +49 -0
  109. package/src/values.config.b.js +49 -0
  110. package/src/values.config.c.js +49 -0
  111. package/src/values.config.d.js +49 -0
  112. package/src/values.config.js +49 -0
  113. package/src/webapi/featureDefinitionActions.js +0 -0
  114. package/src/webapi/featuresActions.js +90 -0
  115. package/src/webapi/helper.js +4 -0
  116. package/src/webapi/index.js +12 -0
  117. package/src/webapi/listingActions.js +176 -0
@@ -0,0 +1,134 @@
1
+ import React from "react";
2
+ import { PlussCore } from "../feature.config";
3
+
4
+ const { Components } = PlussCore;
5
+ const { Text, Button } = Components;
6
+ import styles from "./ErrorBoundary.module.css";
7
+
8
+
9
+ class ErrorBoundary extends React.Component {
10
+ constructor(props) {
11
+ super(props);
12
+ this.state = {
13
+ hasError: false,
14
+ error: null,
15
+ errorInfo: null,
16
+ };
17
+ }
18
+
19
+ static getDerivedStateFromError(error) {
20
+ return { hasError: true };
21
+ }
22
+
23
+ componentDidCatch(error, errorInfo) {
24
+ this.setState({
25
+ error: error,
26
+ errorInfo: errorInfo,
27
+ });
28
+ }
29
+
30
+ handleRetry = () => {
31
+ this.setState({
32
+ hasError: false,
33
+ error: null,
34
+ errorInfo: null,
35
+ });
36
+
37
+ if (this.props.onRetry) {
38
+ this.props.onRetry();
39
+ } else {
40
+ window.location.reload();
41
+ }
42
+ };
43
+
44
+ render() {
45
+ if (this.state.hasError) {
46
+ const {
47
+ title = "Oops! Something went wrong",
48
+ message = "We encountered an unexpected error. Please try again.",
49
+ } = this.props;
50
+
51
+ return (
52
+ <div className="text-center p-6">
53
+ <div className="mb-4">
54
+ <span className={styles.errorIcon}>
55
+
56
+ </span>
57
+ </div>
58
+
59
+ <Text
60
+ type="h2"
61
+ className="mb-4"
62
+ className={styles.errorTitle}
63
+ >
64
+ {title}
65
+ </Text>
66
+
67
+ <Text
68
+ type="body"
69
+ className="mb-6"
70
+ className={styles.errorMessage}
71
+ >
72
+ {message}
73
+ </Text>
74
+
75
+ <Button buttonType="primary" onClick={this.handleRetry}>
76
+ Try Again
77
+ </Button>
78
+
79
+ {process.env.NODE_ENV === "development" && this.state.error && (
80
+ <details className="mt-6 text-left">
81
+ <summary
82
+ className={`cursor-pointer font-bold p-2 bg-gray-50 border rounded mb-3 ${styles.errorDetails}`}
83
+ >
84
+ Error Details (Development Only)
85
+ </summary>
86
+ <div
87
+ className={`p-4 bg-gray-50 border rounded ${styles.errorDetailsContent}`}
88
+ >
89
+ <div className="mb-4">
90
+ <strong className={styles.errorDetailsTitle}>
91
+ Error:
92
+ </strong>
93
+ <pre
94
+ className={`${styles.errorStack}`}
95
+ >
96
+ {this.state.error.toString()}
97
+ </pre>
98
+ </div>
99
+
100
+ {this.state.errorInfo && (
101
+ <div className="mb-4">
102
+ <strong className={styles.componentStackTitle}>
103
+ Component Stack:
104
+ </strong>
105
+ <pre className={`${styles.componentStack}`}>
106
+ >
107
+ {this.state.errorInfo.componentStack}
108
+ </pre>
109
+ </div>
110
+ )}
111
+
112
+ {this.state.error.stack && (
113
+ <div>
114
+ <strong className={styles.componentStackTitle}>
115
+ Stack Trace:
116
+ </strong>
117
+ <pre className={`${styles.componentStack}`}>
118
+ >
119
+ {this.state.error.stack}
120
+ </pre>
121
+ </div>
122
+ )}
123
+ </div>
124
+ </details>
125
+ )}
126
+ </div>
127
+ );
128
+ }
129
+
130
+ return this.props.children;
131
+ }
132
+ }
133
+
134
+ export { ErrorBoundary };
@@ -0,0 +1,77 @@
1
+ /* Error icon */
2
+ .errorIcon {
3
+ font-size: 3rem;
4
+ color: var(--colour-red);
5
+ }
6
+
7
+ /* Error title */
8
+ .errorTitle {
9
+ color: var(--colour-red);
10
+ }
11
+
12
+ /* Error message */
13
+ .errorMessage {
14
+ color: var(--text-dark);
15
+ }
16
+
17
+ /* Error details section */
18
+ .errorDetails {
19
+ color: var(--text-dark);
20
+ background-color: var(--bg-bluegrey);
21
+ padding: 8px;
22
+ margin-bottom: 8px;
23
+ font-weight: bold;
24
+ cursor: pointer;
25
+ }
26
+
27
+ /* Error details content */
28
+ .errorDetailsContent {
29
+ background-color: var(--bg-bluegrey);
30
+ padding: 16px;
31
+ margin-bottom: 16px;
32
+ }
33
+
34
+ /* Error details title */
35
+ .errorDetailsTitle {
36
+ display: block;
37
+ margin-bottom: 8px;
38
+ }
39
+
40
+ /* Error stack trace */
41
+ .errorStack {
42
+ font-size: 0.75rem;
43
+ line-height: 1.4;
44
+ overflow-x: auto;
45
+ background: #f8f9fa;
46
+ padding: 12px;
47
+ border-radius: 4px;
48
+ margin: 0;
49
+ color: var(--text-mid);
50
+ background-color: var(--bg-white);
51
+ border: 1px solid var(--colour-branding-inactive);
52
+ white-space: pre-wrap;
53
+ word-wrap: break-word;
54
+ }
55
+
56
+ /* Component stack */
57
+ .componentStackTitle {
58
+ display: block;
59
+ margin-bottom: 8px;
60
+ color: var(--text-dark);
61
+ }
62
+
63
+ .componentStack {
64
+ font-size: 0.75rem;
65
+ line-height: 1.4;
66
+ font-family: monospace;
67
+ background: #f8f9fa;
68
+ padding: 12px;
69
+ border-radius: 4px;
70
+ margin: 0;
71
+ overflow-x: auto;
72
+ white-space: pre-wrap;
73
+ word-wrap: break-word;
74
+ color: var(--text-mid);
75
+ background-color: var(--bg-white);
76
+ border: 1px solid var(--colour-branding-inactive);
77
+ }
@@ -0,0 +1,85 @@
1
+ import React from "react";
2
+ import { PlussCore } from "../feature.config";
3
+ import styles from "./ErrorMessage.module.css";
4
+
5
+ const { Components } = PlussCore;
6
+ const { FontAwesomeIcon } = Components;
7
+
8
+ const ErrorMessage = ({
9
+ message,
10
+ onClose,
11
+ variant = "error",
12
+ showIcon = true,
13
+ className = "",
14
+ style = {},
15
+ }) => {
16
+ if (!message) return null;
17
+
18
+ const getIcon = () => {
19
+ switch (variant) {
20
+ case "error":
21
+ return "exclamation-circle";
22
+ case "warning":
23
+ return "exclamation-triangle";
24
+ case "success":
25
+ return "check-circle";
26
+ case "info":
27
+ return "info-circle";
28
+ default:
29
+ return "exclamation-circle";
30
+ }
31
+ };
32
+
33
+ const getTextIcon = () => {
34
+ switch (variant) {
35
+ case "error":
36
+ return "⚠";
37
+ case "warning":
38
+ return "⚠";
39
+ case "success":
40
+ return "✓";
41
+ case "info":
42
+ return "ℹ";
43
+ default:
44
+ return "⚠";
45
+ }
46
+ };
47
+
48
+ const getClassName = () => {
49
+ const baseClassName = styles.root;
50
+ const variantClassName = styles[`root--${variant}`];
51
+ const closableClassName = onClose ? styles["root--closable"] : "";
52
+ return [baseClassName, variantClassName, closableClassName, className]
53
+ .filter(Boolean)
54
+ .join(" ");
55
+ };
56
+
57
+ return (
58
+ <div className={getClassName()} style={style}>
59
+ <div className={styles.content}>
60
+ {showIcon && (
61
+ <span className={styles.icon}>
62
+ {FontAwesomeIcon ? (
63
+ <FontAwesomeIcon icon={getIcon()} />
64
+ ) : (
65
+ getTextIcon()
66
+ )}
67
+ </span>
68
+ )}
69
+ <span className={styles.text}>{message}</span>
70
+ </div>
71
+ {onClose && (
72
+ <button
73
+ type="button"
74
+ className={styles.close}
75
+ onClick={onClose}
76
+ aria-label="Dismiss error"
77
+ >
78
+ {FontAwesomeIcon ? <FontAwesomeIcon icon="times" /> : "×"}
79
+ </button>
80
+ )}
81
+ </div>
82
+ );
83
+ };
84
+
85
+ export { ErrorMessage };
@@ -0,0 +1,116 @@
1
+ /* ErrorMessage CSS Module */
2
+
3
+ /* Block */
4
+ .root {
5
+ display: flex;
6
+ align-items: center;
7
+ justify-content: space-between;
8
+ padding: 12px 16px;
9
+ border-radius: 4px;
10
+ margin-bottom: 16px;
11
+ border: 1px solid;
12
+ font-size: var(--font-size-sm);
13
+ line-height: 1.4;
14
+ }
15
+
16
+ /* Content wrapper */
17
+ .content {
18
+ display: flex;
19
+ align-items: center;
20
+ flex: 1;
21
+ gap: 8px;
22
+ }
23
+
24
+ .icon {
25
+ flex-shrink: 0;
26
+ font-size: var(--font-size-base);
27
+ }
28
+
29
+ .text {
30
+ flex: 1;
31
+ word-wrap: break-word;
32
+ }
33
+
34
+ /* Close button */
35
+ .close {
36
+ background: none;
37
+ border: none;
38
+ cursor: pointer;
39
+ padding: 4px;
40
+ margin-left: 8px;
41
+ display: flex;
42
+ align-items: center;
43
+ justify-content: center;
44
+ color: inherit;
45
+ opacity: 0.7;
46
+ transition: opacity 0.2s ease;
47
+ border-radius: 2px;
48
+ flex-shrink: 0;
49
+ }
50
+
51
+ .close:hover {
52
+ opacity: 1;
53
+ background-color: rgba(255, 255, 255, 0.1);
54
+ }
55
+
56
+ /* Variants */
57
+ .root--error {
58
+ background-color: #f8d7da;
59
+ color: #721c24;
60
+ border-color: #f5c6cb;
61
+ }
62
+
63
+ .root--error .close:hover {
64
+ background-color: rgba(114, 28, 36, 0.1);
65
+ }
66
+
67
+ .root--warning {
68
+ background-color: #fff3cd;
69
+ color: #856404;
70
+ border-color: #ffeaa7;
71
+ }
72
+
73
+ .root--warning .close:hover {
74
+ background-color: rgba(133, 100, 4, 0.1);
75
+ }
76
+
77
+ .root--success {
78
+ background-color: #d4edda;
79
+ color: #155724;
80
+ border-color: #c3e6cb;
81
+ }
82
+
83
+ .root--success .close:hover {
84
+ background-color: rgba(21, 87, 36, 0.1);
85
+ }
86
+
87
+ .root--info {
88
+ background-color: #d1ecf1;
89
+ color: #0c5460;
90
+ border-color: #bee5eb;
91
+ }
92
+
93
+ .root--info .close:hover {
94
+ background-color: rgba(12, 84, 96, 0.1);
95
+ }
96
+
97
+ /* Closable modifier for additional spacing */
98
+ .root--closable {
99
+ padding-right: 12px;
100
+ }
101
+
102
+ /* Responsive adjustments */
103
+ @media (max-width: 768px) {
104
+ .root {
105
+ padding: 10px 12px;
106
+ font-size: var(--font-size-sm);
107
+ }
108
+
109
+ .content {
110
+ gap: 6px;
111
+ }
112
+
113
+ .icon {
114
+ font-size: var(--font-size-sm);
115
+ }
116
+ }
@@ -0,0 +1,26 @@
1
+ import React from "react";
2
+ import ActivityCardExample from "./ActivityCardExample.jsx";
3
+ import styles from "./ExampleDisplay.module.css";
4
+
5
+ /**
6
+ * Example Display component for feature preview
7
+ * Shows how feature cards will appear in the app
8
+ * Wraps ActivityCardExample with proper styling
9
+ *
10
+ * @param {Object} props - Component props
11
+ * @param {string} props.displayName - Feature name to display in preview
12
+ * @returns {React.ReactElement} Example feature card display
13
+ *
14
+ * @example
15
+ * <ExampleDisplay displayName="Contact Form" />
16
+ */
17
+ const ExampleDisplay = ({ displayName }) => {
18
+ return (
19
+ <div className={styles.exampleDisplay}>
20
+ {/* Activity Card Example */}
21
+ <ActivityCardExample displayName={displayName} />
22
+ </div>
23
+ );
24
+ };
25
+
26
+ export default ExampleDisplay;
@@ -0,0 +1,3 @@
1
+ /* Example Display Component Styles */
2
+ .exampleDisplay {
3
+ }
@@ -0,0 +1,84 @@
1
+ import React from "react";
2
+ import { withRouter } from "react-router";
3
+ import { useSelector } from "react-redux";
4
+ import { PlussCore } from "../feature.config";
5
+ import { values } from "../values.config.js";
6
+ import { selectDefinition } from "../selectors/featureBuilderSelectors";
7
+ import { capitalizeTextWithFallback } from "../utils/textUtils";
8
+
9
+ const { HubSidebar } = PlussCore.Components;
10
+
11
+ const FeatureBuilderSidebar = ({ history, onCreate }) => {
12
+ // Get the actual feature definition
13
+ const definition = useSelector(selectDefinition);
14
+
15
+ // Extract title and display name from definition
16
+ const featureTitle = definition && definition.title;
17
+ const featureDisplayName = definition && definition.displayName;
18
+
19
+ // Check if we're in edit mode (URL contains /edit/)
20
+ const isEditMode = history.location.pathname.includes("/edit/");
21
+
22
+ // Get listing title from URL for edit mode
23
+ const getListingTitleFromUrl = () => {
24
+ const pathParts = history.location.pathname.split("/");
25
+ const editIndex = pathParts.indexOf("edit");
26
+ if (editIndex !== -1 && pathParts.length > editIndex + 1) {
27
+ return pathParts[editIndex + 1]; // Get the ID after 'edit/'
28
+ }
29
+ return null;
30
+ };
31
+
32
+ // Use feature title for section title, fallback to values config
33
+ const sectionTitle = featureTitle || values.singularName;
34
+
35
+ // Navigate to create listing
36
+ const handleCreateListing = () => {
37
+ if (onCreate) {
38
+ onCreate();
39
+ } else {
40
+ history.push(values.routeCreateListing);
41
+ }
42
+ };
43
+
44
+ // Navigate to listing view
45
+ const handleViewListing = () => {
46
+ history.push(values.routeListingScreen);
47
+ };
48
+
49
+ // Build sidebar sections
50
+ const sections = [
51
+ {
52
+ title: sectionTitle,
53
+ items: [
54
+ {
55
+ type: "newButton",
56
+ text: `Create new ${capitalizeTextWithFallback(featureDisplayName, "listing")}`,
57
+ onClick: handleCreateListing,
58
+ buttonType: "outlined",
59
+ },
60
+ {
61
+ type: "navItem",
62
+ text:
63
+ isEditMode && getListingTitleFromUrl()
64
+ ? `Edit ${capitalizeTextWithFallback(featureDisplayName, "listing")}: ${getListingTitleFromUrl()}`
65
+ : `View ${capitalizeTextWithFallback(featureDisplayName, "listing")} listing`,
66
+ icon: "eye",
67
+ isFontAwesome: true,
68
+ selected: history.location.pathname === values.routeListingScreen,
69
+ onClick: handleViewListing,
70
+ },
71
+ ],
72
+ },
73
+ ];
74
+
75
+ // Help guide configuration
76
+ const helpGuide = {
77
+ text: "Help",
78
+ url: "https://www.plusscommunities.com/user-guide",
79
+ };
80
+
81
+ return <HubSidebar sections={sections} helpGuide={helpGuide} />;
82
+ };
83
+
84
+ export default withRouter(FeatureBuilderSidebar);
@@ -0,0 +1,55 @@
1
+ import React from "react";
2
+ import { PlussCore } from "../feature.config";
3
+ const { Components } = PlussCore;
4
+ const { Popup } = Components;
5
+ import styles from "./FeatureBuilderSuccessPopup.module.css";
6
+
7
+ const FeatureBuilderSuccessPopup = ({
8
+ isOpen,
9
+ onClose,
10
+ featureName,
11
+ displayName,
12
+ }) => {
13
+ if (!isOpen) {
14
+ return null;
15
+ }
16
+
17
+ const buttons = [
18
+ {
19
+ type: "primary",
20
+ text: "Got it",
21
+ onClick: onClose,
22
+ isActive: true,
23
+ },
24
+ ];
25
+
26
+ return (
27
+ <Popup
28
+ title={`${featureName} Created`}
29
+ subtitle={
30
+ <>
31
+ <span>{featureName}</span> is now saved and available for your
32
+ communities!
33
+ </>
34
+ }
35
+ onClose={onClose}
36
+ buttons={buttons}
37
+ hasPadding
38
+ minWidth={500}
39
+ maxWidth={600}
40
+ >
41
+ <div className={styles.successContent}>
42
+ <div className={styles.successMessage}>
43
+ To activate this feature, please add it to your sites using the
44
+ Feature Picker.
45
+ </div>
46
+ <div className={styles.successMessage}>
47
+ Team members with the right permissions can start creating content for
48
+ the communities that have installed the feature.
49
+ </div>
50
+ </div>
51
+ </Popup>
52
+ );
53
+ };
54
+
55
+ export { FeatureBuilderSuccessPopup };
@@ -0,0 +1,43 @@
1
+ .successContent {
2
+ display: flex;
3
+ flex-direction: column;
4
+ align-items: center;
5
+ gap: 20px;
6
+ padding: 20px 0;
7
+ }
8
+
9
+ .gifPlaceholder {
10
+ width: 100%;
11
+ max-width: 400px;
12
+ }
13
+
14
+ .gifContainer {
15
+ width: 100%;
16
+ height: 200px;
17
+ background-color: #f5f5f5;
18
+ border: 2px dashed #ccc;
19
+ border-radius: 8px;
20
+ display: flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ }
24
+
25
+ .gifPlaceholderText {
26
+ color: #999;
27
+ font-size: 14px;
28
+ text-align: center;
29
+ padding: 20px;
30
+ }
31
+
32
+ .successMessage {
33
+ text-align: center;
34
+ color: #666;
35
+ font-size: 16px;
36
+ line-height: 1.5;
37
+ max-width: 400px;
38
+ }
39
+
40
+ .featureName {
41
+ font-weight: 600;
42
+ color: #333;
43
+ }
@@ -0,0 +1,51 @@
1
+ import React from "react";
2
+ import { PlussCore } from "../feature.config";
3
+ const { Components } = PlussCore;
4
+ const { Popup } = Components;
5
+ import styles from "./FeatureBuilderWelcomePopup.module.css";
6
+ const { Text } = Components;
7
+
8
+ const FeatureBuilderWelcomePopup = ({ isOpen, onClose }) => {
9
+ if (!isOpen) {
10
+ return null;
11
+ }
12
+
13
+ const buttons = [
14
+ {
15
+ type: "primary",
16
+ text: "Get Started",
17
+ onClick: onClose,
18
+ isActive: true,
19
+ },
20
+ ];
21
+
22
+ return (
23
+ <Popup
24
+ title="Create a Custom Feature"
25
+ onClose={onClose}
26
+ buttons={buttons}
27
+ hasPadding
28
+ minWidth={600}
29
+ maxWidth={700}
30
+ >
31
+ <div className={styles.welcomeContent}>
32
+ <div className={styles.welcomeMessage}>
33
+ <Text type="bodyLarge">
34
+ Use this form to set up a new feature, such as "Hospitality" or
35
+ "Meet the Team."
36
+ </Text>
37
+ <Text type="bodyLarge">
38
+ You will select the name, the icon, and the specific details
39
+ required. This ensures the feature looks the same at every site.
40
+ </Text>
41
+ <Text type="bodyLarge">
42
+ Once you finish, you can install the feature on any site and
43
+ authorized users can manage its content.
44
+ </Text>
45
+ </div>
46
+ </div>
47
+ </Popup>
48
+ );
49
+ };
50
+
51
+ export { FeatureBuilderWelcomePopup };
@@ -0,0 +1,21 @@
1
+ .welcomeContent {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: 20px;
5
+ padding: 20px 0;
6
+ }
7
+
8
+ .welcomeMessage {
9
+ color: #666;
10
+ font-size: 16px;
11
+ line-height: 1.6;
12
+ width: 100%;
13
+ }
14
+
15
+ .welcomeMessage p {
16
+ margin: 0 0 16px 0;
17
+ }
18
+
19
+ .welcomeMessage p:last-child {
20
+ margin-bottom: 0;
21
+ }