@capillarytech/cap-ui-utils 1.4.6-alpha8.0 → 1.4.6

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.
package/index.js CHANGED
@@ -7,3 +7,4 @@ export { default as formatter } from "./utils/formatter";
7
7
  export { default as validationHelper } from "./utils/validationHelper";
8
8
  export { default as loadable, FORCE_REFRESH_NOTIFIER, FORCE_REFRESH_SECONDS } from './utils/loadable';
9
9
  export { default as GTMTracker } from './utils/gtmTracker';
10
+ export { default as compileHandlebars } from './utils/compileHandlebars';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capillarytech/cap-ui-utils",
3
- "version": "1.4.6-alpha8.0",
3
+ "version": "1.4.6",
4
4
  "description": "Utility functions shared accross all the modules",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -8,14 +8,12 @@
8
8
  },
9
9
  "author": "Rajshekar",
10
10
  "dependencies": {
11
- "@capillarytech/cap-ui-library": "4.1.15",
12
- "prop-types": "^15.8.1",
13
11
  "react": "^16.13.0",
14
12
  "react-ga": "^2.7.0",
15
13
  "tti-polyfill": "^0.2.2",
16
14
  "moment-timezone": "^0.5.25",
17
15
  "react-intl": "2.7.2",
18
16
  "lodash": "4.17.11",
19
- "react-resizable": "^3.0.4"
17
+ "handlebars": "4.0.11"
20
18
  }
21
19
  }
@@ -0,0 +1,49 @@
1
+ import Handlebars from 'handlebars';
2
+ import moment from 'moment';
3
+
4
+ const DATE_FORMAT = 'YYYY-MM-DD';
5
+ const DATE_FORMAT_DISPLAY = 'DD MMM, YYYY';
6
+
7
+ // register helper functions
8
+ Handlebars.registerHelper('makeBold', (name) => `<strong>${name}</strong>`);
9
+
10
+ Handlebars.registerHelper('currentDate', () => moment().format(DATE_FORMAT));
11
+
12
+ Handlebars.registerHelper('formatDate', (value, dtf = DATE_FORMAT_DISPLAY) => {
13
+ const dateValue = moment(value, DATE_FORMAT);
14
+ if (!dateValue.isValid()) return moment().format(dtf);
15
+ return dateValue.format(dtf);
16
+ });
17
+
18
+ Handlebars.registerHelper('compareDate', (value, compareWith, operator = 'equals') => {
19
+ let result = false;
20
+ const dateValue = resetTimeParams(moment(value, DATE_FORMAT));
21
+ const compareWithValue = resetTimeParams(moment(compareWith, DATE_FORMAT));
22
+ switch (operator) {
23
+ case 'equals': result = dateValue.diff(compareWithValue, 'day') === 0; break;
24
+ case 'greaterThan': result = dateValue.isAfter(compareWithValue); break;
25
+ case 'lessThan': result = dateValue.isBefore(compareWithValue); break;
26
+ }
27
+ });
28
+
29
+ // util functions
30
+ const resetTimeParams = (date) => date.hours(0).minutes(0).seconds(0).milliseconds(0);
31
+
32
+ const replaceBraces = (str) => str
33
+ .replace(new RegExp('<%', 'g'), '{{')
34
+ .replace(new RegExp('%>', 'g'), '}}');
35
+
36
+ // format and compile template
37
+ const compileMessage = (template, context = {}) => {
38
+ try {
39
+ const compiledTemplate = Handlebars.compile(replaceBraces(template));
40
+ return compiledTemplate(context);
41
+ }
42
+ catch(err) {
43
+ const error = `[TemplateHandler util function] Error in template parsing: ${err}`;
44
+ console.error(error);
45
+ return error;
46
+ }
47
+ };
48
+
49
+ export default compileMessage;
@@ -1,166 +0,0 @@
1
- import React, { useState } from "react";
2
- import { ResizableBox } from "react-resizable";
3
- import PropTypes from "prop-types";
4
- import CapColumn from "@capillarytech/cap-ui-library/CapColumn";
5
- import CapIcon from "@capillarytech/cap-ui-library/CapIcon";
6
- import CapLink from "@capillarytech/cap-ui-library/CapLink";
7
- import CapHeading from "@capillarytech/cap-ui-library/CapHeading";
8
- import CapRow from "@capillarytech/cap-ui-library/CapRow";
9
- import Draggable from "react-draggable";
10
- import "react-resizable/css/styles.css";
11
-
12
- const ResizablePIP = ({
13
- children,
14
- width = 400,
15
- height = 310,
16
- showMaximised = false,
17
- handleShowMaximised,
18
- minConstraints = [400, 310],
19
- maxConstraints = [1104, 722],
20
- closePIPContainer = () => {},
21
- footerContent = {},
22
- }) => {
23
- const [pipWidth, setPipWidth] = useState(width);
24
- const [pipHeight, setPipHeight] = useState(height);
25
- const [isHovering, setIsHovering] = useState(false);
26
- const handleMouseEnter = () => setIsHovering(true);
27
- const handleMouseLeave = () => setIsHovering(false);
28
- const handleMaximiseView = () => {
29
- if (!showMaximised) {
30
- setPipWidth(1104);
31
- setPipHeight(722);
32
- } else {
33
- setPipWidth(width);
34
- setPipHeight(height);
35
- }
36
- handleShowMaximised(!showMaximised);
37
- };
38
-
39
- const handleOpenDoc = () => window.open(footerContent.supportDoc, "_blank");
40
- return (
41
- <Draggable handle="button">
42
- <div
43
- style={{
44
- zIndex: "1000",
45
- position: "absolute",
46
- left: showMaximised ? 168 : 24,
47
- top: showMaximised ? 60 : 450,
48
- boxSizing: "content-box",
49
- boxShadow:
50
- "1px 3px 3px 0 rgb(0 0 0 / 20%), 1px 3px 15px 2px rgb(0 0 0 / 20%)",
51
- borderRadius: 4,
52
- backgroundColor: "#fff",
53
- }}
54
- >
55
- {(isHovering || showMaximised) && (
56
- <CapIcon
57
- onClick={closePIPContainer}
58
- size="m"
59
- type="close"
60
- style={{
61
- position: "fixed",
62
- top: showMaximised ? "-10px" : "10px",
63
- left: showMaximised ? "1093px" : "365px",
64
- backgroundColor: showMaximised ? "#dfe2e7" : "unset",
65
- borderRadius: 48,
66
- zIndex: 10001,
67
- }}
68
- onMouseEnter={handleMouseEnter}
69
- onMouseLeave={handleMouseLeave}
70
- />
71
- )}
72
- <ResizableBox
73
- onMouseDown={(e) => {
74
- e.stopPropagation();
75
- }}
76
- width={pipWidth}
77
- height={pipHeight}
78
- minConstraints={minConstraints}
79
- maxConstraints={maxConstraints}
80
- >
81
- <div
82
- style={{
83
- height: "calc(100% - 56px)",
84
- opacity: isHovering ? 0.3 : 1,
85
- color: "#000",
86
- backgroundColor: "rgba(0, 0, 0, 0.3)",
87
- transition: "opacity 0.5s ease-in-out",
88
- }}
89
- onMouseEnter={handleMouseEnter}
90
- onMouseLeave={handleMouseLeave}
91
- >
92
- {children}
93
- </div>
94
- <CapRow style={{ height: 56 }}>
95
- <CapColumn span={17}>
96
- <CapHeading style={{ margin: 18 }} type="h3">
97
- {footerContent.videoTitle}
98
- </CapHeading>
99
- </CapColumn>
100
- <CapLink
101
- style={{
102
- float: "right",
103
- margin: "18px 18px 18px 0",
104
- }}
105
- onClick={handleOpenDoc}
106
- title={
107
- <CapHeading type="h5">
108
- View docs
109
- <CapIcon
110
- onClick={handleOpenDoc}
111
- size="s"
112
- type="open-in-new"
113
- />
114
- </CapHeading>
115
- }
116
- />
117
- </CapRow>
118
- </ResizableBox>
119
- {isHovering && (
120
- <div
121
- style={{ position: "fixed" }}
122
- onMouseEnter={handleMouseEnter}
123
- onMouseLeave={handleMouseLeave}
124
- >
125
- <CapIcon
126
- onClick={handleMaximiseView}
127
- size="s"
128
- type="open-in-new"
129
- style={{
130
- float: "right",
131
- position: "fixed",
132
- top: showMaximised ? 635 : 224,
133
- right: 12,
134
- }}
135
- />
136
- <button type="button">
137
- <CapIcon
138
- size="s"
139
- type="draggable"
140
- style={{
141
- float: "right",
142
- position: "fixed",
143
- top: showMaximised ? 635 : 224,
144
- right: 40,
145
- }}
146
- />
147
- </button>
148
- </div>
149
- )}
150
- </div>
151
- </Draggable>
152
- );
153
- };
154
-
155
- ResizablePIP.propTypes = {
156
- children: PropTypes.any,
157
- width: PropTypes.number,
158
- height: PropTypes.number,
159
- minConstraints: PropTypes.array,
160
- maxConstraints: PropTypes.array,
161
- closePIPContainer: PropTypes.func,
162
- handleShowMaximised: PropTypes.func,
163
- showMaximised: PropTypes.bool,
164
- footerContent: PropTypes.object,
165
- };
166
- export default ResizablePIP;
@@ -1,180 +0,0 @@
1
- import React, { useState } from "react";
2
- import PropTypes from "prop-types";
3
- import ResizablePIP from "./ResizablePIP";
4
-
5
- /** Sample targetElementsData
6
- target_elements: {
7
- '.loyalty-graph-header': {
8
- support_link: {
9
- target_url: {
10
- default: {
11
- label: 'Help default',
12
- href: 'https://app.storylane.io/share/v1ilsyhwno8m',
13
- },
14
- en: {
15
- label: 'Help',
16
- href: 'https://app.storylane.io/share/v1ilsyhwno8m',
17
- },
18
- },
19
- // icon: '',
20
- // position: 'right',
21
- // target_opening: '_blank',
22
- },
23
- },
24
- '.performance-time-head-title': {
25
- support_video: {
26
- target_url: {
27
- default: {
28
- label: 'Demo',
29
- href: ' https://www.youtube.com/embed/JJI4eR-G5AM',
30
- },
31
- en: {
32
- label: 'Demo',
33
- href: ' https://www.youtube.com/embed/JJI4eR-G5AM',
34
- },
35
- 'zh-CN': {
36
- label: '演示',
37
- href: ' https://www.youtube.com/embed/JJI4eR-G5AM',
38
- },
39
- },
40
- // icon: 'play',
41
- // position: 'right', // right | left | top | bottom
42
- // target_opening: '_blank',
43
- },
44
- },
45
- },
46
- */
47
- const WithDemoVideosAndLinks = (props) => {
48
- const { children, targetElements, locale = "en" } = props;
49
- const [showPIP, setShowPIP] = useState(false);
50
- const [PIPContentLink, setPIPContentLink] = useState("");
51
- const [PIPFooterContent, setPIPFooterContent] = useState({});
52
- const [showMaximised, setShowMaximised] = useState(false);
53
- const cssSelectors = [];
54
- if (Object.keys(targetElements || {})?.length) {
55
- Object.keys(targetElements).map((targetElement) => {
56
- cssSelectors.push({
57
- cssSelector: targetElement,
58
- locale,
59
- ...targetElements[targetElement],
60
- });
61
- });
62
- }
63
-
64
- cssSelectors.forEach((selector) => {
65
- const {
66
- support_link: { target_url: linkTargetUrl = {} } = {},
67
- support_video: { target_url: videoTargetUrl = {} } = {},
68
- locale,
69
- cssSelector,
70
- } = selector || {};
71
- let matchedNodes = document.querySelectorAll(selector.cssSelector);
72
- const handleOnClickVideoLink = () => {
73
- setPIPContentLink(videoTargetUrl?.[locale]?.href);
74
- setPIPFooterContent({
75
- videoTitle: videoTargetUrl?.[locale]?.videoTitle,
76
- supportDoc: videoTargetUrl?.[locale]?.supportDoc,
77
- });
78
- setShowPIP(true);
79
- };
80
- const handleOpenSupportLink = () =>
81
- window.open(linkTargetUrl?.[locale]?.href, "_blank");
82
-
83
- if (selector?.support_video?.target_url?.default?.href) {
84
- matchedNodes.forEach((node) => {
85
- if (!document.getElementById(`demo-video-${cssSelector}`)) {
86
- let videoAnchor = document.createElement("a");
87
- videoAnchor.textContent = videoTargetUrl?.[locale].label;
88
- videoAnchor.id = `demo-video-${cssSelector}`;
89
- videoAnchor.style.marginLeft = "2px";
90
- videoAnchor.onclick = handleOnClickVideoLink;
91
-
92
- const videoIconElement = document.createElement("i");
93
- videoIconElement.innerHTML = `<svg width="1em" height="1em" viewBox="0 0 24 24" fill="currentColor">
94
- <path
95
- d="M14.756 11.032a1.194 1.194 0 0 1 0 1.921l-2.937 2.17a1.194 1.194 0 0 1-1.904-.96v-4.34a1.194 1.194 0 0 1 1.904-.96l2.937 2.17zM12 19a7 7 0 1 0 0-14 7 7 0 0 0 0 14zm0 2a9 9 0 1 1 0-18 9 9 0 0 1 0 18z"
96
- id="play_svg__a"
97
- ></path>
98
- </svg>`;
99
- videoIconElement.onclick = handleOnClickVideoLink;
100
- videoIconElement.style.marginLeft = "2px";
101
- videoIconElement.style.cursor = "pointer";
102
- videoIconElement.style.color = "#2466eb";
103
- videoIconElement.style.fontSize = "18px";
104
- node.appendChild(videoIconElement);
105
- node.appendChild(videoAnchor);
106
- }
107
- });
108
- } else if (selector?.support_link?.target_url?.default?.href) {
109
- matchedNodes.forEach((node) => {
110
- if (!document.getElementById(`support-link-${cssSelector}`)) {
111
- let linkAnchor = document.createElement("a");
112
- linkAnchor.href = linkTargetUrl?.[locale]?.href;
113
- linkAnchor.textContent = linkTargetUrl?.[locale].label;
114
- linkAnchor.target = "_blank";
115
- linkAnchor.id = `support-link-${cssSelector}`;
116
- linkAnchor.style.marginLeft = "2px";
117
- linkAnchor.onclick = handleOpenSupportLink;
118
-
119
- const helpIconElement = document.createElement("i");
120
- helpIconElement.innerHTML = `<svg width="1em" height="1em" viewBox="0 0 24 24" fill="currentColor">
121
- <path
122
- id="help_svg__a"
123
- d="M9 16h2v-2H9v2zm1-16C4.48 0 0 4.48 0 10s4.48 10 10 10 10-4.48 10-10S15.52 0 10 0zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14C7.79 4 6 5.79 6 8h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z"
124
- ></path>
125
- </svg>`;
126
- helpIconElement.onclick = handleOpenSupportLink;
127
- helpIconElement.style.marginLeft = "2px";
128
- helpIconElement.style.cursor = "pointer";
129
- helpIconElement.style.fontSize = "16px";
130
- helpIconElement.style.color = "#2466eb";
131
-
132
- node.appendChild(helpIconElement);
133
- node.appendChild(linkAnchor);
134
- }
135
- });
136
- }
137
- });
138
-
139
- const handleOpenInNew = () => {
140
- window.open(PIPContentLink, "_blank");
141
- };
142
- const handleShowMaximised = (value) => {
143
- setShowMaximised(value);
144
- };
145
- const handleClosePIPContainer = () => {
146
- setShowMaximised(false);
147
- setShowPIP(false);
148
- };
149
- return (
150
- <div>
151
- {showPIP && (
152
- <ResizablePIP
153
- closePIPContainer={handleClosePIPContainer}
154
- handleOpenInNew={handleOpenInNew}
155
- handleShowMaximised={handleShowMaximised}
156
- showMaximised={showMaximised}
157
- footerContent={PIPFooterContent}
158
- >
159
- <iframe
160
- width="100%"
161
- height="100%"
162
- src={`${PIPContentLink}?controls=0`}
163
- title="YouTube video player"
164
- frameBorder="0"
165
- allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
166
- style={{ borderRadius: 4 }}
167
- />
168
- </ResizablePIP>
169
- )}
170
- {children}
171
- </div>
172
- );
173
- };
174
-
175
- WithDemoVideosAndLinks.propTypes = {
176
- children: PropTypes.any,
177
- locale: PropTypes.string,
178
- targetElements: PropTypes.object,
179
- };
180
- export default WithDemoVideosAndLinks;