@gataca/qr 3.0.0 → 3.0.7

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.
@@ -1,13 +1,20 @@
1
1
  import { h, } from "@stencil/core";
2
2
  import "../gataca-qrdisplay/gataca-qrdisplay";
3
+ import { RESULT_STATUS } from "../../utils/utils";
3
4
  const PHONE_ICON = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAHvSURBVHgB3ZZPTttAFMbfe3YjL7qYLopcpZXSG7Q3CDfIsqrSJpyg5QQtJ2h7glgUdVs4AeEE5AYEQSDAgtnw357Hm0hAQDaeIRFCfFKyeKPxzzPzvc+DUKCZN80GEv1ABgWOQgSdGbOwv7u0nDueV4zjTzUIKhuAZna4vdQFR828azbI0K/TI/qodaLvjlP+tLDGDCs+IKv9Lbsi7kcv0w9541Q0EREPYcoieEQ9KiyECRXHzbpBUOcnYTfPFOOaaGVx9WsLiDrSIp0iU0wFNgIx/AQyc9I/OmOjy+Y8aBvHQcDUYebewc6/Xtk8J5htcg5efEPGhk0JtqkyBjo7DuZcnuO2sqCyKv8rUDmfTS9IBURqBAL+I6CkzBjOMOs22TLY21n8fl17KzXR3uDvb/CQk0GEdfvN07QvpnAOaGfYaRT25JzU6+rnG2tTpcWAy+Cp0m3U/URLms8HWfg/rn6RFaGSs9KQkZMpvGBWNs2Vandt46ac6YNBuc0fDLMaOU5DFybQ8039p/KJ4bq4rwPewtqoM/1gsCm/NfBXvWjgHhhuDAeLyd3qVSifHQULeZkou9EqemLhmUmav8qrZ4GEMGA7ivzjKvfeqGptFV2YdWPMPHHq0cCh3DdpVdLl/XCY9J1gVvbCiWa6N+JLocPFjCsx9cAAAAAASUVORK5CYII=";
5
+ //Default values
6
+ const DEFAULT_SESSION_TIMEOUT = 300; //5mins as in connect
7
+ const DEFAULT_POLLING_FREQ = 3;
4
8
  export class GatacaSSIButton {
5
9
  constructor() {
6
10
  this.buttonText = "Easy login";
11
+ this.autostart = true;
7
12
  this.checkStatus = undefined;
8
13
  this.createSession = undefined;
9
14
  this.successCallback = undefined;
10
15
  this.errorCallback = undefined;
16
+ this.handleCheckAppLoading = undefined;
17
+ this.checkAppTimeout = 6;
11
18
  this.qrRole = undefined;
12
19
  this.callbackServer = undefined;
13
20
  this.sessionTimeout = undefined;
@@ -34,7 +41,11 @@ export class GatacaSSIButton {
34
41
  this.waitingStartSessionLabel = "waiting to start a session";
35
42
  this.hideQrModalDescription = false;
36
43
  this.open = false;
37
- this.qr = (h("gataca-qr", { checkStatus: this.checkStatus, createSession: this.createSession, successCallback: this.successCallback, errorCallback: this.errorCallback, qrRole: this.qrRole, callbackServer: this.callbackServer, sessionTimeout: this.sessionTimeout, pollingFrequency: this.pollingFrequency, autostart: true, autorefresh: this.autorefresh, v: this.v, qrModalTitle: this.qrModalTitle, qrModalDescription: this.qrModalDescription, hideBrandTitle: this.hideBrandTitle, dynamicLink: this.dynamicLink, logoSize: this.logoSize, logoSrc: this.logoSrc, modalTitleColor: this.modalTitleColor, qrCodeExpiredLabel: this.qrCodeExpiredLabel, credentialsNotValidatedLabel: this.credentialsNotValidatedLabel, clickInsideBoxLabel: this.clickInsideBoxLabel, refreshQrLabel: this.refreshQrLabel, scanQrLabel: this.scanQrLabel, userNotScanInTimeErrorLabel: this.userNotScanInTimeErrorLabel, credsNotValidatedErrorLabel: this.credsNotValidatedErrorLabel, failedLoginErrorLabel: this.failedLoginErrorLabel, successLoginLabel: this.successLoginLabel, byBrandLabel: this.byBrandLabel, waitingStartSessionLabel: this.waitingStartSessionLabel, hideQrModalDescription: this.hideQrModalDescription }));
44
+ this.sessionId = undefined;
45
+ this.authenticationRequest = undefined;
46
+ this.sessionData = undefined;
47
+ this.result = RESULT_STATUS.NOT_STARTED;
48
+ this.qr = (h("gataca-qr", { ref: (el) => (this.qrElement = el), checkStatus: this.checkStatus, createSession: this.createSession, successCallback: this.successCallback, errorCallback: this.errorCallback, qrRole: this.qrRole, callbackServer: this.callbackServer, sessionTimeout: this.sessionTimeout, pollingFrequency: this.pollingFrequency, autostart: this.autostart, autorefresh: this.autorefresh, v: this.v, qrModalTitle: this.qrModalTitle, qrModalDescription: this.qrModalDescription, hideBrandTitle: this.hideBrandTitle, dynamicLink: this.dynamicLink, logoSize: this.logoSize, logoSrc: this.logoSrc, modalTitleColor: this.modalTitleColor, qrCodeExpiredLabel: this.qrCodeExpiredLabel, credentialsNotValidatedLabel: this.credentialsNotValidatedLabel, clickInsideBoxLabel: this.clickInsideBoxLabel, refreshQrLabel: this.refreshQrLabel, scanQrLabel: this.scanQrLabel, userNotScanInTimeErrorLabel: this.userNotScanInTimeErrorLabel, credsNotValidatedErrorLabel: this.credsNotValidatedErrorLabel, failedLoginErrorLabel: this.failedLoginErrorLabel, successLoginLabel: this.successLoginLabel, byBrandLabel: this.byBrandLabel, waitingStartSessionLabel: this.waitingStartSessionLabel, hideQrModalDescription: this.hideQrModalDescription }));
38
49
  }
39
50
  /**
40
51
  * Retrieve manually the session data on a successful login
@@ -42,22 +53,195 @@ export class GatacaSSIButton {
42
53
  async getSessionData() {
43
54
  return this.qr.getSessionData();
44
55
  }
56
+ async getSessionId() {
57
+ if (this.sessionId) {
58
+ return this.sessionId;
59
+ }
60
+ let { sessionId, authenticationRequest } = await this.createSession();
61
+ this.sessionId = sessionId;
62
+ this.authenticationRequest = authenticationRequest;
63
+ return this.sessionId;
64
+ }
65
+ /**
66
+ * Force manually the start polling
67
+ */
68
+ async startMobilePolling() {
69
+ await this.getSessionId();
70
+ this.result = RESULT_STATUS.ONGOING;
71
+ this.poll()
72
+ .then((data) => {
73
+ this.result = RESULT_STATUS.SUCCESS;
74
+ this.sessionData = data;
75
+ this.gatacaLoginCompleted.emit(data);
76
+ this.successCallback(data);
77
+ })
78
+ .catch((err) => {
79
+ this.clean();
80
+ let expired = err === RESULT_STATUS.EXPIRED;
81
+ if (expired && this.autorefresh) {
82
+ this.startMobilePolling();
83
+ }
84
+ else {
85
+ if (err !== RESULT_STATUS.NOT_STARTED) {
86
+ let error = expired
87
+ ? new Error(this.userNotScanInTimeErrorLabel)
88
+ : new Error(this.credsNotValidatedErrorLabel);
89
+ this.result = err;
90
+ this.gatacaLoginFailed.emit(error);
91
+ this.errorCallback(error);
92
+ }
93
+ }
94
+ });
95
+ }
96
+ /**
97
+ * Stop manually an ongoing session
98
+ */
99
+ async stop() {
100
+ this.clean();
101
+ if (this.result === RESULT_STATUS.ONGOING || RESULT_STATUS.READ) {
102
+ this.result = RESULT_STATUS.NOT_STARTED;
103
+ }
104
+ }
105
+ clean() {
106
+ this.sessionData = undefined;
107
+ this.sessionId = undefined;
108
+ }
45
109
  renderModal() {
46
110
  return this.qr;
47
111
  }
48
- renderButton() {
112
+ async poll() {
113
+ let endTime = new Date().getTime() +
114
+ (this.sessionTimeout || DEFAULT_SESSION_TIMEOUT) * 1000;
115
+ let interval = (this.pollingFrequency || DEFAULT_POLLING_FREQ) * 1000;
116
+ let checkFunc = async (component) => {
117
+ if (component.result === RESULT_STATUS.NOT_STARTED) {
118
+ return { result: RESULT_STATUS.NOT_STARTED };
119
+ }
120
+ let id = await component.getSessionId();
121
+ return component.checkStatus(id);
122
+ };
123
+ let component = this;
124
+ let checkCondition = async function (resolve, reject) {
125
+ // If the condition is met, we're done!
126
+ let { result, data } = await checkFunc(component);
127
+ switch (result) {
128
+ case RESULT_STATUS.SUCCESS:
129
+ resolve(data);
130
+ break;
131
+ case RESULT_STATUS.READ:
132
+ component.result = RESULT_STATUS.READ;
133
+ case RESULT_STATUS.ONGOING:
134
+ if (component.sessionTimeout > 0 && new Date().getTime() < endTime) {
135
+ setTimeout(checkCondition, interval, resolve, reject);
136
+ }
137
+ else {
138
+ reject(RESULT_STATUS.EXPIRED);
139
+ }
140
+ break;
141
+ default:
142
+ reject(result);
143
+ break;
144
+ }
145
+ };
146
+ return new Promise(checkCondition);
147
+ }
148
+ isAppInstalled(appScheme, callback) {
149
+ let timeout;
150
+ let detected = false;
151
+ if (appScheme === null || appScheme === void 0 ? void 0 : appScheme.length) {
152
+ window.location.href = appScheme;
153
+ }
154
+ const waitTimeToCheckApp = this.checkAppTimeout * 1000;
155
+ timeout = setTimeout(() => {
156
+ if (!detected) {
157
+ callback(false);
158
+ }
159
+ cleanup();
160
+ }, waitTimeToCheckApp);
161
+ const handleVisibilityChange = () => {
162
+ if (document.hidden) {
163
+ detected = true;
164
+ callback(true);
165
+ this.startMobilePolling();
166
+ cleanup();
167
+ }
168
+ };
169
+ document.addEventListener("visibilitychange", handleVisibilityChange);
170
+ function cleanup() {
171
+ clearTimeout(timeout);
172
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
173
+ }
174
+ }
175
+ renderDesktopButton() {
49
176
  return (h("div", { class: "gatacaButtonWrapper" }, h("button", { class: "gatacaButton", onClick: () => {
50
177
  this.open = !this.open;
51
- if (this.open) {
52
- this.qr.display();
53
- }
54
- else {
55
- this.qr.stop();
56
- }
178
+ setTimeout(() => {
179
+ var _a, _b;
180
+ if (this.open) {
181
+ (_a = this.qrElement) === null || _a === void 0 ? void 0 : _a.display();
182
+ }
183
+ else {
184
+ (_b = this.qrElement) === null || _b === void 0 ? void 0 : _b.stop();
185
+ }
186
+ }, 0);
57
187
  } }, h("img", { src: PHONE_ICON, class: "buttonImg", alt: this.buttonText }), h("span", null, this.buttonText))));
58
188
  }
189
+ async getAuthRequest() {
190
+ let { authenticationRequest } = await this.createSession();
191
+ return authenticationRequest;
192
+ }
193
+ renderMobileButton(isAndroid, isIos) {
194
+ if (this.autostart) {
195
+ this.startMobilePolling();
196
+ }
197
+ let loading = false;
198
+ const handleLoading = (isLoading) => {
199
+ loading = isLoading;
200
+ if (this.handleCheckAppLoading) {
201
+ this.handleCheckAppLoading(isLoading);
202
+ }
203
+ };
204
+ const executeRedirection = async () => {
205
+ handleLoading(true);
206
+ const androidStoreLink = "https://play.google.com/store/apps/details?id=com.gataca.identity";
207
+ const iosStoreLink = "https://apps.apple.com/us/app/gataca/id1498607616";
208
+ try {
209
+ const appScheme = await this.getAuthRequest();
210
+ this.isAppInstalled(appScheme, (installed) => {
211
+ if (!installed) {
212
+ this.stop();
213
+ if (isAndroid) {
214
+ window.location.href = androidStoreLink;
215
+ }
216
+ else if (isIos) {
217
+ window.location.href = iosStoreLink;
218
+ }
219
+ }
220
+ handleLoading(false);
221
+ });
222
+ }
223
+ catch (error) {
224
+ this.stop();
225
+ handleLoading(false);
226
+ }
227
+ };
228
+ return (h("div", { class: "gatacaButtonWrapper" }, h("button", { class: "gatacaButton", onClick: () => {
229
+ executeRedirection();
230
+ }, disabled: loading }, h("img", { src: PHONE_ICON, class: "buttonImg", alt: this.buttonText }), h("span", null, this.buttonText))));
231
+ }
59
232
  render() {
60
- return (h("div", { class: "buttonContainer" }, this.renderButton(), this.open && this.renderModal()));
233
+ const userAgent =
234
+ // @ts-ignore
235
+ (navigator === null || navigator === void 0 ? void 0 : navigator.userAgent) || (navigator === null || navigator === void 0 ? void 0 : navigator.vendor) || (window === null || window === void 0 ? void 0 : window.opera);
236
+ const isAndroid = /android/i.test(userAgent);
237
+ const isIos =
238
+ // @ts-ignore
239
+ (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) ||
240
+ (navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1);
241
+ const isMobile = isAndroid || isIos;
242
+ return (h("div", { class: "buttonContainer" }, isMobile && this.v === "3"
243
+ ? this.renderMobileButton(isAndroid, isIos)
244
+ : this.renderDesktopButton(), this.open && (!isMobile || this.v === "3") && this.renderModal()));
61
245
  }
62
246
  static get is() { return "gataca-ssibutton"; }
63
247
  static get encapsulation() { return "shadow"; }
@@ -91,6 +275,24 @@ export class GatacaSSIButton {
91
275
  "reflect": false,
92
276
  "defaultValue": "\"Easy login\""
93
277
  },
278
+ "autostart": {
279
+ "type": "boolean",
280
+ "mutable": false,
281
+ "complexType": {
282
+ "original": "boolean",
283
+ "resolved": "boolean",
284
+ "references": {}
285
+ },
286
+ "required": false,
287
+ "optional": false,
288
+ "docs": {
289
+ "tags": [],
290
+ "text": "_[Optional]_\nSet to start polling when button or QR is displayed. By default it is true"
291
+ },
292
+ "attribute": "autostart",
293
+ "reflect": false,
294
+ "defaultValue": "true"
295
+ },
94
296
  "checkStatus": {
95
297
  "type": "unknown",
96
298
  "mutable": false,
@@ -171,6 +373,40 @@ export class GatacaSSIButton {
171
373
  },
172
374
  "defaultValue": "undefined"
173
375
  },
376
+ "handleCheckAppLoading": {
377
+ "type": "unknown",
378
+ "mutable": false,
379
+ "complexType": {
380
+ "original": "(isCheckingApp?: boolean) => void",
381
+ "resolved": "(isCheckingApp?: boolean) => void",
382
+ "references": {}
383
+ },
384
+ "required": false,
385
+ "optional": true,
386
+ "docs": {
387
+ "tags": [],
388
+ "text": "_[Optional]_\nFunction that runs every time the loading state changes while checking if the App is installed. Only on mobile with v3."
389
+ },
390
+ "defaultValue": "undefined"
391
+ },
392
+ "checkAppTimeout": {
393
+ "type": "number",
394
+ "mutable": false,
395
+ "complexType": {
396
+ "original": "number",
397
+ "resolved": "number",
398
+ "references": {}
399
+ },
400
+ "required": false,
401
+ "optional": true,
402
+ "docs": {
403
+ "tags": [],
404
+ "text": "_[Optional]_\nMaximum time window to check if the App is installed"
405
+ },
406
+ "attribute": "check-app-timeout",
407
+ "reflect": false,
408
+ "defaultValue": "6"
409
+ },
174
410
  "qrRole": {
175
411
  "type": "string",
176
412
  "mutable": false,
@@ -620,7 +856,11 @@ export class GatacaSSIButton {
620
856
  }
621
857
  static get states() {
622
858
  return {
623
- "open": {}
859
+ "open": {},
860
+ "sessionId": {},
861
+ "authenticationRequest": {},
862
+ "sessionData": {},
863
+ "result": {}
624
864
  };
625
865
  }
626
866
  static get events() {
@@ -673,6 +913,42 @@ export class GatacaSSIButton {
673
913
  "text": "Retrieve manually the session data on a successful login",
674
914
  "tags": []
675
915
  }
916
+ },
917
+ "startMobilePolling": {
918
+ "complexType": {
919
+ "signature": "() => Promise<void>",
920
+ "parameters": [],
921
+ "references": {
922
+ "Promise": {
923
+ "location": "global"
924
+ },
925
+ "RESULT_STATUS": {
926
+ "location": "import",
927
+ "path": "../../utils/utils"
928
+ }
929
+ },
930
+ "return": "Promise<void>"
931
+ },
932
+ "docs": {
933
+ "text": "Force manually the start polling",
934
+ "tags": []
935
+ }
936
+ },
937
+ "stop": {
938
+ "complexType": {
939
+ "signature": "() => Promise<void>",
940
+ "parameters": [],
941
+ "references": {
942
+ "Promise": {
943
+ "location": "global"
944
+ }
945
+ },
946
+ "return": "Promise<void>"
947
+ },
948
+ "docs": {
949
+ "text": "Stop manually an ongoing session",
950
+ "tags": []
951
+ }
676
952
  }
677
953
  };
678
954
  }
@@ -1,10 +1,14 @@
1
1
  import { proxyCustomElement, HTMLElement, createEvent, h } from '@stencil/core/internal/client';
2
2
  import { d as defineCustomElement$1 } from './gataca-qrdisplay2.js';
3
+ import { R as RESULT_STATUS } from './gat-icon-alert.js';
3
4
  import { d as defineCustomElement$2 } from './gataca-qr2.js';
4
5
 
5
6
  const gatacaSsibuttonCss = "@import url(\"https://fonts.googleapis.com/css2?family=Work+Sans:wght@300;400&display=swap\"); html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:\"\";content:none}table{border-collapse:collapse;border-spacing:0}.img-fluid{height:auto;max-width:50%}img{margin-left:auto;margin-right:auto}.buttonContainer{display:inline-block;text-align:right;padding:10px;position:relative}.gatacaButtonWrapper{margin:8px}.gatacaButtonWrapper .gatacaButton{display:flex;min-width:100px;padding:8px 8px;background-color:white;font-size:12px;font-family:\"Work Sans\", sans-serif;letter-spacing:1px;font-weight:2;justify-content:space-between;align-items:center;border-radius:6px;border:1px solid rgba(24, 27, 94, 0.5);color:rgba(24, 27, 94, 0.8);box-shadow:0px 1px 3px rgba(48, 48, 48, 0.15);cursor:pointer}.gatacaButtonWrapper .gatacaButton>span{margin-right:10px}.gatacaButtonWrapper .gatacaButton:hover{box-shadow:0px 2px 8px rgba(48, 48, 48, 0.1)}.gatacaButtonWrapper .buttonText{text-align:right;font-size:8px;color:rgba(24, 27, 94, 0.5);font-family:\"Helvetica Neue\", sans-serif;letter-spacing:1px;padding-right:8px;font-weight:1}.gatacaButtonWrapper .buttonImg{height:25px;width:25px;margin:0;margin-right:20px}";
6
7
 
7
8
  const PHONE_ICON = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAHvSURBVHgB3ZZPTttAFMbfe3YjL7qYLopcpZXSG7Q3CDfIsqrSJpyg5QQtJ2h7glgUdVs4AeEE5AYEQSDAgtnw357Hm0hAQDaeIRFCfFKyeKPxzzPzvc+DUKCZN80GEv1ABgWOQgSdGbOwv7u0nDueV4zjTzUIKhuAZna4vdQFR828azbI0K/TI/qodaLvjlP+tLDGDCs+IKv9Lbsi7kcv0w9541Q0EREPYcoieEQ9KiyECRXHzbpBUOcnYTfPFOOaaGVx9WsLiDrSIp0iU0wFNgIx/AQyc9I/OmOjy+Y8aBvHQcDUYebewc6/Xtk8J5htcg5efEPGhk0JtqkyBjo7DuZcnuO2sqCyKv8rUDmfTS9IBURqBAL+I6CkzBjOMOs22TLY21n8fl17KzXR3uDvb/CQk0GEdfvN07QvpnAOaGfYaRT25JzU6+rnG2tTpcWAy+Cp0m3U/URLms8HWfg/rn6RFaGSs9KQkZMpvGBWNs2Vandt46ac6YNBuc0fDLMaOU5DFybQ8039p/KJ4bq4rwPewtqoM/1gsCm/NfBXvWjgHhhuDAeLyd3qVSifHQULeZkou9EqemLhmUmav8qrZ4GEMGA7ivzjKvfeqGptFV2YdWPMPHHq0cCh3DdpVdLl/XCY9J1gVvbCiWa6N+JLocPFjCsx9cAAAAAASUVORK5CYII=";
9
+ //Default values
10
+ const DEFAULT_SESSION_TIMEOUT = 300; //5mins as in connect
11
+ const DEFAULT_POLLING_FREQ = 3;
8
12
  const GatacaSSIButton = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
9
13
  constructor() {
10
14
  super();
@@ -13,10 +17,13 @@ const GatacaSSIButton = /*@__PURE__*/ proxyCustomElement(class extends HTMLEleme
13
17
  this.gatacaLoginCompleted = createEvent(this, "gatacaLoginCompleted", 7);
14
18
  this.gatacaLoginFailed = createEvent(this, "gatacaLoginFailed", 7);
15
19
  this.buttonText = "Easy login";
20
+ this.autostart = true;
16
21
  this.checkStatus = undefined;
17
22
  this.createSession = undefined;
18
23
  this.successCallback = undefined;
19
24
  this.errorCallback = undefined;
25
+ this.handleCheckAppLoading = undefined;
26
+ this.checkAppTimeout = 6;
20
27
  this.qrRole = undefined;
21
28
  this.callbackServer = undefined;
22
29
  this.sessionTimeout = undefined;
@@ -43,7 +50,11 @@ const GatacaSSIButton = /*@__PURE__*/ proxyCustomElement(class extends HTMLEleme
43
50
  this.waitingStartSessionLabel = "waiting to start a session";
44
51
  this.hideQrModalDescription = false;
45
52
  this.open = false;
46
- this.qr = (h("gataca-qr", { checkStatus: this.checkStatus, createSession: this.createSession, successCallback: this.successCallback, errorCallback: this.errorCallback, qrRole: this.qrRole, callbackServer: this.callbackServer, sessionTimeout: this.sessionTimeout, pollingFrequency: this.pollingFrequency, autostart: true, autorefresh: this.autorefresh, v: this.v, qrModalTitle: this.qrModalTitle, qrModalDescription: this.qrModalDescription, hideBrandTitle: this.hideBrandTitle, dynamicLink: this.dynamicLink, logoSize: this.logoSize, logoSrc: this.logoSrc, modalTitleColor: this.modalTitleColor, qrCodeExpiredLabel: this.qrCodeExpiredLabel, credentialsNotValidatedLabel: this.credentialsNotValidatedLabel, clickInsideBoxLabel: this.clickInsideBoxLabel, refreshQrLabel: this.refreshQrLabel, scanQrLabel: this.scanQrLabel, userNotScanInTimeErrorLabel: this.userNotScanInTimeErrorLabel, credsNotValidatedErrorLabel: this.credsNotValidatedErrorLabel, failedLoginErrorLabel: this.failedLoginErrorLabel, successLoginLabel: this.successLoginLabel, byBrandLabel: this.byBrandLabel, waitingStartSessionLabel: this.waitingStartSessionLabel, hideQrModalDescription: this.hideQrModalDescription }));
53
+ this.sessionId = undefined;
54
+ this.authenticationRequest = undefined;
55
+ this.sessionData = undefined;
56
+ this.result = RESULT_STATUS.NOT_STARTED;
57
+ this.qr = (h("gataca-qr", { ref: (el) => (this.qrElement = el), checkStatus: this.checkStatus, createSession: this.createSession, successCallback: this.successCallback, errorCallback: this.errorCallback, qrRole: this.qrRole, callbackServer: this.callbackServer, sessionTimeout: this.sessionTimeout, pollingFrequency: this.pollingFrequency, autostart: this.autostart, autorefresh: this.autorefresh, v: this.v, qrModalTitle: this.qrModalTitle, qrModalDescription: this.qrModalDescription, hideBrandTitle: this.hideBrandTitle, dynamicLink: this.dynamicLink, logoSize: this.logoSize, logoSrc: this.logoSrc, modalTitleColor: this.modalTitleColor, qrCodeExpiredLabel: this.qrCodeExpiredLabel, credentialsNotValidatedLabel: this.credentialsNotValidatedLabel, clickInsideBoxLabel: this.clickInsideBoxLabel, refreshQrLabel: this.refreshQrLabel, scanQrLabel: this.scanQrLabel, userNotScanInTimeErrorLabel: this.userNotScanInTimeErrorLabel, credsNotValidatedErrorLabel: this.credsNotValidatedErrorLabel, failedLoginErrorLabel: this.failedLoginErrorLabel, successLoginLabel: this.successLoginLabel, byBrandLabel: this.byBrandLabel, waitingStartSessionLabel: this.waitingStartSessionLabel, hideQrModalDescription: this.hideQrModalDescription }));
47
58
  }
48
59
  /**
49
60
  * Retrieve manually the session data on a successful login
@@ -51,30 +62,206 @@ const GatacaSSIButton = /*@__PURE__*/ proxyCustomElement(class extends HTMLEleme
51
62
  async getSessionData() {
52
63
  return this.qr.getSessionData();
53
64
  }
65
+ async getSessionId() {
66
+ if (this.sessionId) {
67
+ return this.sessionId;
68
+ }
69
+ let { sessionId, authenticationRequest } = await this.createSession();
70
+ this.sessionId = sessionId;
71
+ this.authenticationRequest = authenticationRequest;
72
+ return this.sessionId;
73
+ }
74
+ /**
75
+ * Force manually the start polling
76
+ */
77
+ async startMobilePolling() {
78
+ await this.getSessionId();
79
+ this.result = RESULT_STATUS.ONGOING;
80
+ this.poll()
81
+ .then((data) => {
82
+ this.result = RESULT_STATUS.SUCCESS;
83
+ this.sessionData = data;
84
+ this.gatacaLoginCompleted.emit(data);
85
+ this.successCallback(data);
86
+ })
87
+ .catch((err) => {
88
+ this.clean();
89
+ let expired = err === RESULT_STATUS.EXPIRED;
90
+ if (expired && this.autorefresh) {
91
+ this.startMobilePolling();
92
+ }
93
+ else {
94
+ if (err !== RESULT_STATUS.NOT_STARTED) {
95
+ let error = expired
96
+ ? new Error(this.userNotScanInTimeErrorLabel)
97
+ : new Error(this.credsNotValidatedErrorLabel);
98
+ this.result = err;
99
+ this.gatacaLoginFailed.emit(error);
100
+ this.errorCallback(error);
101
+ }
102
+ }
103
+ });
104
+ }
105
+ /**
106
+ * Stop manually an ongoing session
107
+ */
108
+ async stop() {
109
+ this.clean();
110
+ if (this.result === RESULT_STATUS.ONGOING || RESULT_STATUS.READ) {
111
+ this.result = RESULT_STATUS.NOT_STARTED;
112
+ }
113
+ }
114
+ clean() {
115
+ this.sessionData = undefined;
116
+ this.sessionId = undefined;
117
+ }
54
118
  renderModal() {
55
119
  return this.qr;
56
120
  }
57
- renderButton() {
121
+ async poll() {
122
+ let endTime = new Date().getTime() +
123
+ (this.sessionTimeout || DEFAULT_SESSION_TIMEOUT) * 1000;
124
+ let interval = (this.pollingFrequency || DEFAULT_POLLING_FREQ) * 1000;
125
+ let checkFunc = async (component) => {
126
+ if (component.result === RESULT_STATUS.NOT_STARTED) {
127
+ return { result: RESULT_STATUS.NOT_STARTED };
128
+ }
129
+ let id = await component.getSessionId();
130
+ return component.checkStatus(id);
131
+ };
132
+ let component = this;
133
+ let checkCondition = async function (resolve, reject) {
134
+ // If the condition is met, we're done!
135
+ let { result, data } = await checkFunc(component);
136
+ switch (result) {
137
+ case RESULT_STATUS.SUCCESS:
138
+ resolve(data);
139
+ break;
140
+ case RESULT_STATUS.READ:
141
+ component.result = RESULT_STATUS.READ;
142
+ case RESULT_STATUS.ONGOING:
143
+ if (component.sessionTimeout > 0 && new Date().getTime() < endTime) {
144
+ setTimeout(checkCondition, interval, resolve, reject);
145
+ }
146
+ else {
147
+ reject(RESULT_STATUS.EXPIRED);
148
+ }
149
+ break;
150
+ default:
151
+ reject(result);
152
+ break;
153
+ }
154
+ };
155
+ return new Promise(checkCondition);
156
+ }
157
+ isAppInstalled(appScheme, callback) {
158
+ let timeout;
159
+ let detected = false;
160
+ if (appScheme === null || appScheme === void 0 ? void 0 : appScheme.length) {
161
+ window.location.href = appScheme;
162
+ }
163
+ const waitTimeToCheckApp = this.checkAppTimeout * 1000;
164
+ timeout = setTimeout(() => {
165
+ if (!detected) {
166
+ callback(false);
167
+ }
168
+ cleanup();
169
+ }, waitTimeToCheckApp);
170
+ const handleVisibilityChange = () => {
171
+ if (document.hidden) {
172
+ detected = true;
173
+ callback(true);
174
+ this.startMobilePolling();
175
+ cleanup();
176
+ }
177
+ };
178
+ document.addEventListener("visibilitychange", handleVisibilityChange);
179
+ function cleanup() {
180
+ clearTimeout(timeout);
181
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
182
+ }
183
+ }
184
+ renderDesktopButton() {
58
185
  return (h("div", { class: "gatacaButtonWrapper" }, h("button", { class: "gatacaButton", onClick: () => {
59
186
  this.open = !this.open;
60
- if (this.open) {
61
- this.qr.display();
62
- }
63
- else {
64
- this.qr.stop();
65
- }
187
+ setTimeout(() => {
188
+ var _a, _b;
189
+ if (this.open) {
190
+ (_a = this.qrElement) === null || _a === void 0 ? void 0 : _a.display();
191
+ }
192
+ else {
193
+ (_b = this.qrElement) === null || _b === void 0 ? void 0 : _b.stop();
194
+ }
195
+ }, 0);
66
196
  } }, h("img", { src: PHONE_ICON, class: "buttonImg", alt: this.buttonText }), h("span", null, this.buttonText))));
67
197
  }
198
+ async getAuthRequest() {
199
+ let { authenticationRequest } = await this.createSession();
200
+ return authenticationRequest;
201
+ }
202
+ renderMobileButton(isAndroid, isIos) {
203
+ if (this.autostart) {
204
+ this.startMobilePolling();
205
+ }
206
+ let loading = false;
207
+ const handleLoading = (isLoading) => {
208
+ loading = isLoading;
209
+ if (this.handleCheckAppLoading) {
210
+ this.handleCheckAppLoading(isLoading);
211
+ }
212
+ };
213
+ const executeRedirection = async () => {
214
+ handleLoading(true);
215
+ const androidStoreLink = "https://play.google.com/store/apps/details?id=com.gataca.identity";
216
+ const iosStoreLink = "https://apps.apple.com/us/app/gataca/id1498607616";
217
+ try {
218
+ const appScheme = await this.getAuthRequest();
219
+ this.isAppInstalled(appScheme, (installed) => {
220
+ if (!installed) {
221
+ this.stop();
222
+ if (isAndroid) {
223
+ window.location.href = androidStoreLink;
224
+ }
225
+ else if (isIos) {
226
+ window.location.href = iosStoreLink;
227
+ }
228
+ }
229
+ handleLoading(false);
230
+ });
231
+ }
232
+ catch (error) {
233
+ this.stop();
234
+ handleLoading(false);
235
+ }
236
+ };
237
+ return (h("div", { class: "gatacaButtonWrapper" }, h("button", { class: "gatacaButton", onClick: () => {
238
+ executeRedirection();
239
+ }, disabled: loading }, h("img", { src: PHONE_ICON, class: "buttonImg", alt: this.buttonText }), h("span", null, this.buttonText))));
240
+ }
68
241
  render() {
69
- return (h("div", { class: "buttonContainer" }, this.renderButton(), this.open && this.renderModal()));
242
+ const userAgent =
243
+ // @ts-ignore
244
+ (navigator === null || navigator === void 0 ? void 0 : navigator.userAgent) || (navigator === null || navigator === void 0 ? void 0 : navigator.vendor) || (window === null || window === void 0 ? void 0 : window.opera);
245
+ const isAndroid = /android/i.test(userAgent);
246
+ const isIos =
247
+ // @ts-ignore
248
+ (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) ||
249
+ (navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1);
250
+ const isMobile = isAndroid || isIos;
251
+ return (h("div", { class: "buttonContainer" }, isMobile && this.v === "3"
252
+ ? this.renderMobileButton(isAndroid, isIos)
253
+ : this.renderDesktopButton(), this.open && (!isMobile || this.v === "3") && this.renderModal()));
70
254
  }
71
255
  static get style() { return gatacaSsibuttonCss; }
72
256
  }, [1, "gataca-ssibutton", {
73
257
  "buttonText": [1, "button-text"],
258
+ "autostart": [4],
74
259
  "checkStatus": [16],
75
260
  "createSession": [16],
76
261
  "successCallback": [16],
77
262
  "errorCallback": [16],
263
+ "handleCheckAppLoading": [16],
264
+ "checkAppTimeout": [2, "check-app-timeout"],
78
265
  "qrRole": [1, "qr-role"],
79
266
  "callbackServer": [1, "callback-server"],
80
267
  "sessionTimeout": [2, "session-timeout"],
@@ -101,7 +288,13 @@ const GatacaSSIButton = /*@__PURE__*/ proxyCustomElement(class extends HTMLEleme
101
288
  "waitingStartSessionLabel": [1, "waiting-start-session-label"],
102
289
  "hideQrModalDescription": [4, "hide-qr-modal-description"],
103
290
  "open": [32],
104
- "getSessionData": [64]
291
+ "sessionId": [32],
292
+ "authenticationRequest": [32],
293
+ "sessionData": [32],
294
+ "result": [32],
295
+ "getSessionData": [64],
296
+ "startMobilePolling": [64],
297
+ "stop": [64]
105
298
  }]);
106
299
  function defineCustomElement() {
107
300
  if (typeof customElements === "undefined") {