@careevolution/mydatahelps-js 2.3.0 → 3.0.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/MyDataHelps.js CHANGED
@@ -1,690 +1,800 @@
1
- var MyDataHelps = {};
2
- // For backwards compatibility
3
- var RKStudioClient = {};
4
-
5
- var accessTokenRenewalBufferSeconds = 120;
6
- var currentMessageID = 1;
7
- var messageHandlers = [];
8
- var registeredEventHandlers = {};
9
- var apiBasePath = 'api/v1/delegated/';
10
-
11
- function getParentOrigin() {
12
- var ancestorOrigins = document.location.ancestorOrigins;
13
- if (ancestorOrigins && ancestorOrigins[0]) {
14
- return ancestorOrigins[0];
15
- }
16
-
17
- return '*';
18
- }
19
-
20
- function acceptableOrigin(origin) {
21
- if (origin === '*') return true;
22
-
23
- var allowedApplicationHosts = [
24
- 'localhost',
25
- 'careevolution.com',
26
- 'internal',
27
- 'b3-deploys.com',
28
- 'mydatahelps.org',
29
- 'platform.joinallofus.org',
30
- 'careevolution.dev',
31
- 'ce.dev'
32
- ];
33
-
34
- var sourceURL = new URL(origin);
35
- for (var k = 0; k < allowedApplicationHosts.length; k++) {
36
- if (sourceURL.hostname === allowedApplicationHosts[k] || sourceURL.hostname.endsWith("." + allowedApplicationHosts[k])) {
37
- return true;
38
- }
39
- }
40
- return false;
41
- }
42
-
43
- var applicationHost = getParentOrigin();
44
- if (!acceptableOrigin(applicationHost)) {
45
- console.error("Application is not hosted at an approved origin.");
46
- throw "Application is not hosted at an approved origin.";
47
- }
48
-
49
- var supportedActions;
50
- if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.ResearchKit) {
51
- supportedActions = {
52
- "GetDelegatedAccessToken": function (data) { window.parent.postMessage({ name: 'GetDelegatedAccessToken', messageID: data.messageID }, applicationHost); },
53
- "GetDeviceInfo": function (data) { window.parent.postMessage({ name: 'GetDeviceInfo', messageID: data.messageID }, applicationHost); }
54
- };
55
- }
56
- else {
57
- supportedActions = {
58
- "GetDelegatedAccessToken": function (data) { window.parent.postMessage({ name: 'GetDelegatedAccessToken', messageID: data.messageID }, applicationHost); },
59
- "GetDeviceInfo": function (data) { window.parent.postMessage({ name: 'GetDeviceInfo', messageID: data.messageID }, applicationHost); },
60
- "StartParticipantSurvey": function (data) { window.parent.postMessage({ name: 'StartParticipantSurvey', messageID: data.messageID, surveyName: data.surveyName }, applicationHost); },
61
- "OpenExternalLink": function (data) { window.parent.postMessage({ name: 'OpenExternalUrl', url: data }, applicationHost); },
62
- "OpenEmbeddedLink": function (data) { window.parent.postMessage({ name: 'OpenEmbeddedUrl', url: data }, applicationHost); },
63
- "OpenExternalApplication": function (data) { window.parent.postMessage({ name: 'OpenApplication', messageID: data.messageID, url: data.url, modal: data.modal }, applicationHost); },
64
- "Dismiss": function () { window.parent.postMessage({ name: 'Dismiss' }, applicationHost); },
65
- "PopNavigation": function () { window.parent.postMessage({ name: 'Back' }, applicationHost); },
66
- "ShowTab": function (data) { window.parent.postMessage({ name: 'ShowTab', tabKey: data }, applicationHost); },
67
- "ShowParticipantDashboard": function (data) { window.parent.postMessage({ name: 'ShowParticipantDashboard', dashboardKey: data.dashboardKey, modal: data.modal }, applicationHost); },
68
- "ShowParticipantWebVisualization": function (data) { window.parent.postMessage({ name: 'ShowParticipantWebVisualization', visualizationKey: data.visualizationKey, parameters: data.parameters, modal: data.modal }, applicationHost); },
69
- "ShowParticipantWebVisualizationPDF": function (data) { window.parent.postMessage({ name: 'ShowParticipantWebVisualizationPDF', visualizationKey: data.visualizationKey, parameters: data.parameters, modal: data.modal, landscape: data.landscape, htmlViewerZoom: data.htmlViewerZoom }, applicationHost); },
70
- "DeleteProviderAccount": function (data) { window.parent.postMessage({ name: 'DeleteProviderAccount', messageID: data.messageID, accountID: data.accountID }, applicationHost); },
71
- "ConnectExternalAccount": function (data) { window.parent.postMessage({ name: 'ConnectExternalAccount', externalAccountProviderID: data.externalAccountProviderID }, applicationHost); },
72
- "ShowProject": function (data) { window.parent.postMessage({ name: 'ShowProject', code: data.code }, applicationHost); },
73
- "JoinProject": function (data) { window.parent.postMessage({ name: 'JoinProject', code: data.code }, applicationHost); }
74
- };
75
- }
76
-
77
- var unsupportedActions = ["SetHeight", "ResearchKit"];
78
-
79
- var supportedEvents = ["surveyDidFinish", "applicationDidBecomeVisible", "externalAccountSyncComplete", "tokenWillExpire"];
80
-
81
- function windowHasAnyActions() {
82
- for (var action in supportedActions) {
83
- if (window.webkit.messageHandlers[action]) {
84
- return true;
85
- }
86
- }
87
- for (var action in unsupportedActions) {
88
- if (window.webkit.messageHandlers[unsupportedActions[action]]) {
89
- return true;
90
- }
91
- }
92
- return false;
93
- }
94
-
95
- if (!window.webkit || !window.webkit.messageHandlers || !windowHasAnyActions()) {
96
- window.webkit = {
97
- messageHandlers: {}
98
- };
99
- }
100
-
101
- for (var action in supportedActions) {
102
- window.webkit.messageHandlers[action] = window.webkit.messageHandlers[action] || { postMessage: supportedActions[action] };
103
- }
104
-
105
- var nextMessageID = function () {
106
- return currentMessageID++;
107
- };
108
-
109
- function validateWindowMessageOrigin(message) {
110
- if (applicationHost === "*") {
111
- return acceptableOrigin(message.origin);
112
- }
113
-
114
- return message.origin === applicationHost;
115
- }
116
-
117
- var receiveWindowMessage = function (message) {
118
- if (!validateWindowMessageOrigin(message)) {
119
- console.error("message.origin '" + message.origin + "' is not allowed.");
120
- throw "message.origin '" + message.origin + "' is not allowed.";
121
- }
122
-
123
- if (message.data.messageID) {
124
- MyDataHelps.setActionResult(message.data);
125
- }
126
- else {
127
- MyDataHelps.triggerEvent(message.data);
128
- }
129
- };
130
-
131
- window.addEventListener("message", receiveWindowMessage, false);
132
-
133
- MyDataHelps.setActionResult = function (data) {
134
- messageHandlers[data.messageID](data);
135
- };
136
-
137
- RKStudioClient.setActionResult = function (data) {
138
- MyDataHelps.setActionResult(data);
139
- };
140
-
141
- MyDataHelps.triggerEvent = function (event) {
142
- var eventName = event.type;
143
- if (supportedEvents.includes(eventName) && registeredEventHandlers[eventName]) {
144
- registeredEventHandlers[eventName].forEach(function (handler) {
145
- handler(event);
146
- });
147
- }
148
- };
149
-
150
- //Authorization
151
-
152
- var refreshTokenPromise = null;
153
- MyDataHelps.connect = function () {
154
- var refreshDelegatedAccessToken = function () {
155
- MyDataHelps.token = null;
156
-
157
- refreshTokenPromise = new Promise(function (resolve, reject) {
158
- var messageID = nextMessageID();
159
- messageHandlers[messageID] = function (tokenResponse) {
160
- if (tokenResponse.success) {
161
- MyDataHelps.tokenExpires = Date.now() + (tokenResponse.data.expires_in * 1000);
162
- MyDataHelps.token = tokenResponse.data;
163
- MyDataHelps.baseUrl = tokenResponse.baseUrl;
164
- window.setTimeout(refreshDelegatedAccessToken, ((tokenResponse.data.expires_in - accessTokenRenewalBufferSeconds) * 1000));
165
- resolve();
166
- } else {
167
- MyDataHelps.token = null;
168
- reject(tokenResponse.message);
169
- }
170
- messageHandlers[messageID] = null;
171
- refreshTokenPromise = null;
172
- };
173
-
174
- window.webkit.messageHandlers.GetDelegatedAccessToken.postMessage({ messageID: messageID });
175
- });
176
- };
177
-
178
- if (MyDataHelps.token && Date.now() < MyDataHelps.tokenExpires) {
179
- return Promise.resolve();
180
- }
181
-
182
- if (!refreshTokenPromise) {
183
- refreshDelegatedAccessToken();
184
- }
185
-
186
- // Re-use promise if refresh already in progress
187
- return refreshTokenPromise;
188
- };
189
-
190
- //Initializing access token manually
191
- MyDataHelps.setParticipantAccessToken = function (token, baseUrl) {
192
- MyDataHelps.token = token;
193
- if (baseUrl) {
194
- MyDataHelps.baseUrl = baseUrl;
195
- }
196
- MyDataHelps.tokenExpires = Date.now() + (token.expires_in * 1000);
197
- window.setTimeout(function () {
198
- MyDataHelps.triggerEvent({ type: "tokenWillExpire" });
199
- }, ((token.expires_in - accessTokenRenewalBufferSeconds) * 1000));
200
- };
201
-
202
- //Actions
203
-
204
- MyDataHelps.completeStep = function (answer) {
205
- if (answer === undefined || answer === null) answer = '';
206
-
207
- if (window.webkit.messageHandlers.ResearchKit) {
208
- window.webkit.messageHandlers.ResearchKit.postMessage(answer);
209
- }
210
- };
211
-
212
- MyDataHelps.startSurvey = function (surveyName) {
213
- var messageID = nextMessageID();
214
- window.webkit.messageHandlers.StartParticipantSurvey.postMessage({ messageID: messageID, surveyName: surveyName });
215
- };
216
-
217
- MyDataHelps.openExternalUrl = function (url) {
218
- window.webkit.messageHandlers.OpenExternalLink.postMessage(url);
219
- };
220
-
221
- MyDataHelps.openEmbeddedUrl = function (url) {
222
- window.webkit.messageHandlers.OpenEmbeddedLink.postMessage(url);
223
- };
224
-
225
- MyDataHelps.openApplication = function (url, options) {
226
- var messageID = nextMessageID();
227
- window.webkit.messageHandlers.OpenExternalApplication.postMessage({ messageID: messageID, url: url, modal: options && options.modal ? true : false });
228
- };
229
-
230
- MyDataHelps.dismiss = function () {
231
- window.webkit.messageHandlers.Dismiss.postMessage({});
232
- };
233
-
234
- MyDataHelps.back = function () {
235
- window.webkit.messageHandlers.PopNavigation.postMessage({});
236
- };
237
-
238
- MyDataHelps.showTab = function (tabKey) {
239
- window.webkit.messageHandlers.ShowTab.postMessage(tabKey);
240
- };
241
-
242
- MyDataHelps.showDashboard = function (dashboardKey, options) {
243
- window.webkit.messageHandlers.ShowParticipantDashboard.postMessage({
244
- dashboardKey: dashboardKey,
245
- modal: options && options.modal ? true : false,
246
- title: options && options.title ? options.title : undefined
247
- });
248
- };
249
-
250
- MyDataHelps.showWebVisualization = function (visualizationKey, parameters, options) {
251
- window.webkit.messageHandlers.ShowParticipantWebVisualization.postMessage({
252
- visualizationKey: visualizationKey,
253
- parameters: parameters,
254
- modal: options && options.modal ? true : false,
255
- title: options && options.title ? options.title : undefined
256
- });
257
- };
258
-
259
- MyDataHelps.showWebVisualizationPdf = function (visualizationKey, parameters, options) {
260
- window.webkit.messageHandlers.ShowParticipantWebVisualizationPDF.postMessage({
261
- visualizationKey: visualizationKey,
262
- parameters: parameters,
263
- landscape: options && options.landscape ? true : false,
264
- htmlViewerZoom: options && options.htmlViewerZoom
265
- });
266
- };
267
-
268
- MyDataHelps.setStatusBarStyle = function (style) {
269
- if (window.webkit.messageHandlers.SetStatusBarStyle) {
270
- window.webkit.messageHandlers.SetStatusBarStyle.postMessage({ style: style });
271
- }
272
- };
273
-
274
- MyDataHelps.requestReview = function (cooldownDays) {
275
- if (window.webkit.messageHandlers.RequestReview) {
276
- window.webkit.messageHandlers.RequestReview.postMessage({ cooldownDays: cooldownDays });
277
- }
278
- };
279
-
280
- MyDataHelps.getDeviceInfo = function () {
281
- return new Promise(function (resolve, reject) {
282
- var messageID = nextMessageID();
283
- messageHandlers[messageID] = function (deviceInfoResponse) {
284
- resolve(deviceInfoResponse.data);
285
- };
286
-
287
- if (window.webkit.messageHandlers.GetDeviceInfo) {
288
- window.webkit.messageHandlers.GetDeviceInfo.postMessage({ messageID: messageID });
289
- } else {
290
- reject();
291
- }
292
- });
293
- };
294
-
295
- MyDataHelps.deleteExternalAccount = function (accountID) {
296
- return new Promise(function (resolve, reject) {
297
- var messageID = nextMessageID();
298
- messageHandlers[messageID] = function (deleteProviderAccountResponse) {
299
- if (!deleteProviderAccountResponse.success) {
300
- reject(deleteProviderAccountResponse);
301
- } else {
302
- resolve(deleteProviderAccountResponse);
303
- }
304
- };
305
-
306
- if (window.webkit.messageHandlers.DeleteProviderAccount) {
307
- window.webkit.messageHandlers.DeleteProviderAccount.postMessage({ messageID: messageID, accountID: accountID });
308
- } else {
309
- reject();
310
- }
311
- });
312
- };
313
-
314
- MyDataHelps.connectExternalAccount = function (externalAccountProviderID) {
315
- if (window.webkit.messageHandlers.ConnectExternalAccount) {
316
- window.webkit.messageHandlers.ConnectExternalAccount.postMessage({ externalAccountProviderID: externalAccountProviderID });
317
- }
318
- };
319
-
320
- MyDataHelps.showProject = function (projectCode) {
321
- if (window.webkit.messageHandlers.ShowProject) {
322
- window.webkit.messageHandlers.ShowProject.postMessage({ code: projectCode });
323
- }
324
- };
325
-
326
- MyDataHelps.joinProject = function (projectCode) {
327
- if (window.webkit.messageHandlers.JoinProject) {
328
- window.webkit.messageHandlers.JoinProject.postMessage({ code: projectCode });
329
- }
330
- };
331
-
332
- MyDataHelps.getCurrentLanguage = function () {
333
- var searchParams = new URLSearchParams(window.location.search);
334
- if (searchParams.has("lang")) {
335
- return searchParams.get("lang");
336
- }
337
- else {
338
- return navigator.language;
339
- }
340
- };
341
-
342
- MyDataHelps.showGoogleFitSettings = function () {
343
- if (window.webkit.messageHandlers.ShowGoogleFitSettings) {
344
- window.webkit.messageHandlers.ShowGoogleFitSettings.postMessage({});
345
- }
346
- };
347
-
348
- //Events
349
-
350
- MyDataHelps.on = function (eventName, eventHandler) {
351
-
352
- if (!supportedEvents.includes(eventName)) {
353
- throw new Error(eventName + " is not a supported event type.");
354
- }
355
-
356
- if (!registeredEventHandlers[eventName]) {
357
- registeredEventHandlers[eventName] = [];
358
- }
359
-
360
- registeredEventHandlers[eventName].push(eventHandler);
361
- };
362
-
363
- MyDataHelps.off = function (eventName, eventHandler) {
364
-
365
- if (!supportedEvents.includes(eventName)) {
366
- throw new Error(eventName + " is not a supported event type.");
367
- }
368
-
369
- if (!registeredEventHandlers[eventName]) return;
370
-
371
- var eventHandlerIndex = registeredEventHandlers[eventName].indexOf(eventHandler);
372
-
373
- if (eventHandlerIndex !== -1) {
374
- registeredEventHandlers[eventName].splice(eventHandlerIndex, 1);
375
- }
376
- };
377
-
378
- //Data
379
-
380
- var makeUrl = function (endpoint) {
381
- if (!MyDataHelps.baseUrl) {
382
- console.error("Cannot use makeUrl without MyDataHelps.baseUrl.");
383
- throw "Cannot use makeUrl without MyDataHelps.baseUrl.";
384
- }
385
-
386
- return MyDataHelps.baseUrl + apiBasePath + endpoint;
387
- };
388
-
389
- var makeRequest = function (endpoint, method, body) {
390
- if (!MyDataHelps.token || !MyDataHelps.token.access_token) {
391
- throw "No access_token available for request authorization.";
392
- }
393
-
394
- var url = makeUrl(endpoint);
395
-
396
- var headers = new Headers();
397
- headers.append('Authorization', 'Bearer ' + MyDataHelps.token.access_token);
398
- headers.append('Accept', 'application/json, text/javascript, */*; q=0.01');
399
- headers.append('Accept-Language', MyDataHelps.getCurrentLanguage());
400
- if (!!body) {
401
- headers.append('Content-Type', 'application/json');
402
- }
403
-
404
- var init = {
405
- method: method,
406
- headers: headers
407
- };
408
- if (!!body) {
409
- init.body = JSON.stringify(body);
410
- }
411
-
412
- return fetch(url, init);
413
- };
414
-
415
- var validateResponse = function (response) {
416
- if (!response.ok) {
417
- throw response.statusText;
418
- }
419
-
420
- return response;
421
- };
422
-
423
- var escapeParam = function (param) {
424
- return String(param)
425
- .replace("\\", "\\\\")
426
- .replace(",", "\\,");
427
- };
428
-
429
- var reduceArrayAndEscape = function (param) {
430
- if (Array.isArray(param)) {
431
- var escapedParams = param.map(function (elem) { return escapeParam(elem); });
432
- return escapedParams.join(",");
433
- }
434
-
435
- return escapeParam(param);
436
- };
437
-
438
- var convertDateToIsoString = function (date) {
439
- var paramAsDate = new Date(date);
440
- if (isNaN(paramAsDate.getTime())) {
441
- throw "Cannot interpret parameter as Date";
442
- }
443
-
444
- return paramAsDate.toISOString();
445
- };
446
-
447
- MyDataHelps.getParticipantInfo = function () {
448
- var endpoint = 'participant';
449
-
450
- return MyDataHelps
451
- .connect()
452
- .then(function () { return makeRequest(endpoint, 'GET', null); })
453
- .then(function (response) { return validateResponse(response); })
454
- .then(function (response) { return response.json(); });
455
- };
456
-
457
- MyDataHelps.querySurveyAnswers = function (queryParameters) {
458
- if (queryParameters.hasOwnProperty("surveyName")) {
459
- queryParameters.surveyName = reduceArrayAndEscape(queryParameters.surveyName);
460
- }
461
- if (queryParameters.hasOwnProperty("stepIdentifier")) {
462
- queryParameters.stepIdentifier = reduceArrayAndEscape(queryParameters.stepIdentifier);
463
- }
464
- if (queryParameters.hasOwnProperty("resultIdentifier")) {
465
- queryParameters.resultIdentifier = reduceArrayAndEscape(queryParameters.resultIdentifier);
466
- }
467
- if (queryParameters.hasOwnProperty("answer")) {
468
- queryParameters.answer = reduceArrayAndEscape(queryParameters.answer);
469
- }
470
- if (queryParameters.hasOwnProperty("before")) {
471
- queryParameters.before = convertDateToIsoString(queryParameters.before);
472
- }
473
- if (queryParameters.hasOwnProperty("after")) {
474
- queryParameters.after = convertDateToIsoString(queryParameters.after);
475
- }
476
-
477
- var queryString = new URLSearchParams(queryParameters).toString();
478
- var endpoint = 'surveyanswers?' + queryString;
479
-
480
- return MyDataHelps
481
- .connect()
482
- .then(function () { return makeRequest(endpoint, 'GET', null); })
483
- .then(function (response) { return validateResponse(response); })
484
- .then(function (response) { return response.json(); });
485
- };
486
-
487
- MyDataHelps.deleteSurveyResult = function (resultID) {
488
- var endpoint = 'surveyresults/' + encodeURIComponent(resultID);
489
-
490
- return MyDataHelps
491
- .connect()
492
- .then(function () { return makeRequest(endpoint, 'DELETE', null); })
493
- .then(function (response) { return validateResponse(response); })
494
- .then(function (response) { return; });
495
- };
496
-
497
- MyDataHelps.queryDeviceData = function (queryParameters) {
498
- if (queryParameters.hasOwnProperty("type")) {
499
- queryParameters.type = reduceArrayAndEscape(queryParameters.type);
500
- }
501
- if (queryParameters.hasOwnProperty("observedBefore")) {
502
- queryParameters.observedBefore = convertDateToIsoString(queryParameters.observedBefore);
503
- }
504
- if (queryParameters.hasOwnProperty("observedAfter")) {
505
- queryParameters.observedAfter = convertDateToIsoString(queryParameters.observedAfter);
506
- }
507
-
508
- var queryString = new URLSearchParams(queryParameters).toString();
509
- var endpoint = 'devicedata?' + queryString;
510
-
511
- return MyDataHelps
512
- .connect()
513
- .then(function () { return makeRequest(endpoint, 'GET', null); })
514
- .then(function (response) { return validateResponse(response); })
515
- .then(function (response) { return response.json(); });
516
- };
517
-
518
- MyDataHelps.persistDeviceData = function (deviceDataPoints) {
519
- var endpoint = 'devicedata';
520
-
521
- return MyDataHelps
522
- .connect()
523
- .then(function () { return makeRequest(endpoint, 'POST', deviceDataPoints); })
524
- .then(function (response) { return validateResponse(response); })
525
- .then(function (response) { return; });
526
- };
527
-
528
- MyDataHelps.trackCustomEvent = function (event) {
529
- var endpoint = 'customevents';
530
-
531
- return MyDataHelps
532
- .connect()
533
- .then(function () { return makeRequest(endpoint, 'POST', event); })
534
- .then(function (response) { return validateResponse(response); })
535
- .then(function (response) { return; });
536
- };
537
-
538
- MyDataHelps.querySurveyTasks = function (queryParameters) {
539
- if (queryParameters.hasOwnProperty("status")) {
540
- queryParameters.status = reduceArrayAndEscape(queryParameters.status);
541
- }
542
- if (queryParameters.hasOwnProperty("surveyName")) {
543
- queryParameters.surveyName = reduceArrayAndEscape(queryParameters.surveyName);
544
- }
545
-
546
- var queryString = new URLSearchParams(queryParameters).toString();
547
- var endpoint = 'surveytasks?' + queryString;
548
-
549
- return MyDataHelps
550
- .connect()
551
- .then(function () { return makeRequest(endpoint, 'GET', null); })
552
- .then(function (response) { return validateResponse(response); })
553
- .then(function (response) { return response.json(); });
554
- };
555
-
556
- MyDataHelps.queryNotifications = function (queryParameters) {
557
- if (queryParameters.hasOwnProperty("sentBefore")) {
558
- queryParameters.sentBefore = convertDateToIsoString(queryParameters.sentBefore);
559
- }
560
- if (queryParameters.hasOwnProperty("sentAfter")) {
561
- queryParameters.sentAfter = convertDateToIsoString(queryParameters.sentAfter);
562
- }
563
-
564
- var queryString = new URLSearchParams(queryParameters).toString();
565
- var endpoint = 'notifications?' + queryString;
566
-
567
- return MyDataHelps
568
- .connect()
569
- .then(function () { return makeRequest(endpoint, 'GET', null); })
570
- .then(function (response) { return validateResponse(response); })
571
- .then(function (response) { return response.json(); });
572
- };
573
-
574
- MyDataHelps.getExternalAccountProviders = function (search, category, pageSize, pageNumber) {
575
- var searchParameters = {};
576
- if (!!search) searchParameters.search = search;
577
- if (!!category) searchParameters.category = category;
578
- if (!!pageSize) searchParameters.pageSize = pageSize;
579
- if (!!pageNumber) searchParameters.pageNumber = pageNumber;
580
-
581
- var queryString = new URLSearchParams(searchParameters).toString();
582
- var endpoint = 'externalaccountproviders?' + queryString;
583
-
584
- return MyDataHelps
585
- .connect()
586
- .then(function () { return makeRequest(endpoint, 'GET', null); })
587
- .then(function (response) { return validateResponse(response); })
588
- .then(function (response) { return response.json(); });
589
- };
590
-
591
- MyDataHelps.getExternalAccounts = function () {
592
- var endpoint = 'externalaccounts';
593
-
594
- return MyDataHelps
595
- .connect()
596
- .then(function () { return makeRequest(endpoint, 'GET', null); })
597
- .then(function (response) { return validateResponse(response); })
598
- .then(function (response) { return response.json(); });
599
- };
600
-
601
- MyDataHelps.refreshExternalAccount = function (accountId) {
602
- var endpoint = 'externalaccounts/refresh/' + accountId;
603
-
604
- return MyDataHelps
605
- .connect()
606
- .then(function () { return makeRequest(endpoint, 'POST', null); })
607
- .then(function (response) { return validateResponse(response); })
608
- .then(function (response) { return; });
609
- };
610
-
611
- MyDataHelps.invokeCustomApi = function (customApi, method, queryParameters, jsonResponse) {
612
- if (customApi.includes('?')) {
613
- throw new Error("Cannot include query parameters directly in the \"customApi\" string. Provide as an argument for \"queryParameters\" instead.");
614
- }
615
-
616
- var endpoint = 'custom/' + customApi;
617
- method = method.toUpperCase();
618
- if (queryParameters !== null && queryParameters !== undefined && (method === 'GET' || method === 'DELETE')) {
619
- var parameterString = new URLSearchParams(queryParameters).toString();
620
- endpoint += "?" + parameterString;
621
- queryParameters = null;
622
- }
623
-
624
- return MyDataHelps
625
- .connect()
626
- .then(function () { return makeRequest(endpoint, method, queryParameters); })
627
- .then(function (response) { return validateResponse(response); })
628
- .then(function (response) { return jsonResponse ? response.json() : undefined; });
629
- };
630
-
631
- //Embedded surveys and tasks
632
-
633
- function getBaseUrl() {
634
- return MyDataHelps.baseUrl || 'https://mydatahelps.org/';
635
- }
636
-
637
- MyDataHelps.startEmbeddedSurvey = function (linkIdentifier, surveyName, language) {
638
- if (!language) { language = this.getCurrentLanguage(); }
639
- var surveyUrl = getBaseUrl() + "mydatahelps/" + linkIdentifier + '/surveylink/' + surveyName + "?lang=" + language;
640
- return startEmbeddedSurvey(surveyUrl);
641
- };
642
-
643
- MyDataHelps.startEmbeddedTask = function (linkIdentifier, taskLinkIdentifier, language) {
644
- if (!language) { language = this.getCurrentLanguage(); }
645
- var surveyUrl = getBaseUrl() + "mydatahelps/" + linkIdentifier + '/tasklink/' + taskLinkIdentifier + "?lang=" + language;
646
- return startEmbeddedSurvey(surveyUrl);
647
- };
648
-
649
- function startEmbeddedSurvey(surveyUrl) {
650
- var mdhSurveyModalId = 'mydatahelps-survey-modal';
651
-
652
- return new Promise(function (resolve, reject) {
653
- if (document.getElementById(mdhSurveyModalId)) {
654
- reject("Survey already in progress");
655
- return;
656
- }
657
-
658
- window.addEventListener("message", function listener(message) {
659
- if (message.origin !== new URL(getBaseUrl()).origin) {
660
- return;
661
- }
662
- var frame = document.getElementById('mydatahelps-survey-frame').contentWindow;
663
- if (message.source !== frame) {
664
- return;
665
- }
666
- if (message.data.name == 'SurveyWindowInitialized') {
667
- document.getElementById(mdhSurveyModalId).className += " loaded";
668
- } else if (message.data.name == 'SurveyFinished') {
669
- document.getElementById(mdhSurveyModalId).remove();
670
- document.body.className = document.body.className.replace("no-scroll", "");
671
- window.removeEventListener("message", listener, true);
672
- resolve(message.data);
673
- }
674
- }, true);
675
-
676
- var surveyModal = document.createElement('div');
677
- surveyModal.className = 'mydatahelps-survey-modal';
678
- surveyModal.id = mdhSurveyModalId;
679
- surveyModal.innerHTML = "<div class='mydatahelps-survey'><div class='loader'>Loading...</div><iframe id='mydatahelps-survey-frame' allow='camera' sandbox='allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts' src='" + surveyUrl + "'></iframe></div>";
680
- document.body.append(surveyModal);
681
- document.body.className += ' no-scroll';
682
- });
1
+ class MyDataHelps {
2
+ constructor() {
3
+ this.allowedApplicationHosts = [
4
+ 'localhost',
5
+ 'careevolution.com',
6
+ 'internal',
7
+ 'b3-deploys.com',
8
+ 'mydatahelps.org',
9
+ 'platform.joinallofus.org',
10
+ 'careevolution.dev',
11
+ 'ce.dev'
12
+ ];
13
+ this.accessTokenRenewalBufferSeconds = 120;
14
+ this.apiBasePath = 'api/v1/delegated/';
15
+ this.unsupportedActions = ["SetHeight", "ResearchKit"];
16
+ this.supportedEvents = ["surveyDidFinish", "applicationDidBecomeVisible", "externalAccountSyncComplete", "tokenWillExpire"];
17
+ this.currentMessageID = 1;
18
+ this.messageHandlers = [];
19
+ this.registeredEventHandlers = {};
20
+ this.refreshTokenPromise = null;
21
+ let mdh = this;
22
+ let applicationHost = getParentOrigin();
23
+ let supportedActions;
24
+ function getParentOrigin() {
25
+ let ancestorOrigins = document.location.ancestorOrigins;
26
+ if (ancestorOrigins && ancestorOrigins[0]) {
27
+ return ancestorOrigins[0];
28
+ }
29
+ return '*';
30
+ }
31
+ function acceptableOrigin(origin) {
32
+ if (origin === '*')
33
+ return true;
34
+ let sourceURL = new URL(origin);
35
+ for (let k = 0; k < mdh.allowedApplicationHosts.length; k++) {
36
+ if (sourceURL.hostname === mdh.allowedApplicationHosts[k] || sourceURL.hostname.endsWith("." + mdh.allowedApplicationHosts[k])) {
37
+ return true;
38
+ }
39
+ }
40
+ return false;
41
+ }
42
+ function validateWindowMessageOrigin(message) {
43
+ if (applicationHost === "*") {
44
+ return acceptableOrigin(message.origin);
45
+ }
46
+ return message.origin === applicationHost;
47
+ }
48
+ function receiveWindowMessage(message) {
49
+ if (!validateWindowMessageOrigin(message)) {
50
+ console.error("message.origin '" + message.origin + "' is not allowed.");
51
+ throw "message.origin '" + message.origin + "' is not allowed.";
52
+ }
53
+ if (message.data.messageID) {
54
+ mdh.setActionResult(message.data);
55
+ }
56
+ else {
57
+ mdh.triggerEvent(message.data);
58
+ }
59
+ }
60
+ if (!acceptableOrigin(applicationHost)) {
61
+ console.error("Application is not hosted at an approved origin.");
62
+ throw "Application is not hosted at an approved origin.";
63
+ }
64
+ if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.ResearchKit) {
65
+ supportedActions = {
66
+ "GetDelegatedAccessToken": function (data) {
67
+ window.parent.postMessage({
68
+ name: 'GetDelegatedAccessToken',
69
+ messageID: data.messageID
70
+ }, applicationHost);
71
+ },
72
+ "GetDeviceInfo": function (data) {
73
+ window.parent.postMessage({ name: 'GetDeviceInfo', messageID: data.messageID }, applicationHost);
74
+ }
75
+ };
76
+ }
77
+ else {
78
+ supportedActions = {
79
+ "GetDelegatedAccessToken": function (data) {
80
+ window.parent.postMessage({
81
+ name: 'GetDelegatedAccessToken',
82
+ messageID: data.messageID
83
+ }, applicationHost);
84
+ },
85
+ "GetDeviceInfo": function (data) {
86
+ window.parent.postMessage({ name: 'GetDeviceInfo', messageID: data.messageID }, applicationHost);
87
+ },
88
+ "StartParticipantSurvey": function (data) {
89
+ window.parent.postMessage({
90
+ name: 'StartParticipantSurvey',
91
+ messageID: data.messageID,
92
+ surveyName: data.surveyName
93
+ }, applicationHost);
94
+ },
95
+ "OpenExternalLink": function (data) {
96
+ window.parent.postMessage({ name: 'OpenExternalUrl', url: data }, applicationHost);
97
+ },
98
+ "OpenEmbeddedLink": function (data) {
99
+ window.parent.postMessage({ name: 'OpenEmbeddedUrl', url: data }, applicationHost);
100
+ },
101
+ "OpenExternalApplication": function (data) {
102
+ window.parent.postMessage({
103
+ name: 'OpenApplication',
104
+ messageID: data.messageID,
105
+ url: data.url,
106
+ modal: data.modal
107
+ }, applicationHost);
108
+ },
109
+ "Dismiss": function () {
110
+ window.parent.postMessage({ name: 'Dismiss' }, applicationHost);
111
+ },
112
+ "PopNavigation": function () {
113
+ window.parent.postMessage({ name: 'Back' }, applicationHost);
114
+ },
115
+ "ShowTab": function (data) {
116
+ window.parent.postMessage({ name: 'ShowTab', tabKey: data }, applicationHost);
117
+ },
118
+ "ShowParticipantDashboard": function (data) {
119
+ window.parent.postMessage({
120
+ name: 'ShowParticipantDashboard',
121
+ dashboardKey: data.dashboardKey,
122
+ modal: data.modal
123
+ }, applicationHost);
124
+ },
125
+ "ShowParticipantWebVisualization": function (data) {
126
+ window.parent.postMessage({
127
+ name: 'ShowParticipantWebVisualization',
128
+ visualizationKey: data.visualizationKey,
129
+ parameters: data.parameters,
130
+ modal: data.modal
131
+ }, applicationHost);
132
+ },
133
+ "ShowParticipantWebVisualizationPDF": function (data) {
134
+ window.parent.postMessage({
135
+ name: 'ShowParticipantWebVisualizationPDF',
136
+ visualizationKey: data.visualizationKey,
137
+ parameters: data.parameters,
138
+ modal: data.modal,
139
+ landscape: data.landscape,
140
+ htmlViewerZoom: data.htmlViewerZoom
141
+ }, applicationHost);
142
+ },
143
+ "DeleteProviderAccount": function (data) {
144
+ window.parent.postMessage({
145
+ name: 'DeleteProviderAccount',
146
+ messageID: data.messageID,
147
+ accountID: data.accountID
148
+ }, applicationHost);
149
+ },
150
+ "ConnectExternalAccount": function (data) {
151
+ window.parent.postMessage({
152
+ name: 'ConnectExternalAccount',
153
+ externalAccountProviderID: data.externalAccountProviderID
154
+ }, applicationHost);
155
+ },
156
+ "ShowProject": function (data) {
157
+ window.parent.postMessage({ name: 'ShowProject', code: data.code }, applicationHost);
158
+ },
159
+ "JoinProject": function (data) {
160
+ window.parent.postMessage({ name: 'JoinProject', code: data.code }, applicationHost);
161
+ }
162
+ };
163
+ }
164
+ function windowHasAnyActions() {
165
+ for (let action in supportedActions) {
166
+ if (window.webkit.messageHandlers[action]) {
167
+ return true;
168
+ }
169
+ }
170
+ for (let action in mdh.unsupportedActions) {
171
+ if (window.webkit.messageHandlers[mdh.unsupportedActions[action]]) {
172
+ return true;
173
+ }
174
+ }
175
+ return false;
176
+ }
177
+ if (!window.webkit || !window.webkit.messageHandlers || !windowHasAnyActions()) {
178
+ window.webkit = {
179
+ messageHandlers: {}
180
+ };
181
+ }
182
+ for (let action in supportedActions) {
183
+ window.webkit.messageHandlers[action] = window.webkit.messageHandlers[action] || { postMessage: supportedActions[action] };
184
+ }
185
+ window.addEventListener("message", receiveWindowMessage, false);
186
+ }
187
+ // Surveys
188
+ startSurvey(surveyName) {
189
+ let messageID = this.nextMessageID();
190
+ window.webkit.messageHandlers.StartParticipantSurvey.postMessage({
191
+ messageID: messageID,
192
+ surveyName: surveyName
193
+ });
194
+ }
195
+ completeStep(answer) {
196
+ if (answer === undefined || answer === null)
197
+ answer = '';
198
+ if (window.webkit.messageHandlers.ResearchKit) {
199
+ window.webkit.messageHandlers.ResearchKit.postMessage(answer);
200
+ }
201
+ }
202
+ querySurveyAnswers(queryParameters) {
203
+ if (queryParameters.hasOwnProperty("surveyName")) {
204
+ queryParameters.surveyName = MyDataHelps.reduceArrayAndEscape(queryParameters.surveyName);
205
+ }
206
+ if (queryParameters.hasOwnProperty("stepIdentifier")) {
207
+ queryParameters.stepIdentifier = MyDataHelps.reduceArrayAndEscape(queryParameters.stepIdentifier);
208
+ }
209
+ if (queryParameters.hasOwnProperty("resultIdentifier")) {
210
+ queryParameters.resultIdentifier = MyDataHelps.reduceArrayAndEscape(queryParameters.resultIdentifier);
211
+ }
212
+ if (queryParameters.hasOwnProperty("answer")) {
213
+ queryParameters.answer = MyDataHelps.reduceArrayAndEscape(queryParameters.answer);
214
+ }
215
+ if (queryParameters.hasOwnProperty("before")) {
216
+ queryParameters.before = MyDataHelps.convertDateToIsoString(queryParameters.before);
217
+ }
218
+ if (queryParameters.hasOwnProperty("after")) {
219
+ queryParameters.after = MyDataHelps.convertDateToIsoString(queryParameters.after);
220
+ }
221
+ const queryString = new URLSearchParams(queryParameters).toString();
222
+ const endpoint = 'surveyanswers?' + queryString;
223
+ const mdh = this;
224
+ return this
225
+ .connect()
226
+ .then(function () {
227
+ return mdh.makeRequest(endpoint, 'GET', null);
228
+ })
229
+ .then(function (response) {
230
+ return MyDataHelps.validateResponse(response);
231
+ })
232
+ .then(function (response) {
233
+ return response.json();
234
+ });
235
+ }
236
+ deleteSurveyResult(resultID) {
237
+ const endpoint = 'surveyresults/' + encodeURIComponent(resultID);
238
+ const mdh = this;
239
+ return this
240
+ .connect()
241
+ .then(function () {
242
+ return mdh.makeRequest(endpoint, 'DELETE', null);
243
+ })
244
+ .then(function (response) {
245
+ return MyDataHelps.validateResponse(response);
246
+ })
247
+ .then(function () {
248
+ return;
249
+ });
250
+ }
251
+ querySurveyTasks(queryParameters) {
252
+ if (queryParameters.hasOwnProperty("status")) {
253
+ queryParameters.status = MyDataHelps.reduceArrayAndEscape(queryParameters.status);
254
+ }
255
+ if (queryParameters.hasOwnProperty("surveyName")) {
256
+ queryParameters.surveyName = MyDataHelps.reduceArrayAndEscape(queryParameters.surveyName);
257
+ }
258
+ const queryString = new URLSearchParams(queryParameters).toString();
259
+ const endpoint = 'surveytasks?' + queryString;
260
+ const mdh = this;
261
+ return this
262
+ .connect()
263
+ .then(function () {
264
+ return mdh.makeRequest(endpoint, 'GET', null);
265
+ })
266
+ .then(function (response) {
267
+ return MyDataHelps.validateResponse(response);
268
+ })
269
+ .then(function (response) {
270
+ return response.json();
271
+ });
272
+ }
273
+ startEmbeddedSurvey(linkIdentifier, surveyName, language) {
274
+ if (!language) {
275
+ language = this.getCurrentLanguage();
276
+ }
277
+ let surveyUrl = this.getBaseUrl() + "mydatahelps/" + linkIdentifier + '/surveylink/' + surveyName + "?lang=" + language;
278
+ return this.startEmbeddedSurveyInternal(surveyUrl);
279
+ }
280
+ startEmbeddedTask(linkIdentifier, taskLinkIdentifier, language) {
281
+ if (!language) {
282
+ language = this.getCurrentLanguage();
283
+ }
284
+ let surveyUrl = this.getBaseUrl() + "mydatahelps/" + linkIdentifier + '/tasklink/' + taskLinkIdentifier + "?lang=" + language;
285
+ return this.startEmbeddedSurveyInternal(surveyUrl);
286
+ }
287
+ // Navigation
288
+ openExternalUrl(url) {
289
+ window.webkit.messageHandlers.OpenExternalLink.postMessage(url);
290
+ }
291
+ openEmbeddedUrl(url) {
292
+ window.webkit.messageHandlers.OpenEmbeddedLink.postMessage(url);
293
+ }
294
+ showTab(tabKey) {
295
+ window.webkit.messageHandlers.ShowTab.postMessage(tabKey);
296
+ }
297
+ openApplication(url, options) {
298
+ let messageID = this.nextMessageID();
299
+ window.webkit.messageHandlers.OpenExternalApplication.postMessage({
300
+ messageID: messageID,
301
+ url: url,
302
+ modal: !!(options && options.modal)
303
+ });
304
+ }
305
+ dismiss() {
306
+ window.webkit.messageHandlers.Dismiss.postMessage({});
307
+ }
308
+ back() {
309
+ window.webkit.messageHandlers.PopNavigation.postMessage({});
310
+ }
311
+ showDashboard(dashboardKey, options) {
312
+ window.webkit.messageHandlers.ShowParticipantDashboard.postMessage({
313
+ dashboardKey: dashboardKey,
314
+ modal: !!(options && options.modal),
315
+ title: options && options.title ? options.title : undefined
316
+ });
317
+ }
318
+ showWebVisualization(visualizationKey, parameters, options) {
319
+ window.webkit.messageHandlers.ShowParticipantWebVisualization.postMessage({
320
+ visualizationKey: visualizationKey,
321
+ parameters: parameters,
322
+ modal: !!(options && options.modal),
323
+ title: options && options.title ? options.title : undefined
324
+ });
325
+ }
326
+ showWebVisualizationPdf(visualizationKey, parameters, options) {
327
+ window.webkit.messageHandlers.ShowParticipantWebVisualizationPDF.postMessage({
328
+ visualizationKey: visualizationKey,
329
+ parameters: parameters,
330
+ landscape: !!(options && options.landscape),
331
+ htmlViewerZoom: options && options.htmlViewerZoom
332
+ });
333
+ }
334
+ showProject(projectCode) {
335
+ if (window.webkit.messageHandlers.ShowProject) {
336
+ window.webkit.messageHandlers.ShowProject.postMessage({ code: projectCode });
337
+ }
338
+ }
339
+ joinProject(projectCode) {
340
+ if (window.webkit.messageHandlers.JoinProject) {
341
+ window.webkit.messageHandlers.JoinProject.postMessage({ code: projectCode });
342
+ }
343
+ }
344
+ //Events
345
+ on(eventName, callback) {
346
+ if (!this.supportedEvents.includes(eventName)) {
347
+ throw new Error(eventName + " is not a supported event type.");
348
+ }
349
+ if (!this.registeredEventHandlers[eventName]) {
350
+ this.registeredEventHandlers[eventName] = [];
351
+ }
352
+ this.registeredEventHandlers[eventName].push(callback);
353
+ }
354
+ off(eventName, callback) {
355
+ if (!this.supportedEvents.includes(eventName)) {
356
+ throw new Error(eventName + " is not a supported event type.");
357
+ }
358
+ if (!this.registeredEventHandlers[eventName])
359
+ return;
360
+ let eventHandlerIndex = this.registeredEventHandlers[eventName].indexOf(callback);
361
+ if (eventHandlerIndex !== -1) {
362
+ this.registeredEventHandlers[eventName].splice(eventHandlerIndex, 1);
363
+ }
364
+ }
365
+ triggerEvent(event) {
366
+ let eventName = event.type;
367
+ if (this.supportedEvents.includes(eventName) && this.registeredEventHandlers[eventName]) {
368
+ this.registeredEventHandlers[eventName].forEach(function (handler) {
369
+ handler(event);
370
+ });
371
+ }
372
+ }
373
+ setActionResult(data) {
374
+ this.messageHandlers[data.messageID](data);
375
+ }
376
+ // Participant Info
377
+ getParticipantInfo() {
378
+ const mdh = this;
379
+ const endpoint = 'participant';
380
+ return this
381
+ .connect()
382
+ .then(function () {
383
+ return mdh.makeRequest(endpoint, 'GET', null);
384
+ })
385
+ .then(function (response) {
386
+ return MyDataHelps.validateResponse(response);
387
+ })
388
+ .then(function (response) {
389
+ return response.json();
390
+ });
391
+ }
392
+ getProjectInfo() {
393
+ const mdh = this;
394
+ const endpoint = 'project';
395
+ return this
396
+ .connect()
397
+ .then(function () {
398
+ return mdh.makeRequest(endpoint, 'GET', null);
399
+ })
400
+ .then(function (response) {
401
+ return MyDataHelps.validateResponse(response);
402
+ })
403
+ .then(function (response) {
404
+ return response.json();
405
+ });
406
+ }
407
+ // Device Data
408
+ queryDeviceData(queryParameters) {
409
+ if (queryParameters.hasOwnProperty("type")) {
410
+ queryParameters.type = MyDataHelps.reduceArrayAndEscape(queryParameters.type);
411
+ }
412
+ if (queryParameters.hasOwnProperty("observedBefore")) {
413
+ queryParameters.observedBefore = MyDataHelps.convertDateToIsoString(queryParameters.observedBefore);
414
+ }
415
+ if (queryParameters.hasOwnProperty("observedAfter")) {
416
+ queryParameters.observedAfter = MyDataHelps.convertDateToIsoString(queryParameters.observedAfter);
417
+ }
418
+ const queryString = new URLSearchParams(queryParameters).toString();
419
+ const endpoint = 'devicedata?' + queryString;
420
+ const mdh = this;
421
+ return this
422
+ .connect()
423
+ .then(function () {
424
+ return mdh.makeRequest(endpoint, 'GET', null);
425
+ })
426
+ .then(function (response) {
427
+ return MyDataHelps.validateResponse(response);
428
+ })
429
+ .then(function (response) {
430
+ return response.json();
431
+ });
432
+ }
433
+ persistDeviceData(deviceDataPoints) {
434
+ const endpoint = 'devicedata';
435
+ const mdh = this;
436
+ return this
437
+ .connect()
438
+ .then(function () {
439
+ return mdh.makeRequest(endpoint, 'POST', deviceDataPoints);
440
+ })
441
+ .then(function (response) {
442
+ return MyDataHelps.validateResponse(response);
443
+ })
444
+ .then(function () {
445
+ return;
446
+ });
447
+ }
448
+ // External Accounts
449
+ getExternalAccountProviders(search, category, pageSize, pageNumber) {
450
+ let searchParameters = {};
451
+ if (!!search)
452
+ searchParameters.search = search;
453
+ if (!!category)
454
+ searchParameters.category = category;
455
+ if (!!pageSize)
456
+ searchParameters.pageSize = pageSize;
457
+ if (!!pageNumber)
458
+ searchParameters.pageNumber = pageNumber;
459
+ const queryString = new URLSearchParams(searchParameters).toString();
460
+ const endpoint = 'externalaccountproviders?' + queryString;
461
+ const mdh = this;
462
+ return this
463
+ .connect()
464
+ .then(function () {
465
+ return mdh.makeRequest(endpoint, 'GET', null);
466
+ })
467
+ .then(function (response) {
468
+ return MyDataHelps.validateResponse(response);
469
+ })
470
+ .then(function (response) {
471
+ return response.json();
472
+ });
473
+ }
474
+ connectExternalAccount(externalAccountProviderID) {
475
+ if (window.webkit.messageHandlers.ConnectExternalAccount) {
476
+ window.webkit.messageHandlers.ConnectExternalAccount.postMessage({ externalAccountProviderID: externalAccountProviderID });
477
+ }
478
+ }
479
+ getExternalAccounts() {
480
+ const endpoint = 'externalaccounts';
481
+ const mdh = this;
482
+ return this
483
+ .connect()
484
+ .then(function () {
485
+ return mdh.makeRequest(endpoint, 'GET', null);
486
+ })
487
+ .then(function (response) {
488
+ return MyDataHelps.validateResponse(response);
489
+ })
490
+ .then(function (response) {
491
+ return response.json();
492
+ });
493
+ }
494
+ refreshExternalAccount(accountID) {
495
+ const endpoint = 'externalaccounts/refresh/' + accountID;
496
+ const mdh = this;
497
+ return this
498
+ .connect()
499
+ .then(function () {
500
+ return mdh.makeRequest(endpoint, 'POST', null);
501
+ })
502
+ .then(function (response) {
503
+ return MyDataHelps.validateResponse(response);
504
+ })
505
+ .then(function () {
506
+ return;
507
+ });
508
+ }
509
+ deleteExternalAccount(accountID) {
510
+ let mdh = this;
511
+ return new Promise(function (resolve, reject) {
512
+ let messageID = mdh.nextMessageID();
513
+ mdh.messageHandlers[messageID] = function (deleteProviderAccountResponse) {
514
+ if (!deleteProviderAccountResponse.success) {
515
+ reject(deleteProviderAccountResponse);
516
+ }
517
+ else {
518
+ resolve(deleteProviderAccountResponse);
519
+ }
520
+ };
521
+ if (window.webkit.messageHandlers.DeleteProviderAccount) {
522
+ window.webkit.messageHandlers.DeleteProviderAccount.postMessage({
523
+ messageID: messageID,
524
+ accountID: accountID
525
+ });
526
+ }
527
+ else {
528
+ reject();
529
+ }
530
+ });
531
+ }
532
+ // Notifications
533
+ queryNotifications(queryParameters) {
534
+ if (queryParameters.hasOwnProperty("sentBefore")) {
535
+ queryParameters.sentBefore = MyDataHelps.convertDateToIsoString(queryParameters.sentBefore);
536
+ }
537
+ if (queryParameters.hasOwnProperty("sentAfter")) {
538
+ queryParameters.sentAfter = MyDataHelps.convertDateToIsoString(queryParameters.sentAfter);
539
+ }
540
+ const queryString = new URLSearchParams(queryParameters).toString();
541
+ const endpoint = 'notifications?' + queryString;
542
+ const mdh = this;
543
+ return this
544
+ .connect()
545
+ .then(function () {
546
+ return mdh.makeRequest(endpoint, 'GET', null);
547
+ })
548
+ .then(function (response) {
549
+ return MyDataHelps.validateResponse(response);
550
+ })
551
+ .then(function (response) {
552
+ return response.json();
553
+ });
554
+ }
555
+ // Authorization
556
+ connect() {
557
+ const mdh = this;
558
+ let refreshDelegatedAccessToken = function () {
559
+ mdh.token = null;
560
+ mdh.refreshTokenPromise = new Promise(function (resolve, reject) {
561
+ let messageID = mdh.nextMessageID();
562
+ mdh.messageHandlers[messageID] = function (tokenResponse) {
563
+ if (tokenResponse.success) {
564
+ mdh.tokenExpires = Date.now() + (tokenResponse.data.expires_in * 1000);
565
+ mdh.token = tokenResponse.data;
566
+ mdh.baseUrl = tokenResponse.baseUrl;
567
+ setTimeout(refreshDelegatedAccessToken, ((tokenResponse.data.expires_in - mdh.accessTokenRenewalBufferSeconds) * 1000));
568
+ resolve(null);
569
+ }
570
+ else {
571
+ mdh.token = null;
572
+ reject(tokenResponse.message);
573
+ }
574
+ mdh.messageHandlers[messageID] = null;
575
+ mdh.refreshTokenPromise = null;
576
+ };
577
+ window.webkit.messageHandlers.GetDelegatedAccessToken.postMessage({ messageID: messageID });
578
+ });
579
+ };
580
+ if (this.token && Date.now() < this.tokenExpires) {
581
+ return Promise.resolve();
582
+ }
583
+ if (!this.refreshTokenPromise) {
584
+ refreshDelegatedAccessToken();
585
+ }
586
+ // Re-use promise if refresh already in progress
587
+ return this.refreshTokenPromise;
588
+ }
589
+ setParticipantAccessToken(token, baseUrl) {
590
+ this.token = token;
591
+ if (baseUrl) {
592
+ this.baseUrl = baseUrl;
593
+ }
594
+ this.tokenExpires = Date.now() + (this.token.expires_in * 1000);
595
+ const mdh = this;
596
+ setTimeout(function () {
597
+ mdh.triggerEvent({ type: "tokenWillExpire" });
598
+ }, ((this.token.expires_in - this.accessTokenRenewalBufferSeconds) * 1000));
599
+ }
600
+ // Miscellaneous
601
+ setStatusBarStyle(style) {
602
+ if (window.webkit.messageHandlers.SetStatusBarStyle) {
603
+ window.webkit.messageHandlers.SetStatusBarStyle.postMessage({ style: style });
604
+ }
605
+ }
606
+ getDeviceInfo() {
607
+ let mdh = this;
608
+ return new Promise(function (resolve, reject) {
609
+ let messageID = mdh.nextMessageID();
610
+ mdh.messageHandlers[messageID] = function (deviceInfoResponse) {
611
+ resolve(deviceInfoResponse.data);
612
+ };
613
+ if (window.webkit.messageHandlers.GetDeviceInfo) {
614
+ window.webkit.messageHandlers.GetDeviceInfo.postMessage({ messageID: messageID });
615
+ }
616
+ else {
617
+ reject();
618
+ }
619
+ });
620
+ }
621
+ getCurrentLanguage() {
622
+ let searchParams = new URLSearchParams(window.location.search);
623
+ if (searchParams.has("lang")) {
624
+ return searchParams.get("lang");
625
+ }
626
+ else {
627
+ return navigator.language;
628
+ }
629
+ }
630
+ showGoogleFitSettings() {
631
+ if (window.webkit.messageHandlers.ShowGoogleFitSettings) {
632
+ window.webkit.messageHandlers.ShowGoogleFitSettings.postMessage({});
633
+ }
634
+ }
635
+ requestReview(cooldownDays) {
636
+ if (window.webkit.messageHandlers.RequestReview) {
637
+ window.webkit.messageHandlers.RequestReview.postMessage({ cooldownDays: cooldownDays });
638
+ }
639
+ }
640
+ trackCustomEvent(event) {
641
+ const endpoint = 'customevents';
642
+ const mdh = this;
643
+ return this
644
+ .connect()
645
+ .then(function () {
646
+ return mdh.makeRequest(endpoint, 'POST', event);
647
+ })
648
+ .then(function (response) {
649
+ return MyDataHelps.validateResponse(response);
650
+ })
651
+ .then(function () {
652
+ return;
653
+ });
654
+ }
655
+ getDataCollectionSettings() {
656
+ const mdh = this;
657
+ const endpoint = 'datacollectionsettings';
658
+ return this
659
+ .connect()
660
+ .then(function () {
661
+ return mdh.makeRequest(endpoint, 'GET', null);
662
+ })
663
+ .then(function (response) {
664
+ return MyDataHelps.validateResponse(response);
665
+ })
666
+ .then(function (response) {
667
+ return response.json();
668
+ });
669
+ }
670
+ invokeCustomApi(customApi, method, queryParameters, jsonResponse) {
671
+ if (customApi.includes('?')) {
672
+ throw new Error("Cannot include query parameters directly in the \"customApi\" string. Provide as an argument for \"queryParameters\" instead.");
673
+ }
674
+ let endpoint = 'custom/' + customApi;
675
+ method = method.toUpperCase();
676
+ if (queryParameters !== null && queryParameters !== undefined && (method === 'GET' || method === 'DELETE')) {
677
+ let parameterString = new URLSearchParams(queryParameters).toString();
678
+ endpoint += "?" + parameterString;
679
+ queryParameters = null;
680
+ }
681
+ const mdh = this;
682
+ return this
683
+ .connect()
684
+ .then(function () {
685
+ return mdh.makeRequest(endpoint, method, queryParameters);
686
+ })
687
+ .then(function (response) {
688
+ return MyDataHelps.validateResponse(response);
689
+ })
690
+ .then(function (response) {
691
+ return jsonResponse ? response.json() : undefined;
692
+ });
693
+ }
694
+ nextMessageID() {
695
+ return this.currentMessageID++;
696
+ }
697
+ getBaseUrl() {
698
+ return this.baseUrl || 'https://mydatahelps.org/';
699
+ }
700
+ makeUrl(endpoint) {
701
+ if (!this.baseUrl) {
702
+ console.error("Cannot use makeUrl without MyDataHelps.baseUrl.");
703
+ throw "Cannot use makeUrl without MyDataHelps.baseUrl.";
704
+ }
705
+ return this.baseUrl + this.apiBasePath + endpoint;
706
+ }
707
+ makeRequest(endpoint, method, body) {
708
+ if (!this.token || !this.token.access_token) {
709
+ throw "No access_token available for request authorization.";
710
+ }
711
+ let url = this.makeUrl(endpoint);
712
+ let headers = new Headers();
713
+ headers.append('Authorization', 'Bearer ' + this.token.access_token);
714
+ headers.append('Accept', 'application/json, text/javascript, */*; q=0.01');
715
+ headers.append('Accept-Language', this.getCurrentLanguage());
716
+ if (!!body) {
717
+ headers.append('Content-Type', 'application/json');
718
+ }
719
+ let init = {
720
+ method: method,
721
+ headers: headers
722
+ };
723
+ if (!!body) {
724
+ init.body = JSON.stringify(body);
725
+ }
726
+ return fetch(url, init);
727
+ }
728
+ static validateResponse(response) {
729
+ if (!response.ok) {
730
+ throw response.statusText;
731
+ }
732
+ return response;
733
+ }
734
+ static escapeParam(param) {
735
+ return String(param)
736
+ .replace("\\", "\\\\")
737
+ .replace(",", "\\,");
738
+ }
739
+ static reduceArrayAndEscape(param) {
740
+ if (Array.isArray(param)) {
741
+ let escapedParams = param.map(function (elem) {
742
+ return MyDataHelps.escapeParam(elem);
743
+ });
744
+ return escapedParams.join(",");
745
+ }
746
+ return this.escapeParam(param);
747
+ }
748
+ static convertDateToIsoString(date) {
749
+ let paramAsDate = new Date(date);
750
+ if (isNaN(paramAsDate.getTime())) {
751
+ throw "Cannot interpret parameter as Date";
752
+ }
753
+ return paramAsDate.toISOString();
754
+ }
755
+ startEmbeddedSurveyInternal(surveyUrl) {
756
+ let mdhSurveyModalId = 'mydatahelps-survey-modal';
757
+ let mdh = this;
758
+ return new Promise(function (resolve, reject) {
759
+ if (document.getElementById(mdhSurveyModalId)) {
760
+ reject("Survey already in progress");
761
+ return;
762
+ }
763
+ window.addEventListener("message", function listener(message) {
764
+ if (message.origin !== new URL(mdh.getBaseUrl()).origin) {
765
+ return;
766
+ }
767
+ let frame = document.getElementById('mydatahelps-survey-frame').contentWindow;
768
+ if (message.source !== frame) {
769
+ return;
770
+ }
771
+ if (message.data.name === 'SurveyWindowInitialized') {
772
+ document.getElementById(mdhSurveyModalId).className += " loaded";
773
+ }
774
+ else if (message.data.name === 'SurveyFinished') {
775
+ document.getElementById(mdhSurveyModalId).remove();
776
+ document.body.className = document.body.className.replace("no-scroll", "");
777
+ window.removeEventListener("message", listener, true);
778
+ resolve(message.data);
779
+ }
780
+ }, true);
781
+ let surveyModal = document.createElement('div');
782
+ surveyModal.className = 'mydatahelps-survey-modal';
783
+ surveyModal.id = mdhSurveyModalId;
784
+ surveyModal.innerHTML = "<div class='mydatahelps-survey'><div class='loader'>Loading...</div><iframe id='mydatahelps-survey-frame' allow='camera' sandbox='allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts' src='" + surveyUrl + "'></iframe></div>";
785
+ document.body.append(surveyModal);
786
+ document.body.className += ' no-scroll';
787
+ });
788
+ }
683
789
  }
684
-
685
790
  //iOS/Android directly invoke window.MyDataHelps and window.RKStudioClient
686
791
  //so it's necessary to explicitly ensure they are present on the window
687
- window.MyDataHelps = MyDataHelps;
688
- window.RKStudioClient = RKStudioClient;
792
+ const mdh = new MyDataHelps();
793
+ window.MyDataHelps = mdh;
794
+ // For backwards compatibility
795
+ window.RKStudioClient = {};
796
+ window.RKStudioClient.setActionResult = function (data) {
797
+ window.MyDataHelps.setActionResult(data);
798
+ };
689
799
 
690
- export { MyDataHelps as default };
800
+ export { MyDataHelps, mdh as default };