@griddo/ax 10.7.7 → 10.7.9

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 (26) hide show
  1. package/package.json +2 -2
  2. package/src/__tests__/components/TableFilters/LiveFilter/LiveFilter.test.tsx +0 -6
  3. package/src/components/BrowserContent/index.tsx +1 -1
  4. package/src/components/Fields/ReferenceField/AutoPanel/index.tsx +2 -1
  5. package/src/components/Fields/ReferenceField/Context/index.tsx +2 -0
  6. package/src/components/Fields/ReferenceField/ItemList/index.tsx +2 -1
  7. package/src/components/Fields/ReferenceField/ManualPanel/index.tsx +2 -2
  8. package/src/components/Fields/ReferenceField/index.tsx +5 -1
  9. package/src/components/Fields/Wysiwyg/index.tsx +11 -4
  10. package/src/components/MainWrapper/AppBar/index.tsx +2 -0
  11. package/src/components/TableFilters/LiveFilter/index.tsx +3 -4
  12. package/src/containers/Navigation/Menu/actions.tsx +13 -6
  13. package/src/containers/Navigation/Menu/constants.tsx +1 -0
  14. package/src/containers/Navigation/Menu/interfaces.tsx +6 -0
  15. package/src/containers/Navigation/Menu/reducer.tsx +4 -0
  16. package/src/forms/editor.tsx +1 -1
  17. package/src/helpers/schemas.tsx +4 -4
  18. package/src/modules/Content/BulkHeader/TableHeader/index.tsx +5 -1
  19. package/src/modules/FramePreview/index.tsx +6 -2
  20. package/src/modules/Navigation/Menus/List/Nav/index.tsx +10 -2
  21. package/src/modules/Navigation/Menus/List/index.tsx +14 -13
  22. package/src/modules/Navigation/Menus/index.tsx +15 -6
  23. package/src/modules/Sites/SitesList/ListView/BulkHeader/TableHeader/index.tsx +1 -1
  24. package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +5 -1
  25. package/src/types/index.tsx +1 -0
  26. /package/src/modules/Navigation/Menus/{List/helpers.tsx → helpers.tsx} +0 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@griddo/ax",
3
3
  "description": "Griddo Author Experience",
4
- "version": "10.7.7",
4
+ "version": "10.7.9",
5
5
  "authors": [
6
6
  "Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
7
7
  "Carlos Torres <carlos.torres@secuoyas.com>",
@@ -229,5 +229,5 @@
229
229
  "publishConfig": {
230
230
  "access": "public"
231
231
  },
232
- "gitHead": "c14eebd4f92f3bb6730b17a304b3f01091a21703"
232
+ "gitHead": "406e9f612d8587a5b08436e7e822bcc8782e0094"
233
233
  }
@@ -17,7 +17,6 @@ const defaultProps = mock<ILiveFilterProps>();
17
17
 
18
18
  describe("LiveFilter component rendering", () => {
19
19
  it("should render live filter", async () => {
20
- defaultProps.hasBasicStatus = false;
21
20
  defaultProps.value = [{ value: "all", label: "All" }];
22
21
  const filterItems = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
23
22
 
@@ -53,7 +52,6 @@ describe("LiveFilter component rendering", () => {
53
52
  });
54
53
 
55
54
  it("should render the component with no options", async () => {
56
- defaultProps.hasBasicStatus = false;
57
55
  defaultProps.value = [{ value: "all", label: "All" }];
58
56
  const filterItems = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
59
57
 
@@ -91,7 +89,6 @@ describe("LiveFilter component rendering", () => {
91
89
 
92
90
  describe("LiveFilter events", () => {
93
91
  it("should render check group on click", async () => {
94
- defaultProps.hasBasicStatus = false;
95
92
  defaultProps.value = [{ value: "all", label: "All" }];
96
93
  const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
97
94
 
@@ -132,7 +129,6 @@ describe("LiveFilter events", () => {
132
129
  });
133
130
 
134
131
  it("should check option on click", async () => {
135
- defaultProps.hasBasicStatus = false;
136
132
  defaultProps.value = [{ value: "all", label: "All" }];
137
133
  const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
138
134
 
@@ -176,7 +172,6 @@ describe("LiveFilter events", () => {
176
172
  });
177
173
 
178
174
  it("should uncheck selected option on click and select 'All' option", async () => {
179
- defaultProps.hasBasicStatus = false;
180
175
  defaultProps.value = [{ value: "all", label: "All" }];
181
176
  const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
182
177
 
@@ -225,7 +220,6 @@ describe("LiveFilter events", () => {
225
220
  });
226
221
 
227
222
  it("should call filterItems action on change", async () => {
228
- defaultProps.hasBasicStatus = false;
229
223
  defaultProps.value = [{ value: "all", label: "All" }];
230
224
  const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
231
225
 
@@ -82,7 +82,7 @@ interface IProps {
82
82
  parentComponent: string | undefined | null,
83
83
  e: React.SyntheticEvent
84
84
  ): void;
85
- selectHoverEditorID?(editorID: number): void;
85
+ selectHoverEditorID?(editorID: number, parentEditorID: number): void;
86
86
  moduleActions?: {
87
87
  deleteModuleAction(editorID: number): void;
88
88
  duplicateModuleAction(editorID: number): void;
@@ -158,6 +158,7 @@ const AutoPanel = (props: IProps): JSX.Element => {
158
158
  preferenceLanguage: state.preferenceLanguage,
159
159
  lang: state.lang,
160
160
  site: state.site,
161
+ fields: state.fields,
161
162
  };
162
163
 
163
164
  onChange(newValue);
@@ -353,7 +354,7 @@ const AutoPanel = (props: IProps): JSX.Element => {
353
354
  <S.ConfigWrapper>
354
355
  <S.SubConfigContent hasMargin={true}>
355
356
  <S.OptionDescription isOpen={configState.isCustomLangOpen}>
356
- By default, content is shown in the page's language. Activate this option to{" "}
357
+ By default, content is shown in the page&apos;s language. Activate this option to{" "}
357
358
  <strong>specifically set a different language</strong> for the content shown in this
358
359
  distributor.
359
360
  </S.OptionDescription>
@@ -96,6 +96,7 @@ export interface IReferenceState {
96
96
  preferenceLanguage: boolean;
97
97
  lang?: number;
98
98
  site?: number;
99
+ fields?: string[];
99
100
  }
100
101
 
101
102
  export interface IRefField {
@@ -109,6 +110,7 @@ export interface IRefField {
109
110
  preferenceLanguage?: boolean;
110
111
  lang?: number;
111
112
  site?: number;
113
+ fields?: string[];
112
114
  }
113
115
 
114
116
  export interface IFilter {
@@ -14,7 +14,7 @@ const ItemList = (props: IProps) => {
14
14
  const { items, currentSite, handleListDelete, handleListMove, site } = props;
15
15
 
16
16
  const { state, setState, setReorderElements } = useReference();
17
- const { fixed, selectedItems, sourceTitles, fullRelations } = state;
17
+ const { fixed, selectedItems, sourceTitles, fullRelations, fields } = state;
18
18
 
19
19
  const getParams = useCallback(() => {
20
20
  const params = {
@@ -22,6 +22,7 @@ const ItemList = (props: IProps) => {
22
22
  fixed: items,
23
23
  fullRelations,
24
24
  site,
25
+ fields,
25
26
  };
26
27
 
27
28
  return params;
@@ -94,8 +94,8 @@ const ManualPanel = (props: IProps) => {
94
94
  setState((state: IReferenceState) => ({ ...state, showSelected: !state.showSelected }));
95
95
 
96
96
  const handleAdd = () => {
97
- const { mode, fixed, fullRelations, site, lang } = state;
98
- const newValue = { mode, fixed, fullRelations, site, lang };
97
+ const { mode, fixed, fullRelations, site, lang, fields } = state;
98
+ const newValue = { mode, fixed, fullRelations, site, lang, fields };
99
99
  onChange(newValue);
100
100
  handleValidation && handleValidation(state.fixed, validators);
101
101
  };
@@ -45,7 +45,7 @@ const ReferenceField = (props: IReferenceFieldProps) => {
45
45
  const isAuto = mode === "auto";
46
46
  const hasMaxItems = !!(value && value.fixed && maxItems && !isAuto && value.fixed.length >= maxItems);
47
47
  const sourcesIDs = sources.map((source: ISource) => source.structuredData);
48
- const { fixed, order, quantity, allLanguages, preferenceLanguage, fullRelations = false } = state;
48
+ const { fixed, order, quantity, allLanguages, preferenceLanguage, fullRelations = false, fields } = state;
49
49
 
50
50
  const handleMode = (mode: string) => {
51
51
  const manualSources: string[] = state.selectedItems.reduce(
@@ -69,12 +69,14 @@ const ReferenceField = (props: IReferenceFieldProps) => {
69
69
  fullRelations,
70
70
  allLanguages,
71
71
  preferenceLanguage,
72
+ fields,
72
73
  }
73
74
  : {
74
75
  mode,
75
76
  sources,
76
77
  fixed,
77
78
  fullRelations,
79
+ fields,
78
80
  };
79
81
  onChange(newValue);
80
82
  setModeAndSource(mode, mappedSources);
@@ -134,6 +136,7 @@ const ReferenceField = (props: IReferenceFieldProps) => {
134
136
  mode,
135
137
  fixed,
136
138
  fullRelations,
139
+ fields,
137
140
  };
138
141
  onChange(newValue);
139
142
  resetValidation && resetValidation();
@@ -144,6 +147,7 @@ const ReferenceField = (props: IReferenceFieldProps) => {
144
147
  mode,
145
148
  fixed,
146
149
  fullRelations,
150
+ fields,
147
151
  };
148
152
  onChange(newValue);
149
153
  };
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import { connect } from "react-redux";
3
- import FroalaEditor from "react-froala-wysiwyg";
3
+ import FroalaEditorComponent from "react-froala-wysiwyg";
4
4
  import { decodeEntities } from "@ax/helpers";
5
5
  import { IImage, ISite, IRootState } from "@ax/types";
6
6
  import { galleryActions } from "@ax/containers/Gallery";
@@ -40,6 +40,7 @@ const Wysiwyg = (props: IWysiwygProps): JSX.Element => {
40
40
  },
41
41
  events: {
42
42
  initialized() {
43
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
43
44
  const editor: any = this;
44
45
  if (disabled) {
45
46
  setTimeout(() => {
@@ -48,12 +49,18 @@ const Wysiwyg = (props: IWysiwygProps): JSX.Element => {
48
49
  }
49
50
  },
50
51
  "image.beforeUpload": async function (images: FileList) {
52
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
51
53
  const editor: any = this;
52
- const { url } = await uploadImage(images[0], imageSite);
53
- editor.image.insert(url, true, null, editor.image.get(), null);
54
+ const response = await uploadImage(images[0], imageSite);
55
+ if (response) {
56
+ editor.image.insert(response.url, null, null, editor.image.get());
57
+ } else {
58
+ editor.image.remove(editor.image.get());
59
+ }
54
60
  return false;
55
61
  },
56
62
  blur: function () {
63
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
57
64
  const editor: any = this;
58
65
  const html = editor.html.get();
59
66
  const stripedHtml = decodeEntities(html);
@@ -66,7 +73,7 @@ const Wysiwyg = (props: IWysiwygProps): JSX.Element => {
66
73
 
67
74
  return (
68
75
  <S.EditorWrapper error={error} disabled={disabled} data-testid="wysiwyg-wrapper">
69
- <FroalaEditor tag="textarea" model={value} config={config} onModelChange={handleChange} />
76
+ <FroalaEditorComponent tag="textarea" model={value} config={config} onModelChange={handleChange} />
70
77
  </S.EditorWrapper>
71
78
  );
72
79
  };
@@ -82,6 +82,8 @@ const AppBar = (props: IProps): JSX.Element => {
82
82
  setLangSelected(item);
83
83
  toggleModal();
84
84
  return;
85
+ } else {
86
+ isOpen && toggleModal();
85
87
  }
86
88
  if (!languageActions || !languageActions.setLanguage) return;
87
89
 
@@ -8,7 +8,7 @@ import { IFilterValue, IPageLiveStatus, IQueryValue } from "@ax/types";
8
8
  import * as S from "./style";
9
9
 
10
10
  const LiveFilter = (props: ILiveFilterProps): JSX.Element => {
11
- const { filterItems, value, hasBasicStatus } = props;
11
+ const { filterItems, value, statusOptions } = props;
12
12
 
13
13
  const filters: IFilterValue[] = [
14
14
  {
@@ -24,7 +24,6 @@ const LiveFilter = (props: ILiveFilterProps): JSX.Element => {
24
24
  const parsedValue = Array.isArray(value) && value.length ? value.map((value) => value.value) : initialState;
25
25
  const [selectedValue, setSelectedValue] = useState(parsedValue);
26
26
  const [options, setOptions] = useState(filters);
27
- const basicStatus = ["offline", "active", "scheduled"];
28
27
 
29
28
  useEffect(() => {
30
29
  const parsedValue = Array.isArray(value) && value.length ? value.map((value) => value.value) : initialState;
@@ -55,7 +54,7 @@ const LiveFilter = (props: ILiveFilterProps): JSX.Element => {
55
54
  title: item.title,
56
55
  icon: item.status,
57
56
  };
58
- if ((hasBasicStatus && basicStatus.includes(newFilter.value)) || !hasBasicStatus) {
57
+ if ((Array.isArray(statusOptions) && statusOptions.includes(newFilter.value)) || !statusOptions) {
59
58
  filters.push(newFilter);
60
59
  }
61
60
  });
@@ -112,7 +111,7 @@ const LiveFilter = (props: ILiveFilterProps): JSX.Element => {
112
111
  export interface ILiveFilterProps {
113
112
  filterItems(pointer: string, filter: IQueryValue[]): void;
114
113
  value: IQueryValue[];
115
- hasBasicStatus?: boolean;
114
+ statusOptions?: string[];
116
115
  isSite?: boolean;
117
116
  }
118
117
 
@@ -13,6 +13,7 @@ import {
13
13
  SET_MENU_FORM_DATA,
14
14
  SET_ORIGINAL_MENU,
15
15
  SET_TOTAL_ITEMS,
16
+ SET_CURRENT_MENU,
16
17
  } from "./constants";
17
18
  import {
18
19
  ISetSavedMenus,
@@ -22,6 +23,7 @@ import {
22
23
  ISetMenuForm,
23
24
  ISetSavedMenu,
24
25
  ISetTotalItems,
26
+ ISetCurrentMenu,
25
27
  } from "./interfaces";
26
28
  import { menuInitialState } from "./reducer";
27
29
 
@@ -70,8 +72,12 @@ function setTotalItems(totalItems: number): ISetTotalItems {
70
72
  return { type: SET_TOTAL_ITEMS, payload: { totalItems } };
71
73
  }
72
74
 
75
+ function setCurrentMenu(currentMenu: string): ISetCurrentMenu {
76
+ return { type: SET_CURRENT_MENU, payload: { currentMenu } };
77
+ }
78
+
73
79
  const getStateValues = (getState: any) => {
74
- const { savedMenus, savedMenu, editorMenu, id, type } = getState().menu;
80
+ const { savedMenus, savedMenu, editorMenu, id, currentMenu } = getState().menu;
75
81
  const { currentSiteInfo } = getState().sites;
76
82
  const { isSaving, isLoading, lang } = getState().app;
77
83
 
@@ -80,7 +86,7 @@ const getStateValues = (getState: any) => {
80
86
  savedMenu,
81
87
  editorMenu,
82
88
  id,
83
- type,
89
+ currentMenu,
84
90
  currentSiteInfo,
85
91
  isLoading,
86
92
  isSaving,
@@ -102,13 +108,13 @@ function setEditorMenuContent(menus: IMenu[], menuType: string, dispatch: Dispat
102
108
  function getMenus(): (dispatch: Dispatch, getState: any) => Promise<void> {
103
109
  return async (dispatch, getState) => {
104
110
  try {
105
- const { currentSiteInfo, type } = getStateValues(getState);
111
+ const { currentSiteInfo, currentMenu } = getStateValues(getState);
106
112
  const id = currentSiteInfo && currentSiteInfo.id;
107
113
 
108
114
  const responseActions = {
109
115
  handleSuccess: (menus: IMenu[]) => {
110
116
  dispatch(setSavedMenus(menus));
111
- setEditorMenuContent(menus, type, dispatch);
117
+ setEditorMenuContent(menus, currentMenu, dispatch);
112
118
  updateTotalItems(dispatch, getState);
113
119
  },
114
120
  handleError: () => console.log("Error en getMenus"),
@@ -228,7 +234,7 @@ function deleteMenuItem(
228
234
  function updateMenu(): (dispatch: Dispatch, getState: any) => Promise<void> {
229
235
  return async (dispatch, getState) => {
230
236
  try {
231
- const { savedMenu, editorMenu, type, id, currentSiteInfo } = getStateValues(getState);
237
+ const { savedMenu, editorMenu, currentMenu, id, currentSiteInfo } = getStateValues(getState);
232
238
  const editorMenuClean = removeMenuEditorIds(editorMenu.elements);
233
239
  savedMenu.elements = editorMenuClean;
234
240
 
@@ -238,7 +244,7 @@ function updateMenu(): (dispatch: Dispatch, getState: any) => Promise<void> {
238
244
  const updatedMenusResponse = await menus.getMenus(currentSiteId);
239
245
  const updatedMenus = updatedMenusResponse.data;
240
246
  dispatch(setSavedMenus(updatedMenus));
241
- setEditorMenuContent(updatedMenus, type, dispatch);
247
+ setEditorMenuContent(updatedMenus, currentMenu, dispatch);
242
248
  },
243
249
  handleError: () => console.log("Error en updateMenu"),
244
250
  };
@@ -328,4 +334,5 @@ export {
328
334
  resetMenuValues,
329
335
  reorderMenu,
330
336
  updateFormValue,
337
+ setCurrentMenu,
331
338
  };
@@ -7,3 +7,4 @@ export const SET_ID: string = `${NAME}/SET_ID`;
7
7
  export const SET_ITEM: string = `${NAME}/SET_ITEM`;
8
8
  export const SET_MENU_FORM_DATA: string = `${NAME}/SET_MENU_FORM_DATA`;
9
9
  export const SET_TOTAL_ITEMS: string = `${NAME}/SET_TOTAL_ITEMS`;
10
+ export const SET_CURRENT_MENU: string = `${NAME}/SET_CURRENT_MENU`;
@@ -6,6 +6,7 @@ import {
6
6
  SET_ID,
7
7
  SET_ITEM,
8
8
  SET_MENU_FORM_DATA,
9
+ SET_CURRENT_MENU,
9
10
  } from "./constants";
10
11
 
11
12
  export interface ISetSavedMenus {
@@ -43,4 +44,9 @@ export interface ISetTotalItems {
43
44
  payload: { totalItems: number };
44
45
  }
45
46
 
47
+ export interface ISetCurrentMenu {
48
+ type: typeof SET_CURRENT_MENU;
49
+ payload: { currentMenu: string };
50
+ }
51
+
46
52
  export type MenuActionsCreators = ISetSavedMenus & ISetEditorMenu & ISetItem & ISetTotalItems;
@@ -6,6 +6,7 @@ import {
6
6
  SET_ITEM,
7
7
  SET_MENU_FORM_DATA,
8
8
  SET_TOTAL_ITEMS,
9
+ SET_CURRENT_MENU,
9
10
  } from "./constants";
10
11
 
11
12
  import { MenuActionsCreators } from "./interfaces";
@@ -19,6 +20,7 @@ export interface IMenuState {
19
20
  item: IMenuItem | null;
20
21
  form: IMenuForm;
21
22
  totalItems: number;
23
+ currentMenu: string;
22
24
  }
23
25
 
24
26
  const initialState = {
@@ -37,6 +39,7 @@ const initialState = {
37
39
  footerStyle: "",
38
40
  },
39
41
  totalItems: 0,
42
+ currentMenu: "",
40
43
  };
41
44
 
42
45
  function reducer(state = initialState, action: MenuActionsCreators): IMenuState {
@@ -48,6 +51,7 @@ function reducer(state = initialState, action: MenuActionsCreators): IMenuState
48
51
  case SET_ITEM:
49
52
  case SET_MENU_FORM_DATA:
50
53
  case SET_TOTAL_ITEMS:
54
+ case SET_CURRENT_MENU:
51
55
  return { ...state, ...action.payload };
52
56
  default:
53
57
  return state;
@@ -203,7 +203,7 @@ const evalueComputedFields = (page: any) => {
203
203
  const updatedPage = deepClone(page);
204
204
  const pageSchemaContent = getTemplate(page.template.templateType).content;
205
205
  pageSchemaContent.forEach((field: any) => {
206
- if (field.hasOwnProperty("computed")) {
206
+ if (Object.prototype.hasOwnProperty.call(field, "computed")) {
207
207
  updatedPage.template[field.key] = field.computed(page);
208
208
  }
209
209
  });
@@ -1,6 +1,6 @@
1
1
  import { schemas, moduleCategories } from "components";
2
2
  import { sortBy } from "@ax/helpers";
3
- import { ModuleCategoryInfo } from "@ax/types";
3
+ import { ISchema, ModuleCategoryInfo } from "@ax/types";
4
4
  import { pageSchemas } from "@ax/schemas";
5
5
 
6
6
  const allSchemas = { ...schemas.all, ...pageSchemas };
@@ -54,9 +54,9 @@ const getTemplateThumbnails = (name: string, theme?: string) => {
54
54
 
55
55
  const getDataPackSchema = (name: string) => schemas.dataPacks[name];
56
56
 
57
- const getDisplayName = (component: string) => {
58
- const schema = getSchema(component);
59
- return schema?.displayName;
57
+ const getDisplayName = (component: string): string => {
58
+ const schema: ISchema = getSchema(component);
59
+ return schema?.displayName || "";
60
60
  };
61
61
 
62
62
  const getSchemaType = (component: string) => {
@@ -76,7 +76,11 @@ const TableHeader = (props: IProps): JSX.Element => {
76
76
  </S.NameWrapper>
77
77
  {activeColumns.includes("live") && (
78
78
  <S.HeaderWrapper>
79
- <LiveFilter filterItems={filterItems} value={filterValues.liveStatus} hasBasicStatus={true} />
79
+ <LiveFilter
80
+ filterItems={filterItems}
81
+ value={filterValues.liveStatus}
82
+ statusOptions={["offline", "active", "scheduled"]}
83
+ />
80
84
  </S.HeaderWrapper>
81
85
  )}
82
86
  {CategoryColumns}
@@ -52,8 +52,12 @@ const FramePreview = (props: IProps) => {
52
52
  }
53
53
  };
54
54
 
55
- const selectHoverEditorID = (editorID: number) =>
56
- window.parent.postMessage({ type: "module-scroll", message: editorID }, "*");
55
+ const selectHoverEditorID = (editorID: number, parentEditorID: number) => {
56
+ const { parent } = findByEditorID(content, parentEditorID);
57
+ if (parent.parentEditorID === 0) {
58
+ window.parent.postMessage({ type: "module-scroll", message: editorID }, "*");
59
+ }
60
+ };
57
61
 
58
62
  const globalTheme = getDefaultTheme();
59
63
  const theme = currentSiteInfo ? currentSiteInfo.theme : globalTheme;
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { useState } from "react";
2
2
  import { connect } from "react-redux";
3
3
  import { NavLink } from "react-router-dom";
4
4
 
@@ -12,19 +12,27 @@ import * as S from "./style";
12
12
  const Nav = (props: INav): JSX.Element => {
13
13
  const { getCurrentMenu, currentType, setCurrentType, isDirty, currentMenus } = props;
14
14
  const { isOpen, toggleModal } = useModal();
15
+ const [oldType, setOldType] = useState(currentType);
15
16
 
16
17
  const discardChanges = () => {
18
+ setOldType(currentType);
17
19
  getCurrentMenu(currentType);
18
20
  toggleModal();
19
21
  };
20
22
 
23
+ const handleClose = () => {
24
+ setCurrentType(oldType);
25
+ toggleModal();
26
+ };
27
+
21
28
  return (
22
29
  <>
23
- <GuardModal isOpen={isOpen} discardChanges={discardChanges} toggleModal={toggleModal} />
30
+ <GuardModal isOpen={isOpen} discardChanges={discardChanges} toggleModal={handleClose} />
24
31
  <SubNav>
25
32
  {currentMenus &&
26
33
  currentMenus.map((category: any, index: number) => {
27
34
  const _handleClick = () => {
35
+ isDirty ? setOldType(currentType) : setOldType(category.name);
28
36
  setCurrentType(category.name);
29
37
  isDirty ? toggleModal() : getCurrentMenu(category.name);
30
38
  };
@@ -1,11 +1,10 @@
1
- import React, { useEffect, useCallback, memo, useState } from "react";
1
+ import React, { useEffect, useCallback, memo } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
4
  import { IGetSitePagesParams, IRootState, IMenuItem } from "@ax/types";
5
5
 
6
6
  import { sitesActions } from "@ax/containers/Sites";
7
7
  import { menuActions } from "@ax/containers/Navigation";
8
- import { useShouldBeSaved } from "./helpers";
9
8
  import { setIsSavedData } from "@ax/forms";
10
9
 
11
10
  import Nav from "./Nav";
@@ -13,16 +12,12 @@ import Table from "./Table";
13
12
  import * as S from "./style";
14
13
 
15
14
  const List = (props: IMenuList): JSX.Element => {
16
- const { getMenus, lang, getSitePages, currentSiteID, editorMenu, savedMenu, savedMenus } = props;
15
+ const { getMenus, lang, getSitePages, currentSiteID, savedMenus, currentMenu, setCurrentMenu, isDirty } = props;
17
16
 
18
17
  if (!currentSiteID) {
19
18
  throw new Error(`ERROR: User reached Menu List with null site info`);
20
19
  }
21
20
 
22
- const initialState = savedMenus && savedMenus.length ? savedMenus[0].name : "";
23
- const [currentType, setCurrentType] = useState(initialState);
24
-
25
- const { isDirty } = useShouldBeSaved(editorMenu, savedMenu, currentType);
26
21
  const memoizedGetMenus = useCallback(() => getMenus(), [getMenus]);
27
22
  const memoizedGetSitePages = useCallback(
28
23
  (params: IGetSitePagesParams) => {
@@ -31,6 +26,11 @@ const List = (props: IMenuList): JSX.Element => {
31
26
  [getSitePages]
32
27
  );
33
28
 
29
+ useEffect(() => {
30
+ const initialState = savedMenus && savedMenus.length ? savedMenus[0].name : "";
31
+ setCurrentMenu(initialState);
32
+ }, []);
33
+
34
34
  useEffect(() => {
35
35
  const params = {
36
36
  siteID: currentSiteID,
@@ -45,7 +45,7 @@ const List = (props: IMenuList): JSX.Element => {
45
45
 
46
46
  return (
47
47
  <S.ListWrapper>
48
- <Nav isDirty={isDirty} currentType={currentType} setCurrentType={setCurrentType} />
48
+ <Nav isDirty={isDirty} currentType={currentMenu} setCurrentType={setCurrentMenu} />
49
49
  <S.TableWrapper>
50
50
  <Table isDirty={isDirty} />
51
51
  </S.TableWrapper>
@@ -56,27 +56,28 @@ const List = (props: IMenuList): JSX.Element => {
56
56
  const mapStateToProps = (state: IRootState) => ({
57
57
  currentSiteID: state.sites.currentSiteInfo && state.sites.currentSiteInfo.id,
58
58
  lang: state.app.lang,
59
- editorMenu: state.menu.editorMenu.elements,
60
- savedMenu: state.menu.savedMenu.elements,
61
59
  savedMenus: state.menu.savedMenus,
60
+ currentMenu: state.menu.currentMenu,
62
61
  });
63
62
 
64
63
  const mapDispatchToProps = {
65
64
  getMenus: menuActions.getMenus,
66
65
  getSitePages: sitesActions.getSitePages,
66
+ setCurrentMenu: menuActions.setCurrentMenu,
67
67
  };
68
68
 
69
69
  interface IStateProps {
70
70
  currentSiteID: number | null;
71
71
  lang: { locale: string; id: number | null };
72
- editorMenu: IMenuItem[] | undefined;
73
- savedMenu: IMenuItem[] | undefined;
74
72
  savedMenus: IMenuItem[] | null;
73
+ currentMenu: string;
74
+ isDirty: boolean;
75
75
  }
76
76
 
77
77
  interface IDispatchProps {
78
78
  getMenus(): void;
79
- getSitePages(params: IGetSitePagesParams): any;
79
+ getSitePages(params: IGetSitePagesParams): Promise<void>;
80
+ setCurrentMenu(currentMenu: string): void;
80
81
  }
81
82
 
82
83
  type IMenuList = IStateProps & IDispatchProps;
@@ -3,16 +3,18 @@ import { connect } from "react-redux";
3
3
 
4
4
  import { menuActions } from "@ax/containers/Navigation";
5
5
  import { appActions } from "@ax/containers/App";
6
- import { IRootState } from "@ax/types";
6
+ import { ILanguage, IMenuItem, IRootState } from "@ax/types";
7
7
  import { setIsSavedData } from "@ax/forms";
8
8
  import { MainWrapper } from "@ax/components";
9
9
  import { usePermission } from "@ax/hooks";
10
10
 
11
+ import { useShouldBeSaved } from "./helpers";
11
12
  import List from "./List";
12
13
 
13
14
  const MenuView = (props: IMenus) => {
14
- const { updateMenu, setLanguage, isSaving, lang, siteLanguages } = props;
15
+ const { updateMenu, setLanguage, isSaving, lang, siteLanguages, editorMenu, savedMenu, currentMenu } = props;
15
16
 
17
+ const { isDirty } = useShouldBeSaved(editorMenu, savedMenu, currentMenu);
16
18
  const isAllowedToMangageMenus = usePermission("navigation.manageSiteMenu");
17
19
 
18
20
  const saveMenu = () => {
@@ -22,8 +24,8 @@ const MenuView = (props: IMenus) => {
22
24
 
23
25
  const rightButtonProps = isAllowedToMangageMenus
24
26
  ? {
25
- label: isSaving ? "Saving" : "Save",
26
- disabled: isSaving,
27
+ label: isSaving ? "Saving" : isDirty ? "Save" : "Saved",
28
+ disabled: isSaving || !isDirty,
27
29
  action: saveMenu,
28
30
  }
29
31
  : undefined;
@@ -39,8 +41,9 @@ const MenuView = (props: IMenus) => {
39
41
  language={lang}
40
42
  availableLanguages={siteLanguages}
41
43
  languageActions={languageActions}
44
+ isDirty={isDirty}
42
45
  >
43
- <List />
46
+ <List isDirty={isDirty} />
44
47
  </MainWrapper>
45
48
  );
46
49
  };
@@ -49,6 +52,9 @@ const mapStateToProps = (state: IRootState) => ({
49
52
  isSaving: state.app.isSaving,
50
53
  lang: state.app.lang,
51
54
  siteLanguages: state.sites.currentSiteLanguages,
55
+ editorMenu: state.menu.editorMenu.elements,
56
+ savedMenu: state.menu.savedMenu.elements,
57
+ currentMenu: state.menu.currentMenu,
52
58
  });
53
59
 
54
60
  const mapDispatchToProps = {
@@ -59,7 +65,10 @@ const mapDispatchToProps = {
59
65
  interface IStateProps {
60
66
  isSaving: boolean;
61
67
  lang: { locale: string; id: number | null };
62
- siteLanguages: any[];
68
+ siteLanguages: ILanguage[];
69
+ editorMenu: IMenuItem[] | undefined;
70
+ savedMenu: IMenuItem[] | undefined;
71
+ currentMenu: string;
63
72
  }
64
73
 
65
74
  interface IDispatchProps {
@@ -49,7 +49,7 @@ const TableHeader = (props: IProps): JSX.Element => {
49
49
  </S.NameWrapper>
50
50
  <S.DomainHeader>Domain</S.DomainHeader>
51
51
  <S.LiveHeader>
52
- <LiveFilter filterItems={filterItems} value={liveFilterValue} hasBasicStatus={true} />
52
+ <LiveFilter filterItems={filterItems} value={liveFilterValue} statusOptions={["offline", "active"]} />
53
53
  </S.LiveHeader>
54
54
  <S.LastAccessCell>
55
55
  <LastAccessFilter sortItems={sortItems} sortedState={sortedListStatus} />
@@ -107,7 +107,11 @@ const TableHeader = (props: IProps): JSX.Element => {
107
107
  </S.NameWrapper>
108
108
  {activeColumns.includes("live") && (
109
109
  <S.HeaderWrapper>
110
- <LiveFilter filterItems={filterItems} value={filterValues.liveStatus} hasBasicStatus={true} />
110
+ <LiveFilter
111
+ filterItems={filterItems}
112
+ value={filterValues.liveStatus}
113
+ statusOptions={["offline", "active", "scheduled"]}
114
+ />
111
115
  </S.HeaderWrapper>
112
116
  )}
113
117
  {CategoryColumns}
@@ -160,6 +160,7 @@ export interface ISchema {
160
160
  type?: string;
161
161
  configTabs: ISchemaTab[];
162
162
  schemaType: string;
163
+ displayName: string;
163
164
  }
164
165
 
165
166
  export interface ISchemaTab {