@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
@@ -0,0 +1,78 @@
1
+ import { IDimension, IDimensionsGroup } from "@ax/types";
2
+ import { AxiosResponse } from "axios";
3
+ import { template } from "./config";
4
+ import { IServiceConfig, sendRequest } from "./utils";
5
+
6
+ const SERVICES: { [key: string]: IServiceConfig } = {
7
+ GET_ANALYTICS: {
8
+ ...template,
9
+ endpoint: ["/site/", "/analytics"],
10
+ method: "GET",
11
+ },
12
+ UPDATE_SCRIPT_CODE: {
13
+ ...template,
14
+ endpoint: ["/site/", "/analytics/script"],
15
+ method: "PUT",
16
+ },
17
+ CREATE_DIMENSIONS: {
18
+ ...template,
19
+ endpoint: ["/analytics/dimensions/site/", "/bulk"],
20
+ method: "POST",
21
+ },
22
+ CREATE_DIMENSIONS_GROUPS: {
23
+ ...template,
24
+ endpoint: ["/analytics/groups/site/", "/bulk"],
25
+ method: "POST",
26
+ },
27
+ };
28
+
29
+ const getAnalytics = async (siteId: number | string): Promise<AxiosResponse> => {
30
+ const {
31
+ host,
32
+ endpoint: [prefix, suffix],
33
+ } = SERVICES.GET_ANALYTICS;
34
+
35
+ SERVICES.GET_ANALYTICS.dynamicUrl = `${host}${prefix}${siteId}${suffix}`;
36
+
37
+ return sendRequest(SERVICES.GET_ANALYTICS);
38
+ };
39
+
40
+ const updateScriptCode = async (siteId: number | string, data: { scriptCode: string }): Promise<AxiosResponse> => {
41
+ const {
42
+ host,
43
+ endpoint: [prefix, suffix],
44
+ } = SERVICES.UPDATE_SCRIPT_CODE;
45
+
46
+ SERVICES.UPDATE_SCRIPT_CODE.dynamicUrl = `${host}${prefix}${siteId}${suffix}`;
47
+
48
+ return sendRequest(SERVICES.UPDATE_SCRIPT_CODE, { ...data });
49
+ };
50
+
51
+ const createDimensions = async (siteId: number | string, data: { dimensions: IDimension[] }): Promise<AxiosResponse> => {
52
+ const {
53
+ host,
54
+ endpoint: [prefix, suffix],
55
+ } = SERVICES.CREATE_DIMENSIONS;
56
+
57
+ SERVICES.CREATE_DIMENSIONS.dynamicUrl = `${host}${prefix}${siteId}${suffix}`;
58
+
59
+ return sendRequest(SERVICES.CREATE_DIMENSIONS, { ...data });
60
+ };
61
+
62
+ const createDimensionsGroups = async (siteId: number | string, data: { groups: IDimensionsGroup[] }): Promise<AxiosResponse> => {
63
+ const {
64
+ host,
65
+ endpoint: [prefix, suffix],
66
+ } = SERVICES.CREATE_DIMENSIONS_GROUPS;
67
+
68
+ SERVICES.CREATE_DIMENSIONS_GROUPS.dynamicUrl = `${host}${prefix}${siteId}${suffix}`;
69
+
70
+ return sendRequest(SERVICES.CREATE_DIMENSIONS_GROUPS, { ...data });
71
+ };
72
+
73
+ export default {
74
+ getAnalytics,
75
+ updateScriptCode,
76
+ createDimensions,
77
+ createDimensionsGroups
78
+ };
package/src/api/index.tsx CHANGED
@@ -15,6 +15,7 @@ import files from "./files";
15
15
  import users from "./users";
16
16
  import domains from "./domains";
17
17
  import redirects from "./redirects";
18
+ import analytics from "./analytics";
18
19
 
19
20
  export {
20
21
  sites,
@@ -34,4 +35,5 @@ export {
34
35
  users,
35
36
  domains,
36
37
  redirects,
38
+ analytics
37
39
  };
@@ -27,6 +27,16 @@ const SERVICES: { [key: string]: IServiceConfig } = {
27
27
  endpoint: "/redirects/bulk",
28
28
  method: "DELETE",
29
29
  },
30
+ CREATE_REDIRECT_BULK_CHECK: {
31
+ ...template,
32
+ endpoint: "/redirect/bulk/check",
33
+ method: "POST",
34
+ },
35
+ CREATE_REDIRECT_BULK: {
36
+ ...template,
37
+ endpoint: "/redirect/bulk",
38
+ method: "POST",
39
+ },
30
40
  };
31
41
 
32
42
  const getRedirects = async (params: any, filters?: string) => {
@@ -34,7 +44,9 @@ const getRedirects = async (params: any, filters?: string) => {
34
44
 
35
45
  const { host, endpoint } = SERVICES.GET_REDIRECTS;
36
46
 
37
- SERVICES.GET_REDIRECTS.dynamicUrl = `${host}${endpoint}?page=${page}&itemsPerPage=${itemsPerPage}&pagination=${pagination}${filters}`;
47
+ const filterString = filters || "";
48
+
49
+ SERVICES.GET_REDIRECTS.dynamicUrl = `${host}${endpoint}?page=${page}&itemsPerPage=${itemsPerPage}&pagination=${pagination}${filterString}`;
38
50
 
39
51
  return sendRequest(SERVICES.GET_REDIRECTS);
40
52
  };
@@ -68,4 +80,20 @@ const deleteRedirectsBulk = async (ids: number[]) => {
68
80
  return sendRequest(SERVICES.DELETE_REDIRECT_BULK, { ids });
69
81
  };
70
82
 
71
- export default { getRedirects, createRedirect, updateRedirect, deleteRedirect, deleteRedirectsBulk };
83
+ const createRedirectsBulkCheck = async (redirects: any[]) => {
84
+ return sendRequest(SERVICES.CREATE_REDIRECT_BULK_CHECK, { redirects });
85
+ };
86
+
87
+ const createRedirectsBulk = async (redirects: any[]) => {
88
+ return sendRequest(SERVICES.CREATE_REDIRECT_BULK, { redirects });
89
+ };
90
+
91
+ export default {
92
+ getRedirects,
93
+ createRedirect,
94
+ updateRedirect,
95
+ deleteRedirect,
96
+ deleteRedirectsBulk,
97
+ createRedirectsBulk,
98
+ createRedirectsBulkCheck,
99
+ };
@@ -4,6 +4,7 @@ export const Button = styled.button`
4
4
  ${(p) => p.theme.textStyle.uiButton};
5
5
  background-color: ${(p) => p.theme.color.interactive01};
6
6
  border-radius: 4px;
7
+ z-index: 0;
7
8
  border: none;
8
9
  color: ${p => p.theme.colors.uiBackground02};
9
10
  min-height: calc(${(p) => p.theme.spacing.s} * 2);
@@ -77,7 +77,7 @@ interface IProps {
77
77
  readonly?: boolean;
78
78
  activatedModules?: string[];
79
79
  isTemplateActivated: boolean;
80
- updateValue: any;
80
+ updateValue: (key: string, value: any, templateID?: number, slugTo?: string) => void;
81
81
  categories?: any;
82
82
  error?: IErrorItem;
83
83
  deleteError(error: IErrorItem): void;
@@ -32,12 +32,13 @@ export const TemplateManager = (props: IProps): JSX.Element => {
32
32
  const modulesDataPacks = activatedPacks.map((pack: IDataPack) => pack.modules).flat();
33
33
 
34
34
  const getFieldProps = (field: any) => {
35
- const { key, type, whiteList = [] } = field;
35
+ const { key, type, whiteList = [], slugTo } = field;
36
36
  const isArr = type === "ComponentArray";
37
37
  const currentContent = isArr ? templateContent[key] : templateContent;
38
38
  const fieldObjKey = !isArr ? `${key}` : `modules`;
39
39
  const mappedField = !isArr ? { ...field, key: fieldObjKey } : field;
40
- const handleUpdate = (fieldKey: string, value: any) => updateValue(fieldKey, value, templateContent.editorID);
40
+ const handleUpdate = (fieldKey: string, value: any) =>
41
+ updateValue(fieldKey, value, templateContent.editorID, slugTo);
41
42
  const error = errors.find((err: any) => err.editorID === templateContent.editorID && err.key === key);
42
43
 
43
44
  const addedModules = modulesDataPacks
@@ -98,7 +99,7 @@ export const TemplateManager = (props: IProps): JSX.Element => {
98
99
 
99
100
  interface IProps {
100
101
  template: any;
101
- updateValue: (key: string, value: any, templateID?: number) => void;
102
+ updateValue: (key: string, value: any, templateID?: number, slugTo?: string) => void;
102
103
  goTo: any;
103
104
  objKey: string;
104
105
  pages: any;
@@ -84,7 +84,7 @@ const PageConnectedField = (props: any) => {
84
84
  // eslint-disable-next-line
85
85
  }, [isPageHome]);
86
86
 
87
- let updateValue = (key: string, value: any, templateID?: number) => {
87
+ let updateValue = (key: string, value: any, templateID?: number, slugTo?: string) => {
88
88
  if (key === "parent") {
89
89
  getPageBreadcrumb(value);
90
90
  }
@@ -95,6 +95,11 @@ const PageConnectedField = (props: any) => {
95
95
  updateEditorContent(selectedEditorID, "isHome", value);
96
96
  }
97
97
 
98
+ if (slugTo) {
99
+ const slugValue = typeof value === "object" && value.content ? value.content : value;
100
+ updateEditorContent(selectedEditorID, slugTo, slugify(slugValue));
101
+ }
102
+
98
103
  const editorID = templateID ? templateID : selectedEditorID;
99
104
 
100
105
  updateEditorContent(editorID, key, value);
@@ -8,7 +8,7 @@ import { FieldsBehavior, HiddenField } from "@ax/components";
8
8
  const FieldContainer = (props: IProps) => {
9
9
  const { selectedContent, updateValue, field, goTo, objKey, lang } = props;
10
10
 
11
- const { type, key, title, hideable } = field;
11
+ const { type, key, title, hideable, slugTo } = field;
12
12
  const isContainer = field.type === "ComponentContainer";
13
13
 
14
14
  const hideField = () => updateValue(key, nullValue);
@@ -19,7 +19,7 @@ const FieldContainer = (props: IProps) => {
19
19
  fieldType: type,
20
20
  value: containerValue,
21
21
  hideField,
22
- onChange: (e: any) => updateValue(key, e),
22
+ onChange: (e: any) => updateValue(key, e, undefined, slugTo),
23
23
  goTo,
24
24
  editorID: selectedContent.editorID,
25
25
  lang,
@@ -0,0 +1,75 @@
1
+ import React from "react";
2
+
3
+ import { FieldsBehavior } from "@ax/components";
4
+ import { splitAndTrim } from "@ax/helpers";
5
+ import { IAnalytics, IDimension } from "@ax/types";
6
+
7
+ import { IState } from "..";
8
+ import * as S from "../style";
9
+
10
+ const DimensionsGroup = (props: { analytics: IAnalytics, state: IState, setDimension: (value: Record<string, string>) => void }): JSX.Element => {
11
+ const { analytics, state, setDimension } = props;
12
+ const { groupSelect, values } = state;
13
+ const selectedGroup = analytics.groups.find((g) => g.name === groupSelect);
14
+ const dimensionNames = splitAndTrim(selectedGroup?.dimensions, ";");
15
+ const groupDimensions = dimensionNames.map((dimensionName) => {
16
+ const dimension = analytics.dimensions.find((dimension) => dimension.name === dimensionName);
17
+ return dimension;
18
+ })
19
+
20
+ return (
21
+ <>
22
+ <S.FieldsDivider />
23
+ {groupDimensions && groupDimensions.map((dimension, idx) => (
24
+ dimension && <DimensionValue key={idx} {...{ dimension, setDimension, values }} />
25
+ ))}
26
+ </>
27
+ )
28
+ }
29
+
30
+ const DimensionsSelection = (props: { analytics: IAnalytics, state: IState, setDimension: (value: Record<string, string>) => void }): JSX.Element => {
31
+ const { analytics, state, setDimension } = props;
32
+ const { dimensionsSelect, values } = state;
33
+ const selectedDimensions = analytics.dimensions.filter((d) => dimensionsSelect.includes(d.name));
34
+
35
+ return (
36
+ <>
37
+ {selectedDimensions.length ? <S.FieldsDivider /> : <></>}
38
+ {selectedDimensions && selectedDimensions.map((dimension, idx) => (
39
+ <DimensionValue key={idx} {...{ dimension, setDimension, values }} />
40
+ ))}
41
+ </>
42
+ )
43
+ }
44
+
45
+ const DimensionValue = (props: { dimension: IDimension, setDimension: (value: Record<string, string>) => void, values: Record<string, string> }) => {
46
+ const { dimension, setDimension, values } = props;
47
+ const dimensionValues = splitAndTrim(dimension?.values, ";");
48
+ const options = dimensionValues.map((option) => ({ label: option, value: option }));
49
+ const handleOnChange = (value: string) => {
50
+ dimension && setDimension({ [dimension.name]: value });
51
+ }
52
+
53
+ const isNullValue = dimensionValues.includes("null");
54
+
55
+ return isNullValue ? (
56
+ <FieldsBehavior
57
+ title={dimension?.name}
58
+ fieldType="TextField"
59
+ value={dimension ? values[dimension.name] : ""}
60
+ onChange={handleOnChange}
61
+ placeholder="Type a variable"
62
+ />
63
+ ) : (
64
+ <FieldsBehavior
65
+ title={dimension?.name}
66
+ fieldType="Select"
67
+ options={options}
68
+ value={dimension ? values[dimension.name] : ""}
69
+ onChange={handleOnChange}
70
+ placeholder="Select variable"
71
+ />
72
+ )
73
+ }
74
+
75
+ export { DimensionsGroup, DimensionsSelection };
@@ -0,0 +1,139 @@
1
+ import React, { useEffect, useState } from "react";
2
+
3
+ import { NoteField, FieldsBehavior, FieldGroup } from "@ax/components";
4
+
5
+ import { IAnalyticsFieldProps, IState } from "..";
6
+ import { DimensionsGroup, DimensionsSelection } from "./atoms";
7
+ import * as S from "../style";
8
+
9
+ const PageAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
10
+ const {
11
+ value,
12
+ onChange,
13
+ analytics,
14
+ } = props;
15
+
16
+ const initialState = {
17
+ contentSelect: "",
18
+ groupSelect: "",
19
+ dimensionsSelect: [],
20
+ values: {}
21
+ }
22
+
23
+ const [state, setState] = useState<IState>(value || initialState);
24
+
25
+ useEffect(() => {
26
+ onChange && onChange(state);
27
+ // eslint-disable-next-line react-hooks/exhaustive-deps
28
+ }, [state]);
29
+
30
+ const handleContentSelect = (contentSelect: string) => {
31
+ setState({ ...initialState, contentSelect });
32
+ }
33
+
34
+ const handleGroupSelect = (groupSelect: string) => {
35
+ setState((state: IState) => ({ ...state, groupSelect, values: {} }));
36
+ }
37
+
38
+ const handleDimensionsSelect = (selection: string[]) => {
39
+ const values: Record<string, string> = {};
40
+ let dimensionsSelect = selection;
41
+
42
+ if (selection.includes("all")) {
43
+ dimensionsSelect = analytics.dimensions.map((dimension) => dimension.name);
44
+ }
45
+
46
+ dimensionsSelect.forEach((dimension) => values[dimension] = state.values[dimension]);
47
+ setState((state: IState) => ({ ...state, dimensionsSelect, values }));
48
+ }
49
+
50
+ const setDimension = (value: Record<string, string>) => {
51
+ setState((state: IState) => ({ ...state, values: { ...state.values, ...value } }));
52
+ }
53
+
54
+ const contentOptions = [
55
+ {
56
+ label: "Dimensions Group",
57
+ value: "group"
58
+ },
59
+ {
60
+ label: "Individual Dimensions",
61
+ value: "individual"
62
+ },
63
+ ]
64
+
65
+ const groupOptions: { label: string, value: string }[] = [];
66
+ analytics.groups?.forEach((group) => {
67
+ groupOptions.push({ label: group.name, value: group.name })
68
+ });
69
+
70
+ const noteText = (
71
+ <>
72
+ Select <strong>Dimension Group</strong> if you want to select one of the groups you created in the global settings (based on the page content).<br /><br />Select <strong>Individual Dimensions</strong> if you want to select the dimensions to track manually.
73
+ </>
74
+ );
75
+
76
+ const isGroup = state.contentSelect === "group";
77
+ const isIndividual = state.contentSelect === "individual";
78
+
79
+ const dimensionOptions = [
80
+ {
81
+ name: "all",
82
+ value: "all",
83
+ title: "Select All",
84
+ },
85
+ ];
86
+ analytics.dimensions.forEach((dimension) => {
87
+ const option = {
88
+ name: dimension.name,
89
+ value: dimension.name,
90
+ title: dimension.name,
91
+ }
92
+ dimensionOptions.push(option);
93
+ });
94
+
95
+ return (
96
+ <FieldGroup title="Analytics Data Layer">
97
+ <NoteField value={{ text: noteText }} />
98
+ <S.FieldWrapper>
99
+ <FieldsBehavior
100
+ title="Content Dimension"
101
+ fieldType="Select"
102
+ options={contentOptions}
103
+ value={state.contentSelect}
104
+ onChange={handleContentSelect}
105
+ placeholder="Select Dimensions Options"
106
+ />
107
+ </S.FieldWrapper>
108
+ {isGroup && (
109
+ <>
110
+ <FieldsBehavior
111
+ title="Select Group"
112
+ fieldType="Select"
113
+ options={groupOptions}
114
+ value={state.groupSelect}
115
+ onChange={handleGroupSelect}
116
+ placeholder="Select Group"
117
+ />
118
+ {!!state.groupSelect && <DimensionsGroup {...{ analytics, state, setDimension }} />}
119
+ </>
120
+ )}
121
+ {isIndividual && (
122
+ <>
123
+ <FieldsBehavior
124
+ title="Select Dimensions"
125
+ fieldType="MultiCheckSelect"
126
+ options={dimensionOptions}
127
+ value={state.dimensionsSelect}
128
+ onChange={handleDimensionsSelect}
129
+ selectAllOption="all"
130
+ placeholder="Select Dimensions"
131
+ />
132
+ {!!state.dimensionsSelect && <DimensionsSelection {...{ analytics, state, setDimension }} />}
133
+ </>
134
+ )}
135
+ </FieldGroup>
136
+ );
137
+ };
138
+
139
+ export default PageAnalytics;
@@ -0,0 +1,77 @@
1
+ import React from "react";
2
+
3
+ import { FieldsBehavior } from "@ax/components";
4
+ import { splitAndTrim } from "@ax/helpers";
5
+ import { IAnalytics, IDimension } from "@ax/types";
6
+
7
+ import { IState } from "..";
8
+
9
+ const TemplateDimensions = (props: ITemplateDimensions): JSX.Element => {
10
+ const { analytics, state, setDimension, dimensionNames } = props;
11
+ const { values } = state;
12
+ const groupDimensions = dimensionNames.map((dimensionName) => {
13
+ const dimension = analytics.dimensions.find((dimension) => dimension.name === dimensionName);
14
+ return dimension;
15
+ })
16
+
17
+ return (
18
+ <>
19
+ {groupDimensions && groupDimensions.map((dimension, idx) => (
20
+ dimension && <DimensionValue key={idx} {...{ dimension, setDimension, values }} />
21
+ ))}
22
+ </>
23
+ )
24
+ }
25
+
26
+ const DimensionsSelection = (props: { analytics: IAnalytics, state: IState, setDimension: (value: Record<string, string>) => void }): JSX.Element => {
27
+ const { analytics, state, setDimension } = props;
28
+ const { dimensionsSelect, values } = state;
29
+ const selectedDimensions = analytics.dimensions.filter((d) => dimensionsSelect.includes(d.name));
30
+
31
+ return (
32
+ <>
33
+ {selectedDimensions && selectedDimensions.map((dimension, idx) => (
34
+ <DimensionValue key={idx} {...{ dimension, setDimension, values }} />
35
+ ))}
36
+ </>
37
+ )
38
+ }
39
+
40
+ const DimensionValue = (props: { dimension: IDimension, setDimension: (value: Record<string, string>) => void, values: Record<string, string> }) => {
41
+ const { dimension, setDimension, values } = props;
42
+ const dimensionValues = splitAndTrim(dimension?.values, ";");
43
+ const options = dimensionValues.map((option) => ({ label: option, value: option }));
44
+ const handleOnChange = (value: string) => {
45
+ dimension && setDimension({ [dimension.name]: value });
46
+ }
47
+
48
+ const isNullValue = dimensionValues.includes("null");
49
+
50
+ return isNullValue ? (
51
+ <FieldsBehavior
52
+ title={dimension?.name}
53
+ fieldType="TextField"
54
+ value={dimension ? values[dimension.name] : ""}
55
+ onChange={handleOnChange}
56
+ placeholder="Type a variable"
57
+ />
58
+ ) : (
59
+ <FieldsBehavior
60
+ title={dimension?.name}
61
+ fieldType="Select"
62
+ options={options}
63
+ value={dimension ? values[dimension.name] : ""}
64
+ onChange={handleOnChange}
65
+ placeholder="Select variable"
66
+ />
67
+ )
68
+ }
69
+
70
+ interface ITemplateDimensions {
71
+ analytics: IAnalytics;
72
+ state: IState;
73
+ setDimension: (value: Record<string, string>) => void;
74
+ dimensionNames: string[];
75
+ }
76
+
77
+ export { TemplateDimensions, DimensionsSelection };
@@ -0,0 +1,89 @@
1
+ import React, { useEffect, useState } from "react";
2
+
3
+ import { FieldsBehavior, FieldGroup } from "@ax/components";
4
+
5
+ import { IAnalyticsFieldProps, IState } from "..";
6
+ import { getTemplateDimensions } from "../utils";
7
+ import { TemplateDimensions, DimensionsSelection } from "./atoms";
8
+ import * as S from "../style";
9
+
10
+ const StructuredDataAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
11
+ const {
12
+ value,
13
+ onChange,
14
+ analytics,
15
+ template,
16
+ } = props;
17
+
18
+ const initialState = {
19
+ dimensionsSelect: [],
20
+ values: {}
21
+ }
22
+
23
+ const [state, setState] = useState<IState>({ ...initialState, ...value });
24
+
25
+ useEffect(() => {
26
+ onChange && onChange(state);
27
+ // eslint-disable-next-line react-hooks/exhaustive-deps
28
+ }, [state]);
29
+
30
+ const templateDimensions = getTemplateDimensions(analytics.groups, template);
31
+
32
+ const handleDimensionsSelect = (selection: string[]) => {
33
+ const values: Record<string, string> = {};
34
+ templateDimensions.forEach((dimension) => values[dimension] = state.values[dimension]);
35
+ let dimensionsSelect = selection;
36
+
37
+ if (selection.includes("all")) {
38
+ dimensionsSelect = dimensionOptions.map((dimension) => dimension.name);
39
+ }
40
+
41
+ dimensionsSelect.forEach((dimension) => values[dimension] = state.values[dimension]);
42
+ setState((state: IState) => ({ ...state, dimensionsSelect, values }));
43
+ }
44
+
45
+ const setDimension = (value: Record<string, string>) => {
46
+ setState((state: IState) => ({ ...state, values: { ...state.values, ...value } }));
47
+ }
48
+
49
+ const dimensionOptions = [
50
+ {
51
+ name: "all",
52
+ value: "all",
53
+ title: "Select All",
54
+ },
55
+ ];
56
+ analytics.dimensions.forEach((dimension) => {
57
+ if (!templateDimensions.includes(dimension.name)) {
58
+ const option = {
59
+ name: dimension.name,
60
+ value: dimension.name,
61
+ title: dimension.name,
62
+ }
63
+ dimensionOptions.push(option);
64
+ }
65
+ });
66
+
67
+ return (
68
+ <FieldGroup title="Analytics Data Layer">
69
+ <TemplateDimensions dimensionNames={templateDimensions} {...{ analytics, state, setDimension }} />
70
+ {dimensionOptions.length > 1 && (
71
+ <>
72
+ <S.FieldsDivider />
73
+ <FieldsBehavior
74
+ title="Add More Dimensions (Optional)"
75
+ fieldType="MultiCheckSelect"
76
+ options={dimensionOptions}
77
+ value={state.dimensionsSelect}
78
+ onChange={handleDimensionsSelect}
79
+ selectAllOption="all"
80
+ placeholder="Select Dimensions"
81
+ />
82
+ {!!state.dimensionsSelect && <DimensionsSelection {...{ analytics, state, setDimension }} />}
83
+ </>
84
+ )}
85
+ </FieldGroup>
86
+ );
87
+ };
88
+
89
+ export default StructuredDataAnalytics;
@@ -0,0 +1,38 @@
1
+ import React from "react";
2
+ import { connect } from "react-redux";
3
+
4
+ import { IAnalytics, IRootState } from "@ax/types";
5
+ import { isEmptyArray } from "@ax/helpers";
6
+
7
+ import PageAnalytics from "./PageAnalytics";
8
+ import StructuredDataAnalytics from "./StructuredDataAnalytics";
9
+ import { getTemplateDimensions } from "./utils";
10
+
11
+ const AnalyticsField = (props: IAnalyticsFieldProps): JSX.Element => {
12
+ const { analytics, template } = props;
13
+
14
+ const templateDimensions = getTemplateDimensions(analytics.groups, template);
15
+
16
+ return isEmptyArray(templateDimensions) ? <PageAnalytics {...props} /> : <StructuredDataAnalytics {...props} />;
17
+ };
18
+
19
+ const mapStateToProps = (state: IRootState) => ({
20
+ analytics: state.analytics,
21
+ template: state.pageEditor.template,
22
+ });
23
+
24
+ export interface IAnalyticsFieldProps {
25
+ value: IState;
26
+ onChange: (value: IState) => void;
27
+ analytics: IAnalytics;
28
+ template: string;
29
+ }
30
+
31
+ export interface IState {
32
+ contentSelect: string;
33
+ groupSelect: string;
34
+ dimensionsSelect: string[];
35
+ values: Record<string, string>;
36
+ }
37
+
38
+ export default connect(mapStateToProps, null)(AnalyticsField);
@@ -0,0 +1,13 @@
1
+ import styled from "styled-components";
2
+
3
+ const FieldWrapper = styled.div`
4
+ margin-top: ${(p) => p.theme.spacing.s};
5
+ margin-bottom: ${(p) => p.theme.spacing.s};
6
+ `;
7
+
8
+ const FieldsDivider = styled.div`
9
+ margin-bottom: ${(p) => p.theme.spacing.s};
10
+ border-bottom: 1px solid ${(p) => p.theme.color.uiLine};
11
+ `;
12
+
13
+ export { FieldWrapper, FieldsDivider };
@@ -0,0 +1,13 @@
1
+ import { IDimensionsGroup } from "@ax/types";
2
+ import { splitAndTrim } from "@ax/helpers";
3
+
4
+ const getTemplateDimensions = (groups: IDimensionsGroup[], template: string): string[] => {
5
+ const templateDimensionsGroups = groups.filter((group) => group.templates?.includes(template));
6
+ const templateDimensions = templateDimensionsGroups.reduce((dimensions: string[], group: IDimensionsGroup) => {
7
+ return [...dimensions, ...splitAndTrim(group.dimensions, ";")];
8
+ }, []);
9
+ const uniqueTemplateDimensions = [...new Set(templateDimensions)];
10
+ return uniqueTemplateDimensions;
11
+ }
12
+
13
+ export { getTemplateDimensions }
@@ -26,7 +26,7 @@ export const Label = styled.div<{ isOpen: boolean }>`
26
26
  `;
27
27
 
28
28
  export const Content = styled.div<{ isOpen: boolean }>`
29
- overflow-y: hidden;
29
+ overflow-y: ${(p) => (p.isOpen ? "visible" : "hidden")};
30
30
  max-height: ${(p) => (p.isOpen ? `auto` : 0)};
31
31
  transition: all 0.5s ease-in-out;
32
32
  `;