@careevolution/mydatahelps-js 2.3.2 → 3.2.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,710 +1,851 @@
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.getProjectInfo = function () {
458
- var endpoint = 'project';
459
-
460
- return MyDataHelps
461
- .connect()
462
- .then(function () { return makeRequest(endpoint, 'GET', null); })
463
- .then(function (response) { return validateResponse(response); })
464
- .then(function (response) { return response.json(); });
465
- };
466
-
467
- MyDataHelps.querySurveyAnswers = function (queryParameters) {
468
- if (queryParameters.hasOwnProperty("surveyName")) {
469
- queryParameters.surveyName = reduceArrayAndEscape(queryParameters.surveyName);
470
- }
471
- if (queryParameters.hasOwnProperty("stepIdentifier")) {
472
- queryParameters.stepIdentifier = reduceArrayAndEscape(queryParameters.stepIdentifier);
473
- }
474
- if (queryParameters.hasOwnProperty("resultIdentifier")) {
475
- queryParameters.resultIdentifier = reduceArrayAndEscape(queryParameters.resultIdentifier);
476
- }
477
- if (queryParameters.hasOwnProperty("answer")) {
478
- queryParameters.answer = reduceArrayAndEscape(queryParameters.answer);
479
- }
480
- if (queryParameters.hasOwnProperty("before")) {
481
- queryParameters.before = convertDateToIsoString(queryParameters.before);
482
- }
483
- if (queryParameters.hasOwnProperty("after")) {
484
- queryParameters.after = convertDateToIsoString(queryParameters.after);
485
- }
486
-
487
- var queryString = new URLSearchParams(queryParameters).toString();
488
- var endpoint = 'surveyanswers?' + queryString;
489
-
490
- return MyDataHelps
491
- .connect()
492
- .then(function () { return makeRequest(endpoint, 'GET', null); })
493
- .then(function (response) { return validateResponse(response); })
494
- .then(function (response) { return response.json(); });
495
- };
496
-
497
- MyDataHelps.deleteSurveyResult = function (resultID) {
498
- var endpoint = 'surveyresults/' + encodeURIComponent(resultID);
499
-
500
- return MyDataHelps
501
- .connect()
502
- .then(function () { return makeRequest(endpoint, 'DELETE', null); })
503
- .then(function (response) { return validateResponse(response); })
504
- .then(function (response) { return; });
505
- };
506
-
507
- MyDataHelps.queryDeviceData = function (queryParameters) {
508
- if (queryParameters.hasOwnProperty("type")) {
509
- queryParameters.type = reduceArrayAndEscape(queryParameters.type);
510
- }
511
- if (queryParameters.hasOwnProperty("observedBefore")) {
512
- queryParameters.observedBefore = convertDateToIsoString(queryParameters.observedBefore);
513
- }
514
- if (queryParameters.hasOwnProperty("observedAfter")) {
515
- queryParameters.observedAfter = convertDateToIsoString(queryParameters.observedAfter);
516
- }
517
-
518
- var queryString = new URLSearchParams(queryParameters).toString();
519
- var endpoint = 'devicedata?' + queryString;
520
-
521
- return MyDataHelps
522
- .connect()
523
- .then(function () { return makeRequest(endpoint, 'GET', null); })
524
- .then(function (response) { return validateResponse(response); })
525
- .then(function (response) { return response.json(); });
526
- };
527
-
528
- MyDataHelps.persistDeviceData = function (deviceDataPoints) {
529
- var endpoint = 'devicedata';
530
-
531
- return MyDataHelps
532
- .connect()
533
- .then(function () { return makeRequest(endpoint, 'POST', deviceDataPoints); })
534
- .then(function (response) { return validateResponse(response); })
535
- .then(function (response) { return; });
536
- };
537
-
538
- MyDataHelps.trackCustomEvent = function (event) {
539
- var endpoint = 'customevents';
540
-
541
- return MyDataHelps
542
- .connect()
543
- .then(function () { return makeRequest(endpoint, 'POST', event); })
544
- .then(function (response) { return validateResponse(response); })
545
- .then(function (response) { return; });
546
- };
547
-
548
- MyDataHelps.querySurveyTasks = function (queryParameters) {
549
- if (queryParameters.hasOwnProperty("status")) {
550
- queryParameters.status = reduceArrayAndEscape(queryParameters.status);
551
- }
552
- if (queryParameters.hasOwnProperty("surveyName")) {
553
- queryParameters.surveyName = reduceArrayAndEscape(queryParameters.surveyName);
554
- }
555
-
556
- var queryString = new URLSearchParams(queryParameters).toString();
557
- var endpoint = 'surveytasks?' + queryString;
558
-
559
- return MyDataHelps
560
- .connect()
561
- .then(function () { return makeRequest(endpoint, 'GET', null); })
562
- .then(function (response) { return validateResponse(response); })
563
- .then(function (response) { return response.json(); });
564
- };
565
-
566
- MyDataHelps.queryNotifications = function (queryParameters) {
567
- if (queryParameters.hasOwnProperty("sentBefore")) {
568
- queryParameters.sentBefore = convertDateToIsoString(queryParameters.sentBefore);
569
- }
570
- if (queryParameters.hasOwnProperty("sentAfter")) {
571
- queryParameters.sentAfter = convertDateToIsoString(queryParameters.sentAfter);
572
- }
573
-
574
- var queryString = new URLSearchParams(queryParameters).toString();
575
- var endpoint = 'notifications?' + queryString;
576
-
577
- return MyDataHelps
578
- .connect()
579
- .then(function () { return makeRequest(endpoint, 'GET', null); })
580
- .then(function (response) { return validateResponse(response); })
581
- .then(function (response) { return response.json(); });
582
- };
583
-
584
- MyDataHelps.getExternalAccountProviders = function (search, category, pageSize, pageNumber) {
585
- var searchParameters = {};
586
- if (!!search) searchParameters.search = search;
587
- if (!!category) searchParameters.category = category;
588
- if (!!pageSize) searchParameters.pageSize = pageSize;
589
- if (!!pageNumber) searchParameters.pageNumber = pageNumber;
590
-
591
- var queryString = new URLSearchParams(searchParameters).toString();
592
- var endpoint = 'externalaccountproviders?' + queryString;
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.getExternalAccounts = function () {
602
- var endpoint = 'externalaccounts';
603
-
604
- return MyDataHelps
605
- .connect()
606
- .then(function () { return makeRequest(endpoint, 'GET', null); })
607
- .then(function (response) { return validateResponse(response); })
608
- .then(function (response) { return response.json(); });
609
- };
610
-
611
- MyDataHelps.refreshExternalAccount = function (accountId) {
612
- var endpoint = 'externalaccounts/refresh/' + accountId;
613
-
614
- return MyDataHelps
615
- .connect()
616
- .then(function () { return makeRequest(endpoint, 'POST', null); })
617
- .then(function (response) { return validateResponse(response); })
618
- .then(function (response) { return; });
619
- };
620
-
621
- MyDataHelps.invokeCustomApi = function (customApi, method, queryParameters, jsonResponse) {
622
- if (customApi.includes('?')) {
623
- throw new Error("Cannot include query parameters directly in the \"customApi\" string. Provide as an argument for \"queryParameters\" instead.");
624
- }
625
-
626
- var endpoint = 'custom/' + customApi;
627
- method = method.toUpperCase();
628
- if (queryParameters !== null && queryParameters !== undefined && (method === 'GET' || method === 'DELETE')) {
629
- var parameterString = new URLSearchParams(queryParameters).toString();
630
- endpoint += "?" + parameterString;
631
- queryParameters = null;
632
- }
633
-
634
- return MyDataHelps
635
- .connect()
636
- .then(function () { return makeRequest(endpoint, method, queryParameters); })
637
- .then(function (response) { return validateResponse(response); })
638
- .then(function (response) { return jsonResponse ? response.json() : undefined; });
639
- };
640
-
641
- //Embedded surveys and tasks
642
-
643
- function getBaseUrl() {
644
- return MyDataHelps.baseUrl || 'https://mydatahelps.org/';
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
+ queryParameters = Object.assign({}, queryParameters);
204
+ if (queryParameters.hasOwnProperty("surveyName")) {
205
+ queryParameters.surveyName = MyDataHelps.reduceArrayAndEscape(queryParameters.surveyName);
206
+ }
207
+ if (queryParameters.hasOwnProperty("stepIdentifier")) {
208
+ queryParameters.stepIdentifier = MyDataHelps.reduceArrayAndEscape(queryParameters.stepIdentifier);
209
+ }
210
+ if (queryParameters.hasOwnProperty("resultIdentifier")) {
211
+ queryParameters.resultIdentifier = MyDataHelps.reduceArrayAndEscape(queryParameters.resultIdentifier);
212
+ }
213
+ if (queryParameters.hasOwnProperty("answer")) {
214
+ queryParameters.answer = MyDataHelps.reduceArrayAndEscape(queryParameters.answer);
215
+ }
216
+ if (queryParameters.hasOwnProperty("before")) {
217
+ queryParameters.before = MyDataHelps.convertDateToIsoString(queryParameters.before);
218
+ }
219
+ if (queryParameters.hasOwnProperty("after")) {
220
+ queryParameters.after = MyDataHelps.convertDateToIsoString(queryParameters.after);
221
+ }
222
+ const queryString = new URLSearchParams(queryParameters).toString();
223
+ const endpoint = 'surveyanswers?' + queryString;
224
+ const mdh = this;
225
+ return this
226
+ .connect()
227
+ .then(function () {
228
+ return mdh.makeRequest(endpoint, 'GET', null);
229
+ })
230
+ .then(function (response) {
231
+ return MyDataHelps.validateResponse(response);
232
+ })
233
+ .then(function (response) {
234
+ return response.json();
235
+ });
236
+ }
237
+ deleteSurveyResult(resultID) {
238
+ const endpoint = 'surveyresults/' + encodeURIComponent(resultID);
239
+ const mdh = this;
240
+ return this
241
+ .connect()
242
+ .then(function () {
243
+ return mdh.makeRequest(endpoint, 'DELETE', null);
244
+ })
245
+ .then(function (response) {
246
+ return MyDataHelps.validateResponse(response);
247
+ })
248
+ .then(function () {
249
+ return;
250
+ });
251
+ }
252
+ querySurveyTasks(queryParameters) {
253
+ queryParameters = Object.assign({}, queryParameters);
254
+ if (queryParameters.hasOwnProperty("status")) {
255
+ queryParameters.status = MyDataHelps.reduceArrayAndEscape(queryParameters.status);
256
+ }
257
+ if (queryParameters.hasOwnProperty("surveyName")) {
258
+ queryParameters.surveyName = MyDataHelps.reduceArrayAndEscape(queryParameters.surveyName);
259
+ }
260
+ const queryString = new URLSearchParams(queryParameters).toString();
261
+ const endpoint = 'surveytasks?' + queryString;
262
+ const mdh = this;
263
+ return this
264
+ .connect()
265
+ .then(function () {
266
+ return mdh.makeRequest(endpoint, 'GET', null);
267
+ })
268
+ .then(function (response) {
269
+ return MyDataHelps.validateResponse(response);
270
+ })
271
+ .then(function (response) {
272
+ return response.json();
273
+ });
274
+ }
275
+ startEmbeddedSurvey(linkIdentifier, surveyName, language) {
276
+ if (!language) {
277
+ language = this.getCurrentLanguage();
278
+ }
279
+ let surveyUrl = this.getBaseUrl() + "mydatahelps/" + linkIdentifier + '/surveylink/' + surveyName + "?lang=" + language;
280
+ return this.startEmbeddedSurveyInternal(surveyUrl);
281
+ }
282
+ startEmbeddedTask(linkIdentifier, taskLinkIdentifier, language) {
283
+ if (!language) {
284
+ language = this.getCurrentLanguage();
285
+ }
286
+ let surveyUrl = this.getBaseUrl() + "mydatahelps/" + linkIdentifier + '/tasklink/' + taskLinkIdentifier + "?lang=" + language;
287
+ return this.startEmbeddedSurveyInternal(surveyUrl);
288
+ }
289
+ // Navigation
290
+ openExternalUrl(url) {
291
+ window.webkit.messageHandlers.OpenExternalLink.postMessage(url);
292
+ }
293
+ openEmbeddedUrl(url) {
294
+ window.webkit.messageHandlers.OpenEmbeddedLink.postMessage(url);
295
+ }
296
+ showTab(tabKey) {
297
+ window.webkit.messageHandlers.ShowTab.postMessage(tabKey);
298
+ }
299
+ openApplication(url, options) {
300
+ let messageID = this.nextMessageID();
301
+ window.webkit.messageHandlers.OpenExternalApplication.postMessage({
302
+ messageID: messageID,
303
+ url: url,
304
+ modal: !!(options && options.modal)
305
+ });
306
+ }
307
+ dismiss() {
308
+ window.webkit.messageHandlers.Dismiss.postMessage({});
309
+ }
310
+ back() {
311
+ window.webkit.messageHandlers.PopNavigation.postMessage({});
312
+ }
313
+ showDashboard(dashboardKey, options) {
314
+ window.webkit.messageHandlers.ShowParticipantDashboard.postMessage({
315
+ dashboardKey: dashboardKey,
316
+ modal: !!(options && options.modal),
317
+ title: options && options.title ? options.title : undefined
318
+ });
319
+ }
320
+ showWebVisualization(visualizationKey, parameters, options) {
321
+ window.webkit.messageHandlers.ShowParticipantWebVisualization.postMessage({
322
+ visualizationKey: visualizationKey,
323
+ parameters: parameters,
324
+ modal: !!(options && options.modal),
325
+ title: options && options.title ? options.title : undefined
326
+ });
327
+ }
328
+ showWebVisualizationPdf(visualizationKey, parameters, options) {
329
+ window.webkit.messageHandlers.ShowParticipantWebVisualizationPDF.postMessage({
330
+ visualizationKey: visualizationKey,
331
+ parameters: parameters,
332
+ landscape: !!(options && options.landscape),
333
+ htmlViewerZoom: options && options.htmlViewerZoom
334
+ });
335
+ }
336
+ showProject(projectCode) {
337
+ if (window.webkit.messageHandlers.ShowProject) {
338
+ window.webkit.messageHandlers.ShowProject.postMessage({ code: projectCode });
339
+ }
340
+ }
341
+ joinProject(projectCode) {
342
+ if (window.webkit.messageHandlers.JoinProject) {
343
+ window.webkit.messageHandlers.JoinProject.postMessage({ code: projectCode });
344
+ }
345
+ }
346
+ //Events
347
+ on(eventName, callback) {
348
+ if (!this.supportedEvents.includes(eventName)) {
349
+ throw new Error(eventName + " is not a supported event type.");
350
+ }
351
+ if (!this.registeredEventHandlers[eventName]) {
352
+ this.registeredEventHandlers[eventName] = [];
353
+ }
354
+ this.registeredEventHandlers[eventName].push(callback);
355
+ }
356
+ off(eventName, callback) {
357
+ if (!this.supportedEvents.includes(eventName)) {
358
+ throw new Error(eventName + " is not a supported event type.");
359
+ }
360
+ if (!this.registeredEventHandlers[eventName])
361
+ return;
362
+ let eventHandlerIndex = this.registeredEventHandlers[eventName].indexOf(callback);
363
+ if (eventHandlerIndex !== -1) {
364
+ this.registeredEventHandlers[eventName].splice(eventHandlerIndex, 1);
365
+ }
366
+ }
367
+ triggerEvent(event) {
368
+ let eventName = event.type;
369
+ if (this.supportedEvents.includes(eventName) && this.registeredEventHandlers[eventName]) {
370
+ this.registeredEventHandlers[eventName].forEach(function (handler) {
371
+ handler(event);
372
+ });
373
+ }
374
+ }
375
+ setActionResult(data) {
376
+ this.messageHandlers[data.messageID](data);
377
+ }
378
+ // Participant Info
379
+ getParticipantInfo() {
380
+ const mdh = this;
381
+ const endpoint = 'participant';
382
+ return this
383
+ .connect()
384
+ .then(function () {
385
+ return mdh.makeRequest(endpoint, 'GET', null);
386
+ })
387
+ .then(function (response) {
388
+ return MyDataHelps.validateResponse(response);
389
+ })
390
+ .then(function (response) {
391
+ return response.json();
392
+ });
393
+ }
394
+ getProjectInfo() {
395
+ const mdh = this;
396
+ const endpoint = 'project';
397
+ return this
398
+ .connect()
399
+ .then(function () {
400
+ return mdh.makeRequest(endpoint, 'GET', null);
401
+ })
402
+ .then(function (response) {
403
+ return MyDataHelps.validateResponse(response);
404
+ })
405
+ .then(function (response) {
406
+ return response.json();
407
+ });
408
+ }
409
+ // Device Data
410
+ queryDeviceData(queryParameters) {
411
+ queryParameters = Object.assign({}, queryParameters);
412
+ if (queryParameters.hasOwnProperty("type")) {
413
+ queryParameters.type = MyDataHelps.reduceArrayAndEscape(queryParameters.type);
414
+ }
415
+ if (queryParameters.hasOwnProperty("observedBefore")) {
416
+ queryParameters.observedBefore = MyDataHelps.convertDateToIsoString(queryParameters.observedBefore);
417
+ }
418
+ if (queryParameters.hasOwnProperty("observedAfter")) {
419
+ queryParameters.observedAfter = MyDataHelps.convertDateToIsoString(queryParameters.observedAfter);
420
+ }
421
+ const queryString = new URLSearchParams(queryParameters).toString();
422
+ const endpoint = 'devicedata?' + queryString;
423
+ const mdh = this;
424
+ return this
425
+ .connect()
426
+ .then(function () {
427
+ return mdh.makeRequest(endpoint, 'GET', null);
428
+ })
429
+ .then(function (response) {
430
+ return MyDataHelps.validateResponse(response);
431
+ })
432
+ .then(function (response) {
433
+ return response.json();
434
+ });
435
+ }
436
+ persistDeviceData(deviceDataPoints) {
437
+ const endpoint = 'devicedata';
438
+ const mdh = this;
439
+ return this
440
+ .connect()
441
+ .then(function () {
442
+ return mdh.makeRequest(endpoint, 'POST', deviceDataPoints);
443
+ })
444
+ .then(function (response) {
445
+ return MyDataHelps.validateResponse(response);
446
+ })
447
+ .then(function () {
448
+ return;
449
+ });
450
+ }
451
+ // External Accounts
452
+ getExternalAccountProviders(search, category, pageSize, pageNumber) {
453
+ let searchParameters = {};
454
+ if (!!search)
455
+ searchParameters.search = search;
456
+ if (!!category)
457
+ searchParameters.category = category;
458
+ if (!!pageSize)
459
+ searchParameters.pageSize = pageSize;
460
+ if (!!pageNumber)
461
+ searchParameters.pageNumber = pageNumber;
462
+ const queryString = new URLSearchParams(searchParameters).toString();
463
+ const endpoint = 'externalaccountproviders?' + queryString;
464
+ const mdh = this;
465
+ return this
466
+ .connect()
467
+ .then(function () {
468
+ return mdh.makeRequest(endpoint, 'GET', null);
469
+ })
470
+ .then(function (response) {
471
+ return MyDataHelps.validateResponse(response);
472
+ })
473
+ .then(function (response) {
474
+ return response.json();
475
+ });
476
+ }
477
+ connectExternalAccount(externalAccountProviderID) {
478
+ if (window.webkit.messageHandlers.ConnectExternalAccount) {
479
+ window.webkit.messageHandlers.ConnectExternalAccount.postMessage({ externalAccountProviderID: externalAccountProviderID });
480
+ }
481
+ }
482
+ getExternalAccounts() {
483
+ const endpoint = 'externalaccounts';
484
+ const mdh = this;
485
+ return this
486
+ .connect()
487
+ .then(function () {
488
+ return mdh.makeRequest(endpoint, 'GET', null);
489
+ })
490
+ .then(function (response) {
491
+ return MyDataHelps.validateResponse(response);
492
+ })
493
+ .then(function (response) {
494
+ return response.json();
495
+ });
496
+ }
497
+ refreshExternalAccount(accountID) {
498
+ const endpoint = 'externalaccounts/refresh/' + accountID;
499
+ const mdh = this;
500
+ return this
501
+ .connect()
502
+ .then(function () {
503
+ return mdh.makeRequest(endpoint, 'POST', null);
504
+ })
505
+ .then(function (response) {
506
+ return MyDataHelps.validateResponse(response);
507
+ })
508
+ .then(function () {
509
+ return;
510
+ });
511
+ }
512
+ deleteExternalAccount(accountID) {
513
+ let mdh = this;
514
+ return new Promise(function (resolve, reject) {
515
+ let messageID = mdh.nextMessageID();
516
+ mdh.messageHandlers[messageID] = function (deleteProviderAccountResponse) {
517
+ if (!deleteProviderAccountResponse.success) {
518
+ reject(deleteProviderAccountResponse);
519
+ }
520
+ else {
521
+ resolve(deleteProviderAccountResponse);
522
+ }
523
+ };
524
+ if (window.webkit.messageHandlers.DeleteProviderAccount) {
525
+ window.webkit.messageHandlers.DeleteProviderAccount.postMessage({
526
+ messageID: messageID,
527
+ accountID: accountID
528
+ });
529
+ }
530
+ else {
531
+ reject();
532
+ }
533
+ });
534
+ }
535
+ // Notifications
536
+ queryNotifications(queryParameters) {
537
+ queryParameters = Object.assign({}, queryParameters);
538
+ if (queryParameters.hasOwnProperty("sentBefore")) {
539
+ queryParameters.sentBefore = MyDataHelps.convertDateToIsoString(queryParameters.sentBefore);
540
+ }
541
+ if (queryParameters.hasOwnProperty("sentAfter")) {
542
+ queryParameters.sentAfter = MyDataHelps.convertDateToIsoString(queryParameters.sentAfter);
543
+ }
544
+ const queryString = new URLSearchParams(queryParameters).toString();
545
+ const endpoint = 'notifications?' + queryString;
546
+ const mdh = this;
547
+ return this
548
+ .connect()
549
+ .then(function () {
550
+ return mdh.makeRequest(endpoint, 'GET', null);
551
+ })
552
+ .then(function (response) {
553
+ return MyDataHelps.validateResponse(response);
554
+ })
555
+ .then(function (response) {
556
+ return response.json();
557
+ });
558
+ }
559
+ // Fitbit
560
+ queryFitbitDailySummaries(queryParameters) {
561
+ queryParameters = Object.assign({}, queryParameters);
562
+ if (queryParameters.hasOwnProperty("startDate")) {
563
+ queryParameters.startDate = MyDataHelps.convertDateToIsoString(queryParameters.startDate);
564
+ }
565
+ if (queryParameters.hasOwnProperty("endDate")) {
566
+ queryParameters.endDate = MyDataHelps.convertDateToIsoString(queryParameters.endDate);
567
+ }
568
+ const queryString = new URLSearchParams(queryParameters).toString();
569
+ const endpoint = 'fitbit/dailySummaries?' + queryString;
570
+ const mdh = this;
571
+ return this
572
+ .connect()
573
+ .then(function () {
574
+ return mdh.makeRequest(endpoint, 'GET', null);
575
+ })
576
+ .then(function (response) {
577
+ return MyDataHelps.validateResponse(response);
578
+ })
579
+ .then(function (response) {
580
+ return response.json();
581
+ });
582
+ }
583
+ queryFitbitSleepLogs(queryParameters) {
584
+ queryParameters = Object.assign({}, queryParameters);
585
+ if (queryParameters.hasOwnProperty("startDate")) {
586
+ queryParameters.startDate = MyDataHelps.convertDateToIsoString(queryParameters.startDate);
587
+ }
588
+ if (queryParameters.hasOwnProperty("endDate")) {
589
+ queryParameters.endDate = MyDataHelps.convertDateToIsoString(queryParameters.endDate);
590
+ }
591
+ const queryString = new URLSearchParams(queryParameters).toString();
592
+ const endpoint = 'fitbit/sleepLogs?' + queryString;
593
+ const mdh = this;
594
+ return this
595
+ .connect()
596
+ .then(function () {
597
+ return mdh.makeRequest(endpoint, 'GET', null);
598
+ })
599
+ .then(function (response) {
600
+ return MyDataHelps.validateResponse(response);
601
+ })
602
+ .then(function (response) {
603
+ return response.json();
604
+ });
605
+ }
606
+ // Authorization
607
+ connect() {
608
+ const mdh = this;
609
+ let refreshDelegatedAccessToken = function () {
610
+ mdh.token = null;
611
+ mdh.refreshTokenPromise = new Promise(function (resolve, reject) {
612
+ let messageID = mdh.nextMessageID();
613
+ mdh.messageHandlers[messageID] = function (tokenResponse) {
614
+ if (tokenResponse.success) {
615
+ mdh.tokenExpires = Date.now() + (tokenResponse.data.expires_in * 1000);
616
+ mdh.token = tokenResponse.data;
617
+ mdh.baseUrl = tokenResponse.baseUrl;
618
+ setTimeout(refreshDelegatedAccessToken, ((tokenResponse.data.expires_in - mdh.accessTokenRenewalBufferSeconds) * 1000));
619
+ resolve(null);
620
+ }
621
+ else {
622
+ mdh.token = null;
623
+ reject(tokenResponse.message);
624
+ }
625
+ mdh.messageHandlers[messageID] = null;
626
+ mdh.refreshTokenPromise = null;
627
+ };
628
+ window.webkit.messageHandlers.GetDelegatedAccessToken.postMessage({ messageID: messageID });
629
+ });
630
+ };
631
+ if (this.token && Date.now() < this.tokenExpires) {
632
+ return Promise.resolve();
633
+ }
634
+ if (!this.refreshTokenPromise) {
635
+ refreshDelegatedAccessToken();
636
+ }
637
+ // Re-use promise if refresh already in progress
638
+ return this.refreshTokenPromise;
639
+ }
640
+ setParticipantAccessToken(token, baseUrl) {
641
+ this.token = token;
642
+ if (baseUrl) {
643
+ this.baseUrl = baseUrl;
644
+ }
645
+ this.tokenExpires = Date.now() + (this.token.expires_in * 1000);
646
+ const mdh = this;
647
+ setTimeout(function () {
648
+ mdh.triggerEvent({ type: "tokenWillExpire" });
649
+ }, ((this.token.expires_in - this.accessTokenRenewalBufferSeconds) * 1000));
650
+ }
651
+ // Miscellaneous
652
+ setStatusBarStyle(style) {
653
+ if (window.webkit.messageHandlers.SetStatusBarStyle) {
654
+ window.webkit.messageHandlers.SetStatusBarStyle.postMessage({ style: style });
655
+ }
656
+ }
657
+ getDeviceInfo() {
658
+ let mdh = this;
659
+ return new Promise(function (resolve, reject) {
660
+ let messageID = mdh.nextMessageID();
661
+ mdh.messageHandlers[messageID] = function (deviceInfoResponse) {
662
+ resolve(deviceInfoResponse.data);
663
+ };
664
+ if (window.webkit.messageHandlers.GetDeviceInfo) {
665
+ window.webkit.messageHandlers.GetDeviceInfo.postMessage({ messageID: messageID });
666
+ }
667
+ else {
668
+ reject();
669
+ }
670
+ });
671
+ }
672
+ getCurrentLanguage() {
673
+ let searchParams = new URLSearchParams(window.location.search);
674
+ if (searchParams.has("lang")) {
675
+ return searchParams.get("lang");
676
+ }
677
+ else {
678
+ return navigator.language;
679
+ }
680
+ }
681
+ showGoogleFitSettings() {
682
+ if (window.webkit.messageHandlers.ShowGoogleFitSettings) {
683
+ window.webkit.messageHandlers.ShowGoogleFitSettings.postMessage({});
684
+ }
685
+ }
686
+ requestReview(cooldownDays) {
687
+ if (window.webkit.messageHandlers.RequestReview) {
688
+ window.webkit.messageHandlers.RequestReview.postMessage({ cooldownDays: cooldownDays });
689
+ }
690
+ }
691
+ trackCustomEvent(event) {
692
+ const endpoint = 'customevents';
693
+ const mdh = this;
694
+ return this
695
+ .connect()
696
+ .then(function () {
697
+ return mdh.makeRequest(endpoint, 'POST', event);
698
+ })
699
+ .then(function (response) {
700
+ return MyDataHelps.validateResponse(response);
701
+ })
702
+ .then(function () {
703
+ return;
704
+ });
705
+ }
706
+ getDataCollectionSettings() {
707
+ const mdh = this;
708
+ const endpoint = 'datacollectionsettings';
709
+ return this
710
+ .connect()
711
+ .then(function () {
712
+ return mdh.makeRequest(endpoint, 'GET', null);
713
+ })
714
+ .then(function (response) {
715
+ return MyDataHelps.validateResponse(response);
716
+ })
717
+ .then(function (response) {
718
+ return response.json();
719
+ });
720
+ }
721
+ invokeCustomApi(customApi, method, queryParameters, jsonResponse) {
722
+ if (customApi.includes('?')) {
723
+ throw new Error("Cannot include query parameters directly in the \"customApi\" string. Provide as an argument for \"queryParameters\" instead.");
724
+ }
725
+ let endpoint = 'custom/' + customApi;
726
+ method = method.toUpperCase();
727
+ if (queryParameters !== null && queryParameters !== undefined && (method === 'GET' || method === 'DELETE')) {
728
+ let parameterString = new URLSearchParams(queryParameters).toString();
729
+ endpoint += "?" + parameterString;
730
+ queryParameters = null;
731
+ }
732
+ const mdh = this;
733
+ return this
734
+ .connect()
735
+ .then(function () {
736
+ return mdh.makeRequest(endpoint, method, queryParameters);
737
+ })
738
+ .then(function (response) {
739
+ return MyDataHelps.validateResponse(response);
740
+ })
741
+ .then(function (response) {
742
+ return jsonResponse ? response.json() : undefined;
743
+ });
744
+ }
745
+ nextMessageID() {
746
+ return this.currentMessageID++;
747
+ }
748
+ getBaseUrl() {
749
+ return this.baseUrl || 'https://mydatahelps.org/';
750
+ }
751
+ makeUrl(endpoint) {
752
+ if (!this.baseUrl) {
753
+ console.error("Cannot use makeUrl without MyDataHelps.baseUrl.");
754
+ throw "Cannot use makeUrl without MyDataHelps.baseUrl.";
755
+ }
756
+ return this.baseUrl + this.apiBasePath + endpoint;
757
+ }
758
+ makeRequest(endpoint, method, body) {
759
+ if (!this.token || !this.token.access_token) {
760
+ throw "No access_token available for request authorization.";
761
+ }
762
+ let url = this.makeUrl(endpoint);
763
+ let headers = new Headers();
764
+ headers.append('Authorization', 'Bearer ' + this.token.access_token);
765
+ headers.append('Accept', 'application/json, text/javascript, */*; q=0.01');
766
+ headers.append('Accept-Language', this.getCurrentLanguage());
767
+ if (!!body) {
768
+ headers.append('Content-Type', 'application/json');
769
+ }
770
+ let init = {
771
+ method: method,
772
+ headers: headers
773
+ };
774
+ if (!!body) {
775
+ init.body = JSON.stringify(body);
776
+ }
777
+ return fetch(url, init);
778
+ }
779
+ static validateResponse(response) {
780
+ if (!response.ok) {
781
+ throw response.statusText;
782
+ }
783
+ return response;
784
+ }
785
+ static escapeParam(param) {
786
+ return String(param)
787
+ .replace("\\", "\\\\")
788
+ .replace(",", "\\,");
789
+ }
790
+ static reduceArrayAndEscape(param) {
791
+ if (Array.isArray(param)) {
792
+ let escapedParams = param.map(function (elem) {
793
+ return MyDataHelps.escapeParam(elem);
794
+ });
795
+ return escapedParams.join(",");
796
+ }
797
+ return this.escapeParam(param);
798
+ }
799
+ static convertDateToIsoString(date) {
800
+ let paramAsDate = new Date(date);
801
+ if (isNaN(paramAsDate.getTime())) {
802
+ throw "Cannot interpret parameter as Date";
803
+ }
804
+ return paramAsDate.toISOString();
805
+ }
806
+ startEmbeddedSurveyInternal(surveyUrl) {
807
+ let mdhSurveyModalId = 'mydatahelps-survey-modal';
808
+ let mdh = this;
809
+ return new Promise(function (resolve, reject) {
810
+ if (document.getElementById(mdhSurveyModalId)) {
811
+ reject("Survey already in progress");
812
+ return;
813
+ }
814
+ window.addEventListener("message", function listener(message) {
815
+ if (message.origin !== new URL(mdh.getBaseUrl()).origin) {
816
+ return;
817
+ }
818
+ let frame = document.getElementById('mydatahelps-survey-frame').contentWindow;
819
+ if (message.source !== frame) {
820
+ return;
821
+ }
822
+ if (message.data.name === 'SurveyWindowInitialized') {
823
+ document.getElementById(mdhSurveyModalId).className += " loaded";
824
+ }
825
+ else if (message.data.name === 'SurveyFinished') {
826
+ document.getElementById(mdhSurveyModalId).remove();
827
+ document.body.className = document.body.className.replace("no-scroll", "");
828
+ window.removeEventListener("message", listener, true);
829
+ resolve(message.data);
830
+ }
831
+ }, true);
832
+ let surveyModal = document.createElement('div');
833
+ surveyModal.className = 'mydatahelps-survey-modal';
834
+ surveyModal.id = mdhSurveyModalId;
835
+ 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>";
836
+ document.body.append(surveyModal);
837
+ document.body.className += ' no-scroll';
838
+ });
839
+ }
645
840
  }
646
-
647
- MyDataHelps.startEmbeddedSurvey = function (linkIdentifier, surveyName, language) {
648
- if (!language) { language = this.getCurrentLanguage(); }
649
- var surveyUrl = getBaseUrl() + "mydatahelps/" + linkIdentifier + '/surveylink/' + surveyName + "?lang=" + language;
650
- return startEmbeddedSurvey(surveyUrl);
651
- };
652
-
653
- MyDataHelps.startEmbeddedTask = function (linkIdentifier, taskLinkIdentifier, language) {
654
- if (!language) { language = this.getCurrentLanguage(); }
655
- var surveyUrl = getBaseUrl() + "mydatahelps/" + linkIdentifier + '/tasklink/' + taskLinkIdentifier + "?lang=" + language;
656
- return startEmbeddedSurvey(surveyUrl);
657
- };
658
-
659
- function startEmbeddedSurvey(surveyUrl) {
660
- var mdhSurveyModalId = 'mydatahelps-survey-modal';
661
-
662
- return new Promise(function (resolve, reject) {
663
- if (document.getElementById(mdhSurveyModalId)) {
664
- reject("Survey already in progress");
665
- return;
666
- }
667
-
668
- window.addEventListener("message", function listener(message) {
669
- if (message.origin !== new URL(getBaseUrl()).origin) {
670
- return;
671
- }
672
- var frame = document.getElementById('mydatahelps-survey-frame').contentWindow;
673
- if (message.source !== frame) {
674
- return;
675
- }
676
- if (message.data.name == 'SurveyWindowInitialized') {
677
- document.getElementById(mdhSurveyModalId).className += " loaded";
678
- } else if (message.data.name == 'SurveyFinished') {
679
- document.getElementById(mdhSurveyModalId).remove();
680
- document.body.className = document.body.className.replace("no-scroll", "");
681
- window.removeEventListener("message", listener, true);
682
- resolve(message.data);
683
- }
684
- }, true);
685
-
686
- var surveyModal = document.createElement('div');
687
- surveyModal.className = 'mydatahelps-survey-modal';
688
- surveyModal.id = mdhSurveyModalId;
689
- 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>";
690
- document.body.append(surveyModal);
691
- document.body.className += ' no-scroll';
692
- });
693
- }
694
-
695
- MyDataHelps.getDataCollectionSettings = function () {
696
- let endpoint = 'datacollectionsettings';
697
-
698
- return MyDataHelps
699
- .connect()
700
- .then(function () { return makeRequest(endpoint, 'GET', null); })
701
- .then(function (response) { return validateResponse(response); })
702
- .then(function (response) { return response.json(); });
703
- };
704
-
705
841
  //iOS/Android directly invoke window.MyDataHelps and window.RKStudioClient
706
842
  //so it's necessary to explicitly ensure they are present on the window
707
- window.MyDataHelps = MyDataHelps;
708
- window.RKStudioClient = RKStudioClient;
843
+ const mdh = new MyDataHelps();
844
+ window.MyDataHelps = mdh;
845
+ // For backwards compatibility
846
+ window.RKStudioClient = {};
847
+ window.RKStudioClient.setActionResult = function (data) {
848
+ window.MyDataHelps.setActionResult(data);
849
+ };
709
850
 
710
- export { MyDataHelps as default };
851
+ export { MyDataHelps, mdh as default };