@griddo/ax 10.4.7 → 10.4.8
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/package.json +2 -2
- package/src/__tests__/components/Browser/Browser.test.tsx +4 -4
- package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/MixableComponentArray.test.tsx +39 -7
- package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/PasteModuleButton.test.tsx +8 -8
- package/src/__tests__/components/Fields/ComponentContainer/ComponentContainer.test.tsx +28 -16
- package/src/components/Browser/index.tsx +5 -5
- package/src/components/BulkSelectionOptions/style.tsx +1 -0
- package/src/components/ConfigPanel/Header/index.tsx +8 -4
- package/src/components/Fields/AsyncCheckGroup/style.tsx +3 -0
- package/src/components/Fields/CheckField/index.tsx +4 -1
- package/src/components/Fields/CheckField/style.tsx +19 -3
- package/src/components/Fields/CheckGroup/index.tsx +3 -2
- package/src/components/Fields/CheckGroup/style.tsx +3 -0
- package/src/components/Fields/ComponentArray/MixableComponentArray/BulkHeader/index.tsx +47 -0
- package/src/components/Fields/ComponentArray/MixableComponentArray/BulkHeader/style.tsx +44 -0
- package/src/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/index.tsx +31 -12
- package/src/components/Fields/ComponentArray/MixableComponentArray/index.tsx +153 -59
- package/src/components/Fields/ComponentArray/SameComponentArray/index.tsx +1 -1
- package/src/components/Fields/ComponentArray/helpers.tsx +45 -4
- package/src/components/Fields/ComponentContainer/EmptyContainer/index.tsx +2 -2
- package/src/components/Fields/ComponentContainer/index.tsx +68 -33
- package/src/components/Fields/ComponentContainer/style.tsx +78 -11
- package/src/components/Fields/ReferenceField/Context/index.tsx +1 -1
- package/src/components/MainWrapper/AppBar/atoms.tsx +5 -8
- package/src/components/SideModal/SideModalOption/index.tsx +5 -3
- package/src/containers/Navigation/Defaults/actions.tsx +86 -55
- package/src/containers/Navigation/Defaults/interfaces.tsx +2 -2
- package/src/containers/Navigation/Defaults/reducer.tsx +3 -3
- package/src/containers/PageEditor/actions.tsx +142 -109
- package/src/containers/PageEditor/interfaces.tsx +1 -1
- package/src/containers/PageEditor/reducer.tsx +2 -2
- package/src/containers/PageEditor/utils.tsx +1 -1
- package/src/containers/Settings/DataPacks/actions.tsx +7 -2
- package/src/forms/elements.tsx +20 -14
- package/src/hooks/bulk.tsx +57 -2
- package/src/hooks/iframe.ts +5 -5
- package/src/modules/Content/index.tsx +10 -1
- package/src/modules/FramePreview/index.tsx +4 -4
- package/src/modules/GlobalEditor/Editor/index.tsx +6 -6
- package/src/modules/GlobalEditor/PageBrowser/index.tsx +2 -2
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +6 -6
- package/src/modules/PageEditor/Editor/index.tsx +7 -7
- package/src/modules/PageEditor/PageBrowser/index.tsx +2 -2
- package/src/modules/Users/UserForm/index.tsx +52 -34
- package/src/types/index.tsx +1 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import
|
|
3
|
-
import { DragDropContext, Droppable, Draggable, DropResult } from "react-beautiful-dnd";
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { DragDropContext, Droppable, Draggable, DropResult, BeforeCapture } from "react-beautiful-dnd";
|
|
4
3
|
|
|
5
|
-
import { IModule } from "@ax/types";
|
|
6
|
-
import { ComponentContainer, SideModal } from "@ax/components";
|
|
7
|
-
import { useModal } from "@ax/hooks";
|
|
4
|
+
import { IModule, INotification, ISchemaField } from "@ax/types";
|
|
5
|
+
import { ComponentContainer, SideModal, Toast } from "@ax/components";
|
|
6
|
+
import { useBulkSelection, useModal, useToast } from "@ax/hooks";
|
|
8
7
|
|
|
9
|
-
import { getComponentProps, containerToComponentArray, getTypefromKey } from "../helpers";
|
|
8
|
+
import { getComponentProps, containerToComponentArray, getTypefromKey, getModulesToPaste } from "../helpers";
|
|
10
9
|
import AddItemButton from "./AddItemButton";
|
|
11
10
|
import PasteModuleButton from "./PasteModuleButton";
|
|
11
|
+
import BulkHeader from "./BulkHeader";
|
|
12
12
|
|
|
13
13
|
import * as S from "./style";
|
|
14
14
|
|
|
@@ -35,36 +35,45 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
35
35
|
setHistoryPush,
|
|
36
36
|
} = props;
|
|
37
37
|
|
|
38
|
-
const
|
|
38
|
+
const {
|
|
39
|
+
addModuleAction,
|
|
40
|
+
addComponentAction,
|
|
41
|
+
deleteModuleAction,
|
|
42
|
+
replaceElementsInCollectionAction,
|
|
43
|
+
pasteModuleAction,
|
|
44
|
+
setNotificationAction,
|
|
45
|
+
copyModuleAction,
|
|
46
|
+
duplicateModuleAction,
|
|
47
|
+
} = actions || {};
|
|
39
48
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}, null);
|
|
49
|
+
// fix for old not array values
|
|
50
|
+
const fixedValue = Array.isArray(value) ? value : containerToComponentArray(value);
|
|
51
|
+
const componentIDs: number[] = fixedValue.map((element: any) => element.editorID);
|
|
44
52
|
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
const { modulesToPaste, unavailableModules } = getModulesToPaste(
|
|
54
|
+
moduleCopy,
|
|
55
|
+
whiteList,
|
|
56
|
+
availableDataPacks,
|
|
57
|
+
template,
|
|
58
|
+
field
|
|
59
|
+
);
|
|
49
60
|
|
|
50
61
|
const type = getTypefromKey(objKey);
|
|
51
62
|
const { contentType = type } = field;
|
|
52
63
|
const { isOpen, toggleModal } = useModal();
|
|
64
|
+
const [isBulkOpen, setIsBulkOpen] = useState(false);
|
|
65
|
+
const [draggingId, setDraggingId] = useState<number | null>(null);
|
|
66
|
+
const { isVisible, toggleToast, setIsVisible, state: toastState } = useToast();
|
|
53
67
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
let deleteModuleAction: any;
|
|
57
|
-
let replaceElementsInCollectionAction: any;
|
|
58
|
-
|
|
59
|
-
if (actions) {
|
|
60
|
-
addModuleAction = actions.addModuleAction;
|
|
61
|
-
addComponentAction = actions.addComponentAction;
|
|
62
|
-
deleteModuleAction = actions.deleteModuleAction;
|
|
63
|
-
replaceElementsInCollectionAction = actions.replaceElementsInCollectionAction;
|
|
64
|
-
}
|
|
68
|
+
const { resetBulkSelection, selectedItems, isSelected, checkState, addToBulkSelection, selectAllItems } =
|
|
69
|
+
useBulkSelection(componentIDs);
|
|
65
70
|
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
if (selectedItems.all.length) {
|
|
73
|
+
setIsBulkOpen(true);
|
|
74
|
+
}
|
|
75
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
76
|
+
}, [selectedItems.all]);
|
|
68
77
|
|
|
69
78
|
const getText = (name: string, index: number) => {
|
|
70
79
|
return fixedValue.length > 1 ? `#${index + 1} ${name}` : name;
|
|
@@ -73,7 +82,8 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
73
82
|
const isComponentModule = contentType === "components";
|
|
74
83
|
const isModuleArr = contentType === "modules";
|
|
75
84
|
|
|
76
|
-
const handleAddModule = (moduleType: string) =>
|
|
85
|
+
const handleAddModule = (moduleType: string) =>
|
|
86
|
+
addModuleAction && addModuleAction(moduleType, objKey, editorID, isComponentModule);
|
|
77
87
|
|
|
78
88
|
const handleAddComponent = (componentType: string) => addComponentAction && addComponentAction(componentType, objKey);
|
|
79
89
|
|
|
@@ -81,27 +91,23 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
81
91
|
|
|
82
92
|
const handleModuleReplace = (moduleType: string) => {
|
|
83
93
|
const { modules } = selectedContent;
|
|
84
|
-
if (isModuleArr) {
|
|
85
|
-
const currentModule = modules[0];
|
|
86
|
-
deleteModuleAction(currentModule
|
|
94
|
+
if (isModuleArr && deleteModuleAction && modules?.length > 0) {
|
|
95
|
+
const currentModule: IModule = modules[0];
|
|
96
|
+
deleteModuleAction([currentModule.editorID], contentType);
|
|
87
97
|
handleAddModule(moduleType);
|
|
88
98
|
} else {
|
|
89
|
-
replaceElementsInCollectionAction(moduleType);
|
|
99
|
+
replaceElementsInCollectionAction && replaceElementsInCollectionAction(moduleType);
|
|
90
100
|
}
|
|
91
101
|
};
|
|
92
102
|
|
|
93
|
-
const
|
|
94
|
-
differenceInSeconds(new Date(), new Date(moduleCopy.date));
|
|
103
|
+
const selectItems = () => (checkState.isAllSelected ? resetBulkSelection() : selectAllItems());
|
|
95
104
|
|
|
96
105
|
const showAddItemButton = (!maxItems || fixedValue.length < maxItems) && !disabled;
|
|
97
|
-
const eightHoursInSeconds = 8 * 60 * 60;
|
|
98
106
|
|
|
99
|
-
const showPasteModuleButton
|
|
107
|
+
const showPasteModuleButton =
|
|
100
108
|
showAddItemButton &&
|
|
101
109
|
(isModuleArr || objKey === "componentModules") &&
|
|
102
|
-
|
|
103
|
-
getTimeSinceModuleCopy(moduleCopy) < eightHoursInSeconds &&
|
|
104
|
-
(whiteList.includes(moduleCopyComponent) || isModuleCopyUnavailable);
|
|
110
|
+
(modulesToPaste.length > 0 || unavailableModules.length > 0);
|
|
105
111
|
|
|
106
112
|
const canReplace = maxItems === 1 && whiteList.length > 1;
|
|
107
113
|
const displayReplaceSideModal = fixedValue.length > 0 && canReplace;
|
|
@@ -110,7 +116,7 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
110
116
|
const Asterisk = () => (mandatory ? <S.Asterisk>*</S.Asterisk> : null);
|
|
111
117
|
|
|
112
118
|
const ComponentList = React.memo(function ComponentList({ components }: any) {
|
|
113
|
-
return components.map((element:
|
|
119
|
+
return components.map((element: IModule, i: number) => {
|
|
114
120
|
const { editorID } = element;
|
|
115
121
|
const { moduleTitle, isModuleDeactivated, componentTitle, displayName, isModule } = getComponentProps(
|
|
116
122
|
element,
|
|
@@ -118,9 +124,14 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
118
124
|
isModuleArr
|
|
119
125
|
);
|
|
120
126
|
const text = getText(componentTitle || displayName, i);
|
|
127
|
+
const isItemSelected = isSelected(editorID);
|
|
128
|
+
const isDraggingSelected = selectedItems.all.includes(draggingId);
|
|
129
|
+
const isGhosting = isItemSelected && !!draggingId && draggingId !== editorID && isDraggingSelected;
|
|
130
|
+
const isMultiDragging = selectedItems.all.length > 1 && draggingId === editorID;
|
|
131
|
+
|
|
121
132
|
return (
|
|
122
133
|
<Draggable draggableId={`${editorID}`} index={i} key={editorID}>
|
|
123
|
-
{(provided) => (
|
|
134
|
+
{(provided, snapshot) => (
|
|
124
135
|
<ComponentContainer
|
|
125
136
|
actionReplace={toggleModal}
|
|
126
137
|
canReplace={canReplace}
|
|
@@ -142,6 +153,13 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
142
153
|
innerRef={provided.innerRef}
|
|
143
154
|
provided={provided}
|
|
144
155
|
isModule={isModule}
|
|
156
|
+
isSelected={isItemSelected}
|
|
157
|
+
onChange={addToBulkSelection}
|
|
158
|
+
hasMenu={selectedItems.all.length > 0}
|
|
159
|
+
toggleToast={toggleToast}
|
|
160
|
+
isMultiDragging={snapshot.isDragging && isMultiDragging}
|
|
161
|
+
draggingCount={selectedItems.all.length}
|
|
162
|
+
className={`${isGhosting ? "ghosting" : ""} ${snapshot.isDragging && isMultiDragging ? "dragging" : ""}`}
|
|
145
163
|
/>
|
|
146
164
|
)}
|
|
147
165
|
</Draggable>
|
|
@@ -150,17 +168,69 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
150
168
|
});
|
|
151
169
|
|
|
152
170
|
const onDragEnd = (result: DropResult) => {
|
|
153
|
-
const { moveModuleAction } = actions;
|
|
171
|
+
const { moveModuleAction } = actions || {};
|
|
154
172
|
|
|
155
|
-
if (!result.destination) {
|
|
173
|
+
if (!moveModuleAction || !result.destination || result.destination.index === result.source.index) {
|
|
174
|
+
setDraggingId(null);
|
|
156
175
|
return;
|
|
157
176
|
}
|
|
158
177
|
|
|
159
|
-
if (
|
|
160
|
-
|
|
178
|
+
if (selectedItems.all.length > 0 && selectedItems.all.includes(parseInt(result.draggableId))) {
|
|
179
|
+
moveModuleAction(selectedItems.all, selectedContent, result.destination.index, objKey);
|
|
180
|
+
} else {
|
|
181
|
+
moveModuleAction([parseInt(result.draggableId)], selectedContent, result.destination.index, objKey);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
setDraggingId(null);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const onBeforeCapture = (start: BeforeCapture) => setDraggingId(parseInt(start.draggableId));
|
|
188
|
+
|
|
189
|
+
const handleCopy = () => {
|
|
190
|
+
const isCopied = copyModuleAction && copyModuleAction(selectedItems.all);
|
|
191
|
+
isCopied &&
|
|
192
|
+
toggleToast(`${selectedItems.all.length} module${selectedItems.all.length > 1 ? "s" : ""} copied to clipboard`);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const handleDuplicate = () => {
|
|
196
|
+
if (maxItems && maxItems - fixedValue.length < selectedItems.all.length) {
|
|
197
|
+
const notification: INotification = {
|
|
198
|
+
type: "error",
|
|
199
|
+
text: "Unable to duplicate modules: The destination area has a limit on the number of modules allowed. Please adjust the selection accordingly.",
|
|
200
|
+
};
|
|
201
|
+
setNotificationAction && setNotificationAction(notification);
|
|
202
|
+
} else {
|
|
203
|
+
duplicateModuleAction && duplicateModuleAction(selectedItems.all, objKey);
|
|
204
|
+
resetBulkSelection();
|
|
161
205
|
}
|
|
206
|
+
};
|
|
162
207
|
|
|
163
|
-
|
|
208
|
+
const handleDelete = () => {
|
|
209
|
+
deleteModuleAction && deleteModuleAction(selectedItems.all, objKey);
|
|
210
|
+
resetBulkSelection();
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const bulkActions = [
|
|
214
|
+
{
|
|
215
|
+
icon: "copy",
|
|
216
|
+
text: "copy",
|
|
217
|
+
action: handleCopy,
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
icon: "duplicate",
|
|
221
|
+
text: "duplicate",
|
|
222
|
+
action: handleDuplicate,
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
icon: "delete",
|
|
226
|
+
text: "delete",
|
|
227
|
+
action: handleDelete,
|
|
228
|
+
},
|
|
229
|
+
];
|
|
230
|
+
|
|
231
|
+
const toggleBulk = () => {
|
|
232
|
+
setIsBulkOpen(false);
|
|
233
|
+
resetBulkSelection();
|
|
164
234
|
};
|
|
165
235
|
|
|
166
236
|
return (
|
|
@@ -169,16 +239,28 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
169
239
|
{title} <Asterisk />
|
|
170
240
|
</S.Title>
|
|
171
241
|
<S.ItemRow>
|
|
172
|
-
|
|
242
|
+
{isBulkOpen ? (
|
|
243
|
+
<BulkHeader
|
|
244
|
+
selectItems={selectItems}
|
|
245
|
+
checkState={checkState}
|
|
246
|
+
totalItems={selectedItems.all.length}
|
|
247
|
+
toggleBulk={toggleBulk}
|
|
248
|
+
actions={bulkActions}
|
|
249
|
+
/>
|
|
250
|
+
) : (
|
|
251
|
+
<S.Subtitle>{fixedValue?.length || 0} items</S.Subtitle>
|
|
252
|
+
)}
|
|
173
253
|
<S.ActionsWrapper data-testid="mixableComponentWrapper">
|
|
174
|
-
{showPasteModuleButton && (
|
|
254
|
+
{showPasteModuleButton && pasteModuleAction && (
|
|
175
255
|
<PasteModuleButton
|
|
176
256
|
editorID={editorID}
|
|
177
|
-
isModuleCopyUnavailable={
|
|
178
|
-
pasteModule={
|
|
179
|
-
setNotification={
|
|
257
|
+
isModuleCopyUnavailable={unavailableModules.length > 0}
|
|
258
|
+
pasteModule={pasteModuleAction}
|
|
259
|
+
setNotification={setNotificationAction}
|
|
180
260
|
setHistoryPush={setHistoryPush}
|
|
181
261
|
arrayKey={objKey}
|
|
262
|
+
modulesToPaste={modulesToPaste}
|
|
263
|
+
slots={maxItems ? maxItems - fixedValue.length : null}
|
|
182
264
|
/>
|
|
183
265
|
)}
|
|
184
266
|
{showAddItemButton && !disabled && (
|
|
@@ -195,7 +277,7 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
195
277
|
</S.ActionsWrapper>
|
|
196
278
|
</S.ItemRow>
|
|
197
279
|
{fixedValue && (
|
|
198
|
-
<DragDropContext onDragEnd={onDragEnd}>
|
|
280
|
+
<DragDropContext onDragEnd={onDragEnd} onBeforeCapture={onBeforeCapture}>
|
|
199
281
|
<Droppable droppableId="list">
|
|
200
282
|
{(provided) => (
|
|
201
283
|
<div ref={provided.innerRef} {...provided.droppableProps}>
|
|
@@ -218,27 +300,39 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
218
300
|
showSearch
|
|
219
301
|
/>
|
|
220
302
|
)}
|
|
303
|
+
{isVisible && <Toast message={toastState} setIsVisible={setIsVisible} />}
|
|
221
304
|
</S.Wrapper>
|
|
222
305
|
);
|
|
223
306
|
};
|
|
224
307
|
|
|
225
308
|
export interface IMixableComponentArrayProps {
|
|
226
|
-
maxItems
|
|
309
|
+
maxItems?: number;
|
|
227
310
|
title: string;
|
|
228
|
-
whiteList:
|
|
311
|
+
whiteList: string[];
|
|
229
312
|
value?: IModule[];
|
|
230
313
|
selectedContent: any;
|
|
231
314
|
editorID: number;
|
|
232
315
|
goTo: (editorID: string) => void;
|
|
233
|
-
actions
|
|
316
|
+
actions?: {
|
|
317
|
+
addComponentAction: (componentType: any, key?: string) => void;
|
|
318
|
+
addModuleAction: (moduleType: string, key: string, selectedID: number, isComponentModule?: boolean) => void;
|
|
319
|
+
deleteModuleAction: (editorID: number[], key?: string) => void;
|
|
320
|
+
duplicateModuleAction: (editorID: number[], key?: string) => number;
|
|
321
|
+
copyModuleAction: (editorID: number[]) => boolean;
|
|
322
|
+
replaceElementsInCollectionAction: (newValue: string, reference?: string) => void;
|
|
323
|
+
moveModuleAction: (moduleID: number[], selectedContent: any, newIndex: number, key: string) => void;
|
|
324
|
+
pasteModuleAction: (editorID: number, key: string, modulesToPaste: IModule[]) => Promise<{ error?: INotification }>;
|
|
325
|
+
setNotificationAction: (notification: INotification) => void;
|
|
326
|
+
replaceModuleAction: (module: any, parent: any, objKey: string) => void;
|
|
327
|
+
};
|
|
234
328
|
categories?: any;
|
|
235
329
|
disabled?: boolean;
|
|
236
330
|
activatedModules: string[];
|
|
237
331
|
objKey: string;
|
|
238
|
-
field:
|
|
332
|
+
field: ISchemaField;
|
|
239
333
|
mandatory?: boolean;
|
|
240
334
|
theme: string;
|
|
241
|
-
moduleCopy: { date:
|
|
335
|
+
moduleCopy: { date: Date; elements: IModule[] } | null;
|
|
242
336
|
availableDataPacks: Record<string, any>[];
|
|
243
337
|
template: any;
|
|
244
338
|
setHistoryPush?: (path: string, isEditor: boolean) => void;
|
|
@@ -69,7 +69,7 @@ const SameComponentArray = (props: ISameComponentArrayProps): JSX.Element => {
|
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
moveModuleAction(parseInt(result.draggableId), selectedContent, result.destination.index, objKey);
|
|
72
|
+
moveModuleAction([parseInt(result.draggableId)], selectedContent, result.destination.index, objKey);
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
const ComponentList = React.memo(function ComponentList({ components }: any) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import differenceInSeconds from "date-fns/differenceInSeconds";
|
|
1
2
|
import { getSchema, getDisplayName, getSchemaType, isComponentEmpty } from "@ax/helpers";
|
|
2
|
-
import { IComponent } from "@ax/types";
|
|
3
|
+
import { IComponent, IModule, ISchemaField } from "@ax/types";
|
|
3
4
|
|
|
4
5
|
const getComponentTitle = (component: string, title: any) => {
|
|
5
6
|
if (!title) return;
|
|
@@ -13,7 +14,7 @@ const getComponentTitle = (component: string, title: any) => {
|
|
|
13
14
|
return defaultTitle === title ? displayName : title;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
|
-
const getComponentProps = (element:
|
|
17
|
+
const getComponentProps = (element: IModule, activatedModules: string[], isModuleArr: boolean) => {
|
|
17
18
|
const { component } = element;
|
|
18
19
|
const schemaType = getSchemaType(component);
|
|
19
20
|
const displayName = getDisplayName(component);
|
|
@@ -27,7 +28,7 @@ const getComponentProps = (element: any, activatedModules: string[], isModuleArr
|
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
const containerToComponentArray = (value?: Record<string, IComponent>): IComponent[] =>
|
|
30
|
-
value ? Object.values(value).filter((item: IComponent) => !isComponentEmpty(item)): [];
|
|
31
|
+
value ? Object.values(value).filter((item: IComponent) => !isComponentEmpty(item)) : [];
|
|
31
32
|
|
|
32
33
|
const getTypefromKey = (key: string) => {
|
|
33
34
|
switch (key) {
|
|
@@ -41,4 +42,44 @@ const getTypefromKey = (key: string) => {
|
|
|
41
42
|
}
|
|
42
43
|
};
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
const getTimeSinceModuleCopy = (moduleCopy: { date: Date; elements: IModule[] }) =>
|
|
46
|
+
differenceInSeconds(new Date(), new Date(moduleCopy.date));
|
|
47
|
+
|
|
48
|
+
const getModulesToPaste = (
|
|
49
|
+
moduleCopy: { date: Date; elements: IModule[] } | null,
|
|
50
|
+
whiteList: string[],
|
|
51
|
+
availableDataPacks: Record<string, any>[],
|
|
52
|
+
template: any,
|
|
53
|
+
field: ISchemaField
|
|
54
|
+
) => {
|
|
55
|
+
const modulesToPaste: IModule[] = [];
|
|
56
|
+
const unavailableModules: IModule[] = [];
|
|
57
|
+
const eightHoursInSeconds = 8 * 60 * 60;
|
|
58
|
+
|
|
59
|
+
if (moduleCopy && getTimeSinceModuleCopy(moduleCopy) < eightHoursInSeconds) {
|
|
60
|
+
moduleCopy.elements.forEach((element) => {
|
|
61
|
+
const { component } = element;
|
|
62
|
+
|
|
63
|
+
const availableDataPackModule = availableDataPacks?.reduce((prev: any, curr: any) => {
|
|
64
|
+
const packModule = curr.modules.find((module: any) => module.id === component);
|
|
65
|
+
return prev || packModule;
|
|
66
|
+
}, null);
|
|
67
|
+
|
|
68
|
+
if (
|
|
69
|
+
availableDataPackModule &&
|
|
70
|
+
!whiteList.includes(component) &&
|
|
71
|
+
!!availableDataPackModule?.sectionList[template.component]?.includes(field.key)
|
|
72
|
+
) {
|
|
73
|
+
unavailableModules.push(element);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (whiteList.includes(component)) {
|
|
77
|
+
modulesToPaste.push(element);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return { modulesToPaste, unavailableModules };
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export { getComponentTitle, getComponentProps, containerToComponentArray, getTypefromKey, getModulesToPaste };
|
|
@@ -33,11 +33,11 @@ const EmptyContainer = (props: IProps) => {
|
|
|
33
33
|
interface IProps {
|
|
34
34
|
hasMultipleOptions: boolean | undefined;
|
|
35
35
|
whiteList: any[] | undefined;
|
|
36
|
-
goTo
|
|
36
|
+
goTo: () => void;
|
|
37
37
|
componentOptions: any;
|
|
38
38
|
title?: string;
|
|
39
39
|
categories?: any;
|
|
40
|
-
handleAdd: any;
|
|
40
|
+
handleAdd: (option: any) => void;
|
|
41
41
|
theme: string;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { DraggableProvided } from "react-beautiful-dnd";
|
|
3
3
|
|
|
4
|
-
import { useModal
|
|
4
|
+
import { useModal } from "@ax/hooks";
|
|
5
5
|
import { isEmptyContainer, getDisplayName, trimText } from "@ax/helpers";
|
|
6
|
-
import { Icon, SideModal
|
|
6
|
+
import { CheckField, Icon, SideModal } from "@ax/components";
|
|
7
|
+
import { ICheck } from "@ax/types";
|
|
7
8
|
import EmptyContainer from "./EmptyContainer";
|
|
8
9
|
import { ArrayContainerButtons, ContainerButtons } from "./atoms";
|
|
9
10
|
|
|
@@ -33,19 +34,19 @@ const ComponentContainer = (props: IComponentContainerProps): JSX.Element => {
|
|
|
33
34
|
innerRef,
|
|
34
35
|
provided,
|
|
35
36
|
isModule,
|
|
37
|
+
isSelected,
|
|
38
|
+
onChange,
|
|
39
|
+
hasMenu = true,
|
|
40
|
+
toggleToast,
|
|
41
|
+
className,
|
|
42
|
+
isMultiDragging = false,
|
|
43
|
+
draggingCount = 0,
|
|
36
44
|
} = props;
|
|
37
45
|
|
|
38
|
-
const {
|
|
46
|
+
const { addComponentAction, deleteModuleAction, duplicateModuleAction, copyModuleAction, replaceModuleAction } =
|
|
47
|
+
actions || {};
|
|
39
48
|
|
|
40
|
-
|
|
41
|
-
let duplicateModuleAction: any;
|
|
42
|
-
let copyModuleAction: any;
|
|
43
|
-
|
|
44
|
-
if (actions) {
|
|
45
|
-
deleteModuleAction = actions.deleteModuleAction;
|
|
46
|
-
duplicateModuleAction = actions.duplicateModuleAction;
|
|
47
|
-
copyModuleAction = actions.copyModuleAction;
|
|
48
|
-
}
|
|
49
|
+
const { isOpen, toggleModal } = useModal();
|
|
49
50
|
|
|
50
51
|
const whiteListFirstItem: any = whiteList && whiteList[0];
|
|
51
52
|
const hasMultipleOptions: boolean | undefined = whiteList && whiteList.length > 1;
|
|
@@ -66,21 +67,21 @@ const ComponentContainer = (props: IComponentContainerProps): JSX.Element => {
|
|
|
66
67
|
componentID = currentComponent.componentID;
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
const { isOpen, toggleModal } = useModal();
|
|
70
|
-
|
|
71
|
-
const handleEmptyContainerClick = () => actions.addComponentAction && actions.addComponentAction(value);
|
|
72
|
-
|
|
73
70
|
const handleClick = () => {
|
|
74
71
|
if (!disabled) {
|
|
75
72
|
goTo(componentID);
|
|
76
73
|
}
|
|
77
74
|
};
|
|
78
75
|
|
|
79
|
-
const
|
|
80
|
-
|
|
76
|
+
const handleCheckClick = (e: React.MouseEvent<HTMLDivElement>) => e.stopPropagation();
|
|
77
|
+
|
|
78
|
+
const removeItem = () => deleteModuleAction && deleteModuleAction([editorID], parentKey);
|
|
79
|
+
|
|
80
|
+
const duplicateItem = () => parentKey && duplicateModuleAction && duplicateModuleAction([editorID], parentKey);
|
|
81
|
+
|
|
81
82
|
const copyItem = () => {
|
|
82
|
-
const isCopied = copyModuleAction(editorID);
|
|
83
|
-
isCopied && toggleToast();
|
|
83
|
+
const isCopied = copyModuleAction && copyModuleAction([editorID]);
|
|
84
|
+
isCopied && toggleToast && toggleToast("1 module copied to clipboard");
|
|
84
85
|
};
|
|
85
86
|
|
|
86
87
|
const copyOpt = {
|
|
@@ -124,16 +125,38 @@ const ComponentContainer = (props: IComponentContainerProps): JSX.Element => {
|
|
|
124
125
|
|
|
125
126
|
const actionMenuIcon = "more";
|
|
126
127
|
|
|
127
|
-
const
|
|
128
|
+
const handleEmptyContainerClick = () => {
|
|
129
|
+
if (addComponentAction) addComponentAction(value);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const handleOptionClick = (option: any) => {
|
|
133
|
+
if (addComponentAction) addComponentAction(option);
|
|
134
|
+
};
|
|
128
135
|
|
|
129
136
|
const compoundKey = parentKey ? `${parentKey}.${objKey}` : objKey;
|
|
130
|
-
const handleReplace = (option: any) =>
|
|
137
|
+
const handleReplace = (option: any) =>
|
|
138
|
+
compoundKey && replaceModuleAction && replaceModuleAction(option, selectedContent, compoundKey);
|
|
131
139
|
|
|
132
140
|
const arrayContainerButtonsProps = {
|
|
133
141
|
options: actionArrayMenuOptions,
|
|
134
142
|
icon: actionMenuIcon,
|
|
135
143
|
};
|
|
136
144
|
|
|
145
|
+
const handleChange = (value: ICheck) => onChange && onChange(value);
|
|
146
|
+
|
|
147
|
+
const textComponents = isMultiDragging ? (
|
|
148
|
+
<S.LabelDrag>
|
|
149
|
+
Dragging <span>{draggingCount}</span> modules
|
|
150
|
+
</S.LabelDrag>
|
|
151
|
+
) : (
|
|
152
|
+
<>
|
|
153
|
+
<S.Label containerInfo={containerInfo} disabled={disabled}>
|
|
154
|
+
{trimText(containerText, 25)}
|
|
155
|
+
</S.Label>
|
|
156
|
+
{moduleTitle && <S.Title disabled={disabled}>{trimText(moduleTitle, 25)}</S.Title>}
|
|
157
|
+
</>
|
|
158
|
+
);
|
|
159
|
+
|
|
137
160
|
return isEmpty ? (
|
|
138
161
|
<EmptyContainer
|
|
139
162
|
whiteList={whiteList}
|
|
@@ -149,7 +172,7 @@ const ComponentContainer = (props: IComponentContainerProps): JSX.Element => {
|
|
|
149
172
|
<>
|
|
150
173
|
<S.Component
|
|
151
174
|
disabled={disabled}
|
|
152
|
-
className={`editorId-${editorID}`}
|
|
175
|
+
className={`editorId-${editorID} ${className}`}
|
|
153
176
|
onClick={handleClick}
|
|
154
177
|
ref={innerRef}
|
|
155
178
|
data-testid="component-container"
|
|
@@ -162,18 +185,18 @@ const ComponentContainer = (props: IComponentContainerProps): JSX.Element => {
|
|
|
162
185
|
</S.IconHandleWrapper>
|
|
163
186
|
</S.HandleWrapper>
|
|
164
187
|
)}
|
|
188
|
+
{isArray && !isMultiDragging && arrayLength > 1 && (
|
|
189
|
+
<S.CheckWrapper onClick={handleCheckClick}>
|
|
190
|
+
<CheckField name="check" value={editorID} checked={isSelected} onChange={handleChange} light={true} />
|
|
191
|
+
</S.CheckWrapper>
|
|
192
|
+
)}
|
|
165
193
|
{containerInfo && !disabled && (
|
|
166
194
|
<S.IconWrapper data-testid="icon-wrapper">
|
|
167
195
|
<Icon name={containerText} />
|
|
168
196
|
</S.IconWrapper>
|
|
169
197
|
)}
|
|
170
|
-
<S.Text>
|
|
171
|
-
|
|
172
|
-
{trimText(containerText, 35)}
|
|
173
|
-
</S.Label>
|
|
174
|
-
{moduleTitle && <S.Title disabled={disabled}>{trimText(moduleTitle, 35)}</S.Title>}
|
|
175
|
-
</S.Text>
|
|
176
|
-
{isArray && !disabled && <ArrayContainerButtons {...arrayContainerButtonsProps} />}
|
|
198
|
+
<S.Text>{textComponents}</S.Text>
|
|
199
|
+
{isArray && !disabled && !hasMenu && <ArrayContainerButtons {...arrayContainerButtonsProps} />}
|
|
177
200
|
{!isArray && !disabled && hasMultipleOptions && (
|
|
178
201
|
<ContainerButtons options={actionMenuOptions} icon={actionMenuIcon} />
|
|
179
202
|
)}
|
|
@@ -191,7 +214,6 @@ const ComponentContainer = (props: IComponentContainerProps): JSX.Element => {
|
|
|
191
214
|
theme={theme}
|
|
192
215
|
/>
|
|
193
216
|
)}
|
|
194
|
-
{isVisible && <Toast message="1 module copied to clipboard" setIsVisible={setIsVisible} />}
|
|
195
217
|
</>
|
|
196
218
|
);
|
|
197
219
|
};
|
|
@@ -199,7 +221,7 @@ const ComponentContainer = (props: IComponentContainerProps): JSX.Element => {
|
|
|
199
221
|
export interface IComponentContainerProps {
|
|
200
222
|
text: string;
|
|
201
223
|
editorID: number;
|
|
202
|
-
whiteList:
|
|
224
|
+
whiteList: string[] | undefined;
|
|
203
225
|
categories?: any[];
|
|
204
226
|
goTo: any;
|
|
205
227
|
isArray?: boolean | undefined;
|
|
@@ -208,7 +230,13 @@ export interface IComponentContainerProps {
|
|
|
208
230
|
moduleTitle?: string;
|
|
209
231
|
selectedContent?: any;
|
|
210
232
|
objKey?: string;
|
|
211
|
-
actions
|
|
233
|
+
actions?: {
|
|
234
|
+
addComponentAction: (componentType: any, key?: string) => void;
|
|
235
|
+
deleteModuleAction: (editorID: number[], key?: string) => void;
|
|
236
|
+
duplicateModuleAction: (editorID: number[], key?: string) => number;
|
|
237
|
+
copyModuleAction: (editorID: number[]) => boolean;
|
|
238
|
+
replaceModuleAction: (module: any, parent: any, objKey: string) => void;
|
|
239
|
+
};
|
|
212
240
|
disabled?: boolean;
|
|
213
241
|
canDuplicate?: boolean;
|
|
214
242
|
parentKey?: string;
|
|
@@ -219,6 +247,13 @@ export interface IComponentContainerProps {
|
|
|
219
247
|
innerRef?: any;
|
|
220
248
|
provided?: DraggableProvided;
|
|
221
249
|
isModule?: boolean;
|
|
250
|
+
isSelected?: boolean;
|
|
251
|
+
onChange?: (value: ICheck) => void;
|
|
252
|
+
hasMenu?: boolean;
|
|
253
|
+
toggleToast?: (state: string) => void;
|
|
254
|
+
className?: string;
|
|
255
|
+
isMultiDragging?: boolean;
|
|
256
|
+
draggingCount?: number;
|
|
222
257
|
}
|
|
223
258
|
|
|
224
259
|
export default ComponentContainer;
|