@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
@@ -3,8 +3,8 @@ import { connect } from "react-redux";
3
3
 
4
4
  import { CheckField, Icon, TruncatedTooltip } from "@ax/components";
5
5
  import { formsActions } from "@ax/containers/Forms";
6
- import { useModal, usePermission } from "@ax/hooks";
7
- import type { FormCategory, ICheck } from "@ax/types";
6
+ import { useModals, usePermissions } from "@ax/hooks";
7
+ import type { FormCategory, ICheck, IRootState } from "@ax/types";
8
8
 
9
9
  import { useSortable } from "@dnd-kit/sortable";
10
10
 
@@ -14,17 +14,29 @@ import CategoryPanel from "../CategoryPanel";
14
14
  import * as S from "./style";
15
15
 
16
16
  const CategoryItem = (props: ICategoryItemProps): JSX.Element => {
17
- const { category, isSelected, hoverCheck, isDragging, isSiteView, deleteFormCategory, onChange, toggleToast } = props;
18
-
19
- const { isOpen, toggleModal } = useModal();
20
- const { isOpen: isDeleteOpen, toggleModal: toggleDeleteModal } = useModal();
17
+ const {
18
+ category,
19
+ isSelected,
20
+ hoverCheck,
21
+ isDragging,
22
+ isSiteView,
23
+ isSaving,
24
+ deleteFormCategory,
25
+ onChange,
26
+ toggleToast,
27
+ } = props;
28
+
29
+ const { isOpen, toggleModal } = useModals(["edit", "delete"]);
30
+
31
+ const isAllowedTo = usePermissions({
32
+ editSiteCategory: "forms.editFormsCategories",
33
+ editGlobalCategory: "global.forms.editFormsCategories",
34
+ deleteSiteCategory: "forms.deleteFormsCategories",
35
+ deleteGlobalCategory: "global.forms.deleteFormsCategories",
36
+ });
21
37
 
22
- const editFormCategoryPermission = isSiteView ? "forms.editFormsCategories" : "global.forms.editFormsCategoriesss";
23
- const deleteFormCategoryPermission = isSiteView
24
- ? "forms.deleteFormsCategories"
25
- : "global.forms.deleteFormsCategories";
26
- const isAllowedToEditFormCategory = usePermission(editFormCategoryPermission);
27
- const isAllowedToDeleteFormCategory = usePermission(deleteFormCategoryPermission);
38
+ const isAllowedToEditFormCategory = isSiteView ? isAllowedTo.editSiteCategory : isAllowedTo.editGlobalCategory;
39
+ const isAllowedToDeleteFormCategory = isSiteView ? isAllowedTo.deleteSiteCategory : isAllowedTo.deleteGlobalCategory;
28
40
 
29
41
  const { attributes, listeners, setNodeRef, transform, transition } = useSortable({
30
42
  id: category.id,
@@ -32,10 +44,10 @@ const CategoryItem = (props: ICategoryItemProps): JSX.Element => {
32
44
 
33
45
  const { content } = category;
34
46
 
35
- const handleClick = () => !isDragging && isAllowedToEditFormCategory && toggleModal();
47
+ const handleClick = () => !isDragging && isAllowedToEditFormCategory && toggleModal("edit");
36
48
 
37
49
  const handleCloseModal = () => {
38
- toggleModal();
50
+ toggleModal("edit");
39
51
  };
40
52
 
41
53
  const handleOnChange = (value: ICheck) => onChange(value);
@@ -46,7 +58,7 @@ const CategoryItem = (props: ICategoryItemProps): JSX.Element => {
46
58
  const deleted = await deleteFormCategory(category.id, category.categoryType);
47
59
 
48
60
  if (deleted) {
49
- isDeleteOpen && toggleDeleteModal();
61
+ isOpen("delete") && toggleModal("delete");
50
62
  toggleToast("1 form category deleted");
51
63
  }
52
64
  };
@@ -56,18 +68,11 @@ const CategoryItem = (props: ICategoryItemProps): JSX.Element => {
56
68
  {
57
69
  label: "delete",
58
70
  icon: "delete",
59
- action: toggleDeleteModal,
71
+ action: () => toggleModal("delete"),
60
72
  },
61
73
  ]
62
74
  : [];
63
75
 
64
- const mainDeleteModalAction = {
65
- title: "delete",
66
- onClick: removeCategory,
67
- };
68
-
69
- const secondaryDeleteModalAction = { title: "Cancel", onClick: toggleDeleteModal };
70
-
71
76
  return (
72
77
  <>
73
78
  <S.CategoryRow
@@ -101,23 +106,21 @@ const CategoryItem = (props: ICategoryItemProps): JSX.Element => {
101
106
  <S.StyledActionMenu icon="more" options={menuOptions} tooltip="Actions" />
102
107
  </S.ActionsCell>
103
108
  </S.CategoryRow>
104
- {isOpen && (
109
+ {isOpen("edit") && (
105
110
  <CategoryPanel
106
- isOpen={isOpen}
111
+ isOpen={isOpen("edit")}
107
112
  toggleModal={handleCloseModal}
108
113
  item={category}
109
114
  toggleToast={toggleToast}
110
115
  type={category.categoryType}
111
116
  />
112
117
  )}
113
- {isDeleteOpen && (
114
- <DeleteModal
115
- isOpen={isDeleteOpen}
116
- toggleModal={toggleDeleteModal}
117
- mainModalAction={mainDeleteModalAction}
118
- secondaryModalAction={secondaryDeleteModalAction}
119
- />
120
- )}
118
+ <DeleteModal
119
+ isOpen={isOpen("delete")}
120
+ toggleModal={() => toggleModal("delete")}
121
+ onDelete={removeCategory}
122
+ isDeleting={isSaving}
123
+ />
121
124
  </>
122
125
  );
123
126
  };
@@ -130,6 +133,7 @@ interface IProps {
130
133
  hoverCheck?: boolean;
131
134
  isDragging: boolean;
132
135
  isSiteView: boolean;
136
+ isSaving: boolean;
133
137
  }
134
138
 
135
139
  interface IDispatchProps {
@@ -138,8 +142,12 @@ interface IDispatchProps {
138
142
 
139
143
  type ICategoryItemProps = IProps & IDispatchProps;
140
144
 
145
+ const mapStateToProps = (state: IRootState) => ({
146
+ isSaving: state.app.isSaving,
147
+ });
148
+
141
149
  const mapDispatchToProps = {
142
150
  deleteFormCategory: formsActions.deleteFormCategory,
143
151
  };
144
152
 
145
- export default connect(null, mapDispatchToProps)(CategoryItem);
153
+ export default connect(mapStateToProps, mapDispatchToProps)(CategoryItem);
@@ -1,12 +1,18 @@
1
- import React from "react";
2
-
3
- import { IModal } from "@ax/types";
4
1
  import { Modal } from "@ax/components";
2
+ import type { IModal } from "@ax/types";
5
3
 
6
4
  import * as S from "./style";
7
5
 
8
- const DeleteModal = (props: IModal): JSX.Element => {
9
- const { isOpen, toggleModal, mainModalAction, secondaryModalAction } = props;
6
+ const DeleteModal = (props: IDeleteModal): JSX.Element => {
7
+ const { isOpen, toggleModal, onDelete, isDeleting } = props;
8
+
9
+ const mainModalAction = {
10
+ title: isDeleting ? "Deleting" : "delete",
11
+ onClick: onDelete,
12
+ disabled: isDeleting,
13
+ };
14
+
15
+ const secondaryModalAction = { title: "Cancel", onClick: toggleModal };
10
16
 
11
17
  return (
12
18
  <Modal
@@ -16,7 +22,7 @@ const DeleteModal = (props: IModal): JSX.Element => {
16
22
  secondaryAction={secondaryModalAction}
17
23
  mainAction={mainModalAction}
18
24
  size="S"
19
- height={240}
25
+ height="auto"
20
26
  >
21
27
  <S.ModalContent>
22
28
  <p>
@@ -30,4 +36,9 @@ const DeleteModal = (props: IModal): JSX.Element => {
30
36
  );
31
37
  };
32
38
 
39
+ interface IDeleteModal extends IModal {
40
+ onDelete: () => void;
41
+ isDeleting?: boolean;
42
+ }
43
+
33
44
  export { DeleteModal };
@@ -5,7 +5,7 @@ import { useParams } from "react-router-dom";
5
5
  import { EmptyState, ErrorToast, MainWrapper, SearchTagsBar, TableList, Toast } from "@ax/components";
6
6
  import { formsActions } from "@ax/containers/Forms";
7
7
  import { getSchemaFormCategories } 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 { FormCategoriesOrderParams, FormCategory, IRootState } from "@ax/types";
10
10
 
11
11
  import {
@@ -29,7 +29,7 @@ import CategoryPanel from "./CategoryPanel";
29
29
  import * as S from "./style";
30
30
 
31
31
  const FormCategoriesList = (props: IProps): JSX.Element => {
32
- const { categories, currentSiteID, getFormCategories, deleteFormCategory, orderFormCategory } = props;
32
+ const { categories, currentSiteID, isSaving, getFormCategories, deleteFormCategory, orderFormCategory } = props;
33
33
 
34
34
  const schemaCategories = getSchemaFormCategories();
35
35
  const { cat: urlCategory } = useParams<{ cat: string }>();
@@ -42,23 +42,22 @@ const FormCategoriesList = (props: IProps): JSX.Element => {
42
42
  const isSiteView = !!currentSiteID;
43
43
 
44
44
  const [isScrolling, setIsScrolling] = useState(false);
45
- const [isBulkLoading, setIsBulkLoading] = useState(false);
46
45
  const [draggingId, setDraggingId] = useState<number | null>(null);
47
46
  const [searchQuery, setSearchQuery] = useState<string>("");
48
47
  const { isVisible, toggleToast, setIsVisible, state: toastState } = useToast();
49
- const { isOpen, toggleModal } = useModal();
50
- const { isOpen: isDeleteOpen, toggleModal: toggleDeleteModal } = useModal();
48
+ const { isOpen, toggleModal } = useModals(["panel", "delete"]);
51
49
  const tableRef = useRef<HTMLDivElement>(null);
52
50
  const isSearching = searchQuery.length > 0;
53
51
 
54
- const createFormCategoryPermission = isSiteView
55
- ? "forms.createFormsCategories"
56
- : "global.forms.createFormsCategories";
57
- const deleteFormCategoryPermission = isSiteView
58
- ? "forms.deleteFormsCategories"
59
- : "global.forms.deleteFormsCategories";
60
- const isAllowedToCreateFormCategory = usePermission(createFormCategoryPermission);
61
- const isAllowedToDeleteFormCategory = usePermission(deleteFormCategoryPermission);
52
+ const isAllowedTo = usePermissions({
53
+ createSiteCategory: "forms.createFormsCategories",
54
+ createGlobalCategory: "global.forms.createFormsCategories",
55
+ deleteSiteCategory: "forms.deleteFormsCategories",
56
+ deleteGlobalCategory: "global.forms.deleteFormsCategories",
57
+ });
58
+
59
+ const isAllowedToCreateFormCategory = isSiteView ? isAllowedTo.createSiteCategory : isAllowedTo.createGlobalCategory;
60
+ const isAllowedToDeleteFormCategory = isSiteView ? isAllowedTo.deleteSiteCategory : isAllowedTo.deleteGlobalCategory;
62
61
 
63
62
  const sensors = useSensors(
64
63
  useSensor(PointerSensor, {
@@ -97,19 +96,17 @@ const FormCategoriesList = (props: IProps): JSX.Element => {
97
96
  const rightButtonProps = isAllowedToCreateFormCategory
98
97
  ? {
99
98
  label: "New",
100
- action: toggleModal,
99
+ action: () => toggleModal("panel"),
101
100
  }
102
101
  : undefined;
103
102
 
104
103
  const bulkDelete = async () => {
105
- setIsBulkLoading(true);
106
104
  const deleted = await deleteFormCategory(selectedItems.all, category);
107
105
  if (deleted) {
108
106
  resetBulkSelection();
109
107
  toggleToast(`${selectedItems.all.length} categor${selectedItems.all.length > 1 ? "ies" : "y"} deleted`);
110
- toggleDeleteModal();
108
+ toggleModal("delete");
111
109
  }
112
- setIsBulkLoading(false);
113
110
  };
114
111
 
115
112
  const selectItems = () => (checkState.isAllSelected ? resetBulkSelection() : selectAllItems());
@@ -126,7 +123,7 @@ const FormCategoriesList = (props: IProps): JSX.Element => {
126
123
  {
127
124
  icon: "delete",
128
125
  text: "delete",
129
- action: toggleDeleteModal,
126
+ action: () => toggleModal("delete"),
130
127
  },
131
128
  ]
132
129
  : [];
@@ -141,7 +138,7 @@ const FormCategoriesList = (props: IProps): JSX.Element => {
141
138
  isScrolling={isScrolling}
142
139
  bulkActions={bulkActions}
143
140
  setHoverCheck={setHoverCheck}
144
- isLoading={isBulkLoading}
141
+ isLoading={isSaving}
145
142
  />
146
143
  );
147
144
 
@@ -178,7 +175,7 @@ const FormCategoriesList = (props: IProps): JSX.Element => {
178
175
  ? "To start using categories in your forms, create as many categories as you need."
179
176
  : "",
180
177
  button: isAllowedToCreateFormCategory ? "New Category" : "",
181
- action: toggleModal,
178
+ action: () => toggleModal("panel"),
182
179
  };
183
180
 
184
181
  const emptySearchStateProps = {
@@ -187,14 +184,6 @@ const FormCategoriesList = (props: IProps): JSX.Element => {
187
184
  message: "We couldn’t find what you are looking for. Please, try another search.",
188
185
  };
189
186
 
190
- const mainDeleteModalAction = {
191
- title: isBulkLoading ? "Deleting" : "delete",
192
- onClick: bulkDelete,
193
- disabled: isBulkLoading,
194
- };
195
-
196
- const secondaryDeleteModalAction = { title: "Cancel", onClick: toggleDeleteModal };
197
-
198
187
  return (
199
188
  <MainWrapper title="Forms" rightButton={rightButtonProps} searchAction={setSearchQuery} searchValue={searchQuery}>
200
189
  <S.CategoryListWrapper>
@@ -252,13 +241,18 @@ const FormCategoriesList = (props: IProps): JSX.Element => {
252
241
  </TableList>
253
242
  </S.TableWrapper>
254
243
  </S.CategoryListWrapper>
255
- <CategoryPanel isOpen={isOpen} toggleModal={toggleModal} toggleToast={toggleToast} type={category} />
256
- {isDeleteOpen && (
244
+ <CategoryPanel
245
+ isOpen={isOpen("panel")}
246
+ toggleModal={() => toggleModal("panel")}
247
+ toggleToast={toggleToast}
248
+ type={category}
249
+ />
250
+ {isOpen("delete") && (
257
251
  <DeleteModal
258
- isOpen={isDeleteOpen}
259
- toggleModal={toggleDeleteModal}
260
- mainModalAction={mainDeleteModalAction}
261
- secondaryModalAction={secondaryDeleteModalAction}
252
+ isOpen={isOpen("delete")}
253
+ toggleModal={() => toggleModal("delete")}
254
+ onDelete={bulkDelete}
255
+ isDeleting={isSaving}
262
256
  />
263
257
  )}
264
258
  {isVisible && <Toast {...toastProps} />}
@@ -268,6 +262,7 @@ const FormCategoriesList = (props: IProps): JSX.Element => {
268
262
 
269
263
  const mapStateToProps = (state: IRootState) => ({
270
264
  categories: state.forms.currentFormCategories,
265
+ isSaving: state.app.isSaving,
271
266
  // biome-ignore lint/complexity/useOptionalChain: TODO: fix this
272
267
  currentSiteID: state.sites.currentSiteInfo && state.sites.currentSiteInfo.id,
273
268
  });
@@ -281,6 +276,7 @@ interface IDispatchProps {
281
276
  interface ICategoriesProps {
282
277
  categories: FormCategory[];
283
278
  currentSiteID: number | null;
279
+ isSaving: boolean;
284
280
  }
285
281
 
286
282
  type IProps = ICategoriesProps & IDispatchProps;
@@ -155,10 +155,13 @@ const FormEditor = (props: IProps) => {
155
155
  onClick: () => toggleModal("use"),
156
156
  });
157
157
  } else {
158
- const allFormVersions = dataLanguages.map((lang: FormLanguage) => lang.id);
159
- const isDeleted = deleteAllVersions ? await deleteForm(allFormVersions) : await deleteForm(id);
160
- if (isDeleted) {
161
- setHistoryPush(backLinkRoute, false);
158
+ try {
159
+ const allFormVersions = dataLanguages.map((lang: FormLanguage) => lang.id);
160
+ const isDeleted = deleteAllVersions ? await deleteForm(allFormVersions) : await deleteForm(id);
161
+ if (isDeleted) {
162
+ setHistoryPush(backLinkRoute, false);
163
+ }
164
+ } finally {
162
165
  toggleModal("delete");
163
166
  }
164
167
  }
@@ -258,7 +261,6 @@ const FormEditor = (props: IProps) => {
258
261
  action: () => (formInUse ? toggleModal("update") : handleSavePage()),
259
262
  };
260
263
 
261
-
262
264
  return isLoading ? (
263
265
  <Loading />
264
266
  ) : (
@@ -317,6 +319,7 @@ const FormEditor = (props: IProps) => {
317
319
  isOpen={isOpen("delete")}
318
320
  toggleModal={() => toggleModal("delete")}
319
321
  onDelete={removeItem}
322
+ isDeleting={isSaving}
320
323
  {...{ title, isTranslated, deleteAllVersions, setDeleteAllVersions }}
321
324
  />
322
325
  <UnPublishModal
@@ -324,9 +327,14 @@ const FormEditor = (props: IProps) => {
324
327
  toggleModal={() => toggleModal("unpublish")}
325
328
  onUnpublish={unpublishForm}
326
329
  title={title}
330
+ isUnpublishing={isSaving}
327
331
  />
328
332
  {isOpen("update") && (
329
- <UpdateModal isOpen={isOpen("update")} toggleModal={() => toggleModal("update")} onUpdate={() => handleSavePage()} />
333
+ <UpdateModal
334
+ isOpen={isOpen("update")}
335
+ toggleModal={() => toggleModal("update")}
336
+ onUpdate={() => handleSavePage()}
337
+ />
330
338
  )}
331
339
  {isOpen("use") && (
332
340
  <FormUseModal
@@ -44,6 +44,7 @@ const FormItem = (props: IFormItemProps): JSX.Element => {
44
44
  currentSiteInfo,
45
45
  hoverCheck,
46
46
  skipReviewOnPublish,
47
+ isSaving,
47
48
  addCategoryColors,
48
49
  onChange,
49
50
  onClick,
@@ -288,13 +289,14 @@ const FormItem = (props: IFormItemProps): JSX.Element => {
288
289
  isOpen={isOpen("delete")}
289
290
  toggleModal={() => toggleModal("delete")}
290
291
  onDelete={removeItem}
291
- {...{ title, isTranslated, deleteAllVersions, setDeleteAllVersions }}
292
+ {...{ title, isTranslated, deleteAllVersions, setDeleteAllVersions, isDeleting: isSaving }}
292
293
  />
293
294
  <UnPublishModal
294
295
  isOpen={isOpen("unpublish")}
295
296
  toggleModal={() => toggleModal("unpublish")}
296
297
  onUnpublish={unpublishForm}
297
298
  title={title}
299
+ isUnpublishing={isSaving}
298
300
  />
299
301
  <DuplicateModal
300
302
  isOpen={isOpen("duplicate")}
@@ -334,6 +336,7 @@ interface IFormItemProps {
334
336
  currentSiteInfo: ISite | null;
335
337
  hoverCheck?: boolean;
336
338
  skipReviewOnPublish?: boolean;
339
+ isSaving: boolean;
337
340
  addCategoryColors(cats: string[]): void;
338
341
  onChange: (value: ICheck) => void;
339
342
  onClick: (id: number) => void;
@@ -351,6 +354,7 @@ interface IFormItemProps {
351
354
  const mapStateToProps = (state: IRootState) => ({
352
355
  currentSiteInfo: state.sites.currentSiteInfo,
353
356
  skipReviewOnPublish: state.app.globalSettings.skipReviewOnPublish,
357
+ isSaving: state.app.isSaving,
354
358
  });
355
359
 
356
360
  const mapDispatchToProps = {
@@ -47,6 +47,7 @@ const FormList = (props: IUserListProps): JSX.Element => {
47
47
  lang,
48
48
  globalLangs,
49
49
  siteLanguages,
50
+ isSaving,
50
51
  setHistoryPush,
51
52
  addTemplate,
52
53
  getForms,
@@ -71,7 +72,6 @@ const FormList = (props: IUserListProps): JSX.Element => {
71
72
 
72
73
  const [page, setPage] = useState(firstPage);
73
74
  const [isScrolling, setIsScrolling] = useState(false);
74
- const [isBulkLoading, setIsBulkLoading] = useState(false);
75
75
  const [selectedTemplate, setSelectedTemplate] = useState<ISchema | null>(null);
76
76
  const [deleteAllVersions, setDeleteAllVersions] = useState(false);
77
77
  const [arePagesTranslated, setArePagesTranslated] = useState(false);
@@ -85,6 +85,7 @@ const FormList = (props: IUserListProps): JSX.Element => {
85
85
 
86
86
  const wrapperRef = useRef<HTMLDivElement>(null);
87
87
  const tableRef = useRef<HTMLDivElement>(null);
88
+ const notificationRef = useRef<HTMLDivElement>(null);
88
89
  const formIds = forms.map((form) => form.id);
89
90
  const isSearching = searchQuery.length > 0;
90
91
  const isFiltering = currentFilterQuery.length > 0;
@@ -132,6 +133,12 @@ const FormList = (props: IUserListProps): JSX.Element => {
132
133
  handleGetForms();
133
134
  }, [getParams, lang]);
134
135
 
136
+ useEffect(() => {
137
+ if (notification && notificationRef.current) {
138
+ notificationRef.current.scrollIntoView({ behavior: "smooth", block: "start" });
139
+ }
140
+ }, [notification]);
141
+
135
142
  const onScroll = (e: any) => setIsScrolling(e.target.scrollTop > 0);
136
143
 
137
144
  const handleSelectAll = () => selectAllItems();
@@ -174,17 +181,14 @@ const FormList = (props: IUserListProps): JSX.Element => {
174
181
  };
175
182
 
176
183
  const publishForm = async () => {
177
- setIsBulkLoading(true);
178
184
  const isUpdated = await updateFormState(selectedItems.all, "active");
179
185
  if (isUpdated) {
180
186
  resetBulkSelection();
181
187
  toggleToast(`${selectedItems.all.length} form${selectedItems.all.length > 1 ? "s" : ""} published`);
182
188
  }
183
- setIsBulkLoading(false);
184
189
  };
185
190
 
186
191
  const unpublishForm = async () => {
187
- setIsBulkLoading(true);
188
192
  const isUsed = forms.some((form) => selectedItems.all.includes(form.id) && !!form.formInUse);
189
193
  if (isUsed) {
190
194
  setNotification({
@@ -198,11 +202,10 @@ const FormList = (props: IUserListProps): JSX.Element => {
198
202
  toggleToast(`${selectedItems.all.length} form${selectedItems.all.length > 1 ? "s" : ""} unpublished`);
199
203
  }
200
204
  }
201
- setIsBulkLoading(false);
205
+ isOpen("unpublish") && toggleModal("unpublish");
202
206
  };
203
207
 
204
208
  const handleDeleteForm = async () => {
205
- setIsBulkLoading(true);
206
209
  const idsToBeDeleted = getAllLangFormsIds(forms, selectedItems.all, deleteAllVersions);
207
210
  const isUsed = forms.some((form) => idsToBeDeleted.includes(form.id) && !!form.formInUse);
208
211
  if (isUsed) {
@@ -217,7 +220,6 @@ const FormList = (props: IUserListProps): JSX.Element => {
217
220
  toggleModal("delete");
218
221
  }
219
222
  }
220
- setIsBulkLoading(false);
221
223
  };
222
224
 
223
225
  const handleToggleBulkDelete = () => {
@@ -273,7 +275,7 @@ const FormList = (props: IUserListProps): JSX.Element => {
273
275
  featuredCategory={featuredCategory}
274
276
  bulkActions={bulkActions}
275
277
  siteID={currentSiteInfo?.id || null}
276
- isLoading={isBulkLoading}
278
+ isLoading={isSaving}
277
279
  />
278
280
  );
279
281
 
@@ -330,7 +332,7 @@ const FormList = (props: IUserListProps): JSX.Element => {
330
332
  <FormsMenu />
331
333
  <S.TableListWrapper>
332
334
  {notification && (
333
- <S.NotificationWrapper>
335
+ <S.NotificationWrapper ref={notificationRef}>
334
336
  <Notification
335
337
  type={notification.type}
336
338
  text={notification.text}
@@ -413,6 +415,7 @@ const FormList = (props: IUserListProps): JSX.Element => {
413
415
  toggleModal={() => toggleModal("unpublish")}
414
416
  onUnpublish={unpublishForm}
415
417
  title={selectedItems.all.length > 1 ? "these forms" : "this form"}
418
+ isUnpublishing={isSaving}
416
419
  />
417
420
  )}
418
421
  {isOpen("delete") && (
@@ -421,6 +424,7 @@ const FormList = (props: IUserListProps): JSX.Element => {
421
424
  toggleModal={() => toggleModal("delete")}
422
425
  onDelete={handleDeleteForm}
423
426
  title={selectedItems.all.length > 1 ? "these forms" : "this form"}
427
+ isDeleting={isSaving}
424
428
  {...{ isTranslated: arePagesTranslated, deleteAllVersions, setDeleteAllVersions }}
425
429
  />
426
430
  )}
@@ -436,6 +440,7 @@ const mapStateToProps = (state: IRootState) => ({
436
440
  siteLanguages: state.sites.currentSiteLanguages,
437
441
  globalLangs: state.app.globalLangs,
438
442
  lang: state.app.lang,
443
+ isSaving: state.app.isSaving,
439
444
  });
440
445
 
441
446
  const mapDispatchToProps = {
@@ -465,6 +470,7 @@ interface IProps {
465
470
  lang: { locale: string; id: number };
466
471
  siteLanguages: ILanguage[];
467
472
  globalLangs: ILanguage[];
473
+ isSaving: boolean;
468
474
  }
469
475
 
470
476
  export type IUserListProps = IProps & IDispatchProps;
@@ -6,7 +6,8 @@ import type { IModal } from "@ax/types";
6
6
  import * as S from "./style";
7
7
 
8
8
  const DeleteModal = (props: IDeleteModal): JSX.Element => {
9
- const { isOpen, toggleModal, onDelete, isTranslated, deleteAllVersions, setDeleteAllVersions, title } = props;
9
+ const { isOpen, toggleModal, onDelete, isTranslated, deleteAllVersions, setDeleteAllVersions, title, isDeleting } =
10
+ props;
10
11
 
11
12
  const options = [
12
13
  {
@@ -23,7 +24,7 @@ const DeleteModal = (props: IDeleteModal): JSX.Element => {
23
24
 
24
25
  const formTitle = title ? <strong>{title}</strong> : "this form";
25
26
 
26
- const mainAction = { title: "Delete form", onClick: onDelete };
27
+ const mainAction = { title: isDeleting ? "Deleting" : "Delete form", onClick: onDelete, disabled: isDeleting };
27
28
  const secondaryAction = { title: "Cancel", onClick: toggleModal };
28
29
 
29
30
  return (
@@ -66,11 +67,11 @@ const DeleteModal = (props: IDeleteModal): JSX.Element => {
66
67
  };
67
68
 
68
69
  const UnPublishModal = (props: IUnpublishModal): JSX.Element => {
69
- const { isOpen, toggleModal, onUnpublish, title } = props;
70
+ const { isOpen, toggleModal, onUnpublish, title, isUnpublishing } = props;
70
71
 
71
72
  const formTitle = title ? <strong>{title}</strong> : "this form";
72
73
 
73
- const mainAction = { title: "Unpublish form", onClick: onUnpublish };
74
+ const mainAction = { title: isUnpublishing ? "Unpublishing" : "Unpublish form", onClick: onUnpublish, disabled: isUnpublishing };
74
75
  const secondaryAction = { title: "Cancel", onClick: toggleModal };
75
76
 
76
77
  return (
@@ -201,11 +202,13 @@ interface IDeleteModal extends IModal {
201
202
  deleteAllVersions: boolean;
202
203
  setDeleteAllVersions: Dispatch<SetStateAction<boolean>>;
203
204
  title?: string;
205
+ isDeleting?: boolean;
204
206
  }
205
207
 
206
208
  interface IUnpublishModal extends IModal {
207
209
  onUnpublish(): void;
208
210
  title?: string;
211
+ isUnpublishing?: boolean;
209
212
  }
210
213
 
211
214
  interface IDuplicateModal extends IModal {
@@ -0,0 +1,77 @@
1
+ import type React from "react";
2
+
3
+ import { FieldsBehavior, Modal } from "@ax/components";
4
+ import type { IModal } from "@ax/types";
5
+
6
+ import * as S from "./style";
7
+
8
+ const DeleteModal = (props: IDeleteModal): JSX.Element => {
9
+ const { isOpen, toggleModal, isTranslated, deleteAllVersions, setDeleteAllVersions, onDelete, isDeleting } = props;
10
+
11
+ const options = [
12
+ {
13
+ title: "Delete only this version",
14
+ name: "deletePage",
15
+ value: false,
16
+ },
17
+ {
18
+ title: "Delete all languages versions",
19
+ name: "deleteAll",
20
+ value: true,
21
+ },
22
+ ];
23
+
24
+ const mainAction = {
25
+ title: isDeleting ? "Deleting" : "Delete page",
26
+ onClick: onDelete,
27
+ disabled: isDeleting,
28
+ };
29
+
30
+ const secondaryAction = { title: "Cancel", onClick: toggleModal };
31
+
32
+ return (
33
+ <Modal
34
+ isOpen={isOpen}
35
+ hide={toggleModal}
36
+ title="Delete Page?"
37
+ secondaryAction={secondaryAction}
38
+ mainAction={mainAction}
39
+ size="S"
40
+ height="auto"
41
+ >
42
+ {isTranslated ? (
43
+ <>
44
+ <S.ModalContent>
45
+ <p>
46
+ You are going to delete this page that have some translations associated. Choose if you want to delete all
47
+ languages versions or only this one.
48
+ </p>
49
+ <FieldsBehavior
50
+ name="removeAllVersions"
51
+ fieldType="RadioGroup"
52
+ value={deleteAllVersions}
53
+ options={options}
54
+ onChange={setDeleteAllVersions}
55
+ />
56
+ </S.ModalContent>
57
+ </>
58
+ ) : (
59
+ <S.ModalContent>
60
+ Are you sure you want to delete this page?
61
+ <br />
62
+ This action <strong>cannot be undone</strong>.
63
+ </S.ModalContent>
64
+ )}
65
+ </Modal>
66
+ );
67
+ };
68
+
69
+ interface IDeleteModal extends IModal {
70
+ isTranslated: boolean;
71
+ deleteAllVersions: boolean;
72
+ setDeleteAllVersions: React.Dispatch<React.SetStateAction<boolean>>;
73
+ onDelete: () => void;
74
+ isDeleting?: boolean;
75
+ }
76
+
77
+ export { DeleteModal };