releasebird-javascript-sdk 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,80 @@
1
+ import RbirdWebsiteWidget from "./RbirdWebsiteWidget";
2
+ import SVGEditor from "./SVGEditor";
3
+ import html2canvas from "html2canvas";
4
+
5
+ export default class RbirdScreenshotManager {
6
+
7
+ static instance;
8
+
9
+ boundary;
10
+
11
+ static getInstance() {
12
+ if (!this.instance) {
13
+ this.instance = new RbirdScreenshotManager();
14
+ }
15
+ return this.instance;
16
+ }
17
+
18
+ activateMarker(allowPointerEvents) {
19
+ document.body.style.overflow = 'hidden';
20
+ RbirdWebsiteWidget.getInstance().closeWebsiteWidget();
21
+ this.boundary = document.createElement('div');
22
+ this.boundary.id = "markerBoundary";
23
+ this.boundary.className = "markerBoundary";
24
+ this.boundary.style.display = 'block';
25
+ this.boundary.style.height = '100%';
26
+
27
+ if (!allowPointerEvents) {
28
+ this.boundary.style.pointerEvents = 'none';
29
+ }
30
+
31
+ const closeButton = document.createElement('div');
32
+ closeButton.id = "screenshotCloseButton";
33
+ closeButton.className = "screenshotCloseButton"
34
+ closeButton.innerText = "Close";
35
+ closeButton.onclick = () => {
36
+ document.body.removeChild(this.boundary);
37
+ }
38
+
39
+ this.boundary.appendChild(closeButton);
40
+ document.body.appendChild(this.boundary);
41
+ // @ts-ignore
42
+ new SVGEditor({
43
+ element: this.boundary,
44
+ dimension: {
45
+ width: "100%",
46
+ height: "100%"
47
+ }
48
+ })
49
+ }
50
+
51
+ deactivateMarker() {
52
+ document.body.style.overflow = 'auto';
53
+ document.body.removeChild(this.boundary);
54
+ RbirdWebsiteWidget.getInstance().openWebsiteWidget();
55
+ }
56
+
57
+ screenshot() {
58
+ let that = this;
59
+ html2canvas(document.body, {
60
+ allowTaint: false,
61
+ useCORS: false,
62
+ logging: false,
63
+ foreignObjectRendering: false
64
+ }).then(function (canvas) {
65
+ if (RbirdWebsiteWidget.getInstance().iframe) {
66
+ RbirdWebsiteWidget.getInstance().iframe.contentWindow?.postMessage({
67
+ type: 'screenshot',
68
+ screenshot: canvas.toDataURL("image/jpeg")
69
+ }, '*');
70
+ }
71
+
72
+ that.deactivateMarker();
73
+
74
+ //document.body.appendChild(canvas);
75
+ }).catch((e) => {
76
+ document.body.appendChild(e.toString());
77
+ });
78
+ }
79
+
80
+ }
@@ -0,0 +1,138 @@
1
+ import RbirdWebsiteWidget from "./RbirdWebsiteWidget";
2
+ import Rbird from "./index";
3
+
4
+ export default class RbirdSessionManager {
5
+
6
+ static instance;
7
+
8
+ widgetSettings;
9
+
10
+ apiKey;
11
+
12
+ anonymousIdentifier;
13
+
14
+ identify;
15
+
16
+ static getInstance() {
17
+ if (!this.instance) {
18
+ this.instance = new RbirdSessionManager();
19
+ }
20
+ return this.instance;
21
+ }
22
+
23
+ generateRandomString() {
24
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
25
+ let result = '';
26
+ for (let i = 0; i < 60; i++) {
27
+ result += characters.charAt(Math.floor(Math.random() * characters.length));
28
+ }
29
+ return result;
30
+ };
31
+
32
+ init(apiKey) {
33
+ this.apiKey = apiKey;
34
+ this.identify = this.getState()?.identify;
35
+ const http = new XMLHttpRequest();
36
+ http.open("GET", `${API}/ewidget`);
37
+ http.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
38
+ http.setRequestHeader("apiKey", apiKey);
39
+ http.onerror = function () {
40
+ //handle error
41
+ };
42
+ const self = this;
43
+ http.onreadystatechange = function (e) {
44
+ if (http.readyState === XMLHttpRequest.DONE) {
45
+ if (http.status === 200 || http.status === 201) {
46
+ try {
47
+ self.widgetSettings = JSON.parse(http.responseText);
48
+ Rbird.setStyles(
49
+ self.widgetSettings.backgroundColor,
50
+ self.widgetSettings.textColor,
51
+ self.widgetSettings.launcherColor,
52
+ self.widgetSettings.launcherPosition,
53
+ self.widgetSettings.spaceLeftRight,
54
+ self.widgetSettings.spaceBottom
55
+ );
56
+ RbirdWebsiteWidget.getInstance().renderWebsiteWidget();
57
+ RbirdWebsiteWidget.getInstance().styleWidget();
58
+ } catch (e) {
59
+ }
60
+ }
61
+ //reject();
62
+ }
63
+ };
64
+ http.send();
65
+ let anonymous = window.localStorage.getItem("Rbird_I");
66
+ if (!anonymous) {
67
+ const i = this.generateRandomString();
68
+ window.localStorage.setItem('Rbird_I', i);
69
+ this.anonymousIdentifier = i;
70
+ } else {
71
+ this.anonymousIdentifier = anonymous;
72
+ }
73
+ this.anonymousIdentifier = this.anonymousIdentifier.replace("\"", "");
74
+ setInterval(() => {
75
+ let state = this.getState();
76
+ if (state?.identify && state?.identify?.properties['external_user_id']) {
77
+ const http = new XMLHttpRequest();
78
+ http.open("POST", `${API}/ewidget/ping`);
79
+ http.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
80
+ http.setRequestHeader("apiKey", apiKey);
81
+ http.send(JSON.stringify(state.identify));
82
+ }
83
+ }, 30000);
84
+ }
85
+
86
+ getState() {
87
+ let state = window.localStorage.getItem('rbird_state');
88
+ if (state) {
89
+ return JSON.parse(state);
90
+ } else if (!state) {
91
+ state = {};
92
+ state.identify = {};
93
+ state.identify['properties'] = {};
94
+ window.localStorage.setItem('rbird_state', JSON.stringify(state));
95
+ }
96
+ return JSON.parse(state);
97
+ }
98
+
99
+ identifyUser(identify, hash) {
100
+ let state = this.getState();
101
+ state.identify.properties = identify;
102
+ state.identify.hash = identify.hash;
103
+ const http = new XMLHttpRequest();
104
+ http.open("POST", `${API}/ewidget/identify`);
105
+ http.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
106
+ http.setRequestHeader("timezone", Intl.DateTimeFormat().resolvedOptions().timeZone);
107
+ http.setRequestHeader("apiKey", this.apiKey);
108
+ http.onerror = (error) => {
109
+ //handle error
110
+ };
111
+ let self = this;
112
+ http.onreadystatechange = function (e) {
113
+ if (http.readyState === 4) {
114
+ if (http.status === 200 || http.status === 201) {
115
+ try {
116
+ //handle success
117
+ let response = JSON.parse(http.responseText);
118
+ if (response.valid) {
119
+ state.identify.people = response.peopleId;
120
+ if (hash) {
121
+ state.identify.hash = hash;
122
+ }
123
+ window.localStorage.setItem("rbird_state", JSON.stringify(state));
124
+ console.log(`${CONTENT_URL}/widget?apiKey=${RbirdSessionManager.getInstance().apiKey}&tab=HOME&people=${response.peopleId}&hash=${hash}&ai=${self.anonymousIdentifier}`);
125
+ RbirdWebsiteWidget.getInstance().updateIframe(`${CONTENT_URL}/widget?apiKey=${RbirdSessionManager.getInstance().apiKey}&tab=HOME&people=${response.peopleId}&hash=${hash}&ai=${self.anonymousIdentifier}`);
126
+ }
127
+ } catch (exp) {
128
+ //handle error
129
+ }
130
+ } else {
131
+ //handle error
132
+ }
133
+ }
134
+ };
135
+ http.send(JSON.stringify(state.identify));
136
+
137
+ }
138
+ }
@@ -0,0 +1,25 @@
1
+ export default class RbirdUtils {
2
+
3
+ static hasClass(el, className) {
4
+ if (el.classList)
5
+ return el.classList.contains(className);
6
+ return !!el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)'));
7
+ }
8
+
9
+ static addClass(el, className) {
10
+ if (el.classList)
11
+ el.classList.add(className)
12
+ else if (!hasClass(el, className))
13
+ el.className += " " + className;
14
+ }
15
+
16
+ static removeClass(el, className) {
17
+ if (el.classList)
18
+ el.classList.remove(className)
19
+ else if (hasClass(el, className)) {
20
+ var reg = new RegExp('(\\s|^)' + className + '(\\s|$)');
21
+ el.className = el.className.replace(reg, ' ');
22
+ }
23
+ }
24
+
25
+ }
@@ -0,0 +1,266 @@
1
+ import RbirdWebsiteWidget from "./RbirdWebsiteWidget";
2
+
3
+ export default class RbirdVideoRecorder {
4
+ static instance;
5
+
6
+ mediaRecorder = null;
7
+
8
+ static getInstance() {
9
+ if (!this.instance) {
10
+ this.instance = new RbirdVideoRecorder();
11
+ }
12
+ return this.instance;
13
+ }
14
+
15
+ onTimer(countdownElement, countDown, countdownTimer, mediaRecorder) {
16
+ countdownElement.innerHTML = '<div style="margin-top: 5px;margin-left: 10px">' + countDown + '</div>'
17
+ countDown--;
18
+ // If the count down is finished
19
+ if (countDown < 0) {
20
+ mediaRecorder.stop();
21
+ clearInterval(countdownTimer);
22
+ }
23
+ }
24
+
25
+ startTimer(countdownElement) {
26
+ let countDown = 60;
27
+ let countdownTimer = setInterval(() => {
28
+ countDown--;
29
+ this.onTimer(countdownElement, countDown, countdownTimer, this.mediaRecorder)
30
+ }, 1000);
31
+ }
32
+
33
+ async startRecording(allowPointerEvents) {
34
+
35
+ let stream;
36
+
37
+ const that = this;
38
+
39
+ try {
40
+ stream = await navigator.mediaDevices.getDisplayMedia({
41
+ audio: true,
42
+ // @ts-ignore
43
+ video: {mediaSource: "screen"}
44
+ });
45
+ } catch (e) {
46
+ alert('Screensharing not allowed by user');
47
+ return;
48
+ }
49
+
50
+ let element = document.createElement('div');
51
+ let countdownElement = this.addCountDownElement(element);
52
+
53
+ if (stream && stream.active) {
54
+
55
+ const boundary
56
+ = document?.getElementById('test')?.getElementsByTagName('rbird-box')[0]?.shadowRoot?.getElementById('markerBoundary');
57
+ if (boundary) {
58
+ boundary.style.display = 'block';
59
+ if (!allowPointerEvents) {
60
+ boundary.style.pointerEvents = 'none';
61
+ }
62
+ if (boundary.querySelector('#screenshotCloseButton') !== null) {
63
+ // @ts-ignore
64
+ boundary.removeChild(boundary.querySelector('#screenshotCloseButton'))
65
+ }
66
+ }
67
+ RbirdWebsiteWidget.getInstance().closeWebsiteWidget();
68
+
69
+ let recordedChunks = [];
70
+
71
+ const options = {mimeType: 'video/webm;codecs=vp9'};
72
+ this.mediaRecorder = new MediaRecorder(stream, options);
73
+
74
+ this.mediaRecorder.ondataavailable = function (e) {
75
+ if (e.data.size > 0) {
76
+ recordedChunks.push(e.data);
77
+ }
78
+ };
79
+
80
+ this.startTimer(countdownElement);
81
+
82
+ this.mediaRecorder.onstop = function () {
83
+ document.body.removeChild(element);
84
+ const modal = document.createElement('div');
85
+ modal.style.width = '100%';
86
+ modal.style.height = '100%';
87
+ modal.style.backgroundColor = 'rgba(0,0,0,0.8)';
88
+ modal.style.overflow = 'auto';
89
+ modal.style.position = 'fixed';
90
+ modal.style.zIndex = '90000000000';
91
+ modal.style.top = '0';
92
+ modal.style.left = '0';
93
+
94
+ const modalContent = document.createElement('div');
95
+ modalContent.style.margin = '15% auto';
96
+ modalContent.style.padding = '20px';
97
+ modalContent.style.border = '1px solid #888';
98
+ modalContent.style.backgroundColor = 'white';
99
+ modalContent.style.borderRadius = '8px';
100
+ modalContent.style.height = '525px';
101
+ modalContent.style.width = '700px';
102
+
103
+ const buttonFooter = document.createElement('div');
104
+
105
+ buttonFooter.style.display = 'flex';
106
+ buttonFooter.style.display = 'block';
107
+ buttonFooter.style.height = '30px';
108
+ buttonFooter.style.marginTop = '20px';
109
+
110
+
111
+ const retryButton = document.createElement('div');
112
+ retryButton.style.backgroundColor = 'orange';
113
+ retryButton.style.color = 'white';
114
+ retryButton.style.fontWeight = '500';
115
+ retryButton.innerHTML = "Retry";
116
+ retryButton.style.float = "left";
117
+ retryButton.style.padding = "13px";
118
+ retryButton.style.paddingTop = "8px";
119
+ retryButton.style.paddingBottom = "8px";
120
+ retryButton.style.fontFamily = "Arial";
121
+ retryButton.style.fontSize = "16px";
122
+ retryButton.style.borderRadius = "8px";
123
+ retryButton.style.marginLeft = "10px";
124
+ retryButton.style.cursor = "pointer";
125
+ retryButton.addEventListener('click', () => {
126
+ URL.revokeObjectURL(blob);
127
+ recordedChunks = [];
128
+ document.body.removeChild(modal);
129
+ element = document.createElement('div');
130
+ countdownElement = that.addCountDownElement(element);
131
+ that.startTimer(countdownElement);
132
+ that.restartRecording();
133
+
134
+ });
135
+
136
+
137
+ const cancelButton = document.createElement('div');
138
+ cancelButton.innerHTML = 'Cancel';
139
+ cancelButton.style.backgroundColor = 'red';
140
+ cancelButton.style.color = 'white';
141
+ cancelButton.style.fontWeight = '500';
142
+ cancelButton.style.float = "left";
143
+ cancelButton.style.padding = "13px";
144
+ cancelButton.style.paddingTop = "8px";
145
+ cancelButton.style.paddingBottom = "8px";
146
+ cancelButton.style.fontFamily = "Arial";
147
+ cancelButton.style.fontSize = "16px";
148
+ cancelButton.style.borderRadius = "8px";
149
+ cancelButton.style.cursor = "pointer";
150
+
151
+ cancelButton.addEventListener('click', () => {
152
+ // stop screen sharing
153
+ stream.getTracks()
154
+ .forEach(track => track.stop());
155
+ // @ts-ignore
156
+ URL.revokeObjectURL(blob);
157
+ recordedChunks = [];
158
+ document.body.removeChild(modal);
159
+ if (boundary) {
160
+ boundary.style.display = 'none';
161
+ }
162
+ RbirdWebsiteWidget.getInstance().openWebsiteWidget();
163
+ });
164
+ buttonFooter.appendChild(cancelButton);
165
+ buttonFooter.appendChild(retryButton);
166
+
167
+ const submitVideo = document.createElement('div');
168
+ submitVideo.innerHTML = 'Continue';
169
+ submitVideo.style.backgroundColor = 'green';
170
+ submitVideo.style.color = 'white';
171
+ submitVideo.style.fontWeight = '500';
172
+ submitVideo.innerHTML = "Submit";
173
+ submitVideo.style.float = "right";
174
+ submitVideo.style.padding = "13px";
175
+ submitVideo.style.paddingTop = "8px";
176
+ submitVideo.style.paddingBottom = "8px";
177
+ submitVideo.style.fontFamily = "Arial";
178
+ submitVideo.style.fontSize = "16px";
179
+ submitVideo.style.borderRadius = "8px";
180
+ submitVideo.style.marginLeft = "10px";
181
+ submitVideo.style.cursor = "pointer";
182
+ submitVideo.addEventListener('click', () => {
183
+ // stop screen sharing
184
+ stream.getTracks()
185
+ .forEach(track => track.stop());
186
+
187
+
188
+ if (RbirdWebsiteWidget.getInstance().iframe) {
189
+ RbirdWebsiteWidget.getInstance().iframe.contentWindow?.postMessage({
190
+ type: 'video',
191
+ video: blob
192
+ }, '*');
193
+ }
194
+
195
+
196
+ // @ts-ignore
197
+ URL.revokeObjectURL(blob);
198
+ recordedChunks = [];
199
+ document.body.removeChild(modal);
200
+ if (boundary) {
201
+ boundary.style.display = 'none';
202
+ }
203
+ RbirdWebsiteWidget.getInstance().openWebsiteWidget();
204
+ });
205
+ buttonFooter.appendChild(submitVideo);
206
+
207
+ const blob = new Blob(recordedChunks, {
208
+ //video/webm;codecs=H264
209
+ type: 'video/webm;codecs=vp9'
210
+ });
211
+
212
+ const video = document.createElement('video');
213
+ video.controls = true;
214
+ video.style.width = '650px';
215
+ video.style.height = '400px';
216
+ const source = document.createElement('source');
217
+ source.type = 'video/webm;codecs=vp9';
218
+ source.src = URL.createObjectURL(blob);
219
+ video.appendChild(source);
220
+
221
+ modalContent.appendChild(video);
222
+ modalContent.appendChild(buttonFooter);
223
+ modal.appendChild(modalContent);
224
+ document.body.appendChild(modal);
225
+ };
226
+ this.mediaRecorder.start(200);
227
+ }
228
+ }
229
+
230
+
231
+
232
+ addCountDownElement(element) {
233
+ element.id = 'rbirdRecorderMenu'
234
+ element.style.position = 'absolute';
235
+ element.style.top = '10px';
236
+ element.style.left = '50%';
237
+ element.style.zIndex = '900000000';
238
+ element.style.backgroundColor = 'white';
239
+ element.style.border = '1px solid lightgrey';
240
+ element.style.padding = '10px';
241
+ element.style.borderRadius = '8px';
242
+ element.style.transform = 'translateX(-50%)';
243
+
244
+ const stopButton = document.createElement('div');
245
+ stopButton.innerHTML = "<svg viewBox=\"0 0 512 512\" width='20pt' height='20pt' xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"><linearGradient id=\"linear-gradient\" gradientUnits=\"userSpaceOnUse\" x1=\"67.69\" x2=\"441.35\" y1=\"67.69\" y2=\"441.35\"><stop offset=\"0\" stop-color=\"#fd7f60\"/><stop offset=\"1\" stop-color=\"#fa262a\"/></linearGradient><g id=\"Layer_2\" data-name=\"Layer 2\"><g id=\"Layer_2_copy_7\" data-name=\"Layer 2 copy 7\"><g id=\"_137\" fill=\"url(#linear-gradient)\" data-name=\"137\"><path id=\"background\" d=\"m256 20c130.34 0 236 105.66 236 236s-105.66 236-236 236-236-105.66-236-236 105.66-236 236-236m0-20a255.93 255.93 0 0 0 -181 437 256 256 0 1 0 280.65-416.87 254.3 254.3 0 0 0 -99.65-20.13z\"/><rect height=\"247.06\" rx=\"38.38\" width=\"247.06\" x=\"132.47\" y=\"132.47\"/></g></g></g></svg>"
246
+ stopButton.style.cursor = 'pointer';
247
+ stopButton.style.float = 'left';
248
+ stopButton.addEventListener("click", () => this.stopRecording())
249
+ element.appendChild(stopButton);
250
+ const countdownElement = document.createElement('div');
251
+ countdownElement.innerHTML = '<div style="margin-top: 5px;margin-left: 10px">60</div>';
252
+ countdownElement.id = "rbirdCountdown";
253
+ countdownElement.style.float = 'left';
254
+ element.appendChild(countdownElement);
255
+ document.body.appendChild(element);
256
+ return countdownElement;
257
+ }
258
+
259
+ async stopRecording() {
260
+ this.mediaRecorder.stop();
261
+ }
262
+
263
+ async restartRecording() {
264
+ this.mediaRecorder.start();
265
+ }
266
+ }