@griddo/ax 11.15.7 → 11.15.8-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/package.json +2 -2
  2. package/src/__tests__/components/Fields/Wysiwyg/Wysiwyg.atoms.test.tsx +409 -0
  3. package/src/__tests__/components/Fields/Wysiwyg/Wysiwyg.helpers.test.tsx +418 -0
  4. package/src/__tests__/components/Fields/Wysiwyg/Wysiwyg.test.tsx +776 -29
  5. package/src/__tests__/components/FieldsBehavior/FieldsBehavior.test.tsx +368 -11
  6. package/src/__tests__/modules/Users/UserList/UserList.test.tsx +6 -6
  7. package/src/components/Fields/IntegrationsField/IntegrationItem/atoms.tsx +14 -5
  8. package/src/components/Fields/IntegrationsField/IntegrationItem/index.tsx +1 -8
  9. package/src/components/Fields/UrlField/index.tsx +5 -4
  10. package/src/components/Fields/Wysiwyg/atoms.tsx +140 -0
  11. package/src/components/Fields/Wysiwyg/config.tsx +190 -9
  12. package/src/components/Fields/Wysiwyg/helpers.tsx +54 -1
  13. package/src/components/Fields/Wysiwyg/index.tsx +210 -61
  14. package/src/components/Fields/Wysiwyg/style.tsx +32 -1
  15. package/src/components/Fields/Wysiwyg/vendors.tsx +0 -1
  16. package/src/components/FieldsBehavior/index.tsx +66 -31
  17. package/src/components/Icon/components/Sync.js +16 -0
  18. package/src/components/Icon/svgs/Sync.svg +3 -0
  19. package/src/components/RestoreModal/index.tsx +1 -3
  20. package/src/components/ScheduleModal/index.tsx +3 -3
  21. package/src/components/TableList/index.tsx +5 -3
  22. package/src/containers/FileDrive/actions.tsx +5 -5
  23. package/src/containers/Forms/actions.tsx +40 -38
  24. package/src/containers/Gallery/actions.tsx +27 -27
  25. package/src/containers/Integrations/actions.tsx +2 -2
  26. package/src/containers/Navigation/Defaults/actions.tsx +1 -1
  27. package/src/containers/PageEditor/actions.tsx +3 -5
  28. package/src/containers/Redirects/actions.tsx +2 -2
  29. package/src/containers/Sites/actions.tsx +15 -8
  30. package/src/containers/StructuredData/actions.tsx +5 -5
  31. package/src/containers/Users/actions.tsx +2 -2
  32. package/src/modules/Categories/CategoriesList/CategoryItem/index.tsx +36 -43
  33. package/src/modules/Categories/CategoriesList/CategoryPanel/index.tsx +15 -11
  34. package/src/modules/Categories/CategoriesList/atoms.tsx +42 -12
  35. package/src/modules/Categories/CategoriesList/index.tsx +8 -30
  36. package/src/modules/Content/PageItem/index.tsx +6 -5
  37. package/src/modules/Content/atoms.tsx +7 -3
  38. package/src/modules/Content/index.tsx +8 -16
  39. package/src/modules/FileDrive/FileModal/DetailPanel/index.tsx +14 -14
  40. package/src/modules/FileDrive/FolderItem/index.tsx +46 -54
  41. package/src/modules/FileDrive/GridItem/index.tsx +32 -37
  42. package/src/modules/FileDrive/ListItem/index.tsx +31 -37
  43. package/src/modules/FileDrive/atoms.tsx +59 -12
  44. package/src/modules/FileDrive/index.tsx +88 -98
  45. package/src/modules/Forms/FormCategoriesList/CategoryItem/index.tsx +42 -34
  46. package/src/modules/Forms/FormCategoriesList/atoms.tsx +17 -6
  47. package/src/modules/Forms/FormCategoriesList/index.tsx +30 -34
  48. package/src/modules/Forms/FormEditor/index.tsx +14 -6
  49. package/src/modules/Forms/FormList/FormItem/index.tsx +5 -1
  50. package/src/modules/Forms/FormList/index.tsx +15 -9
  51. package/src/modules/Forms/atoms.tsx +7 -4
  52. package/src/modules/GlobalEditor/atoms.tsx +77 -0
  53. package/src/modules/GlobalEditor/index.tsx +24 -7
  54. package/src/modules/MediaGallery/FolderItem/index.tsx +36 -52
  55. package/src/modules/MediaGallery/GridItem/index.tsx +27 -38
  56. package/src/modules/MediaGallery/ImageModal/DetailPanel/index.tsx +13 -13
  57. package/src/modules/MediaGallery/ImageModal/index.tsx +2 -16
  58. package/src/modules/MediaGallery/ListItem/index.tsx +25 -37
  59. package/src/modules/MediaGallery/atoms.tsx +84 -15
  60. package/src/modules/MediaGallery/index.tsx +62 -122
  61. package/src/modules/Navigation/Defaults/Item/atoms.tsx +2 -4
  62. package/src/modules/Navigation/Defaults/Item/index.tsx +80 -94
  63. package/src/modules/Navigation/Defaults/atoms.tsx +179 -7
  64. package/src/modules/Navigation/Defaults/index.tsx +51 -18
  65. package/src/modules/Navigation/Defaults/style.tsx +10 -7
  66. package/src/modules/Navigation/Menus/List/Table/Item/atoms.tsx +33 -19
  67. package/src/modules/Navigation/Menus/List/Table/Item/index.tsx +18 -19
  68. package/src/modules/Navigation/Menus/List/Table/index.tsx +15 -13
  69. package/src/modules/Navigation/Menus/List/index.tsx +1 -1
  70. package/src/modules/PageEditor/atoms.tsx +14 -11
  71. package/src/modules/PageEditor/index.tsx +11 -16
  72. package/src/modules/Redirects/RedirectItem/index.tsx +37 -39
  73. package/src/modules/Redirects/atoms.tsx +58 -12
  74. package/src/modules/Redirects/index.tsx +30 -58
  75. package/src/modules/Settings/Integrations/IntegrationItem/CopyModal/index.tsx +1 -1
  76. package/src/modules/Settings/Integrations/IntegrationItem/index.tsx +57 -69
  77. package/src/modules/Settings/Integrations/atoms.tsx +72 -8
  78. package/src/modules/Settings/Integrations/index.tsx +34 -48
  79. package/src/modules/StructuredData/Form/index.tsx +25 -8
  80. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/atoms.tsx +26 -75
  81. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +15 -33
  82. package/src/modules/StructuredData/StructuredDataList/StructuredDataItem/index.tsx +63 -41
  83. package/src/modules/StructuredData/StructuredDataList/StructuredDataItem/style.tsx +13 -8
  84. package/src/modules/StructuredData/StructuredDataList/index.tsx +11 -16
  85. package/src/modules/StructuredData/{StructuredDataList/atoms.tsx → atoms.tsx} +25 -28
  86. package/src/modules/Users/UserList/UserItem/index.tsx +18 -35
  87. package/src/modules/Users/UserList/atoms.tsx +61 -0
  88. package/src/modules/Users/UserList/index.tsx +12 -32
@@ -1,12 +1,12 @@
1
- import { useState } from "react";
2
1
  import { connect } from "react-redux";
3
2
 
4
- import type { ICheck, ILanguage, INavigationLanguage, INavigation } from "@ax/types";
5
- import { useModal, usePermission } from "@ax/hooks";
3
+ import { CheckField } from "@ax/components";
6
4
  import { appActions } from "@ax/containers/App";
7
- import { navigationActions, menuActions } from "@ax/containers/Navigation";
8
- import { CheckField, FieldsBehavior, Modal } from "@ax/components";
5
+ import { menuActions, navigationActions } from "@ax/containers/Navigation";
6
+ import { useModals, usePermissions } from "@ax/hooks";
7
+ import type { ICheck, ILanguage, INavigation, INavigationLanguage, IRootState } from "@ax/types";
9
8
 
9
+ import { DeleteModal, RenameModal, SetDefaultModal } from "../atoms";
10
10
  import { Translations } from "./atoms";
11
11
 
12
12
  import * as S from "./style";
@@ -32,22 +32,28 @@ const DefaultItem = (props: IProps): JSX.Element => {
32
32
  toggleReplaceModal,
33
33
  getMenus,
34
34
  hoverCheck,
35
+ isSaving,
35
36
  } = props;
36
37
 
37
- const [inputValue, setInputValue] = useState("");
38
-
39
- const { isOpen: isRenameOpened, toggleModal: toggleRenameModal } = useModal();
40
- const { isOpen: isDefaultOpened, toggleModal: toggleDefaultModal } = useModal();
38
+ const { isOpen, toggleModal } = useModals(["rename", "default", "delete"]);
41
39
 
42
40
  const { locale } = lang;
43
41
  const { navigationLanguages, type } = defaultContent;
44
42
 
45
- const isAllowedToEditHeaders = usePermission("navigation.editSiteHeaders") && type === "header";
46
- const isAllowedToEditFooters = usePermission("navigation.editSiteFooters") && type === "footer";
47
- const isAllowedToCreateHeaders = usePermission("navigation.createSiteHeaders") && type === "header";
48
- const isAllowedToCreateFooters = usePermission("navigation.createSiteFooters") && type === "footer";
49
- const isAllowedToDeleteHeaders = usePermission("navigation.deleteSiteHeaders") && type === "header";
50
- const isAllowedToDeleteFooters = usePermission("navigation.deleteSiteFooters") && type === "footer";
43
+ const isAllowedTo = usePermissions({
44
+ editHeaders: "navigation.editSiteHeaders",
45
+ editFooters: "navigation.editSiteFooters",
46
+ createHeaders: "navigation.createSiteHeaders",
47
+ createFooters: "navigation.createSiteFooters",
48
+ deleteHeaders: "navigation.deleteSiteHeaders",
49
+ deleteFooters: "navigation.deleteSiteFooters",
50
+ });
51
+
52
+ console.log(navigationLanguages, "langs");
53
+
54
+ const isAllowedToEdit = type === "header" ? isAllowedTo.editHeaders : isAllowedTo.editFooters;
55
+ const isAllowedToCreate = type === "header" ? isAllowedTo.createHeaders : isAllowedTo.createFooters;
56
+ const isAllowedToDelete = type === "header" ? isAllowedTo.deleteHeaders : isAllowedTo.deleteFooters;
51
57
 
52
58
  const goToEditor = () => {
53
59
  handleClick(defaultContent);
@@ -56,8 +62,8 @@ const DefaultItem = (props: IProps): JSX.Element => {
56
62
 
57
63
  const handleOnChange = (value: ICheck) => onChange(value);
58
64
 
59
- const handleRenameItem = () => {
60
- const updatedItem = { ...defaultContent, title: inputValue };
65
+ const handleRenameItem = (newTitle: string) => {
66
+ const updatedItem = { ...defaultContent, title: newTitle };
61
67
  updateNavigation(defaultContent.id!, updatedItem);
62
68
  };
63
69
 
@@ -65,38 +71,43 @@ const DefaultItem = (props: IProps): JSX.Element => {
65
71
 
66
72
  const handleErrorAction = () => toggleReplaceModal();
67
73
 
68
- const removeItem = async () => {
69
- const deleted = await deleteNavigation(defaultContent.id!, defaultContent.type, handleErrorAction);
70
- setDeletedNav(defaultContent.id!);
74
+ const isTranslated = navigationLanguages.length > 1;
75
+
76
+ const handleDeleteConfirm = async (deleteAllVersions: boolean) => {
77
+ const idsToDelete: number | number[] = deleteAllVersions
78
+ ? navigationLanguages.map((nav) => nav.navigationId)
79
+ : defaultContent.id!;
80
+
81
+ const deleted = await deleteNavigation(idsToDelete, defaultContent.type, handleErrorAction);
82
+ setDeletedNav(idsToDelete);
71
83
  if (deleted) {
72
84
  toggleToast();
85
+ toggleModal("delete");
73
86
  }
74
87
  };
75
88
 
76
- const renameOption =
77
- isAllowedToEditFooters || isAllowedToEditHeaders
78
- ? {
79
- label: "Rename",
80
- icon: "edit",
81
- action: toggleRenameModal,
82
- }
83
- : undefined;
84
-
85
- const deleteOption =
86
- isAllowedToDeleteFooters || isAllowedToDeleteHeaders
87
- ? {
88
- label: "Delete",
89
- icon: "delete",
90
- action: removeItem,
91
- }
92
- : undefined;
89
+ const renameOption = isAllowedToEdit
90
+ ? {
91
+ label: "Rename",
92
+ icon: "edit",
93
+ action: () => toggleModal("rename"),
94
+ }
95
+ : undefined;
96
+
97
+ const deleteOption = isAllowedToDelete
98
+ ? {
99
+ label: "Delete",
100
+ icon: "delete",
101
+ action: () => toggleModal("delete"),
102
+ }
103
+ : undefined;
93
104
 
94
105
  const setAsDefaultOption =
95
- !defaultContent.setAsDefault && (isAllowedToEditHeaders || isAllowedToEditFooters)
106
+ !defaultContent.setAsDefault && isAllowedToEdit
96
107
  ? {
97
108
  label: "Set as default",
98
109
  icon: "modules",
99
- action: toggleDefaultModal,
110
+ action: () => toggleModal("default"),
100
111
  }
101
112
  : undefined;
102
113
 
@@ -117,17 +128,6 @@ const DefaultItem = (props: IProps): JSX.Element => {
117
128
 
118
129
  const currentLanguages = getCurrentLanguages();
119
130
 
120
- const handleCloseModal = () => {
121
- setInputValue("");
122
- toggleRenameModal();
123
- };
124
-
125
- const mainRenameModalAction = { title: "Rename", onClick: handleRenameItem, disabled: !inputValue.trim() };
126
- const secondaryRenameModalAction = { title: "Cancel", onClick: handleCloseModal };
127
-
128
- const mainDefaultModalAction = { title: "Yes, set as default", onClick: handleSetDefault };
129
- const secondaryDefaultModalAction = { title: "Cancel", onClick: toggleDefaultModal };
130
-
131
131
  const getSelectedNavLanguage = (navLanguages: INavigationLanguage[], language: ILanguage) =>
132
132
  navLanguages.find((navLang) => navLang.languageId === language.id);
133
133
 
@@ -148,11 +148,11 @@ const DefaultItem = (props: IProps): JSX.Element => {
148
148
  setHistoryPush("/sites/navigations/editor", true);
149
149
  };
150
150
 
151
- const availableLanguages = isAllowedToCreateFooters || isAllowedToCreateHeaders ? languages : currentLanguages;
151
+ const availableLanguages = isAllowedToCreate ? languages : currentLanguages;
152
152
 
153
153
  return (
154
154
  <>
155
- <S.DefaultRow role="rowgroup" selected={isSelected} clickable={isAllowedToEditHeaders || isAllowedToEditFooters}>
155
+ <S.DefaultRow role="rowgroup" selected={isSelected} clickable={isAllowedToEdit}>
156
156
  <S.CheckCell role="cell">
157
157
  <CheckField
158
158
  name="check"
@@ -179,45 +179,26 @@ const DefaultItem = (props: IProps): JSX.Element => {
179
179
  <S.StyledActionMenu icon="more" options={menuOptions} />
180
180
  </S.ActionCell>
181
181
  </S.DefaultRow>
182
- <Modal
183
- isOpen={isRenameOpened}
184
- hide={handleCloseModal}
185
- title={`Rename ${defaultContent.component}`}
186
- secondaryAction={secondaryRenameModalAction}
187
- mainAction={mainRenameModalAction}
188
- size="S"
189
- >
190
- {isRenameOpened ? (
191
- <S.ModalContent>
192
- <FieldsBehavior
193
- fieldType="TextField"
194
- name="name"
195
- title="Name"
196
- mandatory={true}
197
- value={inputValue}
198
- onChange={setInputValue}
199
- placeholder={`Type a new name for the ${defaultContent.type}`}
200
- />
201
- </S.ModalContent>
202
- ) : null}
203
- </Modal>
204
- <Modal
205
- isOpen={isDefaultOpened}
206
- hide={toggleDefaultModal}
207
- title={`Default ${defaultContent.component}`}
208
- secondaryAction={secondaryDefaultModalAction}
209
- mainAction={mainDefaultModalAction}
210
- size="S"
211
- >
212
- {isDefaultOpened ? (
213
- <S.ModalContent>
214
- <p>
215
- There is already a header defined as default. If you change it to this one, it will be shown on all the
216
- pages on this site. Are you sure your want to make this change?
217
- </p>
218
- </S.ModalContent>
219
- ) : null}
220
- </Modal>
182
+ <RenameModal
183
+ isOpen={isOpen("rename")}
184
+ toggleModal={() => toggleModal("rename")}
185
+ defaultContent={defaultContent}
186
+ onRename={handleRenameItem}
187
+ />
188
+ <SetDefaultModal
189
+ isOpen={isOpen("default")}
190
+ toggleModal={() => toggleModal("default")}
191
+ defaultContent={defaultContent}
192
+ onSetDefault={handleSetDefault}
193
+ />
194
+ <DeleteModal
195
+ isOpen={isOpen("delete")}
196
+ toggleModal={() => toggleModal("delete")}
197
+ isTranslated={isTranslated}
198
+ title={defaultContent.title}
199
+ onDelete={handleDeleteConfirm}
200
+ isDeleting={isSaving}
201
+ />
221
202
  </>
222
203
  );
223
204
  };
@@ -232,8 +213,8 @@ interface IProps {
232
213
  isSelected: boolean;
233
214
  toggleToast(): void;
234
215
  onChange: (e: any) => void;
235
- setDeletedNav(item: number): void;
236
- deleteNavigation(navID: number, type: string, errorAction: () => void): Promise<boolean>;
216
+ setDeletedNav(item: number | number[]): void;
217
+ deleteNavigation(navID: number | number[], type: string, errorAction: () => void): Promise<boolean>;
237
218
  setDefaultNavigation(navID: number, type: string): void;
238
219
  setLanguage(lang: { locale: string; id: number | null }): void;
239
220
  createNewTranslation(isNewTranslation: boolean): void;
@@ -242,8 +223,13 @@ interface IProps {
242
223
  toggleReplaceModal: () => void;
243
224
  getMenus(): Promise<void>;
244
225
  hoverCheck: boolean;
226
+ isSaving: boolean;
245
227
  }
246
228
 
229
+ const mapStateToProps = (state: IRootState) => ({
230
+ isSaving: state.app.isSaving,
231
+ });
232
+
247
233
  const mapDispatchToProps = {
248
234
  updateNavigation: navigationActions.updateNavigation,
249
235
  deleteNavigation: navigationActions.deleteNavigation,
@@ -255,4 +241,4 @@ const mapDispatchToProps = {
255
241
  getMenus: menuActions.getMenus,
256
242
  };
257
243
 
258
- export default connect(null, mapDispatchToProps)(DefaultItem);
244
+ export default connect(mapStateToProps, mapDispatchToProps)(DefaultItem);
@@ -1,28 +1,200 @@
1
- import React from "react";
1
+ import type React from "react";
2
+ import { useState } from "react";
3
+
4
+ import { FieldsBehavior, Modal } from "@ax/components";
5
+ import type { IModal, INavigation } from "@ax/types";
6
+
2
7
  import * as S from "./style";
3
8
 
4
9
  const NavigationModulesWarning = (props: INavigationModulesWarning): JSX.Element => {
5
10
  const { goTo } = props;
6
11
 
12
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>) => {
13
+ if (e.key === "Enter") {
14
+ goTo();
15
+ }
16
+ };
17
+
7
18
  return (
8
19
  <S.NavigationModulesWarning>
9
20
  <S.NavigationModulesTitle>Navigation Modules</S.NavigationModulesTitle>
10
21
  <S.NavigationModulesDescription>
11
22
  Create as many headers as you need for your site. You can decide on which page to use each one. To change the
12
23
  header design, you have to go to{" "}
13
- <S.SiteSettingsLink>
14
- <span onClick={goTo} onKeyPress={goTo} role="checkbox" aria-checked="false" tabIndex={0}>
15
- Site Settings
16
- </span>
17
- </S.SiteSettingsLink>
24
+ <button type="button" onClick={goTo} onKeyDown={handleKeyDown} tabIndex={0}>
25
+ Site Settings
26
+ </button>
18
27
  .
19
28
  </S.NavigationModulesDescription>
20
29
  </S.NavigationModulesWarning>
21
30
  );
22
31
  };
23
32
 
33
+ const DeleteModal = (props: IDeleteModal): JSX.Element => {
34
+ const { isOpen, toggleModal, isTranslated, title, onDelete, isDeleting, itemCount } = props;
35
+ const [deleteAllVersions, setDeleteAllVersions] = useState(false);
36
+
37
+ const isBulkDelete = itemCount && itemCount > 1;
38
+
39
+ const options = [
40
+ {
41
+ title: "Delete only this version",
42
+ name: "deletePage",
43
+ value: false,
44
+ },
45
+ {
46
+ title: "Delete all languages versions",
47
+ name: "deleteAll",
48
+ value: true,
49
+ },
50
+ ];
51
+
52
+ const itemTitle = title ? <strong>{title}</strong> : "this";
53
+
54
+ const mainAction = {
55
+ title: isDeleting ? "Deleting" : "Delete",
56
+ onClick: () => onDelete(deleteAllVersions),
57
+ disabled: isDeleting,
58
+ };
59
+
60
+ const secondaryAction = { title: "Cancel", onClick: toggleModal };
61
+
62
+ return (
63
+ <Modal
64
+ isOpen={isOpen}
65
+ hide={toggleModal}
66
+ title="Delete navigation?"
67
+ secondaryAction={secondaryAction}
68
+ mainAction={mainAction}
69
+ size="S"
70
+ height="auto"
71
+ >
72
+ {isTranslated ? (
73
+ <>
74
+ <S.ModalContent>
75
+ <p>
76
+ {isBulkDelete ? (
77
+ <>
78
+ You are going to delete <strong>{itemCount} navigations</strong> that have some translations
79
+ associated. Choose if you want to delete all languages versions or only this one.
80
+ </>
81
+ ) : (
82
+ <>
83
+ You are going to delete {itemTitle} navigation that have some translations associated. Choose if you
84
+ want to delete all languages versions or only this one.
85
+ </>
86
+ )}
87
+ </p>
88
+ <FieldsBehavior
89
+ name="removeAllVersions"
90
+ fieldType="RadioGroup"
91
+ value={deleteAllVersions}
92
+ options={options}
93
+ onChange={setDeleteAllVersions}
94
+ />
95
+ </S.ModalContent>
96
+ </>
97
+ ) : (
98
+ <S.ModalContent>
99
+ {isBulkDelete ? (
100
+ <>
101
+ Are you sure you want to delete <strong>{itemCount} navigations</strong>?
102
+ </>
103
+ ) : (
104
+ <>Are you sure you want to delete {itemTitle} navigation?</>
105
+ )}
106
+ </S.ModalContent>
107
+ )}
108
+ </Modal>
109
+ );
110
+ };
111
+
112
+ const RenameModal = (props: IRenameModal): JSX.Element => {
113
+ const { isOpen, toggleModal, defaultContent, onRename } = props;
114
+ const [inputValue, setInputValue] = useState("");
115
+
116
+ const handleClose = () => {
117
+ setInputValue("");
118
+ toggleModal();
119
+ };
120
+
121
+ const handleRename = () => {
122
+ onRename(inputValue);
123
+ handleClose();
124
+ };
125
+
126
+ return (
127
+ <Modal
128
+ isOpen={isOpen}
129
+ hide={handleClose}
130
+ title={`Rename ${defaultContent.component}`}
131
+ secondaryAction={{ title: "Cancel", onClick: handleClose }}
132
+ mainAction={{ title: "Rename", onClick: handleRename, disabled: !inputValue.trim() }}
133
+ size="S"
134
+ height="auto"
135
+ >
136
+ {isOpen ? (
137
+ <S.ModalContent>
138
+ <FieldsBehavior
139
+ fieldType="TextField"
140
+ name="name"
141
+ title="Name"
142
+ mandatory={true}
143
+ value={inputValue}
144
+ onChange={setInputValue}
145
+ placeholder={`Type a new name for the ${defaultContent.type}`}
146
+ />
147
+ </S.ModalContent>
148
+ ) : null}
149
+ </Modal>
150
+ );
151
+ };
152
+
153
+ const SetDefaultModal = (props: ISetDefaultModal): JSX.Element => {
154
+ const { isOpen, toggleModal, defaultContent, onSetDefault } = props;
155
+
156
+ return (
157
+ <Modal
158
+ isOpen={isOpen}
159
+ hide={toggleModal}
160
+ title={`Default ${defaultContent.component}`}
161
+ secondaryAction={{ title: "Cancel", onClick: toggleModal }}
162
+ mainAction={{ title: "Yes, set as default", onClick: onSetDefault }}
163
+ size="S"
164
+ height="auto"
165
+ >
166
+ {isOpen ? (
167
+ <S.ModalContent>
168
+ <p>
169
+ There is already a header defined as default. If you change it to this one, it will be shown on all the
170
+ pages on this site. Are you sure your want to make this change?
171
+ </p>
172
+ </S.ModalContent>
173
+ ) : null}
174
+ </Modal>
175
+ );
176
+ };
177
+
24
178
  interface INavigationModulesWarning {
25
179
  goTo(): void;
26
180
  }
27
181
 
28
- export { NavigationModulesWarning };
182
+ interface IDeleteModal extends IModal {
183
+ isTranslated: boolean;
184
+ title?: string;
185
+ onDelete: (deleteAllVersions: boolean) => void;
186
+ isDeleting?: boolean;
187
+ itemCount?: number;
188
+ }
189
+
190
+ interface IRenameModal extends IModal {
191
+ defaultContent: INavigation;
192
+ onRename: (value: string) => void;
193
+ }
194
+
195
+ interface ISetDefaultModal extends IModal {
196
+ defaultContent: INavigation;
197
+ onSetDefault: () => void;
198
+ }
199
+
200
+ export { NavigationModulesWarning, DeleteModal, RenameModal, SetDefaultModal };
@@ -5,10 +5,10 @@ import { ErrorToast, MainWrapper, Notification, TableList, Toast } from "@ax/com
5
5
  import { appActions } from "@ax/containers/App";
6
6
  import { menuActions, navigationActions } from "@ax/containers/Navigation";
7
7
  import { capitalize, isMultipleNavigationModules } from "@ax/helpers";
8
- import { useBulkSelection, useModal, usePermission, useToast } from "@ax/hooks";
8
+ import { useBulkSelection, useModals, usePermissions, useToast } from "@ax/hooks";
9
9
  import type { IFooter, IHeader, ILanguage, INavigation, IRootState, ISite } from "@ax/types";
10
10
 
11
- import { NavigationModulesWarning } from "./atoms";
11
+ import { DeleteModal, NavigationModulesWarning } from "./atoms";
12
12
  import BulkHeader from "./BulkHeader";
13
13
  import DefaultItem from "./Item";
14
14
  import DefaultNav from "./Nav";
@@ -38,9 +38,9 @@ const DefaultsList = (props: IProps): JSX.Element => {
38
38
  getMenus,
39
39
  resetDefaultsValues,
40
40
  currentSiteInfo,
41
+ isSaving,
41
42
  } = props;
42
43
 
43
- const [isBulkLoading, setIsBulkLoading] = useState(false);
44
44
  const [page, setPage] = useState(1);
45
45
  const [deletedNav, setDeletedNav] = useState<number | number[] | null>(null);
46
46
  const [updatedPages, setUpdatedPages] = useState<number | null>(null);
@@ -49,10 +49,17 @@ const DefaultsList = (props: IProps): JSX.Element => {
49
49
  const [isScrolling, setIsScrolling] = useState(false);
50
50
  const tableRef = useRef<HTMLDivElement>(null);
51
51
  const [isNavigationNotificationOpen, setIsNavigationNotificationOpen] = useState(false);
52
- const { isOpen: isReplaceOpened, toggleModal: toggleReplaceModal } = useModal();
52
+ const { isOpen, toggleModal } = useModals(["replace", "delete"]);
53
53
 
54
- const isAllowedToCreate = usePermission(`navigation.createSite${selectedDefault}`);
55
- const isAllowedToDelete = usePermission(`navigation.deleteSite${selectedDefault}`);
54
+ const isAllowedTo = usePermissions({
55
+ createHeaders: "navigation.createSiteHeaders",
56
+ createFooters: "navigation.createSiteFooters",
57
+ deleteHeaders: "navigation.deleteSiteHeaders",
58
+ deleteFooters: "navigation.deleteSiteFooters",
59
+ });
60
+
61
+ const isAllowedToCreate = selectedDefault === "Headers" ? isAllowedTo.createHeaders : isAllowedTo.createFooters;
62
+ const isAllowedToDelete = selectedDefault === "Headers" ? isAllowedTo.deleteHeaders : isAllowedTo.deleteFooters;
56
63
 
57
64
  const navIds = useMemo(() => currentDefaultsContent?.map((nav) => nav.id), [currentDefaultsContent]);
58
65
 
@@ -162,16 +169,32 @@ const DefaultsList = (props: IProps): JSX.Element => {
162
169
  togglePagesToast();
163
170
  };
164
171
 
165
- const bulkDelete = async () => {
166
- setIsBulkLoading(true);
167
- const deleted = await deleteNavigation(selectedItems.all, currentType, toggleReplaceModal);
168
- setDeletedNav(selectedItems.all);
172
+ const handleBulkDeleteConfirm = async (deleteAllVersions: boolean) => {
173
+ let idsToDelete = selectedItems.all;
174
+ if (deleteAllVersions) {
175
+ const allTranslationIds = new Set(selectedItems.all);
176
+ selectedItems.all.forEach((id) => {
177
+ const nav = currentDefaultsContent?.find((n) => n.id === id);
178
+ nav?.navigationLanguages.forEach((lang) => {
179
+ allTranslationIds.add(lang.navigationId);
180
+ });
181
+ });
182
+ idsToDelete = Array.from(allTranslationIds);
183
+ }
184
+
185
+ const deleted = await deleteNavigation(idsToDelete, currentType, () => toggleModal("replace"));
186
+ setDeletedNav(idsToDelete);
169
187
  if (deleted) {
170
188
  toggleToast();
189
+ toggleModal("delete");
190
+ resetBulkSelection();
171
191
  }
172
- setIsBulkLoading(false);
173
192
  };
174
193
 
194
+ const hasAnyTranslation = currentDefaultsContent?.some(
195
+ (nav) => selectedItems.all.includes(nav.id) && nav.navigationLanguages.length > 1,
196
+ );
197
+
175
198
  const onScroll = (e: React.UIEvent<HTMLDivElement>) => setIsScrolling((e.target as HTMLDivElement).scrollTop > 0);
176
199
 
177
200
  const bulkActions = isAllowedToDelete
@@ -179,7 +202,7 @@ const DefaultsList = (props: IProps): JSX.Element => {
179
202
  {
180
203
  icon: "delete",
181
204
  text: "delete",
182
- action: bulkDelete,
205
+ action: () => toggleModal("delete"),
183
206
  },
184
207
  ]
185
208
  : [];
@@ -196,7 +219,7 @@ const DefaultsList = (props: IProps): JSX.Element => {
196
219
  checkState={checkState}
197
220
  isScrolling={isScrolling}
198
221
  setHoverCheck={setHoverCheck}
199
- isLoading={isBulkLoading}
222
+ isLoading={isSaving}
200
223
  />
201
224
  ),
202
225
  [
@@ -210,7 +233,7 @@ const DefaultsList = (props: IProps): JSX.Element => {
210
233
  checkState,
211
234
  isScrolling,
212
235
  setHoverCheck,
213
- isBulkLoading,
236
+ isSaving,
214
237
  ],
215
238
  );
216
239
 
@@ -262,7 +285,7 @@ const DefaultsList = (props: IProps): JSX.Element => {
262
285
  onChange={addToBulkSelection}
263
286
  handleClick={setContent}
264
287
  setHistoryPush={setHistoryPush}
265
- toggleReplaceModal={toggleReplaceModal}
288
+ toggleReplaceModal={() => toggleModal("replace")}
266
289
  hoverCheck={checkState.hoverCheck}
267
290
  />
268
291
  );
@@ -272,15 +295,23 @@ const DefaultsList = (props: IProps): JSX.Element => {
272
295
  {isVisible && <Toast {...toastProps} />}
273
296
  {isPagesVisible && <Toast {...toastPagesProps} />}
274
297
  </S.DefaultListWrapper>
275
- {isReplaceOpened && (
298
+ {isOpen("replace") && (
276
299
  <ReplaceNavModal
277
- isOpen={isReplaceOpened}
278
- toggleModal={toggleReplaceModal}
300
+ isOpen={isOpen("replace")}
301
+ toggleModal={() => toggleModal("replace")}
279
302
  type={currentType}
280
303
  navID={deletedNav}
281
304
  toggleToast={handleToast}
282
305
  />
283
306
  )}
307
+ <DeleteModal
308
+ isOpen={isOpen("delete")}
309
+ toggleModal={() => toggleModal("delete")}
310
+ isTranslated={hasAnyTranslation || false}
311
+ onDelete={handleBulkDeleteConfirm}
312
+ isDeleting={isSaving}
313
+ itemCount={selectedItems.all.length}
314
+ />
284
315
  </MainWrapper>
285
316
  );
286
317
  };
@@ -292,6 +323,7 @@ const mapStateToProps = (state: IRootState) => ({
292
323
  currentDefaultsContent: state.navigation.currentDefaultsContent,
293
324
  totalItems: state.navigation.totalItems,
294
325
  currentSiteInfo: state.sites.currentSiteInfo,
326
+ isSaving: state.app.isSaving,
295
327
  });
296
328
 
297
329
  interface IDispatchProps {
@@ -315,6 +347,7 @@ interface IDefaultsProps {
315
347
  currentDefaultsContent: INavigation[];
316
348
  totalItems: number;
317
349
  currentSiteInfo: ISite | null;
350
+ isSaving: boolean;
318
351
  }
319
352
 
320
353
  type IProps = IDefaultsProps & IDispatchProps;
@@ -32,14 +32,17 @@ const NavigationModulesTitle = styled.div`
32
32
 
33
33
  const NavigationModulesDescription = styled.div`
34
34
  ${(p) => p.theme.textStyle.uiM};
35
+ button {
36
+ ${(p) => p.theme.textStyle.uiS};
37
+ color: ${(p) => p.theme.color.interactive01};
38
+ }
35
39
  `;
36
40
 
37
- const SiteSettingsLink = styled.div`
38
- display: inline;
39
- ${(p) => p.theme.textStyle.uiS};
40
- color: ${(p) => p.theme.color.interactive01};
41
- span {
42
- cursor: pointer;
41
+ const ModalContent = styled.div`
42
+ padding: ${(p) => p.theme.spacing.m};
43
+
44
+ p {
45
+ margin-bottom: ${(p) => p.theme.spacing.m};
43
46
  }
44
47
  `;
45
48
 
@@ -50,5 +53,5 @@ export {
50
53
  NavigationModulesWarning,
51
54
  NavigationModulesTitle,
52
55
  NavigationModulesDescription,
53
- SiteSettingsLink,
56
+ ModalContent,
54
57
  };