@griddo/ax 1.73.29 → 1.74.1

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 (98) hide show
  1. package/config/griddo-config/index.js +24 -3
  2. package/config/webpackSchemas.config.js +3 -5
  3. package/package.json +3 -2
  4. package/scripts/griddo-sync-schemas.js +4 -3
  5. package/src/__mocks__/axios/SitesList.ts +84 -0
  6. package/src/__mocks__/store/SitesList.ts +714 -0
  7. package/src/__tests__/components/Avatar/Avatar.test.tsx +119 -0
  8. package/src/__tests__/components/Avatar/__snapshots__/Avatar.test.tsx.snap +61 -0
  9. package/src/__tests__/components/Fields/ReferenceField/ReferenceField.test.tsx +10 -10
  10. package/src/__tests__/components/LanguageMenu/LanguageMenu.test.tsx +221 -0
  11. package/src/__tests__/components/Loading/Loading.test.tsx +23 -0
  12. package/src/__tests__/components/Login/Login.test.tsx +247 -0
  13. package/src/__tests__/components/Login/RecoveryModal/RecoveryModal.test.tsx +185 -0
  14. package/src/__tests__/components/TableFilters/LiveFilter/LiveFilter.test.tsx +6 -6
  15. package/src/__tests__/modules/Sites/Sites.test.tsx +259 -0
  16. package/src/__tests__/modules/Sites/SitesList/ListView/BulkHeader/BulkHeader.test.tsx +51 -0
  17. package/src/__tests__/modules/Sites/SitesList/SitesList.test.tsx +896 -0
  18. package/src/api/sites.tsx +43 -4
  19. package/src/components/ActionMenu/index.tsx +1 -1
  20. package/src/components/Avatar/index.tsx +4 -4
  21. package/src/components/Browser/index.tsx +27 -20
  22. package/src/components/BrowserContent/index.tsx +6 -0
  23. package/src/components/Fields/AsyncSelect/style.tsx +6 -3
  24. package/src/components/Fields/CheckField/index.tsx +1 -0
  25. package/src/components/Fields/DateField/style.tsx +3 -1
  26. package/src/components/Fields/HeadingField/index.tsx +14 -5
  27. package/src/components/Fields/ImageField/index.tsx +3 -0
  28. package/src/components/Fields/ImageField/style.tsx +2 -2
  29. package/src/components/Fields/Select/style.tsx +2 -0
  30. package/src/components/Fields/SliderField/index.tsx +2 -1
  31. package/src/components/Fields/TextField/index.tsx +1 -0
  32. package/src/components/Icon/components/BulletList.js +16 -0
  33. package/src/components/Icon/components/Grid2.js +16 -0
  34. package/src/components/Icon/svgs/Bullet-list.svg +3 -0
  35. package/src/components/Icon/svgs/Grid-2.svg +3 -0
  36. package/src/components/IconAction/index.tsx +4 -2
  37. package/src/components/IconAction/style.tsx +8 -2
  38. package/src/components/LanguageMenu/index.tsx +13 -6
  39. package/src/components/Login/RecoveryModal/index.tsx +5 -4
  40. package/src/components/Login/index.tsx +13 -3
  41. package/src/components/Login/style.tsx +12 -25
  42. package/src/components/Pagination/style.tsx +1 -1
  43. package/src/components/SearchField/index.tsx +9 -1
  44. package/src/components/SideModal/style.tsx +8 -8
  45. package/src/components/TableFilters/LastAccessFilter/index.tsx +52 -0
  46. package/src/components/TableFilters/LastAccessFilter/style.tsx +31 -0
  47. package/src/components/TableFilters/LiveFilter/index.tsx +7 -5
  48. package/src/components/TableFilters/NameFilter/index.tsx +4 -3
  49. package/src/components/TableFilters/index.tsx +2 -0
  50. package/src/components/TableList/index.tsx +2 -1
  51. package/src/components/TableList/style.tsx +2 -2
  52. package/src/components/index.tsx +2 -0
  53. package/src/containers/App/actions.tsx +5 -0
  54. package/src/containers/App/interfaces.tsx +1 -1
  55. package/src/containers/App/reducer.tsx +1 -1
  56. package/src/containers/Navigation/Defaults/actions.tsx +3 -1
  57. package/src/containers/PageEditor/actions.tsx +6 -3
  58. package/src/containers/Sites/actions.tsx +76 -11
  59. package/src/containers/Sites/constants.tsx +2 -0
  60. package/src/containers/Sites/interfaces.tsx +12 -0
  61. package/src/containers/Sites/reducer.tsx +8 -0
  62. package/src/helpers/schemas.tsx +27 -1
  63. package/src/hooks/iframe.ts +56 -0
  64. package/src/hooks/index.tsx +3 -0
  65. package/src/modules/Content/index.tsx +4 -3
  66. package/src/modules/FramePreview/index.tsx +25 -39
  67. package/src/modules/GlobalEditor/Editor/index.tsx +2 -2
  68. package/src/modules/GlobalEditor/PageBrowser/index.tsx +16 -4
  69. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +11 -7
  70. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +4 -3
  71. package/src/modules/Navigation/Menus/List/Table/SidePanel/Form/index.tsx +1 -0
  72. package/src/modules/PageEditor/Editor/index.tsx +2 -2
  73. package/src/modules/PageEditor/PageBrowser/index.tsx +16 -4
  74. package/src/modules/PageEditor/index.tsx +8 -7
  75. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/ConfigPanel/Field/index.tsx +12 -11
  76. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/index.tsx +3 -17
  77. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/style.tsx +2 -10
  78. package/src/modules/Sites/SitesList/GridView/GridHeaderFilter/index.tsx +72 -0
  79. package/src/modules/Sites/SitesList/GridView/GridHeaderFilter/style.tsx +32 -0
  80. package/src/modules/Sites/SitesList/{SiteItem → GridView/GridSiteItem}/index.tsx +17 -27
  81. package/src/modules/Sites/SitesList/{SiteItem → GridView/GridSiteItem}/style.tsx +14 -25
  82. package/src/modules/Sites/SitesList/ListView/BulkHeader/TableHeader/index.tsx +64 -0
  83. package/src/modules/Sites/SitesList/ListView/BulkHeader/TableHeader/style.tsx +50 -0
  84. package/src/modules/Sites/SitesList/ListView/BulkHeader/index.tsx +75 -0
  85. package/src/modules/Sites/SitesList/ListView/BulkHeader/style.tsx +8 -0
  86. package/src/modules/Sites/SitesList/ListView/ListSiteItem/index.tsx +200 -0
  87. package/src/modules/Sites/SitesList/ListView/ListSiteItem/style.tsx +112 -0
  88. package/src/modules/Sites/SitesList/RecentSiteItem/index.tsx +50 -0
  89. package/src/modules/Sites/SitesList/RecentSiteItem/style.tsx +28 -0
  90. package/src/modules/Sites/SitesList/SiteModal/index.tsx +4 -3
  91. package/src/modules/Sites/SitesList/atoms.tsx +47 -0
  92. package/src/modules/Sites/SitesList/hooks.tsx +102 -0
  93. package/src/modules/Sites/SitesList/index.tsx +272 -19
  94. package/src/modules/Sites/SitesList/style.tsx +157 -4
  95. package/src/modules/Sites/SitesList/utils.tsx +33 -0
  96. package/src/modules/Sites/index.tsx +6 -11
  97. package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +1 -1
  98. package/src/types/index.tsx +25 -2
@@ -1,5 +1,7 @@
1
1
  import {
2
2
  SET_SITES,
3
+ SET_RECENT_SITES,
4
+ SET_SITES_TOTAL_ITEMS,
3
5
  SET_SITES_BY_LANG,
4
6
  SET_CURRENT_SITE_INFO,
5
7
  SET_CURRENT_SITE_PAGES,
@@ -20,6 +22,8 @@ export interface ISitesState {
20
22
  currentSiteName: string | null;
21
23
  currentSitePages: IPage[];
22
24
  sites: ISite[];
25
+ recentSites: ISite[];
26
+ sitesTotalItems: number;
23
27
  sitesByLang: ISite[];
24
28
  currentSiteInfo: any;
25
29
  currentFilter: string | null;
@@ -34,10 +38,12 @@ export const initialState = {
34
38
  currentSiteName: null,
35
39
  currentSitePages: [],
36
40
  sites: [],
41
+ recentSites: [],
37
42
  sitesByLang: [],
38
43
  currentSiteInfo: null,
39
44
  currentFilter: "unique-pages",
40
45
  totalItems: 0,
46
+ sitesTotalItems: 0,
41
47
  currentSiteLanguages: [],
42
48
  savedSiteInfo: null,
43
49
  currentSiteErrorPages: [],
@@ -48,6 +54,8 @@ export function reducer(state = initialState, action: SitesActionsCreators): ISi
48
54
  switch (action.type) {
49
55
  case SET_FILTER:
50
56
  case SET_SITES:
57
+ case SET_RECENT_SITES:
58
+ case SET_SITES_TOTAL_ITEMS:
51
59
  case SET_SITES_BY_LANG:
52
60
  case SET_CURRENT_SITE_INFO:
53
61
  case SET_CURRENT_SITE_PAGES:
@@ -6,7 +6,33 @@ import { pageSchemas } from "@ax/schemas";
6
6
  const allSchemas = { ...schemas.all, ...pageSchemas };
7
7
 
8
8
  const getSchema = (name: string) => allSchemas[name];
9
- const getDefaultSchema = (name: string) => (allSchemas[name] ? allSchemas[name].default : {});
9
+
10
+ const getDefaultSchema = (name: string) => {
11
+ const defaultSchema = allSchemas[name] ? allSchemas[name].default : {};
12
+
13
+ for (const key of Object.keys(defaultSchema)) {
14
+ if (
15
+ defaultSchema[key] &&
16
+ typeof defaultSchema[key] === "object" &&
17
+ Object.prototype.hasOwnProperty.call(defaultSchema[key], "schema")
18
+ ) {
19
+ defaultSchema[key] = getDefaultSchema(defaultSchema[key].schema);
20
+ }
21
+ if (defaultSchema[key] instanceof Array) {
22
+ for (const i in defaultSchema[key]) {
23
+ if (
24
+ defaultSchema[key][i] &&
25
+ typeof defaultSchema[key][i] === "object" &&
26
+ Object.prototype.hasOwnProperty.call(defaultSchema[key][i], "schema")
27
+ ) {
28
+ defaultSchema[key][i] = getDefaultSchema(defaultSchema[key][i].schema);
29
+ }
30
+ }
31
+ }
32
+ }
33
+
34
+ return defaultSchema;
35
+ };
10
36
 
11
37
  const getSchemaThumbnails = (name: string, theme?: string) => {
12
38
  if (!allSchemas[name]?.thumbnails) return null;
@@ -0,0 +1,56 @@
1
+ import { useCallback, useEffect } from "react";
2
+
3
+ const useOnMessageReceivedFromIframe = (actions?: {
4
+ setSelectedContentAction: any;
5
+ deleteModuleAction(editorID: number): void;
6
+ duplicateModuleAction(editorID: number): Promise<number>;
7
+ }): void => {
8
+ const onMessageReceivedFromIframe = useCallback(
9
+ async (ev: MessageEvent<{ type: string; message: string }>) => {
10
+ if (typeof ev.data !== "object") return;
11
+ if (!ev.data.type) return;
12
+ if (!ev.data.message) return;
13
+ if (ev.data.type === "module-click") {
14
+ actions?.setSelectedContentAction(ev.data.message);
15
+ }
16
+ if (ev.data.type === "module-delete") {
17
+ actions?.setSelectedContentAction(0);
18
+ actions?.deleteModuleAction(parseInt(ev.data.message));
19
+ }
20
+ if (ev.data.type === "module-duplicate") {
21
+ const duplicatedEditorID = await actions?.duplicateModuleAction(parseInt(ev.data.message));
22
+ actions?.setSelectedContentAction(duplicatedEditorID);
23
+ }
24
+ },
25
+ [actions]
26
+ );
27
+
28
+ useEffect(() => {
29
+ window.addEventListener("message", onMessageReceivedFromIframe);
30
+ return () => window.removeEventListener("message", onMessageReceivedFromIframe);
31
+ }, [onMessageReceivedFromIframe]);
32
+ };
33
+
34
+ const useOnMessageReceivedFromOutside = (setEditorContent: any, setSelectedContent: any): void => {
35
+ const onMessageReceivedFromOutside = useCallback(
36
+ (ev: MessageEvent<{ type: string; message: Record<string, unknown> }>) => {
37
+ if (typeof ev.data !== "object") return;
38
+ if (!ev.data.type) return;
39
+ if (!ev.data.message) return;
40
+ if (ev.data.type === "content-update") {
41
+ setEditorContent(ev.data.message);
42
+ }
43
+ if (ev.data.type === "selected-content") {
44
+ setSelectedContent(ev.data.message);
45
+ }
46
+ },
47
+ [setEditorContent, setSelectedContent]
48
+ );
49
+
50
+ useEffect(() => {
51
+ window.addEventListener("message", onMessageReceivedFromOutside);
52
+ return () => window.removeEventListener("message", onMessageReceivedFromOutside);
53
+ }, [onMessageReceivedFromOutside]);
54
+ };
55
+
56
+ export { useOnMessageReceivedFromIframe, useOnMessageReceivedFromOutside };
@@ -3,6 +3,7 @@ import { useDebounce, useEqualStructured, useIsDirty, usePrevious } from "./form
3
3
  import { useHandleClickOutside, useModal, useToast } from "./modals";
4
4
  import { useURLSearchParam } from "./location";
5
5
  import { useCategoryColors } from "./content";
6
+ import { useOnMessageReceivedFromIframe, useOnMessageReceivedFromOutside } from "./iframe";
6
7
 
7
8
  export {
8
9
  useModal,
@@ -15,4 +16,6 @@ export {
15
16
  useBulkSelection,
16
17
  useURLSearchParam,
17
18
  useCategoryColors,
19
+ useOnMessageReceivedFromIframe,
20
+ useOnMessageReceivedFromOutside,
18
21
  };
@@ -17,6 +17,7 @@ import {
17
17
  ISite,
18
18
  IUser,
19
19
  IErrorItem,
20
+ IGetSitesParams,
20
21
  } from "@ax/types";
21
22
  import { MainWrapper, Modal, TableList, ErrorToast, Toast, EmptyState, Notification } from "@ax/components";
22
23
  import { getFilteredStructuredData, isGlobalStructuredData, isStructuredDataFromPage } from "@ax/helpers";
@@ -255,8 +256,8 @@ const Content = (props: IProps): JSX.Element => {
255
256
  setColumnsState(initialColumns);
256
257
  // eslint-disable-next-line react-hooks/exhaustive-deps
257
258
  }, [filter]);
258
-
259
- const fetchSitesByLang = async () => await getSitesByLang(lang.id);
259
+ const params = { language: lang.id, recentSitesNumber: 7 };
260
+ const fetchSitesByLang = async () => await getSitesByLang(params);
260
261
 
261
262
  useEffect(() => {
262
263
  if (!locationState || locationState.isFromEditor !== true) {
@@ -819,7 +820,7 @@ interface IDispatchProps {
819
820
  restorePage(id: number | number[]): Promise<boolean>;
820
821
  getDataPack: (id: string) => Promise<void>;
821
822
  resetCurrentSiteErrorPages: () => Promise<void>;
822
- getSitesByLang(language: number): Promise<void>;
823
+ getSitesByLang(params: IGetSitesParams): Promise<void>;
823
824
  setContentFilters(contentFilters: Record<string, string> | null): void;
824
825
  deleteAndRemoveFromSiteBulk(pageIds: number[], globalPageIds: number[]): Promise<boolean>;
825
826
  }
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect } from "react";
1
+ import React from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
4
  import { getDefaultTheme } from "@ax/helpers";
@@ -6,7 +6,7 @@ import { Loading, BrowserContent } from "@ax/components";
6
6
  import { ILanguage, IRootState, ISocialState } from "@ax/types";
7
7
  import { pageEditorActions } from "@ax/containers/PageEditor";
8
8
  import { findByEditorID } from "@ax/forms";
9
- import { useURLSearchParam } from "@ax/hooks";
9
+ import { useOnMessageReceivedFromOutside, useURLSearchParam } from "@ax/hooks";
10
10
 
11
11
  import * as S from "./style";
12
12
 
@@ -21,40 +21,14 @@ const FramePreview = (props: IProps) => {
21
21
  globalLangs,
22
22
  setSelectedContent,
23
23
  setEditorContent,
24
+ deleteModule,
25
+ duplicateModule,
24
26
  } = props;
25
27
 
26
28
  const isPreview = useURLSearchParam("preview");
27
29
  const isDisabled = useURLSearchParam("disabled");
28
30
 
29
- const onMessageReceivedFromOutside = useCallback(
30
- (ev: MessageEvent<{ type: string; message: Record<string, unknown> }>) => {
31
- if (typeof ev.data !== "object") return;
32
- if (!ev.data.type) return;
33
- if (ev.data.type !== "content-update") return;
34
- if (!ev.data.message) return;
35
- setEditorContent(ev.data.message);
36
- },
37
- []
38
- );
39
-
40
- useEffect(() => {
41
- window.addEventListener("message", onMessageReceivedFromOutside);
42
- return () => window.removeEventListener("message", onMessageReceivedFromOutside);
43
- }, [onMessageReceivedFromOutside]);
44
-
45
- const onMessageReceivedFromPanel = useCallback((ev: MessageEvent<{ type: string; message: string }>) => {
46
- if (typeof ev.data !== "object") return;
47
- if (!ev.data.type) return;
48
- if (ev.data.type !== "selected-content") return;
49
- if (!ev.data.message) return;
50
- setSelectedContent(parseInt(ev.data.message));
51
- // eslint-disable-next-line react-hooks/exhaustive-deps
52
- }, []);
53
-
54
- useEffect(() => {
55
- window.addEventListener("message", onMessageReceivedFromPanel);
56
- return () => window.removeEventListener("message", onMessageReceivedFromPanel);
57
- }, [onMessageReceivedFromPanel]);
31
+ useOnMessageReceivedFromOutside(setEditorContent, setSelectedContent);
58
32
 
59
33
  const {
60
34
  editorContent: { canonicalSite, language, pageLanguages },
@@ -77,14 +51,7 @@ const FramePreview = (props: IProps) => {
77
51
  const isNavigationModule = ["header", "footer"].includes(selectedComponent.type);
78
52
 
79
53
  if (isPreview === "false" && (isDisabled === "false" || isNavigationModule)) {
80
- window.parent.postMessage(
81
- {
82
- type: "module-click",
83
- message: editorID,
84
- },
85
- "*"
86
- );
87
-
54
+ window.parent.postMessage({ type: "module-click", message: editorID }, "*");
88
55
  setSelectedContent && setSelectedContent(editorID);
89
56
  }
90
57
  };
@@ -94,6 +61,20 @@ const FramePreview = (props: IProps) => {
94
61
  const langs = currentSiteInfo ? siteLangs : globalLangs;
95
62
  const siteID = currentSiteInfo ? currentSiteInfo.id : canonicalSite;
96
63
 
64
+ const deleteModuleSelected = (editorID: number) => {
65
+ window.parent.postMessage({ type: "module-delete", message: editorID }, "*");
66
+ setSelectedContent && setSelectedContent(0);
67
+ deleteModule(editorID);
68
+ };
69
+ const duplicateModuleSelected = (editorID: number) => {
70
+ window.parent.postMessage({ type: "module-duplicate", message: editorID }, "*");
71
+ duplicateModule(editorID);
72
+ };
73
+ const moduleActions = {
74
+ deleteModuleAction: deleteModuleSelected,
75
+ duplicateModuleAction: duplicateModuleSelected,
76
+ };
77
+
97
78
  if (isLoading) return <Loading />;
98
79
 
99
80
  return (
@@ -111,6 +92,7 @@ const FramePreview = (props: IProps) => {
111
92
  footer={currentSiteInfo && footer}
112
93
  languageID={language}
113
94
  pageLanguages={pageLanguages}
95
+ moduleActions={moduleActions}
114
96
  renderer={isPreview === "true" ? "preview" : "editor"}
115
97
  />
116
98
  </S.Wrapper>
@@ -127,6 +109,8 @@ interface IProps {
127
109
  isLoading: boolean;
128
110
  setSelectedContent(editorID: number): void;
129
111
  setEditorContent(editorContent: Record<string, unknown>): void;
112
+ deleteModule(editorID: number): void;
113
+ duplicateModule(editorID: number): void;
130
114
  }
131
115
 
132
116
  const mapStateToProps = (state: IRootState) => ({
@@ -142,6 +126,8 @@ const mapStateToProps = (state: IRootState) => ({
142
126
  const mapDispatchToProps = {
143
127
  setSelectedContent: pageEditorActions.setSelectedContent,
144
128
  setEditorContent: pageEditorActions.setEditorContent,
129
+ deleteModule: pageEditorActions.deleteModule,
130
+ duplicateModule: pageEditorActions.duplicateModule,
145
131
  };
146
132
 
147
133
  export default connect(mapStateToProps, mapDispatchToProps)(FramePreview);
@@ -86,8 +86,8 @@ interface IEditorStateProps {
86
86
  interface IPageBrowserDispatchProps {
87
87
  setSelectedContent(editorID: number): void;
88
88
  setSelectedTab(tab: string): void;
89
- deleteModule(editorID: number, key: string): void;
90
- duplicateModule(editorID: number, key: string): void;
89
+ deleteModule(editorID: number, key?: string): void;
90
+ duplicateModule(editorID: number, key?: string): Promise<number>;
91
91
  addComponent: (componentType: any, key: string) => void;
92
92
  addModule: (moduleType: string, selectedID: number, key: string) => void;
93
93
  moveElement(moduleID: number, selectedContent: any, newIndex: number, key: string): void;
@@ -18,18 +18,25 @@ const PageBrowser = (props: IProps) => {
18
18
  isReadOnly,
19
19
  isPreview,
20
20
  browserRef,
21
+ deleteModule,
22
+ duplicateModule,
21
23
  } = props;
22
24
 
23
25
  const slugWithSlash = slug ? (slug.startsWith("/") ? slug : `/${slug}`) : "";
24
26
  const pathWithoutSlash = path ? (path.endsWith("/") ? path.slice(0, -1) : path) : "";
25
27
  const url = `${pathWithoutSlash}${slugWithSlash}`;
26
28
 
29
+ const actions = {
30
+ deleteModuleAction: deleteModule,
31
+ duplicateModuleAction: duplicateModule,
32
+ setSelectedContentAction: setSelectedContent,
33
+ };
34
+
27
35
  return (
28
36
  <Browser
29
37
  isPage={true}
30
38
  content={props.content.editorContent}
31
39
  socials={socials}
32
- setSelectedContent={setSelectedContent}
33
40
  url={url}
34
41
  theme={theme}
35
42
  cloudinaryName={cloudinaryName}
@@ -39,11 +46,12 @@ const PageBrowser = (props: IProps) => {
39
46
  isPreview={isPreview}
40
47
  showIframe={true}
41
48
  browserRef={browserRef}
49
+ actions={actions}
42
50
  />
43
51
  );
44
52
  };
45
53
 
46
- interface IEditorStateProps {
54
+ interface IPageBrowserStateProps {
47
55
  // TODO: Define content Type
48
56
  content: any;
49
57
  socials: ISocialState;
@@ -60,11 +68,13 @@ interface IPageBrowserDispatchProps {
60
68
  isReadOnly: boolean;
61
69
  isPreview?: boolean;
62
70
  browserRef?: any;
71
+ deleteModule(editorID: number): void;
72
+ duplicateModule(editorID: number): Promise<number>;
63
73
  }
64
74
 
65
- type IProps = IEditorStateProps & IPageBrowserDispatchProps;
75
+ type IProps = IPageBrowserStateProps & IPageBrowserDispatchProps;
66
76
 
67
- const mapStateToProps = (state: IRootState): IEditorStateProps => ({
77
+ const mapStateToProps = (state: IRootState): IPageBrowserStateProps => ({
68
78
  content: { ...state.pageEditor.editorContent },
69
79
  socials: state.social,
70
80
  cloudinaryName: state.app.globalSettings.cloudinaryName,
@@ -76,6 +86,8 @@ const mapStateToProps = (state: IRootState): IEditorStateProps => ({
76
86
 
77
87
  const mapDispatchToProps = {
78
88
  setSelectedContent: pageEditorActions.setSelectedContent,
89
+ deleteModule: pageEditorActions.deleteModule,
90
+ duplicateModule: pageEditorActions.duplicateModule,
79
91
  };
80
92
 
81
93
  export default connect(mapStateToProps, mapDispatchToProps)(PageBrowser);
@@ -10,10 +10,10 @@ const DefaultsBrowser = (props: IProps) => {
10
10
  socials,
11
11
  cloudinaryName,
12
12
  content,
13
- setSelectedContent,
14
13
  currentSiteInfo: { theme, id: siteID },
15
14
  siteLangs,
16
15
  browserRef,
16
+ actions,
17
17
  } = props;
18
18
 
19
19
  const updatedContent = { ...content };
@@ -24,17 +24,22 @@ const DefaultsBrowser = (props: IProps) => {
24
24
  isPage={false}
25
25
  socials={socials}
26
26
  content={updatedContent}
27
- setSelectedContent={setSelectedContent}
28
27
  url={content.slug}
29
28
  theme={theme}
30
29
  cloudinaryName={cloudinaryName}
31
30
  siteLangs={siteLangs}
32
31
  siteID={siteID}
32
+ actions={actions}
33
33
  />
34
34
  );
35
35
  };
36
36
 
37
- interface IEditorStateProps {
37
+ interface IDefaultsBrowserProps {
38
+ actions: any;
39
+ browserRef?: any;
40
+ }
41
+
42
+ interface IDefaultsBrowserStateProps {
38
43
  // TODO: Define content Type
39
44
  content: any;
40
45
  currentSiteInfo: any;
@@ -43,14 +48,13 @@ interface IEditorStateProps {
43
48
  siteLangs: ILanguage[];
44
49
  }
45
50
 
46
- interface IPageBrowserDispatchProps {
51
+ interface IDefaultsBrowserDispatchProps {
47
52
  setSelectedContent(editorID: number): void;
48
- browserRef?: any;
49
53
  }
50
54
 
51
- type IProps = IEditorStateProps & IPageBrowserDispatchProps;
55
+ type IProps = IDefaultsBrowserProps & IDefaultsBrowserStateProps & IDefaultsBrowserDispatchProps;
52
56
 
53
- const mapStateToProps = (state: IRootState): IEditorStateProps => ({
57
+ const mapStateToProps = (state: IRootState): IDefaultsBrowserStateProps => ({
54
58
  content: { ...state.navigation.editorContent },
55
59
  currentSiteInfo: state.sites.currentSiteInfo,
56
60
  socials: state.social,
@@ -33,11 +33,12 @@ const Editor = (props: IProps) => {
33
33
  replaceModuleAction: replaceModule,
34
34
  duplicateModuleAction: duplicateModule,
35
35
  replaceElementsInCollectionAction: replaceElementsInCollection,
36
+ setSelectedContentAction: setSelectedContent,
36
37
  };
37
38
 
38
39
  return (
39
40
  <ResizePanel
40
- leftPanel={<DefaultsBrowser browserRef={browserRef} />}
41
+ leftPanel={<DefaultsBrowser browserRef={browserRef} actions={actions} />}
41
42
  rightPanel={
42
43
  <ConfigPanel
43
44
  schema={schema}
@@ -72,8 +73,8 @@ interface IEditorStateProps {
72
73
  interface IPageBrowserDispatchProps {
73
74
  setSelectedContent(editorID: number): void;
74
75
  setSelectedTab(tab: string): void;
75
- deleteModule(editorID: number, key: string): void;
76
- duplicateModule(editorID: number, key: string): void;
76
+ deleteModule(editorID: number, key?: string): void;
77
+ duplicateModule(editorID: number, key?: string): Promise<number>;
77
78
  addComponent: (componentType: any, key: string) => void;
78
79
  replaceModule(module: any, parent: any, objKey: string): void;
79
80
  replaceElementsInCollection(newValue: string, reference: string): void;
@@ -82,6 +82,7 @@ const Form = (props: IProps): JSX.Element => {
82
82
  <FieldsBehavior
83
83
  title="Image"
84
84
  name="image"
85
+ fullWidth={true}
85
86
  fieldType="ImageField"
86
87
  value={itemImage || null}
87
88
  onChange={setImageValue}
@@ -114,8 +114,8 @@ interface IEditorStateProps {
114
114
  interface IPageBrowserDispatchProps {
115
115
  setSelectedContent(editorID: number): void;
116
116
  setSelectedTab(tab: string): void;
117
- deleteModule(editorID: number, key: string): void;
118
- duplicateModule(editorID: number, key: string): void;
117
+ deleteModule(editorID: number, key?: string): void;
118
+ duplicateModule(editorID: number, key?: string): Promise<number>;
119
119
  addComponent: (componentType: any, key: string) => void;
120
120
  addModule: (moduleType: string, selectedID: number, key: string) => void;
121
121
  moveElement(moduleID: number, selectedContent: any, newIndex: number, key: string): void;
@@ -21,6 +21,8 @@ const PageBrowser = (props: IProps) => {
21
21
  isReadOnly,
22
22
  isPreview,
23
23
  browserRef,
24
+ deleteModule,
25
+ duplicateModule,
24
26
  } = props;
25
27
 
26
28
  const slugWithSlash = slug ? (slug.startsWith("/") ? slug : `/${slug}`) : "";
@@ -28,6 +30,12 @@ const PageBrowser = (props: IProps) => {
28
30
  const url = `${pathWithoutSlash}${slugWithSlash}`;
29
31
  const disabled = isTemplateActivated === false || isReadOnly;
30
32
 
33
+ const actions = {
34
+ deleteModuleAction: deleteModule,
35
+ duplicateModuleAction: duplicateModule,
36
+ setSelectedContentAction: setSelectedContent,
37
+ };
38
+
31
39
  return (
32
40
  <Browser
33
41
  isPage={true}
@@ -35,7 +43,6 @@ const PageBrowser = (props: IProps) => {
35
43
  header={header}
36
44
  footer={footer}
37
45
  socials={socials}
38
- setSelectedContent={setSelectedContent}
39
46
  url={url}
40
47
  theme={theme}
41
48
  cloudinaryName={cloudinaryName}
@@ -45,11 +52,12 @@ const PageBrowser = (props: IProps) => {
45
52
  isPreview={isPreview}
46
53
  showIframe={true}
47
54
  browserRef={browserRef}
55
+ actions={actions}
48
56
  />
49
57
  );
50
58
  };
51
59
 
52
- interface IEditorStateProps {
60
+ interface IPageBrowserStateProps {
53
61
  // TODO: Define content Type
54
62
  content: any;
55
63
  currentSiteInfo: any;
@@ -66,11 +74,13 @@ interface IPageBrowserDispatchProps {
66
74
  isReadOnly: boolean;
67
75
  isPreview?: boolean;
68
76
  browserRef?: any;
77
+ deleteModule(editorID: number): void;
78
+ duplicateModule(editorID: number): Promise<number>;
69
79
  }
70
80
 
71
- type IProps = IEditorStateProps & IPageBrowserDispatchProps;
81
+ type IProps = IPageBrowserStateProps & IPageBrowserDispatchProps;
72
82
 
73
- const mapStateToProps = (state: IRootState): IEditorStateProps => ({
83
+ const mapStateToProps = (state: IRootState): IPageBrowserStateProps => ({
74
84
  content: { ...state.pageEditor.editorContent },
75
85
  currentSiteInfo: state.sites.currentSiteInfo,
76
86
  socials: state.social,
@@ -82,6 +92,8 @@ const mapStateToProps = (state: IRootState): IEditorStateProps => ({
82
92
 
83
93
  const mapDispatchToProps = {
84
94
  setSelectedContent: pageEditorActions.setSelectedContent,
95
+ deleteModule: pageEditorActions.deleteModule,
96
+ duplicateModule: pageEditorActions.duplicateModule,
85
97
  };
86
98
 
87
99
  export default connect(mapStateToProps, mapDispatchToProps)(PageBrowser);
@@ -141,13 +141,14 @@ const PageEditor = (props: IProps) => {
141
141
  status: pageStatus.UPLOAD_PENDING,
142
142
  };
143
143
 
144
- pageID
145
- ? updatePageStatus([pageID], pageStatus.UPLOAD_PENDING)
146
- : savePage(false, publishPage).then((isSaved: boolean) => {
147
- if (isSaved) {
148
- resetDirty();
149
- }
150
- });
144
+ const handleSavePage = async () => {
145
+ const isSaved = await savePage(false, publishPage);
146
+ if (isSaved) {
147
+ resetDirty();
148
+ }
149
+ };
150
+
151
+ pageID ? updatePageStatus([pageID], pageStatus.UPLOAD_PENDING) : await handleSavePage();
151
152
  } else {
152
153
  setNotification({ text: errorNotificationText, type: "error" });
153
154
  }
@@ -19,8 +19,9 @@ const Field = (props: IField): JSX.Element => {
19
19
  theme,
20
20
  } = props;
21
21
  const { isOpen, toggleModal } = useModal();
22
- const options = defaults.filter((component: any) =>
23
- component.type === type && content[component.type]?.id !== component.id && !component.setAsDefault
22
+ const options = defaults.filter(
23
+ (component: any) =>
24
+ component.type === type && content[component.type]?.id !== component.id && !component.setAsDefault
24
25
  );
25
26
  const optionsType = `${type}s`;
26
27
 
@@ -43,9 +44,9 @@ const Field = (props: IField): JSX.Element => {
43
44
  ...(!!dataPackConfigFormData.templates && dataPackConfigFormData.templates[template]),
44
45
  ...(type === "header" && { defaultHeader: option.id }),
45
46
  ...(type === "footer" && { defaultFooter: option.id }),
46
- }
47
+ },
47
48
  },
48
- }
49
+ };
49
50
  updateDataPackFormValue(configFormData);
50
51
  updateEditorContent(pageEditorID, type, option.id);
51
52
  toggleModal();
@@ -53,18 +54,18 @@ const Field = (props: IField): JSX.Element => {
53
54
 
54
55
  const isDefaultNavigation = () => {
55
56
  const defaultType = type === "header" ? "defaultHeader" : "defaultFooter";
56
- const templateNavigation = dataPackConfigFormData.templates && dataPackConfigFormData.templates[template]
57
+ const templateNavigation = dataPackConfigFormData.templates && dataPackConfigFormData.templates[template];
57
58
  const templateDefaultNavigation = templateNavigation && templateNavigation[defaultType];
58
59
  if (!templateDefaultNavigation) return true;
59
60
  const siteDefaultNavigation = defaults.find((navigation: any) => navigation.id === templateDefaultNavigation);
60
61
  return !!siteDefaultNavigation?.isDefault;
61
- }
62
+ };
62
63
 
63
64
  const setDefault = {
64
65
  title: `Put the default ${type}`,
65
66
  action: () => handleReplace({ id: null }),
66
67
  checked: isDefaultNavigation(),
67
- }
68
+ };
68
69
 
69
70
  const hasOptions: boolean | undefined = options?.length > 0 || !isDefaultNavigation();
70
71
 
@@ -90,18 +91,18 @@ const Field = (props: IField): JSX.Element => {
90
91
  />
91
92
  )}
92
93
  </>
93
- )
94
- }
94
+ );
95
+ };
95
96
 
96
97
  interface IField {
97
98
  type: string;
98
99
  template: string;
99
100
  defaults: any;
100
- content: any,
101
+ content: any;
101
102
  dataPackConfigFormData: any;
102
103
  theme: string;
103
104
  updateEditorContent: (selectedEditorID: number, key: string, value: any) => void;
104
105
  updateDataPackFormValue: (value: any) => void;
105
106
  }
106
107
 
107
- export { Field }
108
+ export { Field };
@@ -1,4 +1,4 @@
1
- import React, { useEffect } from "react";
1
+ import React from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
4
  import { IRootState } from "@ax/types";
@@ -12,15 +12,7 @@ import Editor from "./Editor";
12
12
  import * as S from "./style";
13
13
 
14
14
  const TemplateEditor = (props: IProps) => {
15
- const {
16
- isLoading,
17
- isSaving,
18
- editorContent,
19
- setHistoryPush,
20
- template,
21
- updateDataPack,
22
- dataPackSelected,
23
- } = props;
15
+ const { isLoading, isSaving, editorContent, setHistoryPush, template, updateDataPack, dataPackSelected } = props;
24
16
 
25
17
  const { isDirty, setIsDirty } = useIsDirty(editorContent);
26
18
 
@@ -46,13 +38,7 @@ const TemplateEditor = (props: IProps) => {
46
38
  ) : (
47
39
  <>
48
40
  <RouteLeavingGuard when={isDirty} action={goBack} text={leavingGuardText} />
49
- <MainWrapper
50
- title={template}
51
- backLink={true}
52
- rightButton={rightButtonProps}
53
- fixedAppBar={true}
54
- fullWidth={true}
55
- >
41
+ <MainWrapper title={template} backLink={true} rightButton={rightButtonProps} fixedAppBar={true} fullWidth={true}>
56
42
  <ErrorToast size="l" />
57
43
  <S.Content>
58
44
  <Editor />