@griddo/ax 10.1.25 → 10.1.27
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/navigation.tsx +46 -0
- package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/TemplateManager/index.tsx +6 -4
- package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/index.tsx +4 -3
- package/src/components/Fields/Select/index.tsx +3 -3
- package/src/components/Fields/Select/style.tsx +55 -0
- package/src/containers/App/actions.tsx +2 -0
- package/src/containers/App/reducer.tsx +1 -0
- package/src/containers/Navigation/Defaults/actions.tsx +57 -4
- package/src/containers/Navigation/Defaults/constants.tsx +1 -0
- package/src/containers/Navigation/Defaults/interfaces.tsx +7 -1
- package/src/containers/Navigation/Defaults/reducer.tsx +5 -1
- package/src/containers/Sites/actions.tsx +4 -8
- package/src/guards/error/index.tsx +5 -2
- package/src/modules/Navigation/Defaults/Item/index.tsx +12 -8
- package/src/modules/Navigation/Defaults/ReplaceNavModal/index.tsx +205 -0
- package/src/modules/Navigation/Defaults/ReplaceNavModal/style.tsx +99 -0
- package/src/modules/Navigation/Defaults/index.tsx +37 -9
- package/src/modules/Sites/SitesList/index.tsx +7 -8
- package/src/types/index.tsx +12 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@griddo/ax",
|
|
3
3
|
"description": "Griddo Author Experience",
|
|
4
|
-
"version": "10.1.
|
|
4
|
+
"version": "10.1.27",
|
|
5
5
|
"authors": [
|
|
6
6
|
"Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
|
|
7
7
|
"Carlos Torres <carlos.torres@secuoyas.com>",
|
|
@@ -230,5 +230,5 @@
|
|
|
230
230
|
"publishConfig": {
|
|
231
231
|
"access": "public"
|
|
232
232
|
},
|
|
233
|
-
"gitHead": "
|
|
233
|
+
"gitHead": "e536109348c8ffe2b88f14305986fcfe137ddaf0"
|
|
234
234
|
}
|
package/src/api/navigation.tsx
CHANGED
|
@@ -57,6 +57,21 @@ const SERVICES: { [key: string]: IServiceConfig } = {
|
|
|
57
57
|
endpoint: ["/navigations/", "/languages"],
|
|
58
58
|
method: "GET",
|
|
59
59
|
},
|
|
60
|
+
GET_PAGES_BY_HEADER: {
|
|
61
|
+
...template,
|
|
62
|
+
endpoint: ["/navigations/", "/header/site/", "/pages"],
|
|
63
|
+
method: "GET",
|
|
64
|
+
},
|
|
65
|
+
GET_PAGES_BY_FOOTER: {
|
|
66
|
+
...template,
|
|
67
|
+
endpoint: ["/navigations/", "/footer/site/", "/pages"],
|
|
68
|
+
method: "GET",
|
|
69
|
+
},
|
|
70
|
+
UPDATE_PAGE_NAVIGATION: {
|
|
71
|
+
...template,
|
|
72
|
+
endpoint: "/navigations/page/bulk",
|
|
73
|
+
method: "PUT",
|
|
74
|
+
},
|
|
60
75
|
};
|
|
61
76
|
|
|
62
77
|
const getNavigation = (id: number) => {
|
|
@@ -157,6 +172,34 @@ const getNavigationsLanguages = async (navID: number) => {
|
|
|
157
172
|
return sendRequest(SERVICES.GET_NAVIGATIONS_LANGUAGES);
|
|
158
173
|
};
|
|
159
174
|
|
|
175
|
+
const getPagesByHeader = async (headerID: number | number[], siteID: number) => {
|
|
176
|
+
const {
|
|
177
|
+
host,
|
|
178
|
+
endpoint: [prefix, infix, suffix],
|
|
179
|
+
} = SERVICES.GET_PAGES_BY_HEADER;
|
|
180
|
+
|
|
181
|
+
const ids = Array.isArray(headerID) ? headerID.join(",") : headerID;
|
|
182
|
+
|
|
183
|
+
SERVICES.GET_PAGES_BY_HEADER.dynamicUrl = `${host}${prefix}${ids}${infix}${siteID}${suffix}`;
|
|
184
|
+
|
|
185
|
+
return sendRequest(SERVICES.GET_PAGES_BY_HEADER);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const getPagesByFooter = async (footerID: number | number[], siteID: number) => {
|
|
189
|
+
const {
|
|
190
|
+
host,
|
|
191
|
+
endpoint: [prefix, infix, suffix],
|
|
192
|
+
} = SERVICES.GET_PAGES_BY_FOOTER;
|
|
193
|
+
|
|
194
|
+
const ids = Array.isArray(footerID) ? footerID.join(",") : footerID;
|
|
195
|
+
|
|
196
|
+
SERVICES.GET_PAGES_BY_FOOTER.dynamicUrl = `${host}${prefix}${ids}${infix}${siteID}${suffix}`;
|
|
197
|
+
|
|
198
|
+
return sendRequest(SERVICES.GET_PAGES_BY_FOOTER);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const updatePageNavigation = (data: any) => sendRequest(SERVICES.UPDATE_PAGE_NAVIGATION, data);
|
|
202
|
+
|
|
160
203
|
export default {
|
|
161
204
|
getNavigation,
|
|
162
205
|
getHeaders,
|
|
@@ -169,4 +212,7 @@ export default {
|
|
|
169
212
|
getNavigationsLanguages,
|
|
170
213
|
deleteNavigationBulk,
|
|
171
214
|
restoreNavigationBulk,
|
|
215
|
+
getPagesByHeader,
|
|
216
|
+
getPagesByFooter,
|
|
217
|
+
updatePageNavigation,
|
|
172
218
|
};
|
package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/TemplateManager/index.tsx
CHANGED
|
@@ -2,10 +2,10 @@ import React from "react";
|
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
3
|
|
|
4
4
|
import { IDataPack, IErrorItem, IRootState, ISite } from "@ax/types";
|
|
5
|
+
import { getModuleCategories } from "@ax/helpers";
|
|
6
|
+
import Field from "../Field";
|
|
5
7
|
|
|
6
8
|
import * as S from "./style";
|
|
7
|
-
import Field from "../Field";
|
|
8
|
-
import { getModuleCategories } from "@ax/helpers";
|
|
9
9
|
|
|
10
10
|
export const TemplateManager = (props: IProps): JSX.Element => {
|
|
11
11
|
const {
|
|
@@ -37,7 +37,7 @@ export const TemplateManager = (props: IProps): JSX.Element => {
|
|
|
37
37
|
const modulesDataPacks = activatedPacks.map((pack: IDataPack) => pack.modules).flat();
|
|
38
38
|
|
|
39
39
|
const getFieldProps = (field: any) => {
|
|
40
|
-
const { key, type, whiteList = [], slugTo } = field;
|
|
40
|
+
const { key, type, whiteList = [], slugTo, readonly } = field;
|
|
41
41
|
const isArr = type === "ComponentArray";
|
|
42
42
|
const currentContent = isArr ? templateContent[key] : templateContent;
|
|
43
43
|
const fieldObjKey = !isArr ? `${key}` : `modules`;
|
|
@@ -70,6 +70,7 @@ export const TemplateManager = (props: IProps): JSX.Element => {
|
|
|
70
70
|
currentContent,
|
|
71
71
|
handleUpdate,
|
|
72
72
|
error,
|
|
73
|
+
readonly
|
|
73
74
|
};
|
|
74
75
|
};
|
|
75
76
|
|
|
@@ -78,7 +79,7 @@ export const TemplateManager = (props: IProps): JSX.Element => {
|
|
|
78
79
|
{isConfig && templateFields && <S.Title>Template Options</S.Title>}
|
|
79
80
|
{templateFields &&
|
|
80
81
|
templateFields.map((templateField: any, index: number) => {
|
|
81
|
-
const { whiteList, categories, key, fieldObjKey, mappedField, currentContent, handleUpdate, error } =
|
|
82
|
+
const { whiteList, categories, key, fieldObjKey, mappedField, currentContent, handleUpdate, error, readonly } =
|
|
82
83
|
getFieldProps(templateField);
|
|
83
84
|
|
|
84
85
|
return (
|
|
@@ -106,6 +107,7 @@ export const TemplateManager = (props: IProps): JSX.Element => {
|
|
|
106
107
|
template={template}
|
|
107
108
|
setHistoryPush={setHistoryPush}
|
|
108
109
|
lang={lang}
|
|
110
|
+
readonly={readonly}
|
|
109
111
|
/>
|
|
110
112
|
);
|
|
111
113
|
})}
|
|
@@ -3,9 +3,9 @@ import { connect } from "react-redux";
|
|
|
3
3
|
|
|
4
4
|
import { getTemplate, isModuleDisabled, slugify, areEqual } from "@ax/helpers";
|
|
5
5
|
import { IRootState } from "@ax/types";
|
|
6
|
+
import { pageEditorActions } from "@ax/containers/PageEditor";
|
|
6
7
|
|
|
7
8
|
import TemplateManager from "./TemplateManager";
|
|
8
|
-
import { pageEditorActions } from "@ax/containers/PageEditor";
|
|
9
9
|
import Field from "./Field";
|
|
10
10
|
|
|
11
11
|
const PageConnectedField = (props: any) => {
|
|
@@ -61,7 +61,8 @@ const PageConnectedField = (props: any) => {
|
|
|
61
61
|
objKey === "parent" &&
|
|
62
62
|
isTemplateActivated &&
|
|
63
63
|
templateConfig &&
|
|
64
|
-
templateConfig.modifiableOnPage === false
|
|
64
|
+
templateConfig.modifiableOnPage === false &&
|
|
65
|
+
templateConfig.defaultParent) ||
|
|
65
66
|
isReadOnly;
|
|
66
67
|
|
|
67
68
|
const defaultParent =
|
|
@@ -70,7 +71,7 @@ const PageConnectedField = (props: any) => {
|
|
|
70
71
|
const hasDefaultIndex = isTemplateActivated && templateConfig && templateConfig.indexDefault !== undefined;
|
|
71
72
|
|
|
72
73
|
const isFieldReadOnly =
|
|
73
|
-
(["parent", "slug"].includes(objKey) && isPageHome) || parentIsReadOnly;
|
|
74
|
+
(["parent", "slug"].includes(objKey) && isPageHome) || parentIsReadOnly || field.readonly;
|
|
74
75
|
|
|
75
76
|
const isDisabled =
|
|
76
77
|
(!isGlobal &&
|
|
@@ -36,7 +36,7 @@ const Select = (props: ISelectProps): JSX.Element => {
|
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
// tslint:disable-next-line: no-shadowed-variable
|
|
39
|
-
const getObjectValue = (value: string, options: IOptionProps[]) => {
|
|
39
|
+
const getObjectValue = (value: string | number | undefined, options: IOptionProps[]) => {
|
|
40
40
|
if (!value) {
|
|
41
41
|
return null;
|
|
42
42
|
} else {
|
|
@@ -44,7 +44,7 @@ const Select = (props: ISelectProps): JSX.Element => {
|
|
|
44
44
|
}
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
const searchable = type === "inline" ? false : true;
|
|
47
|
+
const searchable = type === "inline" || type === "mini" ? false : true;
|
|
48
48
|
|
|
49
49
|
return (
|
|
50
50
|
<div data-testid="select-component">
|
|
@@ -72,7 +72,7 @@ const Select = (props: ISelectProps): JSX.Element => {
|
|
|
72
72
|
|
|
73
73
|
export interface ISelectProps {
|
|
74
74
|
name: string;
|
|
75
|
-
value: string;
|
|
75
|
+
value: string | undefined;
|
|
76
76
|
options: IOptionProps[];
|
|
77
77
|
error?: boolean;
|
|
78
78
|
disabled?: boolean;
|
|
@@ -139,4 +139,59 @@ export const StyledSelect = styled(Select)<{
|
|
|
139
139
|
${(p) => p.theme.textStyle?.fieldContent};
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
+
|
|
143
|
+
&.mini {
|
|
144
|
+
${(p) => p.theme.textStyle.uiS};
|
|
145
|
+
text-transform: capitalize;
|
|
146
|
+
|
|
147
|
+
.react-select__control {
|
|
148
|
+
height: 24px;
|
|
149
|
+
min-height: 24px;
|
|
150
|
+
justify-content: ${(p) => (p.alignRight ? "flex-end" : "flex-start")};
|
|
151
|
+
padding: 0 5px;
|
|
152
|
+
|
|
153
|
+
.react-select__value-container {
|
|
154
|
+
flex: 0 1 auto;
|
|
155
|
+
padding: 0;
|
|
156
|
+
.react-select__single-value {
|
|
157
|
+
position: relative;
|
|
158
|
+
transform: none;
|
|
159
|
+
overflow: visible;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
.react-select__indicator {
|
|
163
|
+
padding: 0;
|
|
164
|
+
svg {
|
|
165
|
+
width: ${(p) => p.theme.spacing.s};
|
|
166
|
+
height: ${(p) => p.theme.spacing.s};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
.react-select__input {
|
|
170
|
+
input {
|
|
171
|
+
cursor: default;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
.react-select__placeholder {
|
|
175
|
+
position: relative;
|
|
176
|
+
transform: none;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.react-select__control--is-disabled {
|
|
181
|
+
.react-select__value-container {
|
|
182
|
+
.react-select__single-value {
|
|
183
|
+
color: ${(p) => p.theme.color.interactiveDisabled};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.react-select__menu {
|
|
189
|
+
${(p) => p.theme.textStyle.uiXS};
|
|
190
|
+
|
|
191
|
+
.react-select__option {
|
|
192
|
+
padding: ${(p) => p.theme.spacing.xs};
|
|
193
|
+
min-height: auto;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
142
197
|
`;
|
|
@@ -120,6 +120,7 @@ function handleError(response: any, isMultiple = false, msg?: string): (dispatch
|
|
|
120
120
|
btnText,
|
|
121
121
|
actionsBelow,
|
|
122
122
|
text,
|
|
123
|
+
btnAction,
|
|
123
124
|
} = response;
|
|
124
125
|
|
|
125
126
|
const firstMsg = Array.isArray(message) && message[0] ? message[0].error : message || text;
|
|
@@ -129,6 +130,7 @@ function handleError(response: any, isMultiple = false, msg?: string): (dispatch
|
|
|
129
130
|
text: msg ? msg : firstMsg,
|
|
130
131
|
btnText,
|
|
131
132
|
actionsBelow,
|
|
133
|
+
btnAction,
|
|
132
134
|
subErrors: isMultiple ? message : [],
|
|
133
135
|
};
|
|
134
136
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Dispatch } from "redux";
|
|
2
2
|
|
|
3
3
|
import { navigation } from "@ax/api";
|
|
4
|
-
import { IBreadcrumbItem, INotification, ISchema } from "@ax/types";
|
|
4
|
+
import { IBreadcrumbItem, INavPages, INotification, ISchema, IUpdateNavigationParam } from "@ax/types";
|
|
5
5
|
import {
|
|
6
6
|
getDefaultSchema,
|
|
7
7
|
getSchema,
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
getDefaultNavigationModules,
|
|
13
13
|
} from "@ax/helpers";
|
|
14
14
|
import {
|
|
15
|
-
checkMaxModules,
|
|
16
15
|
findByEditorID,
|
|
17
16
|
generateEditorIDs,
|
|
18
17
|
getLastComponentEditorID,
|
|
@@ -44,6 +43,7 @@ import {
|
|
|
44
43
|
SET_IS_NEW_TRANSLATION,
|
|
45
44
|
SET_SELECTED_PARENT,
|
|
46
45
|
SET_COPY_MODULE,
|
|
46
|
+
SET_NAV_PAGES,
|
|
47
47
|
} from "./constants";
|
|
48
48
|
|
|
49
49
|
import {
|
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
ISetIsNewTranslation,
|
|
59
59
|
ISetSelectedParent,
|
|
60
60
|
ISetCopyModule,
|
|
61
|
+
ISetNavPages,
|
|
61
62
|
} from "./interfaces";
|
|
62
63
|
|
|
63
64
|
const { setIsLoading } = appActions;
|
|
@@ -122,6 +123,10 @@ function setCopyModule(moduleCopy: Record<string, unknown> | null): ISetCopyModu
|
|
|
122
123
|
return { type: SET_COPY_MODULE, payload: { moduleCopy } };
|
|
123
124
|
}
|
|
124
125
|
|
|
126
|
+
function setNavPages(navigationPages: INavPages): ISetNavPages {
|
|
127
|
+
return { type: SET_NAV_PAGES, payload: { navigationPages } };
|
|
128
|
+
}
|
|
129
|
+
|
|
125
130
|
// API RELATED FUNCTIONS
|
|
126
131
|
|
|
127
132
|
function getHeaders(params: any): (dispatch: Dispatch, getState: any) => Promise<void> {
|
|
@@ -330,7 +335,8 @@ function updateNavigation(
|
|
|
330
335
|
|
|
331
336
|
function deleteNavigation(
|
|
332
337
|
navID: number | number[],
|
|
333
|
-
type: string
|
|
338
|
+
type: string,
|
|
339
|
+
errorAction: () => void
|
|
334
340
|
): (dispatch: Dispatch, getState: any) => Promise<boolean> {
|
|
335
341
|
return async (dispatch, getState) => {
|
|
336
342
|
try {
|
|
@@ -339,13 +345,18 @@ function deleteNavigation(
|
|
|
339
345
|
handleSuccess: () => getNavigationByType(type)(dispatch, getState),
|
|
340
346
|
handleError: (response: any) => {
|
|
341
347
|
const {
|
|
342
|
-
data: { message },
|
|
348
|
+
data: { message, code },
|
|
343
349
|
} = response;
|
|
344
350
|
|
|
345
351
|
if (isBulk) {
|
|
346
352
|
getNavigationByType(type)(dispatch, getState);
|
|
347
353
|
}
|
|
348
354
|
|
|
355
|
+
if (code === 403) {
|
|
356
|
+
response.btnText = "Show Pages";
|
|
357
|
+
response.btnAction = errorAction;
|
|
358
|
+
}
|
|
359
|
+
|
|
349
360
|
const isMultiple = Array.isArray(message) && message.length > 1;
|
|
350
361
|
const msg = isMultiple ? `The delete action failed due to ${message.length} errors.` : undefined;
|
|
351
362
|
appActions.handleError(response, isMultiple, msg)(dispatch);
|
|
@@ -817,6 +828,46 @@ function resetDefaultsValues(): (dispatch: Dispatch) => Promise<void> {
|
|
|
817
828
|
};
|
|
818
829
|
}
|
|
819
830
|
|
|
831
|
+
function getPagesByNavigation(
|
|
832
|
+
type: string,
|
|
833
|
+
navID: number | number[],
|
|
834
|
+
siteID: number
|
|
835
|
+
): (dispatch: Dispatch) => Promise<void> {
|
|
836
|
+
return async (dispatch) => {
|
|
837
|
+
try {
|
|
838
|
+
const responseActions = {
|
|
839
|
+
handleSuccess: async (response: any) => dispatch(setNavPages(response)),
|
|
840
|
+
handleError: (response: any) => appActions.handleError(response)(dispatch),
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
const callback = async () =>
|
|
844
|
+
type === "header" ? navigation.getPagesByHeader(navID, siteID) : navigation.getPagesByFooter(navID, siteID);
|
|
845
|
+
|
|
846
|
+
await handleRequest(callback, responseActions, [appActions.setIsLoading])(dispatch);
|
|
847
|
+
} catch (e) {
|
|
848
|
+
console.log(e);
|
|
849
|
+
}
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
function updatePageNavigation(data: IUpdateNavigationParam): (dispatch: Dispatch) => Promise<boolean> {
|
|
854
|
+
return async (dispatch) => {
|
|
855
|
+
try {
|
|
856
|
+
const responseActions = {
|
|
857
|
+
handleSuccess: async () => dispatch(appActions.resetError()),
|
|
858
|
+
handleError: (response: any) => appActions.handleError(response)(dispatch),
|
|
859
|
+
};
|
|
860
|
+
|
|
861
|
+
const callback = async () => navigation.updatePageNavigation(data);
|
|
862
|
+
|
|
863
|
+
return await handleRequest(callback, responseActions, [])(dispatch);
|
|
864
|
+
} catch (e) {
|
|
865
|
+
console.log(e);
|
|
866
|
+
return false;
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
|
|
820
871
|
export {
|
|
821
872
|
setEditorContent,
|
|
822
873
|
setBreadcrumb,
|
|
@@ -854,4 +905,6 @@ export {
|
|
|
854
905
|
moveModule,
|
|
855
906
|
copyModule,
|
|
856
907
|
pasteModule,
|
|
908
|
+
getPagesByNavigation,
|
|
909
|
+
updatePageNavigation,
|
|
857
910
|
};
|
|
@@ -15,5 +15,6 @@ export const SET_TOTAL_ITEMS = `${NAME}/SET_TOTAL_ITEMS`;
|
|
|
15
15
|
export const SET_CURRENT_NAVIGATION_LANGUAGES = `${NAME}/SET_CURRENT_NAVIGATION_LANGUAGES`;
|
|
16
16
|
export const SET_IS_NEW_TRANSLATION = `${NAME}/SET_IS_NEW_TRANSLATION`;
|
|
17
17
|
export const SET_COPY_MODULE = `${NAME}/SET_COPY_MODULE`;
|
|
18
|
+
export const SET_NAV_PAGES = `${NAME}/SET_NAV_PAGES`;
|
|
18
19
|
|
|
19
20
|
export const ITEMS_PER_PAGE = 50;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IBreadcrumbItem, ISchema } from "@ax/types";
|
|
1
|
+
import { IBreadcrumbItem, INavPages, ISchema } from "@ax/types";
|
|
2
2
|
import {
|
|
3
3
|
SET_EDITOR_CONTENT,
|
|
4
4
|
SET_BREADCRUMB,
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
SET_IS_NEW_TRANSLATION,
|
|
15
15
|
SET_SELECTED_PARENT,
|
|
16
16
|
SET_COPY_MODULE,
|
|
17
|
+
SET_NAV_PAGES,
|
|
17
18
|
} from "./constants";
|
|
18
19
|
|
|
19
20
|
export interface ISetEditorContent {
|
|
@@ -86,6 +87,11 @@ export interface ISetCopyModule {
|
|
|
86
87
|
payload: { moduleCopy: Record<string, unknown> | null };
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
export interface ISetNavPages {
|
|
91
|
+
type: typeof SET_NAV_PAGES;
|
|
92
|
+
payload: { navigationPages: INavPages };
|
|
93
|
+
}
|
|
94
|
+
|
|
89
95
|
export type NavigationActionsCreators = ISetEditorContent &
|
|
90
96
|
ISetBreadcrumb &
|
|
91
97
|
ISetSchema &
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IBreadcrumbItem, ISchema } from "@ax/types";
|
|
1
|
+
import { IBreadcrumbItem, INavPages, ISchema } from "@ax/types";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
SET_EDITOR_CONTENT,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
SET_IS_NEW_TRANSLATION,
|
|
17
17
|
SET_SELECTED_PARENT,
|
|
18
18
|
SET_COPY_MODULE,
|
|
19
|
+
SET_NAV_PAGES,
|
|
19
20
|
} from "./constants";
|
|
20
21
|
import { NavigationActionsCreators } from "./interfaces";
|
|
21
22
|
|
|
@@ -36,6 +37,7 @@ export interface INavigationState {
|
|
|
36
37
|
isNewTranslation: boolean;
|
|
37
38
|
form: any;
|
|
38
39
|
moduleCopy: { date: string; element: Record<string, unknown> } | null;
|
|
40
|
+
navigationPages: INavPages | null;
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
export const initialState = {
|
|
@@ -55,6 +57,7 @@ export const initialState = {
|
|
|
55
57
|
isNewTranslation: false,
|
|
56
58
|
form: {},
|
|
57
59
|
moduleCopy: null,
|
|
60
|
+
navigationPages: null,
|
|
58
61
|
};
|
|
59
62
|
|
|
60
63
|
export function reducer(state = initialState, action: NavigationActionsCreators): INavigationState {
|
|
@@ -74,6 +77,7 @@ export function reducer(state = initialState, action: NavigationActionsCreators)
|
|
|
74
77
|
case SET_CURRENT_NAVIGATION_LANGUAGES:
|
|
75
78
|
case SET_IS_NEW_TRANSLATION:
|
|
76
79
|
case SET_COPY_MODULE:
|
|
80
|
+
case SET_NAV_PAGES:
|
|
77
81
|
return { ...state, ...action.payload };
|
|
78
82
|
default:
|
|
79
83
|
return state;
|
|
@@ -397,13 +397,11 @@ function publishSite(siteID: number, params?: IGetSitesParams): (dispatch: Dispa
|
|
|
397
397
|
};
|
|
398
398
|
}
|
|
399
399
|
|
|
400
|
-
function publishSitesBulk(ids: number[]): (dispatch: Dispatch) => Promise<void> {
|
|
400
|
+
function publishSitesBulk(ids: number[], params?: IGetSitesParams): (dispatch: Dispatch) => Promise<void> {
|
|
401
401
|
return async (dispatch) => {
|
|
402
402
|
try {
|
|
403
403
|
const responseActions = {
|
|
404
|
-
handleSuccess: () =>
|
|
405
|
-
getSites()(dispatch);
|
|
406
|
-
},
|
|
404
|
+
handleSuccess: () => getSites(params)(dispatch),
|
|
407
405
|
handleError: (response: any) => appActions.handleError(response)(dispatch),
|
|
408
406
|
};
|
|
409
407
|
const callback = async () => sites.publishSiteBulk(ids);
|
|
@@ -428,13 +426,11 @@ function unpublishSite(siteID: number, params?: IGetSitesParams): (dispatch: Dis
|
|
|
428
426
|
};
|
|
429
427
|
}
|
|
430
428
|
|
|
431
|
-
function unpublishSitesBulk(ids: number[]): (dispatch: Dispatch) => Promise<void> {
|
|
429
|
+
function unpublishSitesBulk(ids: number[], params?: IGetSitesParams): (dispatch: Dispatch) => Promise<void> {
|
|
432
430
|
return async (dispatch) => {
|
|
433
431
|
try {
|
|
434
432
|
const responseActions = {
|
|
435
|
-
handleSuccess: () =>
|
|
436
|
-
getSites()(dispatch);
|
|
437
|
-
},
|
|
433
|
+
handleSuccess: () => getSites(params)(dispatch),
|
|
438
434
|
handleError: (response: any) => appActions.handleError(response)(dispatch),
|
|
439
435
|
};
|
|
440
436
|
const callback = async () => sites.unpublishSiteBulk(ids);
|
|
@@ -19,7 +19,7 @@ const ErrorView = (props: any) => {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
const ErrorGuard = (props: IProps) => {
|
|
22
|
-
const { text, code, resetError, btnText, actionsBelow, subErrors } = props;
|
|
22
|
+
const { text, code, resetError, btnText, actionsBelow, subErrors, btnAction } = props;
|
|
23
23
|
|
|
24
24
|
const isBlocking = blockingErrors.includes(code);
|
|
25
25
|
|
|
@@ -38,6 +38,7 @@ const ErrorGuard = (props: IProps) => {
|
|
|
38
38
|
btnText={btnText}
|
|
39
39
|
actionsBelow={actionsBelow}
|
|
40
40
|
subErrors={subErrors}
|
|
41
|
+
onClick={btnAction}
|
|
41
42
|
/>,
|
|
42
43
|
domNode
|
|
43
44
|
)
|
|
@@ -50,7 +51,7 @@ const ErrorGuard = (props: IProps) => {
|
|
|
50
51
|
const mapStateToProps = (state: IRootState) => {
|
|
51
52
|
const {
|
|
52
53
|
app: {
|
|
53
|
-
error: { code, text, btnText, actionsBelow, subErrors },
|
|
54
|
+
error: { code, text, btnText, actionsBelow, subErrors, btnAction },
|
|
54
55
|
},
|
|
55
56
|
} = state;
|
|
56
57
|
return {
|
|
@@ -59,6 +60,7 @@ const mapStateToProps = (state: IRootState) => {
|
|
|
59
60
|
btnText,
|
|
60
61
|
actionsBelow,
|
|
61
62
|
subErrors,
|
|
63
|
+
btnAction,
|
|
62
64
|
};
|
|
63
65
|
};
|
|
64
66
|
|
|
@@ -73,6 +75,7 @@ interface IProps {
|
|
|
73
75
|
btnText?: string;
|
|
74
76
|
actionsBelow?: boolean | undefined;
|
|
75
77
|
subErrors?: any[];
|
|
78
|
+
btnAction?: () => void;
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
export default connect(mapStateToProps, mapDispatchToProps)(ErrorGuard);
|
|
@@ -29,6 +29,7 @@ const DefaultItem = (props: IProps): JSX.Element => {
|
|
|
29
29
|
setDeletedNav,
|
|
30
30
|
onChange,
|
|
31
31
|
isSelected,
|
|
32
|
+
toggleReplaceModal
|
|
32
33
|
} = props;
|
|
33
34
|
|
|
34
35
|
const [inputValue, setInputValue] = useState("");
|
|
@@ -55,13 +56,15 @@ const DefaultItem = (props: IProps): JSX.Element => {
|
|
|
55
56
|
|
|
56
57
|
const handleSetDefault = () => setDefaultNavigation(defaultContent.id, defaultContent.type);
|
|
57
58
|
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
const handleErrorAction = () => toggleReplaceModal();
|
|
60
|
+
|
|
61
|
+
const removeItem = async () => {
|
|
62
|
+
const deleted = await deleteNavigation(defaultContent.id, defaultContent.type, handleErrorAction);
|
|
63
|
+
setDeletedNav(defaultContent.id);
|
|
64
|
+
if (deleted) {
|
|
65
|
+
toggleToast();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
65
68
|
|
|
66
69
|
let menuOptions = [
|
|
67
70
|
{
|
|
@@ -214,12 +217,13 @@ interface IProps {
|
|
|
214
217
|
toggleToast(): void;
|
|
215
218
|
onChange: (e: any) => void;
|
|
216
219
|
setDeletedNav(item: number): void;
|
|
217
|
-
deleteNavigation(navID: number, type: string): Promise<boolean>;
|
|
220
|
+
deleteNavigation(navID: number, type: string, errorAction: () => void): Promise<boolean>;
|
|
218
221
|
setDefaultNavigation(navID: number, type: string): void;
|
|
219
222
|
setLanguage(lang: { locale: string; id: number | null }): void;
|
|
220
223
|
createNewTranslation(isNewTranslation: boolean): void;
|
|
221
224
|
setHeader(id: number | null): void;
|
|
222
225
|
setFooter(id: number | null): void;
|
|
226
|
+
toggleReplaceModal: () => void;
|
|
223
227
|
}
|
|
224
228
|
|
|
225
229
|
const mapDispatchToProps = {
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { connect } from "react-redux";
|
|
3
|
+
|
|
4
|
+
import { navigationActions } from "@ax/containers/Navigation";
|
|
5
|
+
import { CheckField, Loader, Modal, Select } from "@ax/components";
|
|
6
|
+
import { ICheck, IModal, INavPages, IRootState, IUpdateNavigationParam } from "@ax/types";
|
|
7
|
+
import { useBulkSelection } from "@ax/hooks";
|
|
8
|
+
|
|
9
|
+
import * as S from "./style";
|
|
10
|
+
|
|
11
|
+
const ReplaceNavModal = (props: IProps) => {
|
|
12
|
+
const {
|
|
13
|
+
isOpen,
|
|
14
|
+
type,
|
|
15
|
+
navID,
|
|
16
|
+
currentSiteID,
|
|
17
|
+
navigationPages,
|
|
18
|
+
isLoading,
|
|
19
|
+
currentDefaultsContent,
|
|
20
|
+
toggleModal,
|
|
21
|
+
toggleToast,
|
|
22
|
+
getPagesByNavigation,
|
|
23
|
+
updatePageNavigation,
|
|
24
|
+
} = props;
|
|
25
|
+
|
|
26
|
+
const initialItems = navigationPages ? navigationPages.items.pagesInUse : [];
|
|
27
|
+
const totalItems = navigationPages ? navigationPages.items.totalItems : 0;
|
|
28
|
+
const pagesIds = initialItems.map((item) => item.pageId);
|
|
29
|
+
|
|
30
|
+
const [navSelected, setNavSelected] = useState<any>();
|
|
31
|
+
const [items, setItems] = useState(initialItems);
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const getPages = async () => navID && currentSiteID && (await getPagesByNavigation(type, navID, currentSiteID));
|
|
35
|
+
getPages();
|
|
36
|
+
}, []);
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
setItems(initialItems);
|
|
40
|
+
}, [initialItems]);
|
|
41
|
+
|
|
42
|
+
const { resetBulkSelection, selectedItems, isSelected, checkState, addToBulkSelection, selectAllItems } =
|
|
43
|
+
useBulkSelection(pagesIds);
|
|
44
|
+
|
|
45
|
+
const handleAllChange = () => (checkState.isAllSelected ? resetBulkSelection() : selectAllItems());
|
|
46
|
+
|
|
47
|
+
const options = currentDefaultsContent
|
|
48
|
+
.filter(
|
|
49
|
+
(nav) =>
|
|
50
|
+
navID && ((typeof navID === "number" && nav.id !== navID) || (Array.isArray(navID) && !navID.includes(nav.id)))
|
|
51
|
+
)
|
|
52
|
+
.map((nav) => {
|
|
53
|
+
return { value: nav.id, label: nav.title };
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const fullOptions = [{ value: 0, label: `${type} by default` }, ...options];
|
|
57
|
+
|
|
58
|
+
const handleSelectChange = (value: number | string) => {
|
|
59
|
+
if (typeof value !== "number") return;
|
|
60
|
+
setNavSelected(value);
|
|
61
|
+
const newItems = items.map((item) => {
|
|
62
|
+
if (isSelected(item.pageId)) {
|
|
63
|
+
return { ...item, navigationId: value };
|
|
64
|
+
} else {
|
|
65
|
+
return item;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
setItems(newItems);
|
|
69
|
+
resetBulkSelection();
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const handleChangeNav = async () => {
|
|
73
|
+
const newNavs = items.reduce(
|
|
74
|
+
(acc: { navigationId: number | null; type: "header" | "footer"; pageId: number }[], current) => {
|
|
75
|
+
const original = initialItems.find((initItem) => initItem.pageId === current.pageId);
|
|
76
|
+
if (original && original.navigationId !== current.navigationId) {
|
|
77
|
+
const nav = {
|
|
78
|
+
navigationId: current.navigationId === 0 ? null : current.navigationId,
|
|
79
|
+
type,
|
|
80
|
+
pageId: current.pageId,
|
|
81
|
+
};
|
|
82
|
+
return [...acc, nav];
|
|
83
|
+
}
|
|
84
|
+
return acc;
|
|
85
|
+
},
|
|
86
|
+
[]
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const updated = await updatePageNavigation({ navigations: newNavs });
|
|
90
|
+
|
|
91
|
+
if (updated) {
|
|
92
|
+
toggleModal();
|
|
93
|
+
toggleToast(newNavs.length);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const secondaryAction = navSelected !== undefined ? { title: "Cancel", onClick: toggleModal } : undefined;
|
|
98
|
+
const mainAction = navSelected !== undefined ? { title: "Change Navigation", onClick: handleChangeNav } : undefined;
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<Modal
|
|
102
|
+
isOpen={isOpen}
|
|
103
|
+
hide={toggleModal}
|
|
104
|
+
title="Pages in use"
|
|
105
|
+
size="L"
|
|
106
|
+
secondaryAction={secondaryAction}
|
|
107
|
+
mainAction={mainAction}
|
|
108
|
+
>
|
|
109
|
+
{isLoading ? (
|
|
110
|
+
<S.LoadingWrapper>
|
|
111
|
+
<Loader name="circle" />
|
|
112
|
+
</S.LoadingWrapper>
|
|
113
|
+
) : (
|
|
114
|
+
<S.ModalContent>
|
|
115
|
+
<S.TotalWrapper>
|
|
116
|
+
This {type} appears on <strong>{totalItems} pages</strong>:
|
|
117
|
+
</S.TotalWrapper>
|
|
118
|
+
<S.Header>
|
|
119
|
+
<S.CheckWrapper>
|
|
120
|
+
<CheckField
|
|
121
|
+
name="checkAll"
|
|
122
|
+
value="checkAll"
|
|
123
|
+
checked={checkState.isAllSelected}
|
|
124
|
+
indeterminate={checkState.indeterminate}
|
|
125
|
+
onChange={handleAllChange}
|
|
126
|
+
/>
|
|
127
|
+
</S.CheckWrapper>
|
|
128
|
+
<S.PageInfo>
|
|
129
|
+
<S.Text>Select All</S.Text>
|
|
130
|
+
</S.PageInfo>
|
|
131
|
+
<S.HeaderInfo>
|
|
132
|
+
{selectedItems.all.length > 0 && (
|
|
133
|
+
<Select
|
|
134
|
+
options={fullOptions}
|
|
135
|
+
name="selectNav"
|
|
136
|
+
type="mini"
|
|
137
|
+
value={navSelected}
|
|
138
|
+
onChange={handleSelectChange}
|
|
139
|
+
placeholder={`Change ${type}`}
|
|
140
|
+
/>
|
|
141
|
+
)}
|
|
142
|
+
</S.HeaderInfo>
|
|
143
|
+
</S.Header>
|
|
144
|
+
<S.ItemList>
|
|
145
|
+
{items.map((item) => {
|
|
146
|
+
const handleChange = (value: ICheck) => addToBulkSelection(value);
|
|
147
|
+
const navigation =
|
|
148
|
+
item.navigationId === 0
|
|
149
|
+
? { title: `${type} by default` }
|
|
150
|
+
: currentDefaultsContent.find((nav: any) => nav.id === item.navigationId);
|
|
151
|
+
const original = initialItems.find((initItem) => initItem.pageId === item.pageId);
|
|
152
|
+
return (
|
|
153
|
+
<S.Item key={item.pageId}>
|
|
154
|
+
<S.CheckWrapper>
|
|
155
|
+
<CheckField
|
|
156
|
+
name={`check-${item.pageId}`}
|
|
157
|
+
value={item.pageId}
|
|
158
|
+
checked={isSelected(item.pageId)}
|
|
159
|
+
onChange={handleChange}
|
|
160
|
+
/>
|
|
161
|
+
</S.CheckWrapper>
|
|
162
|
+
<S.PageInfo>
|
|
163
|
+
<S.Title>{item.pageTitle}</S.Title>
|
|
164
|
+
<S.PagePath>{item.pathString}</S.PagePath>
|
|
165
|
+
</S.PageInfo>
|
|
166
|
+
<S.HeaderInfo>
|
|
167
|
+
<S.Tag active={original?.navigationId !== item.navigationId}>{navigation?.title}</S.Tag>
|
|
168
|
+
</S.HeaderInfo>
|
|
169
|
+
</S.Item>
|
|
170
|
+
);
|
|
171
|
+
})}
|
|
172
|
+
</S.ItemList>
|
|
173
|
+
</S.ModalContent>
|
|
174
|
+
)}
|
|
175
|
+
</Modal>
|
|
176
|
+
);
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
interface IReplaceModalProps {
|
|
180
|
+
type: "header" | "footer";
|
|
181
|
+
navID: number | number[] | null;
|
|
182
|
+
currentSiteID: number | null;
|
|
183
|
+
navigationPages: INavPages | null;
|
|
184
|
+
isLoading: boolean;
|
|
185
|
+
currentDefaultsContent: any[];
|
|
186
|
+
toggleToast: (pages: number) => void;
|
|
187
|
+
getPagesByNavigation: (type: string, navID: number | number[], siteID: number) => Promise<void>;
|
|
188
|
+
updatePageNavigation: (data: IUpdateNavigationParam) => Promise<boolean>;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
type IProps = IModal & IReplaceModalProps;
|
|
192
|
+
|
|
193
|
+
const mapStateToProps = (state: IRootState) => ({
|
|
194
|
+
currentSiteID: state.sites.currentSiteInfo && state.sites.currentSiteInfo.id,
|
|
195
|
+
navigationPages: state.navigation.navigationPages,
|
|
196
|
+
isLoading: state.app.isLoading,
|
|
197
|
+
currentDefaultsContent: state.navigation.currentDefaultsContent,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const mapDispatchToProps = {
|
|
201
|
+
getPagesByNavigation: navigationActions.getPagesByNavigation,
|
|
202
|
+
updatePageNavigation: navigationActions.updatePageNavigation,
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
export default connect(mapStateToProps, mapDispatchToProps)(ReplaceNavModal);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const ModalContent = styled.div`
|
|
4
|
+
padding: ${(p) => p.theme.spacing.m};
|
|
5
|
+
`;
|
|
6
|
+
|
|
7
|
+
const LoadingWrapper = styled.div`
|
|
8
|
+
position: relative;
|
|
9
|
+
width: 100%;
|
|
10
|
+
height: 100%;
|
|
11
|
+
svg {
|
|
12
|
+
position: absolute;
|
|
13
|
+
top: 50%;
|
|
14
|
+
left: 50%;
|
|
15
|
+
transform: translate(-50%, -50%);
|
|
16
|
+
}
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
const TotalWrapper = styled.div`
|
|
20
|
+
${(p) => p.theme.textStyle.uiM};
|
|
21
|
+
color: ${(p) => p.theme.color.textHighEmphasis};
|
|
22
|
+
margin-bottom: ${(p) => p.theme.spacing.s};
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
const ItemList = styled.div`
|
|
26
|
+
overflow: auto;
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
const Header = styled.div`
|
|
30
|
+
display: flex;
|
|
31
|
+
border-bottom: ${(p) => `1px solid ${p.theme.color.uiLine}`};
|
|
32
|
+
padding: ${(p) => `${p.theme.spacing.xs} ${p.theme.spacing.xs} 0 ${p.theme.spacing.xs}`};
|
|
33
|
+
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
34
|
+
min-height: 45px;
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
const Item = styled.div`
|
|
38
|
+
display: flex;
|
|
39
|
+
border-bottom: ${(p) => `1px solid ${p.theme.color.uiLine}`};
|
|
40
|
+
padding: ${(p) => p.theme.spacing.xs};
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
const CheckWrapper = styled.div`
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: flex-start;
|
|
46
|
+
`;
|
|
47
|
+
|
|
48
|
+
const PageInfo = styled.div`
|
|
49
|
+
flex-grow: 2;
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
const Title = styled.div`
|
|
53
|
+
${(p) => p.theme.textStyle.uiL};
|
|
54
|
+
color: ${(p) => p.theme.color.textHighEmphasis};
|
|
55
|
+
margin-bottom: ${(p) => p.theme.spacing.xxs};
|
|
56
|
+
`;
|
|
57
|
+
|
|
58
|
+
const PagePath = styled.div`
|
|
59
|
+
${(p) => p.theme.textStyle.uiXS};
|
|
60
|
+
color: ${(p) => p.theme.color.textMediumEmphasis};
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
const Text = styled.div`
|
|
64
|
+
${(p) => p.theme.textStyle.uiS};
|
|
65
|
+
color: ${(p) => p.theme.color.textMediumEmphasis};
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
const HeaderInfo = styled.div`
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
const Tag = styled.div<{ active: boolean}>`
|
|
74
|
+
${(p) => p.theme.textStyle.uiXS};
|
|
75
|
+
color: ${(p) => p.theme.color.textMediumEmphasis};
|
|
76
|
+
background-color: ${(p) => p.active ? p.theme.color?.interactive02 : p.theme.colors.uiBackground03};
|
|
77
|
+
box-sizing: border-box;
|
|
78
|
+
border-radius: ${(p) => p.theme.radii.xs};
|
|
79
|
+
white-space: nowrap;
|
|
80
|
+
display: inline-block;
|
|
81
|
+
padding: 3px 8px;
|
|
82
|
+
text-transform: capitalize;
|
|
83
|
+
`;
|
|
84
|
+
|
|
85
|
+
export {
|
|
86
|
+
ModalContent,
|
|
87
|
+
LoadingWrapper,
|
|
88
|
+
TotalWrapper,
|
|
89
|
+
ItemList,
|
|
90
|
+
Header,
|
|
91
|
+
Item,
|
|
92
|
+
PageInfo,
|
|
93
|
+
PagePath,
|
|
94
|
+
Title,
|
|
95
|
+
HeaderInfo,
|
|
96
|
+
Tag,
|
|
97
|
+
CheckWrapper,
|
|
98
|
+
Text,
|
|
99
|
+
};
|
|
@@ -4,7 +4,7 @@ import { connect } from "react-redux";
|
|
|
4
4
|
import { appActions } from "@ax/containers/App";
|
|
5
5
|
import { menuActions } from "@ax/containers/Navigation";
|
|
6
6
|
import { IRootState, IHeader, IFooter } from "@ax/types";
|
|
7
|
-
import { useBulkSelection, useToast } from "@ax/hooks";
|
|
7
|
+
import { useBulkSelection, useModal, useToast } from "@ax/hooks";
|
|
8
8
|
import { capitalize, isMultipleNavigationModules } from "@ax/helpers";
|
|
9
9
|
import { navigationActions } from "@ax/containers/Navigation";
|
|
10
10
|
import { MainWrapper, TableList, ErrorToast, Toast, Notification } from "@ax/components";
|
|
@@ -14,6 +14,8 @@ import DefaultNav from "./Nav";
|
|
|
14
14
|
import BulkHeader from "./BulkHeader";
|
|
15
15
|
|
|
16
16
|
import { NavigationModulesWarning } from "./atoms";
|
|
17
|
+
import ReplaceNavModal from "./ReplaceNavModal";
|
|
18
|
+
|
|
17
19
|
import * as S from "./style";
|
|
18
20
|
|
|
19
21
|
const DefaultsList = (props: IProps): JSX.Element => {
|
|
@@ -39,10 +41,13 @@ const DefaultsList = (props: IProps): JSX.Element => {
|
|
|
39
41
|
|
|
40
42
|
const [page, setPage] = useState(1);
|
|
41
43
|
const [deletedNav, setDeletedNav] = useState<number | number[] | null>(null);
|
|
44
|
+
const [updatedPages, setUpdatedPages] = useState<number | null>(null);
|
|
42
45
|
const { isVisible, toggleToast, setIsVisible } = useToast();
|
|
46
|
+
const { isVisible: isPagesVisible, toggleToast: togglePagesToast, setIsVisible: setIsPagesVisible } = useToast();
|
|
43
47
|
const [isScrolling, setIsScrolling] = useState(false);
|
|
44
48
|
const tableRef = useRef<HTMLDivElement>(null);
|
|
45
49
|
const [isNavigationNotificationOpen, setIsNavigationNotificationOpen] = useState(false);
|
|
50
|
+
const { isOpen: isReplaceOpened, toggleModal: toggleReplaceModal } = useModal();
|
|
46
51
|
|
|
47
52
|
const navIds = currentDefaultsContent && currentDefaultsContent.map((nav: any) => nav.id);
|
|
48
53
|
|
|
@@ -153,13 +158,25 @@ const DefaultsList = (props: IProps): JSX.Element => {
|
|
|
153
158
|
message: deletedNav ? `${capitalize(currentType)} deleted` : "",
|
|
154
159
|
};
|
|
155
160
|
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
161
|
+
const toastPagesProps = {
|
|
162
|
+
setIsVisible: setIsPagesVisible,
|
|
163
|
+
message: `${updatedPages} pages updated with new ${currentType}s.`,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const handleToast = (pages: number) => {
|
|
167
|
+
setUpdatedPages(pages);
|
|
168
|
+
togglePagesToast();
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const handleErrorAction = () => toggleReplaceModal();
|
|
172
|
+
|
|
173
|
+
const bulkDelete = async () => {
|
|
174
|
+
const deleted = await deleteNavigation(selectedItems.all, currentType, handleErrorAction);
|
|
175
|
+
setDeletedNav(selectedItems.all);
|
|
176
|
+
if (deleted) {
|
|
177
|
+
toggleToast();
|
|
178
|
+
}
|
|
179
|
+
};
|
|
163
180
|
|
|
164
181
|
const unselectAllItems = () => resetBulkSelection();
|
|
165
182
|
|
|
@@ -224,13 +241,24 @@ const DefaultsList = (props: IProps): JSX.Element => {
|
|
|
224
241
|
onChange={addToBulkSelection}
|
|
225
242
|
handleClick={setContent}
|
|
226
243
|
setHistoryPush={setHistoryPush}
|
|
244
|
+
toggleReplaceModal={toggleReplaceModal}
|
|
227
245
|
/>
|
|
228
246
|
);
|
|
229
247
|
})}
|
|
230
248
|
</TableList>
|
|
231
249
|
</S.TableWrapper>
|
|
232
250
|
{isVisible && <Toast {...toastProps} />}
|
|
251
|
+
{isPagesVisible && <Toast {...toastPagesProps} />}
|
|
233
252
|
</S.DefaultListWrapper>
|
|
253
|
+
{isReplaceOpened && (
|
|
254
|
+
<ReplaceNavModal
|
|
255
|
+
isOpen={isReplaceOpened}
|
|
256
|
+
toggleModal={toggleReplaceModal}
|
|
257
|
+
type={currentType}
|
|
258
|
+
navID={deletedNav}
|
|
259
|
+
toggleToast={handleToast}
|
|
260
|
+
/>
|
|
261
|
+
)}
|
|
234
262
|
</MainWrapper>
|
|
235
263
|
);
|
|
236
264
|
};
|
|
@@ -253,7 +281,7 @@ interface IDispatchProps {
|
|
|
253
281
|
setHeader(id: number | null): void;
|
|
254
282
|
setFooter(id: number | null): void;
|
|
255
283
|
restoreNavigation(navID: number | number[], type: string): void;
|
|
256
|
-
deleteNavigation(navID: number[], type: string): Promise<boolean>;
|
|
284
|
+
deleteNavigation(navID: number[], type: string, errorAction: () => void): Promise<boolean>;
|
|
257
285
|
getMenus(): void;
|
|
258
286
|
resetDefaultsValues(): void;
|
|
259
287
|
}
|
|
@@ -255,15 +255,14 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
255
255
|
|
|
256
256
|
const bulkPublishAction = async (isPublish: boolean) => {
|
|
257
257
|
const { notPublished, published } = selectedItems;
|
|
258
|
+
const params = getParams();
|
|
259
|
+
|
|
258
260
|
if (notPublished.length > 0 && isPublish) {
|
|
259
|
-
publishSitesBulk(notPublished);
|
|
261
|
+
await publishSitesBulk(notPublished, params);
|
|
260
262
|
}
|
|
261
263
|
if (published.length > 0 && !isPublish) {
|
|
262
|
-
unpublishSitesBulk(published);
|
|
264
|
+
await unpublishSitesBulk(published, params);
|
|
263
265
|
}
|
|
264
|
-
|
|
265
|
-
const params = getParams();
|
|
266
|
-
getSites(params);
|
|
267
266
|
unselectAllItems();
|
|
268
267
|
};
|
|
269
268
|
|
|
@@ -383,9 +382,9 @@ const mapStateToProps = (state: IRootState) => ({
|
|
|
383
382
|
interface IDispatchProps {
|
|
384
383
|
setHistoryPush(path: string, isEditor?: boolean): void;
|
|
385
384
|
saveSettings(form: ISettingsForm): Promise<boolean>;
|
|
386
|
-
getSites(params: IGetSitesParams): void
|
|
387
|
-
publishSitesBulk(ids: number[]): void
|
|
388
|
-
unpublishSitesBulk(ids: number[]): void
|
|
385
|
+
getSites(params: IGetSitesParams): Promise<void>;
|
|
386
|
+
publishSitesBulk(ids: number[], params?: IGetSitesParams): Promise<void>;
|
|
387
|
+
unpublishSitesBulk(ids: number[], params?: IGetSitesParams): Promise<void>;
|
|
389
388
|
setListConfig(config: ISiteListConfig): void;
|
|
390
389
|
}
|
|
391
390
|
|
package/src/types/index.tsx
CHANGED
|
@@ -833,6 +833,18 @@ export interface ICreatePasswordParams {
|
|
|
833
833
|
retypedPassword: string;
|
|
834
834
|
}
|
|
835
835
|
|
|
836
|
+
export interface INavPages {
|
|
837
|
+
availableNavigationsInSite: { id: number; isDefault: boolean };
|
|
838
|
+
items: {
|
|
839
|
+
pagesInUse: { pageId: number; pageTitle: string; pathString: string; navigationId: number }[];
|
|
840
|
+
totalItems: number;
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
export interface IUpdateNavigationParam {
|
|
845
|
+
navigations: { navigationId: number | null; type: "header" | "footer"; pageId: number }[];
|
|
846
|
+
}
|
|
847
|
+
|
|
836
848
|
export type Field =
|
|
837
849
|
| "AsyncCheckGroup"
|
|
838
850
|
| "AsyncSelect"
|