@capillarytech/cap-ui-utils 1.4.4 → 1.4.6-alpha.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.
package/index.js
CHANGED
|
@@ -5,4 +5,5 @@ export { default as utilsSessionStorageApi } from "./utils/utilsSessionStorageAp
|
|
|
5
5
|
export { default as dateHelper } from "./utils/date/dateHelper";
|
|
6
6
|
export { default as formatter } from "./utils/formatter";
|
|
7
7
|
export { default as validationHelper } from "./utils/validationHelper";
|
|
8
|
+
export { default as loadable, FORCE_REFRESH_NOTIFIER, FORCE_REFRESH_SECONDS } from './utils/loadable';
|
|
8
9
|
export { default as GTMTracker } from './utils/gtmTracker';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capillarytech/cap-ui-utils",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.6-alpha.0",
|
|
4
4
|
"description": "Utility functions shared accross all the modules",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -8,11 +8,14 @@
|
|
|
8
8
|
},
|
|
9
9
|
"author": "Rajshekar",
|
|
10
10
|
"dependencies": {
|
|
11
|
+
"@capillarytech/cap-ui-library": "4.0.1",
|
|
12
|
+
"prop-types": "^15.8.1",
|
|
11
13
|
"react": "^16.13.0",
|
|
12
14
|
"react-ga": "^2.7.0",
|
|
13
15
|
"tti-polyfill": "^0.2.2",
|
|
14
16
|
"moment-timezone": "^0.5.25",
|
|
15
17
|
"react-intl": "2.7.2",
|
|
16
|
-
"lodash": "4.17.11"
|
|
18
|
+
"lodash": "4.17.11",
|
|
19
|
+
"react-resizable": "^3.0.4"
|
|
17
20
|
}
|
|
18
21
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { lazy } from 'react';
|
|
2
|
+
|
|
3
|
+
export const FORCE_REFRESH_NOTIFIER = 'showForceRefreshNotifier';
|
|
4
|
+
export const FORCE_REFRESH_SECONDS = 5;
|
|
5
|
+
|
|
6
|
+
const reloadWithDelay = (delay = FORCE_REFRESH_SECONDS) =>
|
|
7
|
+
new Promise((resolve) => {
|
|
8
|
+
setTimeout(() => {
|
|
9
|
+
// reload page
|
|
10
|
+
resolve(window.location.reload());
|
|
11
|
+
}, delay * 1000);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const lazyWithRetry = (importFunction) =>
|
|
15
|
+
lazy(async () => {
|
|
16
|
+
// get refresh flag from session storage
|
|
17
|
+
const pageHasAlreadyBeenForceRefreshed = JSON.parse(
|
|
18
|
+
window.sessionStorage.getItem(
|
|
19
|
+
'page-has-been-force-refreshed'
|
|
20
|
+
) || 'false'
|
|
21
|
+
);
|
|
22
|
+
try {
|
|
23
|
+
const component = await importFunction();
|
|
24
|
+
// set refresh flag to false once component is imported
|
|
25
|
+
window.sessionStorage.setItem(
|
|
26
|
+
'page-has-been-force-refreshed',
|
|
27
|
+
'false'
|
|
28
|
+
);
|
|
29
|
+
return component;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (!pageHasAlreadyBeenForceRefreshed) {
|
|
32
|
+
// Assuming that the user is NOT on the latest version of the application.
|
|
33
|
+
window.sessionStorage.setItem(
|
|
34
|
+
'page-has-been-force-refreshed',
|
|
35
|
+
'true'
|
|
36
|
+
);
|
|
37
|
+
// Notify the main app to show notification if needed
|
|
38
|
+
window.postMessage(FORCE_REFRESH_NOTIFIER, window.location.origin);
|
|
39
|
+
// Let's refresh the page immediately.
|
|
40
|
+
return reloadWithDelay();
|
|
41
|
+
}
|
|
42
|
+
// The page has already been reloaded
|
|
43
|
+
// Assuming that user is already using the latest version of the application.
|
|
44
|
+
// Let's let the application crash and raise the error.
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
export default lazyWithRetry;
|
|
@@ -0,0 +1,126 @@
|
|
|
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 CapRow from "@capillarytech/cap-ui-library/CapRow";
|
|
7
|
+
import Draggable from "react-draggable";
|
|
8
|
+
import "react-resizable/css/styles.css";
|
|
9
|
+
|
|
10
|
+
const ResizablePIP = ({
|
|
11
|
+
children,
|
|
12
|
+
width = 400,
|
|
13
|
+
height = 260,
|
|
14
|
+
showMaximised = false,
|
|
15
|
+
setShowMaximised,
|
|
16
|
+
minConstraints = [400, 260],
|
|
17
|
+
maxConstraints = [1404, 900],
|
|
18
|
+
closePIPContainer = () => {},
|
|
19
|
+
handleOpenInNew = () => {},
|
|
20
|
+
}) => {
|
|
21
|
+
const [pipWidth, setPipWidth] = useState(width);
|
|
22
|
+
const [pipHeight, setPipHeight] = useState(height);
|
|
23
|
+
const handleMaximiseView = () => {
|
|
24
|
+
setPipWidth(1404);
|
|
25
|
+
setPipHeight(730);
|
|
26
|
+
setShowMaximised(!showMaximised);
|
|
27
|
+
};
|
|
28
|
+
return (
|
|
29
|
+
<div
|
|
30
|
+
style={{
|
|
31
|
+
position: "absolute",
|
|
32
|
+
left: 8,
|
|
33
|
+
top: -56,
|
|
34
|
+
}}
|
|
35
|
+
>
|
|
36
|
+
<Draggable>
|
|
37
|
+
<div
|
|
38
|
+
style={{
|
|
39
|
+
backgroundColor: "#242d36",
|
|
40
|
+
zIndex: "100000",
|
|
41
|
+
position: "fixed",
|
|
42
|
+
fontSize: "14px",
|
|
43
|
+
fontWeight: "200",
|
|
44
|
+
lineHeight: "1.5",
|
|
45
|
+
color: "rgb(248, 248, 249)",
|
|
46
|
+
boxSizing: "content-box",
|
|
47
|
+
boxShadow:
|
|
48
|
+
"1px 3px 3px 0 rgb(0 0 0 / 20%), 1px 3px 15px 2px rgb(0 0 0 / 20%)",
|
|
49
|
+
borderRadius: "0.28571429rem",
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
<CapRow>
|
|
53
|
+
<CapRow>
|
|
54
|
+
<CapColumn span={1} offset={18}>
|
|
55
|
+
<CapIcon
|
|
56
|
+
onClick={handleMaximiseView}
|
|
57
|
+
style={{ marginTop: "8px" }}
|
|
58
|
+
type="help"
|
|
59
|
+
/>
|
|
60
|
+
</CapColumn>
|
|
61
|
+
<CapColumn span={1} offset={1}>
|
|
62
|
+
<CapIcon
|
|
63
|
+
onClick={handleOpenInNew}
|
|
64
|
+
style={{ marginTop: "8px" }}
|
|
65
|
+
type="open-in-new"
|
|
66
|
+
/>
|
|
67
|
+
</CapColumn>
|
|
68
|
+
<CapColumn span={1} offset={1}>
|
|
69
|
+
<CapIcon
|
|
70
|
+
onClick={closePIPContainer}
|
|
71
|
+
style={{ marginTop: "8px" }}
|
|
72
|
+
type="close"
|
|
73
|
+
/>
|
|
74
|
+
</CapColumn>
|
|
75
|
+
</CapRow>
|
|
76
|
+
<CapRow>
|
|
77
|
+
<ResizableBox
|
|
78
|
+
onMouseDown={(e) => {
|
|
79
|
+
e.stopPropagation();
|
|
80
|
+
}}
|
|
81
|
+
style={{
|
|
82
|
+
background: "#202429",
|
|
83
|
+
margin: "8px",
|
|
84
|
+
borderRadius: "4px",
|
|
85
|
+
overflow: "auto",
|
|
86
|
+
}}
|
|
87
|
+
width={pipWidth}
|
|
88
|
+
height={pipHeight}
|
|
89
|
+
minConstraints={minConstraints}
|
|
90
|
+
maxConstraints={maxConstraints}
|
|
91
|
+
>
|
|
92
|
+
{children}
|
|
93
|
+
</ResizableBox>
|
|
94
|
+
</CapRow>
|
|
95
|
+
</CapRow>
|
|
96
|
+
</div>
|
|
97
|
+
</Draggable>
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
ResizablePIP.propTypes = {
|
|
103
|
+
children: PropTypes.any,
|
|
104
|
+
width: PropTypes.number,
|
|
105
|
+
height: PropTypes.number,
|
|
106
|
+
minConstraints: PropTypes.array,
|
|
107
|
+
maxConstraints: PropTypes.array,
|
|
108
|
+
closePIPContainer: PropTypes.func,
|
|
109
|
+
handleOpenInNew: PropTypes.func,
|
|
110
|
+
setShowMaximised: PropTypes.func,
|
|
111
|
+
showMaximised: PropTypes.bool,
|
|
112
|
+
};
|
|
113
|
+
export default ResizablePIP;
|
|
114
|
+
|
|
115
|
+
/** put this is draggable div
|
|
116
|
+
* .pipWindow:hover {
|
|
117
|
+
cursor: grab;
|
|
118
|
+
}
|
|
119
|
+
.pipWindow:active {
|
|
120
|
+
cursor: grabbing;
|
|
121
|
+
outline: -webkit-focus-ring-color auto 1px;
|
|
122
|
+
outline-color: -webkit-focus-ring-color;
|
|
123
|
+
outline-style: auto;
|
|
124
|
+
outline-width: 1px;
|
|
125
|
+
}
|
|
126
|
+
*/
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import ResizablePIP from './ResizablePIP';
|
|
3
|
+
|
|
4
|
+
const withDemoVideosAndLinks = (WrappedComponent, publicPath) => props => {
|
|
5
|
+
const [showPIP, setShowPIP] = useState(false);
|
|
6
|
+
const [PIPContentLink, setPIPContentLink] = useState('');
|
|
7
|
+
const [showMaximised, setShowMaximised] = useState(false);
|
|
8
|
+
const {
|
|
9
|
+
demoVideoAndLinkJSONData: { demoVideoAndLinkJSON = {} } = {},
|
|
10
|
+
userData: {
|
|
11
|
+
user: { lang: userLocale = '' } = {},
|
|
12
|
+
currentOrgDetails: {
|
|
13
|
+
basicDetails: { base_language: orgLocale = '' } = {},
|
|
14
|
+
} = {},
|
|
15
|
+
} = {},
|
|
16
|
+
match: { path = '' } = {},
|
|
17
|
+
} = props || {};
|
|
18
|
+
const JSONInContext = demoVideoAndLinkJSON?.[publicPath];
|
|
19
|
+
const currentPathJSON = JSONInContext?.find(
|
|
20
|
+
routeEle => routeEle.route === path,
|
|
21
|
+
);
|
|
22
|
+
const locale = userLocale || orgLocale || 'default';
|
|
23
|
+
|
|
24
|
+
const targetElements = currentPathJSON?.target_elements;
|
|
25
|
+
const cssSelectors = [];
|
|
26
|
+
if (Object.keys(targetElements)?.length) {
|
|
27
|
+
Object.keys(targetElements).map(targetElement => {
|
|
28
|
+
cssSelectors.push({
|
|
29
|
+
cssSelector: targetElement,
|
|
30
|
+
locale,
|
|
31
|
+
...targetElements[targetElement],
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
cssSelectors.forEach(selector => {
|
|
37
|
+
const {
|
|
38
|
+
support_link: { target_url: linkTargetUrl = {} } = {},
|
|
39
|
+
support_video: { target_url: videoTargetUrl = {} } = {},
|
|
40
|
+
locale,
|
|
41
|
+
cssSelector,
|
|
42
|
+
} = selector || {};
|
|
43
|
+
let matchedNodes = document.querySelectorAll(selector.cssSelector);
|
|
44
|
+
const handleOnClickVideoLink = () => {
|
|
45
|
+
setPIPContentLink(videoTargetUrl?.[locale]?.href);
|
|
46
|
+
setShowPIP(true);
|
|
47
|
+
};
|
|
48
|
+
const handleOpenSupportLink = () =>
|
|
49
|
+
window.open(linkTargetUrl?.[locale]?.href, '_blank');
|
|
50
|
+
|
|
51
|
+
if (selector?.support_video?.target_url?.default?.href) {
|
|
52
|
+
matchedNodes.forEach(node => {
|
|
53
|
+
if (!document.getElementById(`demo-video-${cssSelector}`)) {
|
|
54
|
+
let videoAnchor = document.createElement('a');
|
|
55
|
+
videoAnchor.textContent = videoTargetUrl?.[locale].label;
|
|
56
|
+
videoAnchor.id = `demo-video-${cssSelector}`;
|
|
57
|
+
videoAnchor.style.marginLeft = '2px';
|
|
58
|
+
videoAnchor.onclick = handleOnClickVideoLink;
|
|
59
|
+
|
|
60
|
+
const videoIconElement = document.createElement('i');
|
|
61
|
+
videoIconElement.innerHTML = `<svg width="1em" height="1em" viewBox="0 0 24 24" fill="currentColor">
|
|
62
|
+
<path
|
|
63
|
+
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"
|
|
64
|
+
id="play_svg__a"
|
|
65
|
+
></path>
|
|
66
|
+
</svg>`;
|
|
67
|
+
videoIconElement.onclick = handleOnClickVideoLink;
|
|
68
|
+
videoIconElement.style.marginLeft = '2px';
|
|
69
|
+
videoIconElement.style.cursor = 'pointer';
|
|
70
|
+
videoIconElement.style.color = '#2466eb';
|
|
71
|
+
videoIconElement.style.fontSize = '18px';
|
|
72
|
+
node.appendChild(videoIconElement);
|
|
73
|
+
node.appendChild(videoAnchor);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
} else if (selector?.support_link?.target_url?.default?.href) {
|
|
77
|
+
matchedNodes.forEach(node => {
|
|
78
|
+
if (!document.getElementById(`support-link-${cssSelector}`)) {
|
|
79
|
+
let linkAnchor = document.createElement('a');
|
|
80
|
+
linkAnchor.href = linkTargetUrl?.[locale]?.href;
|
|
81
|
+
linkAnchor.textContent = linkTargetUrl?.[locale].label;
|
|
82
|
+
linkAnchor.target = '_blank';
|
|
83
|
+
linkAnchor.id = `support-link-${cssSelector}`;
|
|
84
|
+
linkAnchor.style.marginLeft = '2px';
|
|
85
|
+
linkAnchor.onclick = handleOpenSupportLink;
|
|
86
|
+
|
|
87
|
+
const helpIconElement = document.createElement('i');
|
|
88
|
+
helpIconElement.innerHTML = `<svg width="1em" height="1em" viewBox="0 0 24 24" fill="currentColor">
|
|
89
|
+
<path
|
|
90
|
+
id="help_svg__a"
|
|
91
|
+
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"
|
|
92
|
+
></path>
|
|
93
|
+
</svg>`;
|
|
94
|
+
helpIconElement.onclick = handleOpenSupportLink;
|
|
95
|
+
helpIconElement.style.marginLeft = '2px';
|
|
96
|
+
helpIconElement.style.cursor = 'pointer';
|
|
97
|
+
helpIconElement.style.fontSize = '16px';
|
|
98
|
+
helpIconElement.style.color = '#2466eb';
|
|
99
|
+
|
|
100
|
+
node.appendChild(helpIconElement);
|
|
101
|
+
node.appendChild(linkAnchor);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const handleOpenInNew = () => {
|
|
108
|
+
window.open(PIPContentLink, '_blank');
|
|
109
|
+
};
|
|
110
|
+
const handleShowMaximised = () => {
|
|
111
|
+
setShowMaximised(!showMaximised);
|
|
112
|
+
};
|
|
113
|
+
const handleClosePIPContainer = () => setShowPIP(false);
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
<div>
|
|
117
|
+
{showPIP && (
|
|
118
|
+
<ResizablePIP
|
|
119
|
+
closePIPContainer={handleClosePIPContainer}
|
|
120
|
+
handleOpenInNew={handleOpenInNew}
|
|
121
|
+
handleShowMaximised={handleShowMaximised}
|
|
122
|
+
showMaximised={showMaximised}
|
|
123
|
+
>
|
|
124
|
+
<iframe
|
|
125
|
+
width="100%"
|
|
126
|
+
height="100%"
|
|
127
|
+
src={PIPContentLink}
|
|
128
|
+
title="YouTube video player"
|
|
129
|
+
frameBorder="0"
|
|
130
|
+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
|
131
|
+
/>
|
|
132
|
+
</ResizablePIP>
|
|
133
|
+
)}
|
|
134
|
+
<WrappedComponent {...props} />
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export default withDemoVideosAndLinks;
|