@griddo/ax 10.4.37 → 10.5.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/package.json +2 -2
- package/src/api/checkgroups.tsx +1 -1
- package/src/api/structuredData.tsx +109 -18
- package/src/components/Fields/AsyncCheckGroup/index.tsx +56 -19
- package/src/components/Fields/AsyncCheckGroup/style.tsx +21 -4
- package/src/components/Fields/CheckField/style.tsx +1 -1
- package/src/components/Fields/NoteField/style.tsx +1 -1
- package/src/components/Fields/ReferenceField/AutoPanel/AutoItem/index.tsx +58 -20
- package/src/components/Fields/ReferenceField/AutoPanel/AutoItem/style.tsx +20 -1
- package/src/components/Fields/ReferenceField/Context/index.tsx +9 -9
- package/src/components/LanguageMenu/index.tsx +1 -1
- package/src/components/Tag/index.tsx +3 -2
- package/src/components/Tag/style.tsx +5 -4
- package/src/containers/StructuredData/actions.tsx +169 -82
- package/src/containers/StructuredData/constants.tsx +2 -2
- package/src/containers/StructuredData/interfaces.tsx +16 -9
- package/src/containers/StructuredData/reducer.tsx +11 -7
- package/src/containers/StructuredData/utils.tsx +2 -2
- package/src/global.d.ts +0 -1
- package/src/modules/Categories/CategoriesList/BulkHeader/TableHeader/index.tsx +10 -3
- package/src/modules/Categories/CategoriesList/BulkHeader/TableHeader/style.tsx +12 -6
- package/src/modules/Categories/CategoriesList/BulkHeader/index.tsx +21 -2
- package/src/modules/Categories/CategoriesList/CategoryItem/index.tsx +131 -63
- package/src/modules/Categories/CategoriesList/CategoryItem/style.tsx +67 -7
- package/src/modules/Categories/CategoriesList/CategoryNav/index.tsx +2 -8
- package/src/modules/Categories/CategoriesList/CategoryPanel/Form/index.tsx +88 -33
- package/src/modules/Categories/CategoriesList/CategoryPanel/index.tsx +130 -56
- package/src/modules/Categories/CategoriesList/CategoryPanel/style.tsx +1 -1
- package/src/modules/Categories/CategoriesList/atoms.tsx +46 -19
- package/src/modules/Categories/CategoriesList/helpers.tsx +116 -0
- package/src/modules/Categories/CategoriesList/hooks.tsx +61 -0
- package/src/modules/Categories/CategoriesList/index.tsx +283 -97
- package/src/modules/Categories/CategoriesList/style.tsx +54 -2
- package/src/modules/Categories/CategoriesList/utils.tsx +34 -14
- package/src/modules/StructuredData/StructuredDataList/StructuredDataItem/index.tsx +1 -1
- package/src/modules/Users/UserList/hooks.tsx +5 -4
- package/src/types/index.tsx +64 -3
- package/tsconfig.paths.json +0 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { IQueryValue } from "@ax/types";
|
|
3
|
+
|
|
4
|
+
const useFilterQuery = () => {
|
|
5
|
+
const initialQueryValues: Record<string, IQueryValue[]> = {
|
|
6
|
+
translated: [{ value: "all", label: "All" }],
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const [query, setQuery] = useState(initialQueryValues);
|
|
10
|
+
const [currentFilterQuery, setCurrentFilterQuery] = useState("");
|
|
11
|
+
|
|
12
|
+
const setFilterQuery = (filterValues: Record<string, IQueryValue[]>) => {
|
|
13
|
+
const { translated } = filterValues;
|
|
14
|
+
let filterQuery = "";
|
|
15
|
+
|
|
16
|
+
const currentQuery = (pointer: string, values: IQueryValue[]): string => {
|
|
17
|
+
const stringValues =
|
|
18
|
+
Array.isArray(values) && values.length
|
|
19
|
+
? values.map((value) => (value.value !== "all" ? value.value : "")).join(",")
|
|
20
|
+
: "";
|
|
21
|
+
|
|
22
|
+
return !stringValues.length
|
|
23
|
+
? filterQuery
|
|
24
|
+
: filterQuery.length
|
|
25
|
+
? filterQuery.concat(`&${pointer}=${stringValues}`)
|
|
26
|
+
: `&${pointer}=${stringValues}`;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const isNotInitialValue = (pointer: string) => {
|
|
30
|
+
return filterValues[pointer] && initialQueryValues[pointer] !== filterValues[pointer];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
if (isNotInitialValue("translated")) filterQuery = currentQuery("translated", translated);
|
|
34
|
+
|
|
35
|
+
setCurrentFilterQuery(filterQuery);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const setFiltersSelection = (pointer: string, filter: IQueryValue[]) => {
|
|
39
|
+
const { translated } = query;
|
|
40
|
+
const filterValues = {
|
|
41
|
+
translated: pointer === "translated" ? filter : translated,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
setQuery(filterValues);
|
|
45
|
+
setFilterQuery(filterValues);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const resetFilterQuery = () => {
|
|
49
|
+
setQuery(initialQueryValues);
|
|
50
|
+
setCurrentFilterQuery("");
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
setFiltersSelection,
|
|
55
|
+
resetFilterQuery,
|
|
56
|
+
filterValues: query,
|
|
57
|
+
filterQuery: currentFilterQuery,
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export { useFilterQuery };
|
|
@@ -1,18 +1,56 @@
|
|
|
1
1
|
import React, { useEffect, useCallback, useState, useRef, useLayoutEffect } from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
|
+
import Tree, {
|
|
4
|
+
mutateTree,
|
|
5
|
+
moveItemOnTree,
|
|
6
|
+
RenderItemParams,
|
|
7
|
+
TreeItem,
|
|
8
|
+
TreeData,
|
|
9
|
+
ItemId,
|
|
10
|
+
TreeSourcePosition,
|
|
11
|
+
TreeDestinationPosition,
|
|
12
|
+
} from "@atlaskit/tree";
|
|
3
13
|
|
|
4
14
|
import { structuredDataActions } from "@ax/containers/StructuredData";
|
|
5
15
|
import { appActions } from "@ax/containers/App";
|
|
6
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
IRootState,
|
|
18
|
+
IStructuredData,
|
|
19
|
+
IGetStructuredDataParams,
|
|
20
|
+
IDataPack,
|
|
21
|
+
IStructuredDataCategory,
|
|
22
|
+
ICategoryGroup,
|
|
23
|
+
IOrderCategoryParams,
|
|
24
|
+
IQueryValue,
|
|
25
|
+
} from "@ax/types";
|
|
7
26
|
import { useBulkSelection, useModal, usePermission, useToast } from "@ax/hooks";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
27
|
+
import {
|
|
28
|
+
MainWrapper,
|
|
29
|
+
TableList,
|
|
30
|
+
ErrorToast,
|
|
31
|
+
Toast,
|
|
32
|
+
EmptyState,
|
|
33
|
+
Icon,
|
|
34
|
+
SearchTagsBar,
|
|
35
|
+
FilterTagsBar,
|
|
36
|
+
} from "@ax/components";
|
|
37
|
+
import { sortBy } from "@ax/helpers";
|
|
38
|
+
|
|
39
|
+
import { DeleteGroupModal, DeleteModal } from "./atoms";
|
|
40
|
+
import { filterCategoriesAndGroups, getAllLangCategoriesIds } from "./utils";
|
|
12
41
|
import CategoryItem from "./CategoryItem";
|
|
13
42
|
import CategoryPanel from "./CategoryPanel";
|
|
14
43
|
import CategoryNav from "./CategoryNav";
|
|
15
44
|
import BulkHeader from "./BulkHeader";
|
|
45
|
+
import {
|
|
46
|
+
findChild,
|
|
47
|
+
findChildByIndex,
|
|
48
|
+
formatItem,
|
|
49
|
+
getElementsFromTree,
|
|
50
|
+
getIDsFromTree,
|
|
51
|
+
normalizeItems,
|
|
52
|
+
} from "./helpers";
|
|
53
|
+
import { useFilterQuery } from "./hooks";
|
|
16
54
|
|
|
17
55
|
import * as S from "./style";
|
|
18
56
|
|
|
@@ -22,7 +60,6 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
22
60
|
currentStructuredData,
|
|
23
61
|
currentDataContent,
|
|
24
62
|
getStructuredDataContents,
|
|
25
|
-
resetCategoryValues,
|
|
26
63
|
lang,
|
|
27
64
|
siteLanguages,
|
|
28
65
|
globalLangs,
|
|
@@ -32,19 +69,22 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
32
69
|
setSelectedCategory,
|
|
33
70
|
activatedDataPacks,
|
|
34
71
|
deleteDataContent,
|
|
35
|
-
restoreDataContent,
|
|
36
72
|
setHistoryPush,
|
|
37
73
|
resetCurrentData,
|
|
74
|
+
deleteCategoryGroup,
|
|
75
|
+
orderCategory,
|
|
38
76
|
} = props;
|
|
39
77
|
|
|
40
|
-
const
|
|
41
|
-
const [page, setPage] = useState(1);
|
|
78
|
+
const [tree, setTree] = useState<TreeData>({ rootId: "root", items: {} });
|
|
42
79
|
const [isScrolling, setIsScrolling] = useState(false);
|
|
43
|
-
const [
|
|
44
|
-
const [
|
|
45
|
-
const
|
|
80
|
+
const [deleteGroupCategories, setDeleteGroupCategories] = useState(false);
|
|
81
|
+
const [itemDragging, setItemDragging] = useState<ItemId | null>(null);
|
|
82
|
+
const [searchQuery, setSearchQuery] = useState<string>("");
|
|
83
|
+
const { isVisible, toggleToast, setIsVisible, state: toastState } = useToast();
|
|
46
84
|
const { isOpen: isDeleteOpen, toggleModal: toggleDeleteModal } = useModal();
|
|
85
|
+
const { isOpen: isGroupOpen, toggleModal: toggleGroupModal } = useModal();
|
|
47
86
|
const tableRef = useRef<HTMLDivElement>(null);
|
|
87
|
+
const { setFiltersSelection, resetFilterQuery, filterValues, filterQuery } = useFilterQuery();
|
|
48
88
|
|
|
49
89
|
const allowedToCreateSiteCategory = usePermission("categories.createSiteTaxonomies");
|
|
50
90
|
const allowedToCreateGlobalCategory = usePermission("global.globalData.createTaxonomies");
|
|
@@ -54,9 +94,9 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
54
94
|
const allowedToCreateTaxonomy = currentSiteID ? allowedToCreateSiteCategory : allowedToCreateGlobalCategory;
|
|
55
95
|
|
|
56
96
|
const scope = currentSiteID ? "site" : "global";
|
|
57
|
-
const currentCategories = categories[scope];
|
|
97
|
+
const currentCategories = categories[scope].sort(sortBy("title", false));
|
|
58
98
|
|
|
59
|
-
const catIds = currentDataContent
|
|
99
|
+
const catIds = getIDsFromTree(currentDataContent);
|
|
60
100
|
|
|
61
101
|
const {
|
|
62
102
|
resetBulkSelection,
|
|
@@ -68,70 +108,81 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
68
108
|
selectAllItems,
|
|
69
109
|
} = useBulkSelection(catIds);
|
|
70
110
|
|
|
71
|
-
const getParams = useCallback(() => {
|
|
111
|
+
const getParams = useCallback((): IGetStructuredDataParams => {
|
|
72
112
|
return {
|
|
73
|
-
page,
|
|
74
|
-
itemsPerPage,
|
|
75
|
-
pagination:
|
|
113
|
+
page: 1,
|
|
114
|
+
itemsPerPage: 50,
|
|
115
|
+
pagination: false,
|
|
76
116
|
deleted: false,
|
|
77
117
|
include_draft: false,
|
|
118
|
+
groupingCategories: true,
|
|
119
|
+
query: searchQuery,
|
|
120
|
+
filterQuery,
|
|
78
121
|
};
|
|
79
|
-
}, [
|
|
122
|
+
}, [searchQuery, filterQuery]);
|
|
80
123
|
|
|
81
124
|
const getContents = useCallback(
|
|
82
125
|
async (id: string) => {
|
|
83
|
-
const params
|
|
126
|
+
const params = getParams();
|
|
84
127
|
params.dataID = id;
|
|
85
|
-
setSelectedCategory(id, scope);
|
|
86
128
|
await getStructuredDataContents(params, currentSiteID);
|
|
87
129
|
},
|
|
88
|
-
[getStructuredDataContents, currentSiteID, getParams
|
|
130
|
+
[getStructuredDataContents, currentSiteID, getParams]
|
|
89
131
|
);
|
|
90
132
|
|
|
91
|
-
useEffect(() => {
|
|
92
|
-
currentStructuredData && getContents(currentStructuredData.id);
|
|
93
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
94
|
-
}, [lang, currentStructuredData, page]);
|
|
95
|
-
|
|
96
133
|
useLayoutEffect(() => {
|
|
134
|
+
if (currentCategories.length) {
|
|
135
|
+
setSelectedCategory(currentCategories[0].id, scope);
|
|
136
|
+
}
|
|
97
137
|
return () => {
|
|
98
138
|
resetCurrentData();
|
|
99
139
|
};
|
|
140
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
100
141
|
}, []);
|
|
101
142
|
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
currentStructuredData?.taxonomy && getContents(currentStructuredData.id);
|
|
145
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
146
|
+
}, [lang, currentStructuredData, searchQuery, filterValues]);
|
|
147
|
+
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
setTree(normalizeItems(currentDataContent, tree));
|
|
150
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
151
|
+
}, [currentDataContent]);
|
|
152
|
+
|
|
102
153
|
const handleClick = (dataID: string) => {
|
|
103
154
|
setSelectedCategory(dataID, scope);
|
|
104
155
|
};
|
|
105
156
|
|
|
106
157
|
const { isOpen, toggleModal } = useModal();
|
|
107
158
|
|
|
108
|
-
const openModal = () => {
|
|
109
|
-
resetCategoryValues();
|
|
110
|
-
toggleModal();
|
|
111
|
-
};
|
|
112
|
-
|
|
113
159
|
const rightButtonProps = allowedToCreateTaxonomy
|
|
114
160
|
? {
|
|
115
161
|
label: "New",
|
|
116
|
-
action:
|
|
162
|
+
action: toggleModal,
|
|
117
163
|
}
|
|
118
164
|
: undefined;
|
|
119
165
|
|
|
120
166
|
const bulkDelete = async () => {
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
|
|
167
|
+
const { groups, categories } = filterCategoriesAndGroups(currentDataContent);
|
|
168
|
+
const idsCatsToBeDeleted = getAllLangCategoriesIds(categories, selectedItems);
|
|
169
|
+
const idsGroupsToBeDeleted = getAllLangCategoriesIds(groups, selectedItems);
|
|
170
|
+
const deletedCats = idsCatsToBeDeleted.length && (await deleteDataContent(idsCatsToBeDeleted, false));
|
|
171
|
+
const deletedGroups =
|
|
172
|
+
idsGroupsToBeDeleted.length && (await deleteCategoryGroup(idsGroupsToBeDeleted, deleteGroupCategories, false));
|
|
173
|
+
if (deletedCats || deletedGroups) {
|
|
174
|
+
currentStructuredData && getContents(currentStructuredData.id);
|
|
175
|
+
toggleToast(`${selectedItems.all.length} categories and/or groups deleted`);
|
|
124
176
|
unselectAllItems();
|
|
125
|
-
setDeletedItem(idsToBeDeleted);
|
|
126
177
|
isDeleteOpen && toggleDeleteModal();
|
|
127
|
-
|
|
178
|
+
isGroupOpen && toggleGroupModal();
|
|
128
179
|
}
|
|
129
180
|
};
|
|
130
181
|
|
|
131
182
|
const handleToggleDeleteModal = () => {
|
|
132
183
|
const selectedCategories = currentDataContent.filter((category) => selectedItems.all.includes(category.id));
|
|
133
|
-
const
|
|
134
|
-
|
|
184
|
+
const hasGroups = selectedCategories.some((category) => category.type === "group");
|
|
185
|
+
hasGroups ? toggleGroupModal() : toggleDeleteModal();
|
|
135
186
|
};
|
|
136
187
|
|
|
137
188
|
const unselectAllItems = () => resetBulkSelection();
|
|
@@ -142,17 +193,12 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
142
193
|
|
|
143
194
|
const onScroll = (e: any) => setIsScrolling(e.target.scrollTop > 0);
|
|
144
195
|
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
restoreDataContent(deletedItem);
|
|
148
|
-
}
|
|
149
|
-
setIsVisible(false);
|
|
150
|
-
};
|
|
196
|
+
const filterItems = async (filterPointer: string, filtersSelected: IQueryValue[]) =>
|
|
197
|
+
setFiltersSelection(filterPointer, filtersSelected);
|
|
151
198
|
|
|
152
199
|
const toastProps = {
|
|
153
|
-
action: () => undoAction(),
|
|
154
200
|
setIsVisible,
|
|
155
|
-
message:
|
|
201
|
+
message: toastState,
|
|
156
202
|
};
|
|
157
203
|
|
|
158
204
|
const bulkActions = allowedToDeleteTaxonomy
|
|
@@ -174,6 +220,8 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
174
220
|
checkState={checkState}
|
|
175
221
|
isScrolling={isScrolling}
|
|
176
222
|
bulkActions={bulkActions}
|
|
223
|
+
filterValues={filterValues}
|
|
224
|
+
filterItems={filterItems}
|
|
177
225
|
/>
|
|
178
226
|
);
|
|
179
227
|
|
|
@@ -185,11 +233,121 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
185
233
|
setLanguage,
|
|
186
234
|
};
|
|
187
235
|
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
236
|
+
const getIcon = (item: TreeItem, onExpand: (itemId: ItemId) => void, onCollapse: (itemId: ItemId) => void) => {
|
|
237
|
+
const handleCollapse = (e: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent) => {
|
|
238
|
+
e.stopPropagation();
|
|
239
|
+
onCollapse(item.id);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const handleExpand = (e: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent) => {
|
|
243
|
+
e.stopPropagation();
|
|
244
|
+
onExpand(item.id);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
if (item.children && item.children.length > 0) {
|
|
248
|
+
return item.isExpanded ? (
|
|
249
|
+
<div onClick={handleCollapse} role="button" tabIndex={0} onKeyDown={handleCollapse}>
|
|
250
|
+
<Icon name="UpArrow" />
|
|
251
|
+
</div>
|
|
252
|
+
) : (
|
|
253
|
+
<div onClick={handleExpand} role="button" tabIndex={0} onKeyDown={handleExpand}>
|
|
254
|
+
<Icon name="DownArrow" />
|
|
255
|
+
</div>
|
|
256
|
+
);
|
|
257
|
+
} else {
|
|
258
|
+
return <></>;
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const renderItem = ({ item, onExpand, onCollapse, provided }: RenderItemParams) => {
|
|
263
|
+
const category = formatItem(item, tree);
|
|
264
|
+
const isItemSelected = isSelected(category.id);
|
|
265
|
+
return (
|
|
266
|
+
<S.Draggable ref={provided.innerRef} {...provided.draggableProps}>
|
|
267
|
+
<CategoryItem
|
|
268
|
+
category={category}
|
|
269
|
+
key={category.id}
|
|
270
|
+
languages={availableLanguages}
|
|
271
|
+
lang={lang}
|
|
272
|
+
isTranslatable={isTranslatable}
|
|
273
|
+
isSelected={isItemSelected}
|
|
274
|
+
onChange={addToBulkSelection}
|
|
275
|
+
toggleToast={toggleToast}
|
|
276
|
+
getContents={getContents}
|
|
277
|
+
icon={getIcon(item, onExpand, onCollapse)}
|
|
278
|
+
dragHandleProps={provided.dragHandleProps}
|
|
279
|
+
/>
|
|
280
|
+
</S.Draggable>
|
|
281
|
+
);
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
const onExpand = (itemId: ItemId) => {
|
|
285
|
+
const newTree = mutateTree(tree, itemId, { isExpanded: true });
|
|
286
|
+
setTree(newTree);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const onCollapse = (itemId: ItemId) => {
|
|
290
|
+
const newTree = mutateTree(tree, itemId, { isExpanded: false });
|
|
291
|
+
setTree(newTree);
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const onDragStart = (item: ItemId) => setItemDragging(item);
|
|
295
|
+
|
|
296
|
+
const onDragEnd = async (source: TreeSourcePosition, destination?: TreeDestinationPosition) => {
|
|
297
|
+
if (!destination) {
|
|
298
|
+
setItemDragging(null);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (destination.index === source.index && destination.parentId === source.parentId) {
|
|
303
|
+
setItemDragging(null);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const item = itemDragging ? findChild(tree, itemDragging) : null;
|
|
308
|
+
|
|
309
|
+
if (!item) {
|
|
310
|
+
setItemDragging(null);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const { parentId } = destination;
|
|
315
|
+
const parentIdNumber = parentId === "root" ? 0 : parseInt(parentId as string);
|
|
316
|
+
const parent: any = getElementsFromTree(tree).find((data: any) => data.id === parentIdNumber);
|
|
317
|
+
|
|
318
|
+
if (parentId === "root" || parent?.type === "group") {
|
|
319
|
+
const newTree = moveItemOnTree(tree, source, destination);
|
|
320
|
+
newTree.items[parentId].isExpanded = true;
|
|
321
|
+
setTree(newTree);
|
|
322
|
+
|
|
323
|
+
const isGoingUp =
|
|
324
|
+
(destination.parentId === source.parentId &&
|
|
325
|
+
destination.index !== undefined &&
|
|
326
|
+
destination.index < source.index) ||
|
|
327
|
+
destination.parentId !== source.parentId;
|
|
328
|
+
|
|
329
|
+
const index =
|
|
330
|
+
destination.index !== undefined
|
|
331
|
+
? destination.index - (isGoingUp ? 1 : 0)
|
|
332
|
+
: parent
|
|
333
|
+
? parent.children.length - 1
|
|
334
|
+
: 0;
|
|
335
|
+
|
|
336
|
+
const itemDestination = findChildByIndex(tree, parentId, index);
|
|
337
|
+
|
|
338
|
+
const params: IOrderCategoryParams = {
|
|
339
|
+
contentId: item.id,
|
|
340
|
+
type: item.type,
|
|
341
|
+
position: itemDestination ? itemDestination.position + 1 : 1,
|
|
342
|
+
parentGroup: parentIdNumber,
|
|
343
|
+
structuredData: item.structuredData,
|
|
344
|
+
relatedSite: currentSiteID || null,
|
|
345
|
+
language: lang.id,
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
await orderCategory(params);
|
|
349
|
+
setItemDragging(null);
|
|
350
|
+
}
|
|
193
351
|
};
|
|
194
352
|
|
|
195
353
|
const isEmpty = currentDataContent && currentDataContent.length === 0;
|
|
@@ -200,16 +358,23 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
200
358
|
? `To start using ${categoryName} categories, create as many of them as yo need.`
|
|
201
359
|
: "To start using categories in your site, you must active all Content type packages as you need.",
|
|
202
360
|
button: hasCategories ? `Create ${categoryName} category` : "Activate Content type packages",
|
|
203
|
-
action: hasCategories ?
|
|
361
|
+
action: hasCategories ? toggleModal : () => setHistoryPush("/sites/settings/content-types"),
|
|
204
362
|
};
|
|
205
363
|
|
|
206
364
|
const mainDeleteModalAction = {
|
|
207
|
-
title: "
|
|
365
|
+
title: "Yes, delete it",
|
|
208
366
|
onClick: bulkDelete,
|
|
209
367
|
};
|
|
210
368
|
|
|
211
369
|
const secondaryDeleteModalAction = { title: "Cancel", onClick: toggleDeleteModal };
|
|
212
370
|
|
|
371
|
+
const mainDeleteGroupModalAction = {
|
|
372
|
+
title: "Delete",
|
|
373
|
+
onClick: bulkDelete,
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
const secondaryDeleteGroupModalAction = { title: "Cancel", onClick: toggleGroupModal };
|
|
377
|
+
|
|
213
378
|
return (
|
|
214
379
|
<MainWrapper
|
|
215
380
|
title="Categories"
|
|
@@ -217,6 +382,8 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
217
382
|
language={lang}
|
|
218
383
|
availableLanguages={availableLanguages}
|
|
219
384
|
languageActions={languageActions}
|
|
385
|
+
searchAction={setSearchQuery}
|
|
386
|
+
searchValue={searchQuery}
|
|
220
387
|
>
|
|
221
388
|
<S.CategoryListWrapper>
|
|
222
389
|
<CategoryNav
|
|
@@ -224,52 +391,71 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
224
391
|
categories={currentCategories}
|
|
225
392
|
onClick={handleClick}
|
|
226
393
|
dataPacks={activatedDataPacks}
|
|
227
|
-
setSelectedCategory={setSelectedCategory}
|
|
228
|
-
scope={scope}
|
|
229
394
|
/>
|
|
230
395
|
<S.TableWrapper>
|
|
231
396
|
<ErrorToast />
|
|
232
|
-
<
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
397
|
+
<S.Intro>
|
|
398
|
+
<S.IntroTitle>Create and manage categories</S.IntroTitle>
|
|
399
|
+
<div>Define your categories by creating the elements you need and asign them to your content types.</div>
|
|
400
|
+
</S.Intro>
|
|
401
|
+
<TableList tableHeader={TableHeader} onScroll={onScroll} hasFixedHeader={true} tableRef={tableRef}>
|
|
402
|
+
<S.SearchTags>
|
|
403
|
+
<SearchTagsBar query={searchQuery} setQuery={setSearchQuery} />
|
|
404
|
+
<FilterTagsBar
|
|
405
|
+
filters={filterValues}
|
|
406
|
+
setFilters={setFiltersSelection}
|
|
407
|
+
resetFilters={resetFilterQuery}
|
|
408
|
+
labels={{ translated: "Translated" }}
|
|
409
|
+
/>
|
|
410
|
+
</S.SearchTags>
|
|
239
411
|
{isEmpty ? (
|
|
240
412
|
<S.EmptyWrapper>
|
|
241
413
|
<EmptyState {...emptyStateProps} />
|
|
242
414
|
</S.EmptyWrapper>
|
|
243
415
|
) : (
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
<
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
416
|
+
<>
|
|
417
|
+
<S.Notification>
|
|
418
|
+
Arrange your category list by <strong>drag & drop</strong>. You can move categories between groups,
|
|
419
|
+
but <strong>it's not possible to nest one category within another to create a new group.</strong>
|
|
420
|
+
</S.Notification>
|
|
421
|
+
<S.Droppable>
|
|
422
|
+
<Tree
|
|
423
|
+
tree={tree}
|
|
424
|
+
renderItem={renderItem}
|
|
425
|
+
onExpand={onExpand}
|
|
426
|
+
onCollapse={onCollapse}
|
|
427
|
+
onDragEnd={onDragEnd}
|
|
428
|
+
onDragStart={onDragStart}
|
|
429
|
+
isDragEnabled
|
|
430
|
+
isNestingEnabled
|
|
258
431
|
/>
|
|
259
|
-
|
|
260
|
-
|
|
432
|
+
</S.Droppable>
|
|
433
|
+
</>
|
|
261
434
|
)}
|
|
262
435
|
</TableList>
|
|
263
436
|
</S.TableWrapper>
|
|
264
437
|
</S.CategoryListWrapper>
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
438
|
+
{isOpen && (
|
|
439
|
+
<CategoryPanel isOpen={isOpen} toggleModal={toggleModal} getContents={getContents} toggleToast={toggleToast} />
|
|
440
|
+
)}
|
|
441
|
+
{isDeleteOpen && (
|
|
442
|
+
<DeleteModal
|
|
443
|
+
isOpen={isDeleteOpen}
|
|
444
|
+
toggleModal={toggleDeleteModal}
|
|
445
|
+
mainModalAction={mainDeleteModalAction}
|
|
446
|
+
secondaryModalAction={secondaryDeleteModalAction}
|
|
447
|
+
/>
|
|
448
|
+
)}
|
|
449
|
+
{isGroupOpen && (
|
|
450
|
+
<DeleteGroupModal
|
|
451
|
+
isOpen={isGroupOpen}
|
|
452
|
+
toggleModal={toggleGroupModal}
|
|
453
|
+
mainModalAction={mainDeleteGroupModalAction}
|
|
454
|
+
secondaryModalAction={secondaryDeleteGroupModalAction}
|
|
455
|
+
deleteGroupCategories={deleteGroupCategories}
|
|
456
|
+
setDeleteGroupCategories={setDeleteGroupCategories}
|
|
457
|
+
/>
|
|
458
|
+
)}
|
|
273
459
|
{isVisible && <Toast {...toastProps} />}
|
|
274
460
|
</MainWrapper>
|
|
275
461
|
);
|
|
@@ -280,7 +466,7 @@ const mapStateToProps = (state: IRootState) => ({
|
|
|
280
466
|
currentSiteID: state.sites.currentSiteInfo && state.sites.currentSiteInfo.id,
|
|
281
467
|
siteLanguages: state.sites.currentSiteLanguages,
|
|
282
468
|
globalLangs: state.app.globalLangs,
|
|
283
|
-
currentDataContent: state.structuredData.
|
|
469
|
+
currentDataContent: state.structuredData.currentDataCategory,
|
|
284
470
|
currentStructuredData: state.structuredData.currentStructuredData,
|
|
285
471
|
lang: state.app.lang,
|
|
286
472
|
totalItems: state.sites.totalItems,
|
|
@@ -289,24 +475,24 @@ const mapStateToProps = (state: IRootState) => ({
|
|
|
289
475
|
|
|
290
476
|
interface IDispatchProps {
|
|
291
477
|
getStructuredDataContents(params: IGetStructuredDataParams, siteID: number | null): Promise<void>;
|
|
292
|
-
resetCategoryValues(): void;
|
|
293
478
|
setLanguage(lang: { locale: string; id: number | null }): void;
|
|
294
479
|
setSelectedCategory(id: string, scope: string): void;
|
|
295
|
-
deleteDataContent(catID: number[]): Promise<boolean>;
|
|
296
|
-
restoreDataContent(catID: number | number[]): void;
|
|
480
|
+
deleteDataContent(catID: number[], refresh?: boolean): Promise<boolean>;
|
|
297
481
|
setHistoryPush(path: string): void;
|
|
298
482
|
resetCurrentData(): Promise<void>;
|
|
483
|
+
deleteCategoryGroup(id: number | number[], deleteChildren: boolean, refresh?: boolean): Promise<boolean>;
|
|
484
|
+
orderCategory(params: IOrderCategoryParams): Promise<boolean>;
|
|
299
485
|
}
|
|
300
486
|
|
|
301
487
|
interface ICategoriesProps {
|
|
302
488
|
currentSiteID: number | null;
|
|
303
|
-
currentDataContent:
|
|
489
|
+
currentDataContent: (IStructuredDataCategory | ICategoryGroup)[];
|
|
304
490
|
currentStructuredData: IStructuredData | null;
|
|
305
|
-
lang: { locale: string; id: number
|
|
491
|
+
lang: { locale: string; id: number };
|
|
306
492
|
siteLanguages: any[];
|
|
307
493
|
globalLangs: any[];
|
|
308
494
|
totalItems: number;
|
|
309
|
-
categories:
|
|
495
|
+
categories: { global: IStructuredData[]; site: IStructuredData[] };
|
|
310
496
|
activatedDataPacks: IDataPack[];
|
|
311
497
|
}
|
|
312
498
|
|
|
@@ -314,13 +500,13 @@ type IProps = ICategoriesProps & IDispatchProps;
|
|
|
314
500
|
|
|
315
501
|
const mapDispatchToProps = {
|
|
316
502
|
getStructuredDataContents: structuredDataActions.getStructuredDataContents,
|
|
317
|
-
resetCategoryValues: structuredDataActions.resetCategoryValues,
|
|
318
503
|
setLanguage: appActions.setLanguage,
|
|
319
504
|
setSelectedCategory: structuredDataActions.setSelectedCategory,
|
|
320
505
|
deleteDataContent: structuredDataActions.deleteStructuredDataContent,
|
|
321
|
-
|
|
506
|
+
deleteCategoryGroup: structuredDataActions.deleteCategoryGroup,
|
|
322
507
|
setHistoryPush: appActions.setHistoryPush,
|
|
323
508
|
resetCurrentData: structuredDataActions.resetCurrentData,
|
|
509
|
+
orderCategory: structuredDataActions.orderCategory,
|
|
324
510
|
};
|
|
325
511
|
|
|
326
512
|
export default connect(mapStateToProps, mapDispatchToProps)(CategoriesList);
|