@griddo/ax 1.60.9 → 1.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/package.json +4 -2
  2. package/public/fonts/fonts.css +48 -660
  3. package/public/index.html +19 -16
  4. package/public/templates/template-redirects.csv +2 -0
  5. package/src/GlobalStore.tsx +3 -0
  6. package/src/Style/fonts.tsx +98 -72
  7. package/src/api/analytics.tsx +78 -0
  8. package/src/api/index.tsx +2 -0
  9. package/src/api/redirects.tsx +30 -2
  10. package/src/components/Button/style.tsx +1 -0
  11. package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/Field/index.tsx +1 -1
  12. package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/TemplateManager/index.tsx +4 -3
  13. package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/index.tsx +6 -1
  14. package/src/components/FieldContainer/index.tsx +2 -2
  15. package/src/components/Fields/AnalyticsField/PageAnalytics/atoms.tsx +75 -0
  16. package/src/components/Fields/AnalyticsField/PageAnalytics/index.tsx +139 -0
  17. package/src/components/Fields/AnalyticsField/StructuredDataAnalytics/atoms.tsx +77 -0
  18. package/src/components/Fields/AnalyticsField/StructuredDataAnalytics/index.tsx +89 -0
  19. package/src/components/Fields/AnalyticsField/index.tsx +38 -0
  20. package/src/components/Fields/AnalyticsField/style.tsx +13 -0
  21. package/src/components/Fields/AnalyticsField/utils.tsx +13 -0
  22. package/src/components/Fields/FieldGroup/style.tsx +1 -1
  23. package/src/components/Fields/ImageField/index.tsx +1 -1
  24. package/src/components/Fields/MultiCheckSelect/index.tsx +23 -6
  25. package/src/components/Fields/MultiCheckSelect/style.tsx +1 -0
  26. package/src/components/Fields/NoteField/index.tsx +1 -1
  27. package/src/components/Fields/RadioGroup/index.tsx +4 -3
  28. package/src/components/Fields/RadioGroup/style.tsx +8 -3
  29. package/src/components/Fields/RichText/index.tsx +13 -8
  30. package/src/components/Fields/TextArea/index.tsx +1 -3
  31. package/src/components/Fields/TextArea/style.tsx +3 -3
  32. package/src/components/Fields/UrlField/style.tsx +1 -0
  33. package/src/components/Fields/index.tsx +2 -0
  34. package/src/components/Modal/index.tsx +1 -1
  35. package/src/components/Modal/style.tsx +5 -1
  36. package/src/components/Notification/style.tsx +2 -5
  37. package/src/components/TableFilters/LiveFilter/index.tsx +4 -0
  38. package/src/components/TableFilters/NameFilter/style.tsx +1 -0
  39. package/src/components/TableFilters/TypeFilter/index.tsx +7 -2
  40. package/src/containers/Analytics/actions.tsx +58 -0
  41. package/src/containers/Analytics/constants.tsx +5 -0
  42. package/src/containers/Analytics/index.tsx +4 -0
  43. package/src/containers/Analytics/interfaces.tsx +9 -0
  44. package/src/containers/Analytics/reducer.tsx +26 -0
  45. package/src/containers/PageEditor/actions.tsx +1 -0
  46. package/src/containers/Redirects/actions.tsx +49 -3
  47. package/src/containers/Redirects/constants.tsx +12 -1
  48. package/src/containers/Redirects/interfaces.tsx +11 -1
  49. package/src/containers/Redirects/reducer.tsx +12 -1
  50. package/src/containers/Sites/actions.tsx +3 -0
  51. package/src/global.d.ts +2 -0
  52. package/src/helpers/index.tsx +4 -0
  53. package/src/helpers/requests.tsx +12 -7
  54. package/src/helpers/strings.tsx +13 -0
  55. package/src/hooks/forms.tsx +1 -1
  56. package/src/modules/Analytics/DimensionItem/index.tsx +71 -0
  57. package/src/modules/Analytics/DimensionItem/style.tsx +59 -0
  58. package/src/modules/Analytics/DimensionPanel/index.tsx +110 -0
  59. package/src/modules/Analytics/DimensionPanel/style.tsx +14 -0
  60. package/src/modules/Analytics/GroupItem/index.tsx +75 -0
  61. package/src/modules/Analytics/GroupItem/style.tsx +80 -0
  62. package/src/modules/Analytics/GroupPanel/index.tsx +178 -0
  63. package/src/modules/Analytics/GroupPanel/style.tsx +67 -0
  64. package/src/modules/Analytics/GroupPanel/utils.tsx +29 -0
  65. package/src/modules/Analytics/index.tsx +207 -0
  66. package/src/modules/Analytics/style.tsx +68 -0
  67. package/src/modules/Content/BulkHeader/TableHeader/index.tsx +1 -1
  68. package/src/modules/Content/PageItem/index.tsx +3 -3
  69. package/src/modules/Content/PageItem/style.tsx +1 -1
  70. package/src/modules/Content/hooks.tsx +2 -2
  71. package/src/modules/Content/index.tsx +22 -20
  72. package/src/modules/GlobalEditor/index.tsx +1 -1
  73. package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +2 -2
  74. package/src/modules/PageEditor/index.tsx +1 -1
  75. package/src/modules/Redirects/RedirectItem/index.tsx +6 -2
  76. package/src/modules/Redirects/RedirectPanel/index.tsx +2 -0
  77. package/src/modules/Redirects/atoms.tsx +212 -0
  78. package/src/modules/Redirects/index.tsx +85 -27
  79. package/src/modules/Redirects/style.tsx +124 -3
  80. package/src/modules/Settings/ContentTypes/DataPacks/index.tsx +1 -1
  81. package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +1 -1
  82. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +12 -3
  83. package/src/modules/StructuredData/StructuredDataList/index.tsx +17 -2
  84. package/src/routes/multisite.tsx +20 -2
  85. package/src/schemas/pages/GlobalPage.tsx +75 -64
  86. package/src/schemas/pages/Page.tsx +79 -67
  87. package/src/types/index.tsx +25 -3
  88. package/public/fonts/Source_Sans_Pro-200-cyrillic-ext107.woff2 +0 -0
  89. package/public/fonts/Source_Sans_Pro-200-cyrillic-ext149.woff2 +0 -0
  90. package/public/fonts/Source_Sans_Pro-200-cyrillic108.woff2 +0 -0
  91. package/public/fonts/Source_Sans_Pro-200-cyrillic150.woff2 +0 -0
  92. package/public/fonts/Source_Sans_Pro-200-greek-ext109.woff2 +0 -0
  93. package/public/fonts/Source_Sans_Pro-200-greek-ext151.woff2 +0 -0
  94. package/public/fonts/Source_Sans_Pro-200-greek110.woff2 +0 -0
  95. package/public/fonts/Source_Sans_Pro-200-greek152.woff2 +0 -0
  96. package/public/fonts/Source_Sans_Pro-200-vietnamese111.woff2 +0 -0
  97. package/public/fonts/Source_Sans_Pro-200-vietnamese153.woff2 +0 -0
  98. package/public/fonts/Source_Sans_Pro-300-cyrillic-ext114.woff2 +0 -0
  99. package/public/fonts/Source_Sans_Pro-300-cyrillic-ext156.woff2 +0 -0
  100. package/public/fonts/Source_Sans_Pro-300-cyrillic115.woff2 +0 -0
  101. package/public/fonts/Source_Sans_Pro-300-cyrillic157.woff2 +0 -0
  102. package/public/fonts/Source_Sans_Pro-300-greek-ext116.woff2 +0 -0
  103. package/public/fonts/Source_Sans_Pro-300-greek-ext158.woff2 +0 -0
  104. package/public/fonts/Source_Sans_Pro-300-greek117.woff2 +0 -0
  105. package/public/fonts/Source_Sans_Pro-300-greek159.woff2 +0 -0
  106. package/public/fonts/Source_Sans_Pro-300-vietnamese118.woff2 +0 -0
  107. package/public/fonts/Source_Sans_Pro-300-vietnamese160.woff2 +0 -0
  108. package/public/fonts/Source_Sans_Pro-400-cyrillic-ext121.woff2 +0 -0
  109. package/public/fonts/Source_Sans_Pro-400-cyrillic-ext163.woff2 +0 -0
  110. package/public/fonts/Source_Sans_Pro-400-cyrillic122.woff2 +0 -0
  111. package/public/fonts/Source_Sans_Pro-400-cyrillic164.woff2 +0 -0
  112. package/public/fonts/Source_Sans_Pro-400-greek-ext123.woff2 +0 -0
  113. package/public/fonts/Source_Sans_Pro-400-greek-ext165.woff2 +0 -0
  114. package/public/fonts/Source_Sans_Pro-400-greek124.woff2 +0 -0
  115. package/public/fonts/Source_Sans_Pro-400-greek166.woff2 +0 -0
  116. package/public/fonts/Source_Sans_Pro-400-vietnamese125.woff2 +0 -0
  117. package/public/fonts/Source_Sans_Pro-400-vietnamese167.woff2 +0 -0
  118. package/public/fonts/Source_Sans_Pro-600-cyrillic-ext128.woff2 +0 -0
  119. package/public/fonts/Source_Sans_Pro-600-cyrillic-ext170.woff2 +0 -0
  120. package/public/fonts/Source_Sans_Pro-600-cyrillic129.woff2 +0 -0
  121. package/public/fonts/Source_Sans_Pro-600-cyrillic171.woff2 +0 -0
  122. package/public/fonts/Source_Sans_Pro-600-greek-ext130.woff2 +0 -0
  123. package/public/fonts/Source_Sans_Pro-600-greek-ext172.woff2 +0 -0
  124. package/public/fonts/Source_Sans_Pro-600-greek131.woff2 +0 -0
  125. package/public/fonts/Source_Sans_Pro-600-greek173.woff2 +0 -0
  126. package/public/fonts/Source_Sans_Pro-600-vietnamese132.woff2 +0 -0
  127. package/public/fonts/Source_Sans_Pro-600-vietnamese174.woff2 +0 -0
  128. package/public/fonts/Source_Sans_Pro-700-cyrillic-ext135.woff2 +0 -0
  129. package/public/fonts/Source_Sans_Pro-700-cyrillic-ext177.woff2 +0 -0
  130. package/public/fonts/Source_Sans_Pro-700-cyrillic136.woff2 +0 -0
  131. package/public/fonts/Source_Sans_Pro-700-cyrillic178.woff2 +0 -0
  132. package/public/fonts/Source_Sans_Pro-700-greek-ext137.woff2 +0 -0
  133. package/public/fonts/Source_Sans_Pro-700-greek-ext179.woff2 +0 -0
  134. package/public/fonts/Source_Sans_Pro-700-greek138.woff2 +0 -0
  135. package/public/fonts/Source_Sans_Pro-700-greek180.woff2 +0 -0
  136. package/public/fonts/Source_Sans_Pro-700-vietnamese139.woff2 +0 -0
  137. package/public/fonts/Source_Sans_Pro-700-vietnamese181.woff2 +0 -0
  138. package/public/fonts/Source_Sans_Pro-900-cyrillic-ext142.woff2 +0 -0
  139. package/public/fonts/Source_Sans_Pro-900-cyrillic-ext184.woff2 +0 -0
  140. package/public/fonts/Source_Sans_Pro-900-cyrillic143.woff2 +0 -0
  141. package/public/fonts/Source_Sans_Pro-900-cyrillic185.woff2 +0 -0
  142. package/public/fonts/Source_Sans_Pro-900-greek-ext144.woff2 +0 -0
  143. package/public/fonts/Source_Sans_Pro-900-greek-ext186.woff2 +0 -0
  144. package/public/fonts/Source_Sans_Pro-900-greek145.woff2 +0 -0
  145. package/public/fonts/Source_Sans_Pro-900-greek187.woff2 +0 -0
  146. package/public/fonts/Source_Sans_Pro-900-vietnamese146.woff2 +0 -0
  147. package/public/fonts/Source_Sans_Pro-900-vietnamese188.woff2 +0 -0
@@ -26,6 +26,7 @@ import { appActions } from "@ax/containers/App";
26
26
  import { structuredDataActions } from "@ax/containers/StructuredData";
27
27
  import { navigationActions, menuActions } from "@ax/containers/Navigation";
28
28
  import { pageEditorActions } from "@ax/containers/PageEditor";
29
+ import { analyticsActions } from "@ax/containers/Analytics";
29
30
  import { dataPacksActions } from "@ax/containers/Settings/DataPacks";
30
31
  import { socialActions } from "@ax/containers/Settings/Social";
31
32
  import { handleRequest, isReqOk, sortBy } from "@ax/helpers";
@@ -34,6 +35,7 @@ const { setIsLoading, setIsSaving, setLanguage } = appActions;
34
35
  const { resetDefaultsValues } = navigationActions;
35
36
  const { resetPageEditor } = pageEditorActions;
36
37
  const { resetMenuValues } = menuActions;
38
+ const { getAnalytics } = analyticsActions;
37
39
 
38
40
  function setSites(sitesList: ISite[]): ISetSitesAction {
39
41
  return { type: SET_SITES, payload: { sites: sitesList } };
@@ -345,6 +347,7 @@ const resetSiteValues = (dispatch: Dispatch) => {
345
347
  resetMenuValues(dispatch);
346
348
  dispatch(setCurrentSitePages([]));
347
349
  dispatch(setTotalItems(0));
350
+ getAnalytics()(dispatch);
348
351
  };
349
352
 
350
353
  function saveCurrentSiteInfo(): (dispatch: Dispatch, getState: any) => Promise<void> {
package/src/global.d.ts CHANGED
@@ -7,3 +7,5 @@ declare module "is-wsl";
7
7
  declare module "react-draft-wysiwyg";
8
8
  declare module "history";
9
9
  declare module "@griddo/core";
10
+ declare module "draftjs-to-html";
11
+ declare module "html-to-draftjs";
@@ -17,6 +17,8 @@ import {
17
17
  decodeEntities,
18
18
  isNumber,
19
19
  getFileExtension,
20
+ splitAndJoin,
21
+ splitAndTrim,
20
22
  } from "./strings";
21
23
 
22
24
  import {
@@ -152,4 +154,6 @@ export {
152
154
  getFileExtension,
153
155
  moveArrayElement,
154
156
  isDevelopment,
157
+ splitAndJoin,
158
+ splitAndTrim,
155
159
  };
@@ -13,13 +13,18 @@ function handleRequest(callback: any, responseActions: any, loadingActions: any[
13
13
 
14
14
  const response = await callback();
15
15
 
16
- let result = false;
17
- if (isReqOk(response.status)) {
18
- handleSuccess(response.data);
19
- result = true;
20
- } else {
21
- handleError(response);
22
- }
16
+ const responseArr = Array.isArray(response) ? response : [response];
17
+
18
+ let result = true;
19
+
20
+ responseArr.forEach((response) => {
21
+ if (!isReqOk(response.status)) {
22
+ result = false;
23
+ handleError(response);
24
+ }
25
+ })
26
+
27
+ if (result) handleSuccess(response.data);
23
28
 
24
29
  loadingActions.map(action => dispatch(action(false)));
25
30
 
@@ -81,6 +81,17 @@ const getFileExtension = (fileName: string): string | null => {
81
81
  return extension && extension[0].slice(1);
82
82
  };
83
83
 
84
+ const splitAndJoin = (str = "", splitterIn = ",", splitterOut = ", "): string => {
85
+ return str?.split(splitterIn)
86
+ .map((str: string) => str.trim())
87
+ .filter((str: string) => str.length)
88
+ .join(splitterOut) || "";
89
+ }
90
+
91
+ const splitAndTrim = (str?: string, splitter = ","): (string | never)[] => {
92
+ return str?.split(splitter).map((str: string) => str.trim()).filter((str: string) => str.length) || [];
93
+ }
94
+
84
95
  export {
85
96
  filterImageText,
86
97
  splitCamelCase,
@@ -93,4 +104,6 @@ export {
93
104
  decodeEntities,
94
105
  isNumber,
95
106
  getFileExtension,
107
+ splitAndJoin,
108
+ splitAndTrim,
96
109
  };
@@ -116,7 +116,7 @@ const useIsDirty = (
116
116
  }
117
117
 
118
118
  if (isNew) {
119
- setIsDirty(true);
119
+ setIsDirty(false);
120
120
  } else if (prevContent && updatedValues) {
121
121
  const isUpdated = hasChanged();
122
122
 
@@ -0,0 +1,71 @@
1
+ import React from "react";
2
+
3
+ import { IDimension } from "@ax/types";
4
+ import { useModal } from "@ax/hooks";
5
+ import { splitAndJoin, trimText } from "@ax/helpers";
6
+ import { Modal } from "@ax/components";
7
+
8
+ import DimensionPanel from "../DimensionPanel";
9
+ import * as S from "./style";
10
+
11
+ const Item = (props: IProps): JSX.Element => {
12
+ const { item, setDimensionItem, removeDimension } = props;
13
+
14
+ const { isOpen, toggleModal } = useModal();
15
+ const { isOpen: isRemoveOpen, toggleModal: toggleRemoveModal } = useModal();
16
+
17
+ const handleClick = () => toggleModal();
18
+
19
+ const values = splitAndJoin(item.values, ";", "; ");
20
+ const hasValues = !["", "null"].includes(values);
21
+ const valuesText = hasValues ? values : "The value is defined on page";
22
+
23
+ const dimensionOptions = [
24
+ {
25
+ label: "Delete",
26
+ icon: "delete",
27
+ action: toggleRemoveModal,
28
+ },
29
+ ];
30
+
31
+ const mainRemoveModalAction = {
32
+ title: "Delete Dimension",
33
+ onClick: removeDimension,
34
+ };
35
+
36
+ const secondaryRemoveModalAction = { title: "Cancel", onClick: toggleRemoveModal };
37
+
38
+ return (
39
+ <>
40
+ <S.Component onClick={handleClick}>
41
+ <S.Name>{item.name}</S.Name><S.Values>{trimText(valuesText, 75)}</S.Values>
42
+ <S.StyledActionMenu icon="more" options={dimensionOptions} tooltip="Dimension actions" />
43
+ </S.Component>
44
+ <DimensionPanel item={item} isOpen={isOpen} toggleModal={toggleModal} setDimensionItem={setDimensionItem} />
45
+ <Modal
46
+ isOpen={isRemoveOpen}
47
+ hide={toggleRemoveModal}
48
+ title="Delete Dimension?"
49
+ secondaryAction={secondaryRemoveModalAction}
50
+ mainAction={mainRemoveModalAction}
51
+ size="S"
52
+ >
53
+ <S.ModalContent>
54
+ <p>
55
+ Are you sure you want to delete <strong>{item.name} dimension</strong>? If you delete it, this dimension will no longer be measurable.
56
+ <br />
57
+ This action <strong>cannot be undone</strong>.
58
+ </p>
59
+ </S.ModalContent>
60
+ </Modal>
61
+ </>
62
+ );
63
+ };
64
+
65
+ interface IProps {
66
+ item: IDimension;
67
+ setDimensionItem(content: IDimension): void;
68
+ removeDimension: () => void;
69
+ }
70
+
71
+ export default Item;
@@ -0,0 +1,59 @@
1
+ import styled from "styled-components";
2
+ import { ActionMenu } from "@ax/components";
3
+
4
+ const StyledActionMenu = styled(ActionMenu)`
5
+ opacity: 0;
6
+ width: 32px;
7
+ display: flex;
8
+ margin-left: auto;
9
+ `;
10
+
11
+ const Component = styled.div`
12
+ ${(p) => p.theme.textStyle.fieldLabel};
13
+ color: ${(p) => p.theme.color.textHighEmphasis};
14
+ position: relative;
15
+ display: flex;
16
+ align-items: center;
17
+ width: 100%;
18
+ height: ${(p) => p.theme.spacing.l};
19
+ background: ${(p) => p.theme.color.uiBackground02};
20
+ border: 1px solid transparent;
21
+ margin-bottom: ${(p) => p.theme.spacing.xs};
22
+ padding: 0 ${(p) => p.theme.spacing.s};
23
+ border-radius: ${(p) => p.theme.radii.s};
24
+ box-shadow: ${(p) => p.theme.shadow.shadowS};
25
+ text-align: left;
26
+ cursor: pointer;
27
+
28
+ &:hover {
29
+ background: ${(p) => p.theme.color.overlayHoverPrimary};
30
+ }
31
+
32
+ &:hover ${StyledActionMenu} {
33
+ opacity: 1;
34
+ }
35
+ `;
36
+
37
+ const Name = styled.div`
38
+ ${(p) => p.theme.textStyle.fieldLabel};
39
+ color: ${(p) => p.theme.color.textHighEmphasis};
40
+ width: 40%;
41
+ `
42
+
43
+ const Values = styled.div`
44
+ ${(p) => p.theme.textStyle.uiXS};
45
+ color: ${(p) => p.theme.color.textMediumEmphasis};
46
+ `
47
+
48
+ const Button = styled.div`
49
+ ${(p) => p.theme.textStyle.uiXS};
50
+ display: flex;
51
+ color: ${(p) => p.theme.color.interactive01};
52
+ margin-left: auto;
53
+ `;
54
+
55
+ const ModalContent = styled.div`
56
+ padding: ${(p) => p.theme.spacing.m};
57
+ `;
58
+
59
+ export { Component, Button, Name, Values, StyledActionMenu, ModalContent };
@@ -0,0 +1,110 @@
1
+ import React, { useEffect, useState } from "react";
2
+
3
+ import { IDimension } from "@ax/types";
4
+ import { FloatingPanel, Button, FieldsBehavior, NoteField } from "@ax/components";
5
+ import { camelize, splitAndJoin } from "@ax/helpers";
6
+
7
+ import * as S from "./style";
8
+
9
+ const DimensionPanel = (props: IProps): JSX.Element => {
10
+ const { isOpen, toggleModal, item, setDimensionItem } = props;
11
+
12
+ const [type, setType] = useState("dimensionsAndValues");
13
+ const [name, setName] = useState("");
14
+ const [values, setValues] = useState("");
15
+
16
+ const resetState = () => {
17
+ setType("dimensionsAndValues");
18
+ setName(item?.name || "");
19
+
20
+ const values = splitAndJoin(item?.values, ";", ";");
21
+ const _values = values === "null" ? "" : values;
22
+ setValues(_values || "");
23
+ }
24
+
25
+ useEffect(() => {
26
+ isOpen && resetState();
27
+ // eslint-disable-next-line react-hooks/exhaustive-deps
28
+ }, [isOpen]);
29
+
30
+ useEffect(() => {
31
+ type === "onlyDimensions" && setValues("")
32
+ }, [type]);
33
+
34
+ const editItemAction = () => {
35
+ setDimensionItem({ ...item, name: camelize(name), values });
36
+ toggleModal();
37
+ };
38
+
39
+ const title = item ? "Update Dimension" : "Add Dimension";
40
+
41
+ const editButton = {
42
+ label: title,
43
+ action: editItemAction,
44
+ };
45
+
46
+ const typeOptions = [
47
+ {
48
+ title: "Dimensions & Values",
49
+ name: "dimensionsAndValues",
50
+ value: "dimensionsAndValues",
51
+ },
52
+ {
53
+ title: "Only Dimensions",
54
+ name: "onlyDimensions",
55
+ value: "onlyDimensions",
56
+ },
57
+ ];
58
+
59
+ const noteTitle = "Dimensions & Values"
60
+ const noteText = "Create a dimension and its values. You define the values now and select them on any page later. Your analytics data will be homogeneous avoiding duplicates that might cause inaccurate data results."
61
+
62
+ return (
63
+ <FloatingPanel title={title} toggleModal={toggleModal} isOpen={isOpen}>
64
+ <FieldsBehavior
65
+ name="removeItemChildren"
66
+ fieldType="RadioGroup"
67
+ title="Dimension type"
68
+ value={type}
69
+ options={typeOptions}
70
+ onChange={setType}
71
+ mandatory
72
+ />
73
+ <S.NoteWrapper>
74
+ <NoteField value={{ text: noteText, title: noteTitle }} />
75
+ </S.NoteWrapper>
76
+ <FieldsBehavior
77
+ title="Dimension"
78
+ name="name"
79
+ fieldType="TextField"
80
+ value={name}
81
+ onChange={setName}
82
+ mandatory
83
+ />
84
+ {type === "dimensionsAndValues" ? (
85
+ <FieldsBehavior
86
+ title="Values"
87
+ name="values"
88
+ fieldType="TextArea"
89
+ value={values}
90
+ onChange={setValues}
91
+ mandatory
92
+ />
93
+ ) : <></>}
94
+ <S.Footer>
95
+ <Button className="button" type="button" onClick={editButton.action}>
96
+ {editButton.label}
97
+ </Button>
98
+ </S.Footer>
99
+ </FloatingPanel>
100
+ );
101
+ };
102
+
103
+ interface IProps {
104
+ item?: IDimension;
105
+ isOpen: boolean;
106
+ toggleModal: () => void;
107
+ setDimensionItem(content: IDimension): void;
108
+ }
109
+
110
+ export default DimensionPanel;
@@ -0,0 +1,14 @@
1
+ import styled from "styled-components";
2
+
3
+ const Footer = styled.div`
4
+ position: absolute;
5
+ bottom: ${(p) => p.theme.spacing.m};
6
+ right: ${(p) => p.theme.spacing.m};
7
+ `;
8
+
9
+ const NoteWrapper = styled.div`
10
+ margin-bottom: ${(p) => p.theme.spacing.m};
11
+
12
+ `
13
+
14
+ export { Footer, NoteWrapper };
@@ -0,0 +1,75 @@
1
+ import React from "react";
2
+
3
+ import { IDimension, IDimensionsGroup } from "@ax/types";
4
+ import { useModal } from "@ax/hooks";
5
+ import { splitAndJoin } from "@ax/helpers";
6
+ import { Modal } from "@ax/components";
7
+
8
+ import GroupPanel from "../GroupPanel";
9
+ import * as S from "./style";
10
+
11
+ const Item = (props: IProps): JSX.Element => {
12
+ const { item, setGroupItem, dimensions, removeGroup } = props;
13
+
14
+ const { isOpen, toggleModal } = useModal();
15
+ const { isOpen: isRemoveOpen, toggleModal: toggleRemoveModal } = useModal();
16
+
17
+ const handleClick = () => toggleModal();
18
+
19
+ const contentType = splitAndJoin(item.templates, ";", ", ");
20
+ const hasContentType = !["null", ""].includes(contentType);
21
+ const contentTypeText = hasContentType ? "Content Type" : "No Content Type";
22
+
23
+ const groupOptions = [
24
+ {
25
+ label: "Delete",
26
+ icon: "delete",
27
+ action: toggleRemoveModal,
28
+ },
29
+ ];
30
+
31
+ const mainRemoveModalAction = {
32
+ title: "Delete Group",
33
+ onClick: removeGroup,
34
+ };
35
+
36
+ const secondaryRemoveModalAction = { title: "Cancel", onClick: toggleRemoveModal };
37
+
38
+ return (
39
+ <>
40
+ <S.Component onClick={handleClick}>
41
+ <S.Name>{item.name}</S.Name>
42
+ <S.ComponentInfo>
43
+ <S.Values>{contentTypeText}{hasContentType && <S.ContentType>{contentType}</S.ContentType>}</S.Values>
44
+ <S.StyledActionMenu icon="more" options={groupOptions} tooltip="Dimensions group actions" />
45
+ </S.ComponentInfo>
46
+ </S.Component>
47
+ <GroupPanel item={item} isOpen={isOpen} toggleModal={toggleModal} setGroupItem={setGroupItem} dimensions={dimensions} />
48
+ <Modal
49
+ isOpen={isRemoveOpen}
50
+ hide={toggleRemoveModal}
51
+ title="Delete Group?"
52
+ secondaryAction={secondaryRemoveModalAction}
53
+ mainAction={mainRemoveModalAction}
54
+ size="S"
55
+ >
56
+ <S.ModalContent>
57
+ <p>
58
+ Are you sure you want to delete <strong>{item.name} dimensions</strong>? If you delete it, you will no longer be able to use it.
59
+ <br />
60
+ This action <strong>cannot be undone</strong>.
61
+ </p>
62
+ </S.ModalContent>
63
+ </Modal>
64
+ </>
65
+ );
66
+ };
67
+
68
+ interface IProps {
69
+ item: IDimensionsGroup;
70
+ setGroupItem(content: IDimensionsGroup): void;
71
+ dimensions: IDimension[];
72
+ removeGroup: () => void;
73
+ }
74
+
75
+ export default Item;
@@ -0,0 +1,80 @@
1
+ import styled from "styled-components";
2
+ import { ActionMenu } from "@ax/components";
3
+
4
+ const StyledActionMenu = styled(ActionMenu)`
5
+ opacity: 0;
6
+ width: 32px;
7
+ display: flex;
8
+ margin-left: ${(p) => p.theme.spacing.s};
9
+ `;
10
+
11
+ const Component = styled.div`
12
+ ${(p) => p.theme.textStyle.fieldLabel};
13
+ color: ${(p) => p.theme.color.textHighEmphasis};
14
+ position: relative;
15
+ display: flex;
16
+ align-items: center;
17
+ justify-content: space-between;
18
+ width: 100%;
19
+ height: ${(p) => p.theme.spacing.l};
20
+ background: ${(p) => p.theme.color.uiBackground02};
21
+ border: 1px solid transparent;
22
+ margin-bottom: ${(p) => p.theme.spacing.xs};
23
+ padding: 0 ${(p) => p.theme.spacing.s};
24
+ border-radius: ${(p) => p.theme.radii.s};
25
+ box-shadow: ${(p) => p.theme.shadow.shadowS};
26
+ text-align: left;
27
+ cursor: pointer;
28
+
29
+ &:hover {
30
+ background: ${(p) => p.theme.color.overlayHoverPrimary};
31
+ }
32
+
33
+ &:hover ${StyledActionMenu} {
34
+ opacity: 1;
35
+ }
36
+ `;
37
+
38
+ const Name = styled.div`
39
+ ${(p) => p.theme.textStyle.fieldLabel};
40
+ color: ${(p) => p.theme.color.textHighEmphasis};
41
+ `
42
+
43
+ const Values = styled.div`
44
+ display: flex;
45
+ ${(p) => p.theme.textStyle.uiXS};
46
+ color: ${(p) => p.theme.color.textMediumEmphasis};
47
+ `
48
+
49
+ const Button = styled.div`
50
+ ${(p) => p.theme.textStyle.uiXS};
51
+ display: flex;
52
+ color: ${(p) => p.theme.color.interactive01};
53
+ margin-left: auto;
54
+ `;
55
+
56
+ const ContentType = styled.div`
57
+ margin-left: ${(p) => p.theme.spacing.xxs};
58
+ ${(p) => p.theme.textStyle.uiXS};
59
+ color: ${(p) => p.theme.color.interactive01};
60
+ `
61
+
62
+ const ModalContent = styled.div`
63
+ padding: ${(p) => p.theme.spacing.m};
64
+ `;
65
+
66
+ const ComponentInfo = styled.div`
67
+ display: flex;
68
+ align-items: center;
69
+ `
70
+
71
+ export {
72
+ Component,
73
+ Button,
74
+ Name,
75
+ Values,
76
+ ContentType,
77
+ StyledActionMenu,
78
+ ModalContent,
79
+ ComponentInfo
80
+ };
@@ -0,0 +1,178 @@
1
+ import React, { useState, useEffect } from "react";
2
+
3
+ import { IDimension, IDimensionsGroup } from "@ax/types";
4
+ import { FloatingPanel, Button, FieldsBehavior, CheckGroup, RadioGroup } from "@ax/components";
5
+ import { splitAndTrim } from "@ax/helpers";
6
+
7
+ import * as S from "./style";
8
+ import { getTemplateOptions } from "./utils";
9
+
10
+ const GroupPanel = (props: IProps): JSX.Element => {
11
+ const { isOpen, toggleModal, item, setGroupItem, dimensions } = props;
12
+
13
+ const [name, setName] = useState("");
14
+ const [selectedDimensions, setSelectedDimensions] = useState<(string | never)[]>(["all"]);
15
+ const [selectedTemplates, setSelectedTemplates] = useState<(string | never)[]>([]);
16
+ const [hasTemplate, setHasTemplate] = useState(false);
17
+
18
+ const templates = getTemplateOptions();
19
+ const resetState = () => {
20
+ setName(item?.name || "");
21
+
22
+ const dimensionOptions = [];
23
+ const dimensionsArr = splitAndTrim(item?.dimensions, ";");
24
+ const isAllDimensions = dimensionsArr.length === dimensions.length;
25
+ (!item || isAllDimensions)
26
+ ? dimensionOptions.push("all")
27
+ : dimensionOptions.push(...dimensionsArr);
28
+ setSelectedDimensions(dimensionOptions);
29
+
30
+ const templateOptions = [];
31
+ const templatesArr = splitAndTrim(item?.templates, ";");
32
+ !!item && templateOptions.push(...templatesArr);
33
+ const _templateOptions = templateOptions.filter((option) => option !== "null");
34
+ setSelectedTemplates(_templateOptions);
35
+
36
+ const hasTemplate = !!templateOptions.length && !templateOptions.includes("null");
37
+ setHasTemplate(hasTemplate);
38
+ }
39
+
40
+ useEffect(() => {
41
+ isOpen && resetState();
42
+ // eslint-disable-next-line react-hooks/exhaustive-deps
43
+ }, [isOpen]);
44
+
45
+ const editItemAction = () => {
46
+ const dimensionsArr = selectedDimensions.includes("all")
47
+ ? dimensions.map((dimension) => dimension.name)
48
+ : selectedDimensions;
49
+ const dimensionsStr = `;${dimensionsArr.join(";")}`;
50
+ const templatesStr = `;${selectedTemplates.join(";")}`;
51
+
52
+ const value = {
53
+ ...item,
54
+ name,
55
+ dimensions: dimensionsStr,
56
+ templates: templatesStr
57
+ };
58
+ setGroupItem(value);
59
+
60
+ toggleModal();
61
+ };
62
+
63
+ const title = item ? "Update Dimensions Group" : "Create Dimensions Group";
64
+
65
+ const editButton = {
66
+ label: title,
67
+ action: editItemAction,
68
+ };
69
+
70
+ const initialDimensionOption = {
71
+ name: "all",
72
+ value: "all",
73
+ title: "All Dimensions",
74
+ };
75
+ const dimensionOptions = [{ ...initialDimensionOption }];
76
+ dimensions?.forEach((dimension) => {
77
+ const { name } = dimension;
78
+ const option = { name, value: name, title: name };
79
+ return dimensionOptions.push(option);
80
+ });
81
+
82
+ const setDimensions = (selection: any) => {
83
+ if (!selection.length) selection = ["all"];
84
+ setSelectedDimensions([...selection]);
85
+ }
86
+
87
+ const setTemplates = (selection: any) => {
88
+ setSelectedTemplates([...selection]);
89
+ }
90
+
91
+ const selectedDimensionsN = selectedDimensions.includes("all")
92
+ ? dimensions?.length
93
+ : selectedDimensions.length;
94
+
95
+ const hasTemplateOpts = [
96
+ {
97
+ title: "No",
98
+ value: "no",
99
+ name: "no",
100
+ },
101
+ {
102
+ title: "Yes",
103
+ value: "yes",
104
+ name: "yes",
105
+ },
106
+ ];
107
+ const handleChangeHasTemplate = (value: string | boolean) => {
108
+ const hasTemplate = value === "yes";
109
+ setHasTemplate(hasTemplate);
110
+ !hasTemplate && setSelectedTemplates([]);
111
+
112
+ }
113
+
114
+ return (
115
+ <FloatingPanel title={title} toggleModal={toggleModal} isOpen={isOpen}>
116
+ <S.ContentWrapper>
117
+ <FieldsBehavior
118
+ title="Dimension"
119
+ name="name"
120
+ fieldType="TextField"
121
+ value={name}
122
+ onChange={setName}
123
+ mandatory
124
+ />
125
+ <S.Divider />
126
+ <S.Heading>
127
+ <S.HeadingText>Dimensions</S.HeadingText>
128
+ <S.HeadingCounter>{selectedDimensionsN}/{dimensions?.length}</S.HeadingCounter>
129
+ </S.Heading>
130
+ <S.Description>Select the dimensions to this content.</S.Description>
131
+ <CheckGroup
132
+ options={dimensionOptions}
133
+ value={selectedDimensions}
134
+ onChange={setDimensions}
135
+ selectAllOption="all"
136
+ />
137
+ <S.Divider />
138
+ <S.Heading $spaceBetween>
139
+ <S.HeadingText>Dimensions</S.HeadingText>
140
+ <S.RadioTemplate>
141
+ <RadioGroup
142
+ name="hasTemplate"
143
+ value={hasTemplate ? "yes" : "no"}
144
+ options={hasTemplateOpts}
145
+ onChange={handleChangeHasTemplate}
146
+ inline
147
+ />
148
+ </S.RadioTemplate>
149
+ </S.Heading>
150
+ <S.Description>If you create a page of this template, it will appear with these dimensions by default.</S.Description>
151
+ {hasTemplate ? (
152
+ <CheckGroup
153
+ options={templates}
154
+ value={selectedTemplates}
155
+ onChange={setTemplates}
156
+ />
157
+ ) : (
158
+ <></>
159
+ )}
160
+ </S.ContentWrapper>
161
+ <S.Footer>
162
+ <Button className="button" type="button" onClick={editButton.action}>
163
+ {editButton.label}
164
+ </Button>
165
+ </S.Footer>
166
+ </FloatingPanel>
167
+ );
168
+ };
169
+
170
+ interface IProps {
171
+ item?: IDimensionsGroup;
172
+ isOpen: boolean;
173
+ toggleModal: () => void;
174
+ setGroupItem(content: IDimensionsGroup): void;
175
+ dimensions: IDimension[];
176
+ }
177
+
178
+ export default GroupPanel;