@griddo/ax 1.64.10 → 1.65.2

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 (35) hide show
  1. package/package.json +2 -2
  2. package/src/components/CategoryCell/style.tsx +3 -2
  3. package/src/components/Fields/FieldGroup/index.test.tsx +61 -0
  4. package/src/components/Fields/FieldGroup/index.tsx +7 -5
  5. package/src/components/Fields/ImageField/index.tsx +7 -2
  6. package/src/components/FloatingPanel/index.tsx +12 -2
  7. package/src/components/Modal/style.tsx +3 -3
  8. package/src/components/SideModal/index.tsx +6 -1
  9. package/src/components/SideModal/style.tsx +7 -2
  10. package/src/components/TableFilters/CategoryFilter/index.tsx +1 -1
  11. package/src/components/TableFilters/DateFilter/index.tsx +7 -4
  12. package/src/components/TableFilters/LiveFilter/index.tsx +1 -1
  13. package/src/components/TableFilters/NameFilter/index.tsx +7 -4
  14. package/src/components/TableFilters/SiteFilter/index.tsx +1 -1
  15. package/src/components/TableFilters/StatusFilter/index.tsx +7 -4
  16. package/src/components/TableFilters/TranslationsFilter/index.tsx +1 -1
  17. package/src/components/TableFilters/TypeFilter/index.tsx +2 -2
  18. package/src/containers/Navigation/Menu/reducer.tsx +2 -1
  19. package/src/containers/PageEditor/actions.tsx +9 -8
  20. package/src/containers/StructuredData/actions.tsx +4 -3
  21. package/src/forms/errors.tsx +1 -0
  22. package/src/forms/index.tsx +2 -2
  23. package/src/forms/validators.tsx +55 -41
  24. package/src/modules/Content/PageItem/index.tsx +2 -1
  25. package/src/modules/CreatePass/index.tsx +4 -2
  26. package/src/modules/GlobalEditor/index.tsx +48 -35
  27. package/src/modules/Navigation/Menus/List/Table/Item/index.tsx +1 -0
  28. package/src/modules/Navigation/Menus/List/Table/SidePanel/Form/index.tsx +16 -5
  29. package/src/modules/Navigation/Menus/List/Table/SidePanel/index.tsx +31 -22
  30. package/src/modules/Navigation/Menus/List/Table/SidePanel/style.tsx +18 -2
  31. package/src/modules/PageEditor/index.tsx +47 -34
  32. package/src/modules/Sites/SitesList/index.tsx +15 -6
  33. package/src/modules/StructuredData/Form/index.tsx +29 -21
  34. package/src/modules/StructuredData/StructuredDataList/utils.tsx +1 -1
  35. package/src/types/index.tsx +3 -1
@@ -399,7 +399,8 @@ const PageItem = (props: IPageItemProps): JSX.Element => {
399
399
  const CategoryColumns =
400
400
  isGlobal &&
401
401
  categoryColumns.map((col: any) => {
402
- const type = structuredDataContent[col.from];
402
+ const fromVal = col.from.includes(".") ? col.from.split(".")[1] : col.from;
403
+ const type = structuredDataContent && (structuredDataContent[fromVal] || structuredDataContent[col.from]);
403
404
  const categories = Array.isArray(type) && type.map((cat: any) => cat.label || cat.title);
404
405
  return (
405
406
  activeColumns.includes(col.key) && (
@@ -6,7 +6,7 @@ import { isReqOk } from "@ax/helpers";
6
6
  import { global } from "@ax/api";
7
7
  import { appActions } from "@ax/containers/App";
8
8
  import { usersActions } from "@ax/containers/Users";
9
- import { Button, FieldsBehavior } from "@ax/components";
9
+ import { Button, FieldsBehavior, ErrorToast } from "@ax/components";
10
10
 
11
11
  import * as S from "./style";
12
12
 
@@ -55,7 +55,7 @@ const CreatePass = (props: IProps) => {
55
55
  <S.Subtitle>Welcome to Griddo</S.Subtitle>
56
56
  <S.Title>Create your password</S.Title>
57
57
  </S.Header>
58
-
58
+ <ErrorToast />
59
59
  <S.Form onSubmit={handleSubmit}>
60
60
  <FieldsBehavior
61
61
  fieldType="TextField"
@@ -64,6 +64,7 @@ const CreatePass = (props: IProps) => {
64
64
  mandatory={true}
65
65
  value={state.pass1}
66
66
  onChange={handlePass1Change}
67
+ validators={{ mandatory: true }}
67
68
  />
68
69
  <FieldsBehavior
69
70
  fieldType="TextField"
@@ -72,6 +73,7 @@ const CreatePass = (props: IProps) => {
72
73
  mandatory={true}
73
74
  value={state.pass2}
74
75
  onChange={handlePass2Change}
76
+ validators={{ isSamePass: state.pass1, mandatory: true }}
75
77
  />
76
78
  <Button type="submit" disabled={!validPasswords}>
77
79
  Create and log in
@@ -103,7 +103,7 @@ const GlobalEditor = (props: IProps) => {
103
103
  const { deletePage } = props;
104
104
  const path = "/sites/pages";
105
105
 
106
- await deletePage().then((deleted: boolean) => {
106
+ deletePage().then((deleted: boolean) => {
107
107
  if (deleted) {
108
108
  setRoute(path);
109
109
  }
@@ -111,68 +111,81 @@ const GlobalEditor = (props: IProps) => {
111
111
  };
112
112
 
113
113
  const publishPage = async () => {
114
- const { updatePageStatus, savePage, pageID } = props;
114
+ const { updatePageStatus, savePage, pageID, validatePage } = props;
115
115
 
116
- const publishPage = {
117
- status: pageStatus.UPLOAD_PENDING,
118
- };
116
+ const validated = await validatePage(true);
119
117
 
120
- pageID
121
- ? await updatePageStatus([pageID], pageStatus.UPLOAD_PENDING)
122
- : await savePage(false, publishPage).then((isSaved: boolean) => {
123
- if (isSaved) {
124
- resetDirty();
125
- }
126
- });
118
+ if (validated) {
119
+ const publishPage = {
120
+ status: pageStatus.UPLOAD_PENDING,
121
+ };
122
+
123
+ pageID
124
+ ? updatePageStatus([pageID], pageStatus.UPLOAD_PENDING)
125
+ : savePage(false, publishPage).then((isSaved: boolean) => {
126
+ if (isSaved) {
127
+ resetDirty();
128
+ }
129
+ });
130
+ }
127
131
  };
128
132
 
129
133
  const publishChanges = async () => {
130
- const { savePage } = props;
134
+ const { savePage, validatePage } = props;
131
135
 
132
- const publishPage = {
133
- status: pageStatus.UPLOAD_PENDING,
134
- };
136
+ const validated = await validatePage(true);
135
137
 
136
- await savePage(false, publishPage).then((isSaved: boolean) => {
137
- if (isSaved) {
138
- resetDirty();
139
- }
140
- });
138
+ if (validated) {
139
+ const publishPage = {
140
+ status: pageStatus.UPLOAD_PENDING,
141
+ };
142
+
143
+ savePage(false, publishPage).then((isSaved: boolean) => {
144
+ if (isSaved) {
145
+ resetDirty();
146
+ }
147
+ });
148
+ }
141
149
  };
142
150
 
143
- const unpublishPage = async () => {
151
+ const unpublishPage = () => {
144
152
  const { updatePageStatus, pageID } = props;
145
153
 
146
- await updatePageStatus([pageID], pageStatus.OFFLINE_PENDING);
154
+ updatePageStatus([pageID], pageStatus.OFFLINE_PENDING);
147
155
  };
148
156
 
149
- const cancelPublishPage = async () => {
157
+ const cancelPublishPage = () => {
150
158
  const { updatePageStatus, pageID } = props;
151
159
 
152
- await updatePageStatus([pageID], pageStatus.OFFLINE);
160
+ updatePageStatus([pageID], pageStatus.OFFLINE);
153
161
  };
154
162
 
155
- const reviewPage = async () => {
163
+ const reviewPage = () => {
156
164
  const { validatePage } = props;
157
- await validatePage();
165
+ validatePage();
158
166
  };
159
167
 
160
168
  const handlePublishDraft = async () => {
161
- const { savePage } = props;
162
- const isSaved = await savePage(false, null, true);
163
- if (isSaved) resetDirty();
169
+ const { savePage, validatePage } = props;
170
+
171
+ const validated = await validatePage(true);
172
+
173
+ if (validated) {
174
+ const isSaved = await savePage(false, null, true);
175
+ if (isSaved) resetDirty();
176
+ }
164
177
  };
165
178
 
166
- const handleDiscardDraft = async () => {
179
+ const handleDiscardDraft = () => {
167
180
  const { discardDraft } = props;
168
181
  resetDirty();
169
- await discardDraft();
182
+ discardDraft();
170
183
  };
171
184
 
172
- const handleDiscarChanges = async () => {
185
+ const handleDiscarChanges = () => {
173
186
  const { getPage, pageID } = props;
174
187
  resetDirty();
175
- await getPage(pageID, true);
188
+ getPage(pageID, true);
176
189
  };
177
190
 
178
191
  const getPublishButton = (status: string) => {
@@ -536,7 +549,7 @@ interface IPageEditorDispatchProps {
536
549
  getPage(pageID?: number, global?: boolean): Promise<void>;
537
550
  savePage(createDraft: boolean, publishPage?: any, publishDraft?: boolean): Promise<boolean>;
538
551
  deletePage(params?: ISavePageParams): Promise<boolean>;
539
- validatePage(): Promise<boolean>;
552
+ validatePage(publish?: boolean): Promise<boolean>;
540
553
  updatePageStatus(id: number[], status: string): Promise<boolean>;
541
554
  setHistoryPush(path: string, isEditor: boolean): void;
542
555
  setLanguage?(lang: { locale: string; id: number | null }): void;
@@ -51,6 +51,7 @@ const Item = (props: IItemProps): JSX.Element => {
51
51
  updateFormValue({ itemLink: item.url });
52
52
  updateFormValue({ itemLabel: item.label });
53
53
  updateFormValue({ itemAuxText: item.auxText });
54
+ updateFormValue({ itemImage: item.image });
54
55
  updateFormValue({ type });
55
56
  updateFormValue({ headerStyle });
56
57
  updateFormValue({ footerStyle });
@@ -5,17 +5,18 @@ import { menuActions } from "@ax/containers/Navigation";
5
5
  import { sitesActions } from "@ax/containers/Sites";
6
6
  import { FieldsBehavior } from "@ax/components";
7
7
 
8
- import { IRootState, IMenuForm } from "@ax/types";
8
+ import { IRootState, IMenuForm, IImage } from "@ax/types";
9
9
 
10
10
  const Form = (props: IProps): JSX.Element => {
11
- const { form, updateForm, toggleSecondaryPanel } = props;
11
+ const { form, updateForm, toggleSecondaryPanel, setIsGalleryOpened } = props;
12
12
 
13
- const { itemLink, itemLabel, itemAuxText, type } = form;
13
+ const { itemLink, itemLabel, itemAuxText, type, itemImage } = form;
14
14
 
15
15
  const setLinkValue = (value: any) => updateForm({ itemLink: value });
16
16
  const setLabelValue = (value: string) => updateForm({ itemLabel: value });
17
17
  const setAuxTextValue = (value: string) => updateForm({ itemAuxText: value });
18
18
  const setTypeValue = (value: string) => updateForm({ type: value });
19
+ const setImageValue = (value: IImage) => updateForm({ itemImage: value });
19
20
 
20
21
  const typeLinkOptions = [
21
22
  {
@@ -36,8 +37,8 @@ const Form = (props: IProps): JSX.Element => {
36
37
  <>
37
38
  <FieldsBehavior
38
39
  title="Type"
39
- fieldType="RadioGroup"
40
40
  name="quantityGroup"
41
+ fieldType="RadioGroup"
41
42
  options={typeLinkOptions}
42
43
  value={typeLink}
43
44
  onChange={setTypeValue}
@@ -50,7 +51,16 @@ const Form = (props: IProps): JSX.Element => {
50
51
  value={itemLabel || ""}
51
52
  onChange={setLabelValue}
52
53
  />
53
- {type === "link" && (
54
+ {type !== "link" ? (
55
+ <FieldsBehavior
56
+ title="Image"
57
+ name="image"
58
+ fieldType="ImageField"
59
+ value={itemImage || null}
60
+ onChange={setImageValue}
61
+ setIsGalleryOpened={setIsGalleryOpened}
62
+ />
63
+ ) : (
54
64
  <>
55
65
  <FieldsBehavior
56
66
  title="Auxiliar Text"
@@ -90,6 +100,7 @@ interface IStateProps {
90
100
 
91
101
  interface IFormProps {
92
102
  toggleSecondaryPanel(): any;
103
+ setIsGalleryOpened?: (isGalleryOpened: boolean) => void;
93
104
  }
94
105
  interface IDispatchProps {
95
106
  updateForm(value: any): void;
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { useState } from "react";
2
2
 
3
3
  import { connect } from "react-redux";
4
4
  import { menuActions } from "@ax/containers/Navigation";
@@ -14,30 +14,37 @@ const SidePanel = (props: IProps): JSX.Element => {
14
14
  const { isOpen, isOpenedSecond, toggleModal, toggleSecondaryPanel, addMenuItem, updateMenuItem, item, edit, form } =
15
15
  props;
16
16
 
17
- const { itemLabel, itemLink, itemAuxText, type, headerStyle, footerStyle } = form;
17
+ const { itemLabel, itemLink, itemImage, itemAuxText, type, headerStyle, footerStyle } = form;
18
18
 
19
- let page: any = {
19
+ const [isGalleryOpened, setIsGalleryOpened] = useState(false);
20
+
21
+ const setIsOpenedGallery = () => {
22
+ setIsGalleryOpened(!isGalleryOpened);
23
+ };
24
+
25
+ let menuItem: any = {
20
26
  label: itemLabel,
21
27
  url: itemLink,
28
+ image: itemImage,
22
29
  auxText: itemAuxText,
23
30
  component: "Menu",
24
31
  config: { type, headerStyle, footerStyle },
25
32
  };
26
33
 
27
- page.children = edit && item ? item.children : [];
34
+ menuItem.children = edit && item ? item.children : [];
28
35
 
29
36
  if (edit && item && item.id) {
30
- page = { ...page, id: item.id };
37
+ menuItem = { ...menuItem, id: item.id };
31
38
  }
32
39
 
33
40
  const addItemAction = () => {
34
- addMenuItem(page);
41
+ addMenuItem(menuItem);
35
42
  toggleModal();
36
43
  };
37
44
 
38
45
  const editItemAction = () => {
39
- page = { ...page, editorID: item && item.editorID };
40
- updateMenuItem(page);
46
+ menuItem = { ...menuItem, editorID: item && item.editorID };
47
+ updateMenuItem(menuItem);
41
48
  toggleModal();
42
49
  };
43
50
 
@@ -61,19 +68,21 @@ const SidePanel = (props: IProps): JSX.Element => {
61
68
  toggleModal={toggleModal}
62
69
  isOpen={isOpen}
63
70
  isOpenedSecond={isOpenedSecond}
71
+ closeOnOutsideClick={!isGalleryOpened}
64
72
  handlePanel={toggleSecondaryPanel}
65
73
  >
66
- <Form toggleSecondaryPanel={toggleSecondaryPanel} />
74
+ <S.FormWrapper>
75
+ <Form toggleSecondaryPanel={toggleSecondaryPanel} setIsGalleryOpened={setIsOpenedGallery} />
76
+ </S.FormWrapper>
67
77
  <S.Footer>
68
- {edit ? (
69
- <Button className="button" type="button" onClick={editButton.action} disabled={editButton.disabled}>
70
- {editButton.label}
71
- </Button>
72
- ) : (
73
- <Button className="button" type="button" onClick={addButton.action} disabled={addButton.disabled}>
74
- {addButton.label}
75
- </Button>
76
- )}
78
+ <Button
79
+ className="button"
80
+ type="button"
81
+ onClick={edit ? editButton.action : addButton.action}
82
+ disabled={edit ? editButton.disabled : addButton.disabled}
83
+ >
84
+ {edit ? editButton.label : addButton.label}
85
+ </Button>
77
86
  </S.Footer>
78
87
  </FloatingPanel>
79
88
  );
@@ -99,13 +108,13 @@ interface ISidePanelProps {
99
108
  edit?: boolean;
100
109
  isOpen: boolean;
101
110
  isOpenedSecond: boolean;
102
- toggleSecondaryPanel(): any;
103
- toggleModal(): any;
111
+ toggleSecondaryPanel: () => void;
112
+ toggleModal: () => void;
104
113
  }
105
114
 
106
115
  interface IDispatchProps {
107
- addMenuItem(page: any): void;
108
- updateMenuItem(page: any): void;
116
+ addMenuItem(menuItem: any): void;
117
+ updateMenuItem(menuItem: any): void;
109
118
  }
110
119
 
111
120
  type IProps = IDispatchProps & ISidePanelProps & IStateProps;
@@ -2,6 +2,22 @@ import styled from "styled-components";
2
2
 
3
3
  export const Footer = styled.div`
4
4
  position: absolute;
5
- bottom: ${(p) => p.theme.spacing.m};
6
- right: ${(p) => p.theme.spacing.m};
5
+ bottom: 0;
6
+ width: 100%;
7
+ right: 0;
8
+ height: 73px;
9
+ background: ${(p) => p.theme.colors.uiBackground01};
10
+ z-index: 3;
11
+ & button {
12
+ position: absolute;
13
+ right: ${(p) => p.theme.spacing.m};
14
+ bottom: ${(p) => p.theme.spacing.m};
15
+ }
16
+ `;
17
+
18
+ export const FormWrapper = styled.div`
19
+ height: calc(100% - ${(p) => p.theme.spacing.s} - 73px);
20
+ overflow: auto;
21
+ margin: -${(p) => p.theme.spacing.m};
22
+ padding: ${(p) => p.theme.spacing.m};
7
23
  `;
@@ -115,69 +115,82 @@ const PageEditor = (props: IProps) => {
115
115
  };
116
116
 
117
117
  const publishPage = async () => {
118
- const { updatePageStatus, savePage, pageID } = props;
118
+ const { updatePageStatus, savePage, pageID, validatePage } = props;
119
119
 
120
- const publishPage = {
121
- status: pageStatus.UPLOAD_PENDING,
122
- };
120
+ const validated = await validatePage(true);
123
121
 
124
- pageID
125
- ? await updatePageStatus([pageID], pageStatus.UPLOAD_PENDING)
126
- : await savePage(false, publishPage).then((isSaved: boolean) => {
127
- if (isSaved) {
128
- resetDirty();
129
- }
130
- });
122
+ if (validated) {
123
+ const publishPage = {
124
+ status: pageStatus.UPLOAD_PENDING,
125
+ };
126
+
127
+ pageID
128
+ ? updatePageStatus([pageID], pageStatus.UPLOAD_PENDING)
129
+ : savePage(false, publishPage).then((isSaved: boolean) => {
130
+ if (isSaved) {
131
+ resetDirty();
132
+ }
133
+ });
134
+ }
131
135
  };
132
136
 
133
137
  const publishChanges = async () => {
134
- const { savePage } = props;
138
+ const { savePage, validatePage } = props;
135
139
 
136
- const publishPage = {
137
- status: pageStatus.UPLOAD_PENDING,
138
- };
140
+ const validated = await validatePage(true);
139
141
 
140
- await savePage(false, publishPage).then((isSaved: boolean) => {
141
- if (isSaved) {
142
- resetDirty();
143
- }
144
- });
142
+ if (validated) {
143
+ const publishPage = {
144
+ status: pageStatus.UPLOAD_PENDING,
145
+ };
146
+
147
+ savePage(false, publishPage).then((isSaved: boolean) => {
148
+ if (isSaved) {
149
+ resetDirty();
150
+ }
151
+ });
152
+ }
145
153
  };
146
154
 
147
- const unpublishPage = async () => {
155
+ const unpublishPage = () => {
148
156
  const { updatePageStatus, pageID } = props;
149
157
 
150
- await updatePageStatus([pageID], pageStatus.OFFLINE_PENDING);
158
+ updatePageStatus([pageID], pageStatus.OFFLINE_PENDING);
151
159
  };
152
160
 
153
- const cancelPublishPage = async () => {
161
+ const cancelPublishPage = () => {
154
162
  const { updatePageStatus, pageID } = props;
155
163
 
156
- await updatePageStatus([pageID], pageStatus.OFFLINE);
164
+ updatePageStatus([pageID], pageStatus.OFFLINE);
157
165
  };
158
166
 
159
- const reviewPage = async () => {
167
+ const reviewPage = () => {
160
168
  const { validatePage } = props;
161
- await validatePage();
169
+ validatePage();
162
170
  };
163
171
 
164
172
  const handlePublishDraft = async () => {
165
- const { savePage } = props;
166
- const isSaved = await savePage(false, null, true);
167
- if (isSaved) resetDirty();
173
+ const { savePage, validatePage } = props;
174
+
175
+ const validated = await validatePage(true);
176
+
177
+ if (validated) {
178
+ const isSaved = await savePage(false, null, true);
179
+ if (isSaved) resetDirty();
180
+ }
168
181
  };
169
182
 
170
- const handleDiscardDraft = async () => {
183
+ const handleDiscardDraft = () => {
171
184
  const { discardDraft } = props;
172
185
  resetDirty();
173
- await discardDraft();
186
+ discardDraft();
174
187
  };
175
188
 
176
- const handleDiscarChanges = async () => {
189
+ const handleDiscarChanges = () => {
177
190
  const { getPage, pageID } = props;
178
191
  resetDirty();
179
192
 
180
- await getPage(pageID);
193
+ getPage(pageID);
181
194
  };
182
195
 
183
196
  const getPublishButton = (status: string) => {
@@ -596,7 +609,7 @@ interface IPageEditorDispatchProps {
596
609
  getPage(pageID?: number): Promise<void>;
597
610
  savePage(createDraft: boolean, publishPage?: any, publishDraft?: boolean): Promise<boolean>;
598
611
  deletePage(params?: ISavePageParams): Promise<boolean>;
599
- validatePage(): Promise<boolean>;
612
+ validatePage(publish?: boolean): Promise<boolean>;
600
613
  updatePageStatus(id: number[], status: string): Promise<boolean>;
601
614
  setHistoryPush(path: string, isEditor: boolean): void;
602
615
  setLanguage?(lang: { locale: string; id: number | null }): void;
@@ -3,7 +3,7 @@ import { connect } from "react-redux";
3
3
 
4
4
  import { appActions } from "@ax/containers/App";
5
5
  import { sitesActions } from "@ax/containers/Sites";
6
- import { ISettingsForm, ISite } from "@ax/types";
6
+ import { IRootState, ISettingsForm, ISite, IUser } from "@ax/types";
7
7
  import { useModal } from "@ax/hooks";
8
8
  import { MainWrapper, Modal, ErrorToast } from "@ax/components";
9
9
 
@@ -13,7 +13,7 @@ import SiteItem from "./SiteItem";
13
13
  import * as S from "./style";
14
14
 
15
15
  const SitesList = (props: IProps): JSX.Element => {
16
- const { sites, saveSettings, setHistoryPush } = props;
16
+ const { sites, saveSettings, setHistoryPush, currentUser } = props;
17
17
 
18
18
  const initialState = {
19
19
  name: "",
@@ -50,13 +50,17 @@ const SitesList = (props: IProps): JSX.Element => {
50
50
  const mainAction = { title: "Create site", onClick: saveSiteSettings, disabled: isSubmitDisabled };
51
51
  const secondaryAction = { title: "Cancel", onClick: toggleModal };
52
52
 
53
+ const userHasSite = (siteID: number) => currentUser.sites.includes("all") || currentUser.sites.includes(siteID);
54
+
53
55
  return (
54
56
  <MainWrapper title="Sites" rightButton={rightButtonProps}>
55
57
  <ErrorToast />
56
58
  <S.Sites>
57
- {sites.map((site: ISite) => (
58
- <SiteItem key={site.id} site={site} />
59
- ))}
59
+ {sites
60
+ .filter((site: ISite) => userHasSite(site.id))
61
+ .map((site: ISite) => (
62
+ <SiteItem key={site.id} site={site} />
63
+ ))}
60
64
  </S.Sites>
61
65
  <Modal
62
66
  isOpen={isOpen}
@@ -74,8 +78,13 @@ const SitesList = (props: IProps): JSX.Element => {
74
78
 
75
79
  interface ISitesProps {
76
80
  sites: ISite[];
81
+ currentUser: IUser;
77
82
  }
78
83
 
84
+ const mapStateToProps = (state: IRootState) => ({
85
+ currentUser: state.users.currentUser,
86
+ });
87
+
79
88
  interface IDispatchProps {
80
89
  setHistoryPush(path: string, isEditor?: boolean): void;
81
90
  saveSettings(form: ISettingsForm): Promise<boolean>;
@@ -88,4 +97,4 @@ const mapDispatchToProps = {
88
97
 
89
98
  type IProps = ISitesProps & IDispatchProps;
90
99
 
91
- export default connect(null, mapDispatchToProps)(SitesList);
100
+ export default connect(mapStateToProps, mapDispatchToProps)(SitesList);
@@ -38,6 +38,7 @@ const Form = (props: IProps) => {
38
38
  deleteStructuredDataContent,
39
39
  errors,
40
40
  validated,
41
+ validateForm,
41
42
  } = props;
42
43
 
43
44
  const [isNewStructuredData, setIsNewStructuredData] = useState(!form.id);
@@ -75,29 +76,33 @@ const Form = (props: IProps) => {
75
76
  });
76
77
 
77
78
  const handleSave = async (publish?: boolean) => {
78
- setIsSavedData(true);
79
- const status = isNewStructuredData ? true : form.draft;
80
-
81
- let payload: any = {
82
- structuredData: currentStructuredData ? currentStructuredData.id : null,
83
- content: form.content,
84
- draft: publish === true ? false : status,
85
- relatedSite: currentSite ? currentSite.id : null,
86
- entity: form.entity ? form.entity : null,
87
- };
79
+ const validated = publish ? await validateForm(true) : true;
80
+
81
+ if (validated) {
82
+ setIsSavedData(true);
83
+ const status = isNewStructuredData ? true : form.draft;
84
+
85
+ let payload: any = {
86
+ structuredData: currentStructuredData ? currentStructuredData.id : null,
87
+ content: form.content,
88
+ draft: publish === true ? false : status,
89
+ relatedSite: currentSite ? currentSite.id : null,
90
+ entity: form.entity ? form.entity : null,
91
+ };
88
92
 
89
- if (!isNewStructuredData) {
90
- payload = { ...payload, ...form };
91
- }
93
+ if (!isNewStructuredData) {
94
+ payload = { ...payload, ...form };
95
+ }
92
96
 
93
- let saved = false;
94
- if (isNewStructuredData) {
95
- saved = await createStructuredDataContent(payload);
96
- saved && setIsNewStructuredData(false);
97
- } else {
98
- saved = await updateStructuredDataContent(payload);
97
+ let saved = false;
98
+ if (isNewStructuredData) {
99
+ saved = await createStructuredDataContent(payload);
100
+ saved && setIsNewStructuredData(false);
101
+ } else {
102
+ saved = await updateStructuredDataContent(payload);
103
+ }
104
+ saved && resetDirty();
99
105
  }
100
- saved && resetDirty();
101
106
  };
102
107
 
103
108
  const getSaveLabel = () => {
@@ -171,6 +176,9 @@ const Form = (props: IProps) => {
171
176
  };
172
177
 
173
178
  const publishItem = async () => {
179
+ const validated = await validateForm(true);
180
+ if (!validated) return;
181
+
174
182
  if (!isNewStructuredData) {
175
183
  setDataStatus(form.id, "undraft").then((updated: boolean) => {
176
184
  if (updated) {
@@ -306,7 +314,7 @@ interface IProps {
306
314
  getSiteDataPack(packID: string): void;
307
315
  setDataStatus(id: number, status: string): Promise<boolean>;
308
316
  deleteStructuredDataContent(id: number): Promise<boolean>;
309
- validateForm(): Promise<boolean>;
317
+ validateForm(publish?: boolean): Promise<boolean>;
310
318
  }
311
319
 
312
320
  const mapStateToProps = (state: IRootState) => ({
@@ -113,7 +113,7 @@ const getSortedListStatus = (orderPointer: string, isAscending: boolean) => {
113
113
  isAscending,
114
114
  sortedByTitle: orderPointer === "title",
115
115
  sortedByURL: orderPointer === "slug",
116
- sortedByDate: orderPointer === "modified",
116
+ sortedByDate: ["modified", "date"].includes(orderPointer),
117
117
  };
118
118
 
119
119
  return sortedListStatus;
@@ -314,6 +314,7 @@ export interface IMenuItem {
314
314
  url: any;
315
315
  auxText: string;
316
316
  children: any[];
317
+ image?: IImage | string | null;
317
318
  isExpanded?: boolean;
318
319
  config: IMenuItemConfig | null;
319
320
  parentEditorID?: number;
@@ -329,6 +330,7 @@ export interface IMenuForm {
329
330
  itemLink: any;
330
331
  itemLabel: string;
331
332
  itemAuxText: string;
333
+ itemImage: IImage | string | null;
332
334
  type: string;
333
335
  headerStyle: string;
334
336
  footerStyle: string;
@@ -535,7 +537,7 @@ export interface IUser {
535
537
  enabled?: boolean;
536
538
  timezone?: string;
537
539
  status?: string;
538
- sites?: any;
540
+ sites: (number | string)[];
539
541
  }
540
542
 
541
543
  export interface ISelectOption {