@griddo/ax 1.58.6 → 1.59.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 (120) hide show
  1. package/package.json +2 -2
  2. package/src/GlobalStore.tsx +3 -1
  3. package/src/api/checkgroups.tsx +1 -1
  4. package/src/api/domains.tsx +26 -0
  5. package/src/api/index.tsx +3 -1
  6. package/src/api/sites.tsx +25 -8
  7. package/src/api/utils.tsx +1 -1
  8. package/src/components/Browser/index.tsx +8 -3
  9. package/src/components/ElementsTooltip/index.tsx +23 -8
  10. package/src/components/ElementsTooltip/style.tsx +4 -5
  11. package/src/components/ErrorCenter/index.tsx +11 -1
  12. package/src/components/ErrorCenter/style.tsx +4 -3
  13. package/src/components/Fields/CheckGroup/index.tsx +5 -4
  14. package/src/components/Fields/ComponentArray/MixableComponentArray/AddItemButton/index.tsx +1 -0
  15. package/src/components/Fields/ReferenceField/Context/index.tsx +10 -6
  16. package/src/components/Fields/ReferenceField/ItemList/Item/index.tsx +2 -2
  17. package/src/components/Fields/ReferenceField/ItemList/index.tsx +15 -14
  18. package/src/components/FieldsBehavior/index.tsx +2 -1
  19. package/src/components/FloatingMenu/index.tsx +3 -1
  20. package/src/components/FloatingMenu/style.tsx +7 -5
  21. package/src/components/Gallery/GalleryPanel/DetailPanel/index.tsx +17 -19
  22. package/src/components/Gallery/GalleryPanel/DetailPanel/style.tsx +32 -19
  23. package/src/components/Gallery/style.tsx +1 -1
  24. package/src/components/Icon/components/Category.js +5 -6
  25. package/src/components/Icon/components/Refresh.js +12 -0
  26. package/src/components/Icon/svgs/Category.svg +1 -1
  27. package/src/components/Icon/svgs/Refresh.svg +3 -0
  28. package/src/components/Lists/style.tsx +10 -9
  29. package/src/components/MainWrapper/AppBar/index.tsx +16 -5
  30. package/src/components/MainWrapper/AppBar/style.tsx +2 -1
  31. package/src/components/SideModal/index.tsx +10 -4
  32. package/src/components/TableCounter/style.tsx +1 -4
  33. package/src/components/TableFilters/CategoryFilter/index.tsx +92 -0
  34. package/src/{modules/Content/HeaderMenus/Translations → components/TableFilters/CategoryFilter}/style.tsx +4 -3
  35. package/src/components/TableFilters/CustomizeFilters/index.tsx +52 -0
  36. package/src/components/TableFilters/CustomizeFilters/style.tsx +28 -0
  37. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Live → components/TableFilters/LiveFilter}/index.tsx +18 -6
  38. package/src/{modules/Content/HeaderMenus/Live → components/TableFilters/LiveFilter}/style.tsx +0 -0
  39. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Name → components/TableFilters/NameFilter}/index.tsx +18 -9
  40. package/src/{modules/Content/HeaderMenus/Name → components/TableFilters/NameFilter}/style.tsx +0 -0
  41. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Site → components/TableFilters/SiteFilter}/index.tsx +3 -3
  42. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Site → components/TableFilters/SiteFilter}/style.tsx +1 -1
  43. package/src/{modules/Content/HeaderMenus/Status → components/TableFilters/StatusFilter}/index.tsx +7 -4
  44. package/src/{modules/Content/HeaderMenus/Status → components/TableFilters/StatusFilter}/style.tsx +0 -0
  45. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Translations → components/TableFilters/TranslationsFilter}/index.tsx +4 -4
  46. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Translations → components/TableFilters/TranslationsFilter}/style.tsx +0 -0
  47. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Types → components/TableFilters/TypeFilter}/index.tsx +13 -9
  48. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Types → components/TableFilters/TypeFilter}/style.tsx +1 -1
  49. package/src/components/TableFilters/index.tsx +19 -0
  50. package/src/components/Tag/index.tsx +1 -1
  51. package/src/components/Tag/style.tsx +10 -11
  52. package/src/components/index.tsx +19 -0
  53. package/src/containers/Domains/actions.tsx +51 -0
  54. package/src/containers/Domains/constants.tsx +5 -0
  55. package/src/containers/Domains/index.tsx +4 -0
  56. package/src/containers/Domains/interfaces.tsx +9 -0
  57. package/src/containers/Domains/reducer.tsx +22 -0
  58. package/src/containers/Gallery/actions.tsx +0 -1
  59. package/src/containers/PageEditor/actions.tsx +7 -0
  60. package/src/containers/PageEditor/utils.tsx +1 -1
  61. package/src/containers/Settings/Languages/constants.tsx +3 -3
  62. package/src/containers/Settings/Languages/index.tsx +2 -5
  63. package/src/containers/Sites/actions.tsx +3 -2
  64. package/src/containers/StructuredData/actions.tsx +62 -3
  65. package/src/containers/StructuredData/constants.tsx +4 -0
  66. package/src/containers/StructuredData/interfaces.tsx +13 -1
  67. package/src/containers/StructuredData/reducer.tsx +9 -1
  68. package/src/forms/editor.tsx +4 -0
  69. package/src/forms/elements.tsx +2 -5
  70. package/src/forms/index.tsx +2 -1
  71. package/src/forms/validators.tsx +12 -5
  72. package/src/helpers/arrays.tsx +12 -1
  73. package/src/helpers/index.tsx +4 -1
  74. package/src/helpers/strings.tsx +7 -0
  75. package/src/hooks/content.tsx +41 -0
  76. package/src/hooks/index.tsx +3 -1
  77. package/src/modules/Categories/CategoriesList/CategoryNav/NavItem/style.tsx +9 -9
  78. package/src/modules/Content/BulkHeader/TableHeader/index.tsx +95 -24
  79. package/src/modules/Content/BulkHeader/TableHeader/style.tsx +6 -19
  80. package/src/modules/Content/BulkHeader/index.tsx +16 -0
  81. package/src/modules/Content/ContentFilters/index.tsx +4 -4
  82. package/src/modules/Content/OptionTable/style.tsx +1 -1
  83. package/src/modules/Content/PageItem/atoms.tsx +28 -0
  84. package/src/modules/Content/PageItem/index.tsx +67 -24
  85. package/src/modules/Content/PageItem/style.tsx +14 -7
  86. package/src/modules/Content/hooks.tsx +27 -17
  87. package/src/modules/Content/index.tsx +53 -6
  88. package/src/modules/GlobalEditor/index.tsx +5 -11
  89. package/src/modules/GlobalSettings/Robots/Item/RobotsPanel/index.tsx +61 -0
  90. package/src/modules/GlobalSettings/Robots/Item/RobotsPanel/style.tsx +30 -0
  91. package/src/modules/GlobalSettings/Robots/Item/index.tsx +33 -0
  92. package/src/modules/GlobalSettings/Robots/Item/style.tsx +28 -0
  93. package/src/modules/GlobalSettings/Robots/index.tsx +120 -0
  94. package/src/modules/GlobalSettings/Robots/style.tsx +32 -0
  95. package/src/modules/GlobalSettings/index.tsx +26 -0
  96. package/src/modules/PageEditor/index.tsx +2 -5
  97. package/src/modules/Settings/Globals/style.tsx +1 -1
  98. package/src/modules/StructuredData/Form/ConnectedField/index.tsx +10 -2
  99. package/src/modules/StructuredData/Form/index.tsx +48 -9
  100. package/src/modules/StructuredData/Form/style.tsx +3 -6
  101. package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +84 -35
  102. package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/style.tsx +6 -25
  103. package/src/modules/StructuredData/StructuredDataList/BulkHeader/index.tsx +10 -1
  104. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/atoms.tsx +24 -3
  105. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +53 -22
  106. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/style.tsx +16 -9
  107. package/src/modules/StructuredData/StructuredDataList/OptionTable/style.tsx +1 -1
  108. package/src/modules/StructuredData/StructuredDataList/hooks.tsx +9 -2
  109. package/src/modules/StructuredData/StructuredDataList/index.tsx +45 -5
  110. package/src/routes/multisite.tsx +8 -0
  111. package/src/types/index.tsx +28 -11
  112. package/src/modules/Content/HeaderMenus/Live/index.tsx +0 -93
  113. package/src/modules/Content/HeaderMenus/Name/index.tsx +0 -52
  114. package/src/modules/Content/HeaderMenus/Translations/index.tsx +0 -62
  115. package/src/modules/Content/HeaderMenus/Types/index.tsx +0 -73
  116. package/src/modules/Content/HeaderMenus/Types/style.tsx +0 -34
  117. package/src/modules/StructuredData/StructuredDataList/HeaderMenus/Live/style.tsx +0 -37
  118. package/src/modules/StructuredData/StructuredDataList/HeaderMenus/Name/style.tsx +0 -29
  119. package/src/modules/StructuredData/StructuredDataList/HeaderMenus/Status/index.tsx +0 -47
  120. package/src/modules/StructuredData/StructuredDataList/HeaderMenus/Status/style.tsx +0 -30
@@ -15,7 +15,6 @@ const CheckCell = styled(Cell)`
15
15
  `;
16
16
 
17
17
  const NameCell = styled(Cell)`
18
- width: 35%;
19
18
  flex-grow: 1;
20
19
  svg {
21
20
  height: ${(p) => p.theme.spacing.s};
@@ -35,12 +34,12 @@ const Title = styled.div`
35
34
  const Slug = styled.div``;
36
35
 
37
36
  const TypeCell = styled(Cell)`
38
- width: 140px;
37
+ flex: 0 0 170px;
39
38
  align-items: center;
40
39
  `;
41
40
 
42
41
  const LiveCell = styled(Cell)`
43
- width: 80px;
42
+ flex: 0 0 80px;
44
43
  align-items: center;
45
44
  svg {
46
45
  width: ${(p) => p.theme.spacing.m};
@@ -49,7 +48,7 @@ const LiveCell = styled(Cell)`
49
48
  `;
50
49
 
51
50
  const StatusCell = styled(Cell)`
52
- width: 170px;
51
+ flex: 0 0 170px;
53
52
  align-items: center;
54
53
  div:nth-child(2) {
55
54
  margin-top: ${(p) => p.theme.spacing.xs};
@@ -58,18 +57,19 @@ const StatusCell = styled(Cell)`
58
57
 
59
58
  const TransCell = styled(Cell)`
60
59
  ${(p) => p.theme.textStyle.uiXS};
61
- width: 90px;
60
+ flex: 0 0 115px;
62
61
  position: relative;
63
62
  align-items: center;
64
63
  `;
65
64
 
66
65
  const SeoCell = styled(Cell)`
67
66
  ${(p) => p.theme.textStyle.uiXS};
68
- width: 124px;
67
+ flex: 0 0 124px;
69
68
  `;
70
69
 
71
70
  const GlobalCell = styled(Cell)`
72
71
  width: 24px;
72
+ flex: 0 0 24px;
73
73
  `;
74
74
 
75
75
  const Mark = styled.div`
@@ -89,7 +89,13 @@ const Wrapper = styled.div`
89
89
  `;
90
90
 
91
91
  const ActionsCell = styled(Cell)`
92
- width: 92px;
92
+ flex: 0 0 100px;
93
+ `;
94
+
95
+ const CategoryCell = styled(Cell)`
96
+ flex: 0 0 150px;
97
+ align-items: center;
98
+ position: relative;
93
99
  `;
94
100
 
95
101
  const StyledActionMenu = styled(ActionMenu)`
@@ -191,4 +197,5 @@ export {
191
197
  ModalContent,
192
198
  GlobalCell,
193
199
  Mark,
200
+ CategoryCell,
194
201
  };
@@ -1,18 +1,23 @@
1
1
  import { useState } from "react";
2
2
 
3
3
  const useSortedListStatus = () => {
4
- const sortedInitialState: {isAscending: boolean; sortedByTitle: boolean; sortedByURL: boolean; sortedByDate: boolean;} = {
4
+ const sortedInitialState: {
5
+ isAscending: boolean;
6
+ sortedByTitle: boolean;
7
+ sortedByURL: boolean;
8
+ sortedByDate: boolean;
9
+ } = {
5
10
  isAscending: false,
6
11
  sortedByTitle: false,
7
12
  sortedByURL: false,
8
- sortedByDate: false
13
+ sortedByDate: false,
9
14
  };
10
15
 
11
- const [ sortedListStatus, setSortedListStatus ] = useState(sortedInitialState);
16
+ const [sortedListStatus, setSortedListStatus] = useState(sortedInitialState);
12
17
 
13
18
  return {
14
19
  sortedListStatus,
15
- setSortedListStatus
20
+ setSortedListStatus,
16
21
  };
17
22
  };
18
23
 
@@ -20,20 +25,19 @@ const useFilterQuery = () => {
20
25
  const initialQueryValues = {
21
26
  type: "",
22
27
  translated: "",
23
- liveStatus: "",
24
- order: ""
28
+ liveStatus: "all",
29
+ order: "",
30
+ categories: "all",
25
31
  };
26
32
 
27
33
  const [query, setQuery] = useState(initialQueryValues);
28
34
 
29
35
  const setFilterQuery = (filterValues: any) => {
30
- const { type, translated, liveStatus, order } = filterValues;
36
+ const { type, translated, liveStatus, order, categories } = filterValues;
31
37
  let filterQuery = "";
32
38
 
33
39
  const currentQuery = (pointer: string, values: string) => {
34
- return filterQuery
35
- ? filterQuery.concat(`&${pointer}=${values}`)
36
- : `?${pointer}=${values}`;
40
+ return filterQuery ? filterQuery.concat(`&${pointer}=${values}`) : `?${pointer}=${values}`;
37
41
  };
38
42
 
39
43
  if (type) {
@@ -52,17 +56,22 @@ const useFilterQuery = () => {
52
56
  filterQuery = currentQuery("order", order);
53
57
  }
54
58
 
59
+ if (categories) {
60
+ filterQuery = currentQuery("categories", categories);
61
+ }
62
+
55
63
  return filterQuery;
56
64
  };
57
65
 
58
66
  const setFiltersSelection = (pointer: string, filter: string, isAscendent?: boolean) => {
59
- const { type, translated, liveStatus, order } = query;
67
+ const { type, translated, liveStatus, order, categories } = query;
60
68
  const orderMethod = isAscendent ? "asc" : "desc";
61
69
  const filterValues = {
62
70
  type: pointer === "type" ? filter : type,
63
71
  translated: pointer === "translated" ? filter : translated,
64
72
  liveStatus: pointer === "liveStatus" ? filter : liveStatus,
65
- order: pointer === "order" ? `${filter}-${orderMethod}` : order
73
+ order: pointer === "order" ? `${filter}-${orderMethod}` : order,
74
+ categories: pointer === "categories" ? filter : categories,
66
75
  };
67
76
 
68
77
  setQuery(filterValues);
@@ -70,13 +79,14 @@ const useFilterQuery = () => {
70
79
  return filterValues;
71
80
  };
72
81
 
82
+ const resetFilterQuery = () => setQuery(initialQueryValues);
83
+
73
84
  return {
74
85
  setFiltersSelection,
75
- setFilterQuery
86
+ setFilterQuery,
87
+ resetFilterQuery,
88
+ filterValues: query,
76
89
  };
77
90
  };
78
91
 
79
- export {
80
- useSortedListStatus,
81
- useFilterQuery
82
- };
92
+ export { useSortedListStatus, useFilterQuery };
@@ -2,7 +2,7 @@ import React, { useEffect, useCallback, useState, useRef } from "react";
2
2
  import { connect } from "react-redux";
3
3
  import { useLocation } from "react-router-dom";
4
4
 
5
- import { useModal, useBulkSelection, useToast } from "@ax/hooks";
5
+ import { useModal, useBulkSelection, useToast, useCategoryColors } from "@ax/hooks";
6
6
  import {
7
7
  IRootState,
8
8
  IPage,
@@ -12,6 +12,7 @@ import {
12
12
  IEmptyStateProps,
13
13
  ICheck,
14
14
  IGetSitePagesParams,
15
+ IColumn,
15
16
  } from "@ax/types";
16
17
  import { MainWrapper, Modal, TableList, ErrorToast, Toast, EmptyState } from "@ax/components";
17
18
  import { getFilteredStructuredData, isStructuredDataFromPage } from "@ax/helpers";
@@ -87,18 +88,43 @@ const Content = (props: IProps): JSX.Element => {
87
88
  const { isOpen: isNewOpen, toggleModal: toggleNewModal } = useModal();
88
89
  const { isOpen: isImporterOpen, toggleModal: toggleImporterModal } = useModal();
89
90
  const { sortedListStatus, setSortedListStatus } = useSortedListStatus();
90
- const { setFiltersSelection, setFilterQuery } = useFilterQuery();
91
+ const { setFiltersSelection, setFilterQuery, resetFilterQuery, filterValues } = useFilterQuery();
91
92
  const { state: locationState } = useLocation<{ isFromEditor: boolean }>();
92
93
 
93
94
  const currentFilter = getCurrentFilter(structuredData, filter);
94
95
  const checkFromPage = currentFilter ? currentFilter.fromPage : undefined;
95
96
  const isStructuredData = filter !== "unique-pages" && !checkFromPage;
97
+ const isGlobalPages = filter !== "unique-pages" && checkFromPage;
96
98
  const isDataEditable = !isStructuredData || (currentStructuredData && currentStructuredData.editable);
97
99
 
98
100
  const pagesIds = currentSitePages && currentSitePages.map((page: any) => page.id);
99
101
  const dataIds = currentDataContent && currentDataContent.map((data: any) => data.id);
100
102
  const contentIds = isStructuredData ? dataIds : pagesIds;
101
103
 
104
+ const categoryColumns =
105
+ currentStructuredData && currentStructuredData.schema
106
+ ? currentStructuredData.schema.fields.filter((field: any) => field.showList)
107
+ : [];
108
+
109
+ const defaultColumns: Record<string, IColumn> = {
110
+ type: { title: "Types", show: true },
111
+ live: { title: "Live", show: true },
112
+ status: { title: "Status", show: true },
113
+ translation: { title: "Trans.", show: true },
114
+ seo: { title: "SEO", show: true },
115
+ };
116
+
117
+ const extraColumns = categoryColumns.reduce((acc: Record<string, IColumn>, cur: any) => {
118
+ acc[cur.key] = { title: cur.title, show: false };
119
+ return acc;
120
+ }, {});
121
+
122
+ const filterColumns = { ...extraColumns, ...defaultColumns };
123
+
124
+ const initialColumns = isGlobalPages ? filterColumns : defaultColumns;
125
+
126
+ const [columnsState, setColumnsState] = useState(initialColumns);
127
+
102
128
  const {
103
129
  resetBulkSelection,
104
130
  selectedItems,
@@ -132,6 +158,8 @@ const Content = (props: IProps): JSX.Element => {
132
158
  setIsVisible: setIsVisibleRemovedToast,
133
159
  } = useToast();
134
160
 
161
+ const { categoryColors, addCategoryColors } = useCategoryColors();
162
+
135
163
  const getParams = useCallback(() => {
136
164
  const siteID = currentSiteInfo ? currentSiteInfo.id : null;
137
165
  const params = isStructuredData
@@ -176,7 +204,7 @@ const Content = (props: IProps): JSX.Element => {
176
204
  getOrderedSitePages(siteID, fullQuery);
177
205
  } else {
178
206
  const pageFilter = isStructuredDataPage ? filter : undefined;
179
- getSitePages(params, pageFilter);
207
+ getSitePages(params, pageFilter, filterQuery);
180
208
  }
181
209
  };
182
210
 
@@ -198,7 +226,12 @@ const Content = (props: IProps): JSX.Element => {
198
226
  // eslint-disable-next-line
199
227
  }, [page, filter, currentFilterQuery, searchQuery]);
200
228
 
201
- useEffect(() => setPage(firstPage), [filter]);
229
+ useEffect(() => {
230
+ setPage(firstPage);
231
+ const initialColumns = filter !== "unique-pages" ? filterColumns : defaultColumns;
232
+ setColumnsState(initialColumns);
233
+ // eslint-disable-next-line react-hooks/exhaustive-deps
234
+ }, [filter]);
202
235
 
203
236
  useEffect(() => {
204
237
  if (!locationState || locationState.isFromEditor !== true) {
@@ -342,6 +375,11 @@ const Content = (props: IProps): JSX.Element => {
342
375
  sortedListStatus={sortedListStatus}
343
376
  filterItems={filterItems}
344
377
  isEditable={isDataEditable}
378
+ filterValues={filterValues}
379
+ categoryColumns={categoryColumns}
380
+ columns={columnsState}
381
+ setColumns={setColumnsState}
382
+ isGlobalPages={isGlobalPages}
345
383
  />
346
384
  );
347
385
 
@@ -445,6 +483,10 @@ const Content = (props: IProps): JSX.Element => {
445
483
  activatedTemplates={activatedTemplates}
446
484
  toggleToast={toggleRemovedToast}
447
485
  setRemovedPage={setRemovedPage}
486
+ categoryColumns={categoryColumns}
487
+ columns={columnsState}
488
+ categoryColors={categoryColors}
489
+ addCategoryColors={addCategoryColors}
448
490
  />
449
491
  );
450
492
  });
@@ -519,6 +561,11 @@ const Content = (props: IProps): JSX.Element => {
519
561
  ? { onClick: handleImport, title: "NEXT" }
520
562
  : { onClick: createContent, title: "ADD" };
521
563
 
564
+ const resetFilter = () => {
565
+ resetFilterQuery();
566
+ setCurrentFilterQuery("");
567
+ };
568
+
522
569
  return (
523
570
  <MainWrapper
524
571
  title={title}
@@ -529,7 +576,7 @@ const Content = (props: IProps): JSX.Element => {
529
576
  searchAction={setSearchQuery}
530
577
  >
531
578
  <S.ContentListWrapper>
532
- <ContentFilters current={filter} dynamicValues={structuredData} />
579
+ <ContentFilters current={filter} dynamicValues={structuredData} resetFilter={resetFilter} />
533
580
  <S.TableWrapper>
534
581
  <ErrorToast />
535
582
  <TableList
@@ -599,7 +646,7 @@ interface IDispatchProps {
599
646
  setCurrentPageStatus(currentPageStatus: string | null): ISetCurrentPageStatusAction;
600
647
  setCurrentPageName(currentPageName: string): ISetCurrentPageNameAction;
601
648
  addTemplate(template: string): void;
602
- getSitePages(params: IGetSitePagesParams, structuredData?: string | undefined): Promise<void>;
649
+ getSitePages(params: IGetSitePagesParams, structuredData?: string | undefined, filterQuery?: string): Promise<void>;
603
650
  updatePageStatus(ids: number[], status: string, updatePageStatus?: boolean): Promise<boolean>;
604
651
  deletePage(params?: ISavePageParams): any;
605
652
  setHistoryPush(page: string, isEditor: boolean): any;
@@ -147,12 +147,8 @@ const GlobalEditor = (props: IProps) => {
147
147
 
148
148
  const handlePublishDraft = async () => {
149
149
  const { savePage } = props;
150
-
151
- await savePage(false, null, true).then((isSaved: boolean) => {
152
- if (isSaved) {
153
- resetDirty();
154
- }
155
- });
150
+ const isSaved = await savePage(false, null, true);
151
+ if (isSaved) resetDirty();
156
152
  };
157
153
 
158
154
  const handleDiscardDraft = async () => {
@@ -254,11 +250,9 @@ const GlobalEditor = (props: IProps) => {
254
250
 
255
251
  const createDraft = isPublished && !hasDraft;
256
252
  const status = props.pageStatus === pageStatus.PUBLISHED && !createDraft ? publishPage : undefined;
257
- await savePage(createDraft, status).then((isSaved: boolean) => {
258
- if (isSaved) {
259
- resetDirty();
260
- }
261
- });
253
+
254
+ const isSaved = await savePage(createDraft, status);
255
+ if (isSaved) resetDirty();
262
256
  };
263
257
 
264
258
  const goToPages = (path: string) => setRoute(path);
@@ -0,0 +1,61 @@
1
+ import React, { useState } from "react";
2
+
3
+ import { IDomainRobot } from "@ax/types";
4
+ import { FloatingPanel, Button, FieldsBehavior } from "@ax/components";
5
+
6
+ import * as S from "./style";
7
+
8
+ const RobotsPanel = (props: IProps): JSX.Element => {
9
+ const { isOpen, toggleModal, item, setItemContent } = props;
10
+
11
+ const [value, setValue] = useState(item.content);
12
+
13
+ const editItemAction = () => {
14
+ setItemContent(value);
15
+ toggleModal();
16
+ };
17
+
18
+ const resetItem = () => setValue("");
19
+
20
+ const title = item.content ? "Update Robots.txt" : "Add Robots.txt";
21
+
22
+ const editButton = {
23
+ label: title,
24
+ action: editItemAction,
25
+ };
26
+
27
+ const placeholder = "User-agent: * \nDisallow: *";
28
+
29
+ return (
30
+ <FloatingPanel title={title} toggleModal={toggleModal} isOpen={isOpen}>
31
+ <S.Item>
32
+ <S.ItemHeader>You are editing</S.ItemHeader>
33
+ <S.ItemContent>{item.fullUrl}</S.ItemContent>
34
+ </S.Item>
35
+ <FieldsBehavior
36
+ fieldType="TextArea"
37
+ onChange={setValue}
38
+ value={value}
39
+ title="Robots.txt"
40
+ placeholder={placeholder}
41
+ />
42
+ <Button buttonStyle="text" type="button" icon="refresh" disabled={!value} onClick={resetItem}>
43
+ Reset to default
44
+ </Button>
45
+ <S.Footer>
46
+ <Button className="button" type="button" onClick={editButton.action}>
47
+ {editButton.label}
48
+ </Button>
49
+ </S.Footer>
50
+ </FloatingPanel>
51
+ );
52
+ };
53
+
54
+ interface IProps {
55
+ item: IDomainRobot;
56
+ isOpen: boolean;
57
+ toggleModal(): any;
58
+ setItemContent(content: string): void;
59
+ }
60
+
61
+ export default RobotsPanel;
@@ -0,0 +1,30 @@
1
+ import styled from "styled-components";
2
+
3
+ const Item = styled.div`
4
+ background-color: ${(p) => p.theme.color.uiBarBackground};
5
+ padding: ${(p) => p.theme.spacing.s};
6
+ margin-bottom: ${(p) => p.theme.spacing.m};
7
+ border: 1px solid ${(p) => p.theme.color.uiLine};
8
+ box-sizing: border-box;
9
+ border-radius: ${(p) => p.theme.radii.s};
10
+ `;
11
+
12
+ const ItemHeader = styled.div`
13
+ ${(p) => p.theme.textStyle.headingXXS};
14
+ color: ${(p) => p.theme.color.textLowEmphasis};
15
+ margin-bottom: ${(p) => p.theme.spacing.xxs};
16
+ `;
17
+
18
+ const ItemContent = styled.div`
19
+ ${(p) => p.theme.textStyle.fieldContent};
20
+ display: flex;
21
+ color: ${(p) => p.theme.color.textHighEmphasis};
22
+ `;
23
+
24
+ const Footer = styled.div`
25
+ position: absolute;
26
+ bottom: ${(p) => p.theme.spacing.m};
27
+ right: ${(p) => p.theme.spacing.m};
28
+ `;
29
+
30
+ export { Item, ItemHeader, ItemContent, Footer };
@@ -0,0 +1,33 @@
1
+ import React from "react";
2
+
3
+ import { IDomainRobot } from "@ax/types";
4
+ import { useModal } from "@ax/hooks";
5
+ import RobotsPanel from "./RobotsPanel";
6
+
7
+ import * as S from "./style";
8
+
9
+ const Item = (props: IProps): JSX.Element => {
10
+ const { item, setItemContent } = props;
11
+
12
+ const { isOpen, toggleModal } = useModal();
13
+
14
+ const handleClick = () => toggleModal();
15
+
16
+ const buttonText = item.content.trim() !== "" ? "Edit robots.txt" : "Add robots.txt";
17
+
18
+ return (
19
+ <>
20
+ <S.Component onClick={handleClick}>
21
+ {item.fullUrl} <S.Button>{buttonText}</S.Button>
22
+ </S.Component>
23
+ <RobotsPanel item={item} isOpen={isOpen} toggleModal={toggleModal} setItemContent={setItemContent} />
24
+ </>
25
+ );
26
+ };
27
+
28
+ interface IProps {
29
+ item: IDomainRobot;
30
+ setItemContent(content: string): void;
31
+ }
32
+
33
+ export default Item;
@@ -0,0 +1,28 @@
1
+ import styled from "styled-components";
2
+
3
+ const Component = styled.div`
4
+ ${(p) => p.theme.textStyle.fieldLabel};
5
+ color: ${(p) => p.theme.color.textHighEmphasis};
6
+ position: relative;
7
+ display: flex;
8
+ align-items: center;
9
+ width: 100%;
10
+ height: ${(p) => p.theme.spacing.l};
11
+ background: ${(p) => p.theme.color.uiBackground02};
12
+ border: 1px solid transparent;
13
+ margin-bottom: ${(p) => p.theme.spacing.xs};
14
+ padding: 0 ${(p) => p.theme.spacing.s};
15
+ border-radius: ${(p) => p.theme.radii.s};
16
+ box-shadow: ${(p) => p.theme.shadow.shadowS};
17
+ text-align: left;
18
+ cursor: pointer;
19
+ `;
20
+
21
+ const Button = styled.div`
22
+ ${(p) => p.theme.textStyle.uiXS};
23
+ display: flex;
24
+ color: ${(p) => p.theme.color.interactive01};
25
+ margin-left: auto;
26
+ `;
27
+
28
+ export { Component, Button };
@@ -0,0 +1,120 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { connect } from "react-redux";
3
+
4
+ import { IDomainRobot, INavItem, IRootState } from "@ax/types";
5
+ import { appActions } from "@ax/containers/App";
6
+ import { domainsActions } from "@ax/containers/Domains";
7
+ import { MainWrapper, ErrorToast, Nav, Loading } from "@ax/components";
8
+ import { RouteLeavingGuard } from "@ax/guards";
9
+ import { useIsDirty } from "@ax/hooks";
10
+ import Item from "./Item";
11
+
12
+ import * as S from "./style";
13
+
14
+ const Robots = (props: IProps): JSX.Element => {
15
+ const {
16
+ isSaving,
17
+ isLoading,
18
+ navItems,
19
+ currentNavItem,
20
+ robots,
21
+ getDomainsRobots,
22
+ setHistoryPush,
23
+ updateDomainRobots,
24
+ } = props;
25
+
26
+ const [robotItems, setRobotItems] = useState(robots);
27
+ const { isDirty, setIsDirty } = useIsDirty(robotItems);
28
+
29
+ useEffect(() => {
30
+ getDomainsRobots();
31
+ }, [getDomainsRobots]);
32
+
33
+ useEffect(() => {
34
+ setRobotItems(robots);
35
+ }, [robots]);
36
+
37
+ const handleSave = async () => {
38
+ const isSaved = await updateDomainRobots(robotItems);
39
+ if (isSaved) {
40
+ setIsDirty(false);
41
+ }
42
+ };
43
+
44
+ const rightButtonProps = {
45
+ label: isSaving ? "Saving" : "Save",
46
+ disabled: isSaving,
47
+ action: () => handleSave(),
48
+ };
49
+
50
+ const handleMenuClick = (path: string) => {
51
+ setHistoryPush(path);
52
+ };
53
+
54
+ const mapItemList = (items: IDomainRobot[]) =>
55
+ Array.isArray(items) &&
56
+ items.map((item: IDomainRobot, i: number) => {
57
+ const handleSetItem = (newContent: string) => {
58
+ const newItems = [...robotItems];
59
+ newItems[i].content = newContent;
60
+ setRobotItems(newItems);
61
+ };
62
+
63
+ return <Item key={`${item.path}${i}`} item={item} setItemContent={handleSetItem} />;
64
+ });
65
+
66
+ const setRoute = (path: string) => setHistoryPush(path);
67
+ const modalText = (
68
+ <>
69
+ Some robots <strong>are not saved</strong>.{" "}
70
+ </>
71
+ );
72
+
73
+ return (
74
+ <>
75
+ <RouteLeavingGuard when={isDirty} action={setRoute} text={modalText} />
76
+ <MainWrapper backLink={false} title="SEO Settings" rightButton={rightButtonProps}>
77
+ <S.Wrapper>
78
+ <Nav current={currentNavItem} items={navItems} onClick={handleMenuClick} />
79
+ <S.ContentWrapper>
80
+ <ErrorToast />
81
+ <S.Title>Robots.txt editor</S.Title>
82
+ <S.Description>
83
+ You can edit your robots.txt files to show search engines which pages on your site to track.
84
+ </S.Description>
85
+ {isLoading ? <Loading /> : <S.Table>{robotItems && mapItemList(robotItems)}</S.Table>}
86
+ </S.ContentWrapper>
87
+ </S.Wrapper>
88
+ </MainWrapper>
89
+ </>
90
+ );
91
+ };
92
+
93
+ const mapStateToProps = (state: IRootState) => ({
94
+ isSaving: state.app.isSaving,
95
+ isLoading: state.app.isLoading,
96
+ robots: state.domains.robots,
97
+ });
98
+
99
+ const mapDispatchToProps = {
100
+ setHistoryPush: appActions.setHistoryPush,
101
+ getDomainsRobots: domainsActions.getDomainsRobots,
102
+ updateDomainRobots: domainsActions.updateDomainsRobots,
103
+ };
104
+ interface IRobotsProps {
105
+ isSaving: boolean;
106
+ isLoading: boolean;
107
+ navItems: INavItem[];
108
+ currentNavItem: INavItem;
109
+ robots: IDomainRobot[];
110
+ }
111
+
112
+ interface IDispatchProps {
113
+ getDomainsRobots(): void;
114
+ setHistoryPush(path: string, isEditor?: boolean): void;
115
+ updateDomainRobots(robots: IDomainRobot[]): Promise<boolean>;
116
+ }
117
+
118
+ type IProps = IRobotsProps & IDispatchProps;
119
+
120
+ export default connect(mapStateToProps, mapDispatchToProps)(Robots);
@@ -0,0 +1,32 @@
1
+ import styled from "styled-components";
2
+
3
+ const Wrapper = styled.div`
4
+ display: flex;
5
+ height: 100%;
6
+ `;
7
+
8
+ const ContentWrapper = styled.div`
9
+ display: flex;
10
+ overflow: auto;
11
+ flex-direction: column;
12
+ width: 100%;
13
+ padding: ${(p) => p.theme.spacing.m};
14
+ `;
15
+
16
+ const Table = styled.div`
17
+ display: flex;
18
+ flex-direction: column;
19
+ width: 100%;
20
+ margin-top: ${(p) => p.theme.spacing.m};
21
+ `;
22
+
23
+ const Title = styled.div`
24
+ ${(p) => p.theme.textStyle.headingXS};
25
+ margin-bottom: ${(p) => p.theme.spacing.xs};
26
+ `;
27
+
28
+ const Description = styled.div`
29
+ ${(p) => p.theme.textStyle.uiM};
30
+ `;
31
+
32
+ export { Wrapper, ContentWrapper, Table, Title, Description };
@@ -0,0 +1,26 @@
1
+ import React from "react";
2
+ import { Switch, Route } from "react-router-dom";
3
+
4
+ import Robots from "./Robots";
5
+
6
+ const navItems = [
7
+ {
8
+ title: "Robots.txt Editor",
9
+ path: "/settings/robots",
10
+ component: Robots,
11
+ },
12
+ ];
13
+
14
+ const GlobalSettings = (): JSX.Element => {
15
+ return (
16
+ <Switch>
17
+ {navItems.map((item, index) => (
18
+ <Route exact path={item.path} key={index}>
19
+ {React.createElement(item.component, { navItems, currentNavItem: item }, null)}
20
+ </Route>
21
+ ))}
22
+ </Switch>
23
+ );
24
+ };
25
+
26
+ export default GlobalSettings;
@@ -154,11 +154,8 @@ const PageEditor = (props: IProps) => {
154
154
 
155
155
  const handlePublishDraft = async () => {
156
156
  const { savePage } = props;
157
- await savePage(false, null, true).then((isSaved: boolean) => {
158
- if (isSaved) {
159
- resetDirty();
160
- }
161
- });
157
+ const isSaved = await savePage(false, null, true);
158
+ if (isSaved) resetDirty();
162
159
  };
163
160
 
164
161
  const handleDiscardDraft = async () => {