smartcomply-web-sdk 1.0.62 → 1.0.64
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/dist/esm/flow/DocumentCapture.d.ts +21 -1
- package/dist/esm/flow/DocumentCapture.d.ts.map +1 -1
- package/dist/esm/flow/DocumentCapture.js +155 -84
- package/dist/esm/flow/DocumentCapture.js.map +1 -1
- package/dist/esm/flow/SmartComplyFlow.d.ts +1 -0
- package/dist/esm/flow/SmartComplyFlow.d.ts.map +1 -1
- package/dist/esm/flow/SmartComplyFlow.js +89 -105
- package/dist/esm/flow/SmartComplyFlow.js.map +1 -1
- package/dist/esm/flow/icons.d.ts +14 -0
- package/dist/esm/flow/icons.d.ts.map +1 -0
- package/dist/esm/flow/icons.js +34 -0
- package/dist/esm/flow/icons.js.map +1 -0
- package/dist/esm/flow/spinner.d.ts +15 -0
- package/dist/esm/flow/spinner.d.ts.map +1 -0
- package/dist/esm/flow/spinner.js +55 -0
- package/dist/esm/flow/spinner.js.map +1 -0
- package/dist/esm/flow/theme.d.ts +19 -0
- package/dist/esm/flow/theme.d.ts.map +1 -1
- package/dist/esm/flow/theme.js +19 -0
- package/dist/esm/flow/theme.js.map +1 -1
- package/dist/esm/modules/liveness/LivenessUI.d.ts +10 -0
- package/dist/esm/modules/liveness/LivenessUI.d.ts.map +1 -1
- package/dist/esm/modules/liveness/LivenessUI.js +17 -16
- package/dist/esm/modules/liveness/LivenessUI.js.map +1 -1
- package/dist/esm/modules/liveness/liveness.d.ts +2 -0
- package/dist/esm/modules/liveness/liveness.d.ts.map +1 -1
- package/dist/esm/modules/liveness/liveness.js +1 -1
- package/dist/esm/modules/liveness/liveness.js.map +1 -1
- package/dist/flow/DocumentCapture.d.ts +21 -1
- package/dist/flow/DocumentCapture.d.ts.map +1 -1
- package/dist/flow/DocumentCapture.js +155 -84
- package/dist/flow/DocumentCapture.js.map +1 -1
- package/dist/flow/SmartComplyFlow.d.ts +1 -0
- package/dist/flow/SmartComplyFlow.d.ts.map +1 -1
- package/dist/flow/SmartComplyFlow.js +88 -104
- package/dist/flow/SmartComplyFlow.js.map +1 -1
- package/dist/flow/icons.d.ts +14 -0
- package/dist/flow/icons.d.ts.map +1 -0
- package/dist/flow/icons.js +37 -0
- package/dist/flow/icons.js.map +1 -0
- package/dist/flow/spinner.d.ts +15 -0
- package/dist/flow/spinner.d.ts.map +1 -0
- package/dist/flow/spinner.js +59 -0
- package/dist/flow/spinner.js.map +1 -0
- package/dist/flow/theme.d.ts +19 -0
- package/dist/flow/theme.d.ts.map +1 -1
- package/dist/flow/theme.js +20 -1
- package/dist/flow/theme.js.map +1 -1
- package/dist/modules/liveness/LivenessUI.d.ts +10 -0
- package/dist/modules/liveness/LivenessUI.d.ts.map +1 -1
- package/dist/modules/liveness/LivenessUI.js +17 -16
- package/dist/modules/liveness/LivenessUI.js.map +1 -1
- package/dist/modules/liveness/liveness.d.ts +2 -0
- package/dist/modules/liveness/liveness.d.ts.map +1 -1
- package/dist/modules/liveness/liveness.js +1 -1
- package/dist/modules/liveness/liveness.js.map +1 -1
- package/dist/smartcomply.browser.js +333 -209
- package/dist/smartcomply.browser.js.map +4 -4
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SmartComplyFlow.d.ts","sourceRoot":"","sources":["../../../src/flow/SmartComplyFlow.ts"],"names":[],"mappings":"AACA,OAAO,EAA6B,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAIxF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"SmartComplyFlow.d.ts","sourceRoot":"","sources":["../../../src/flow/SmartComplyFlow.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { SmartComply } from "../client/Smartcomply";
|
|
2
|
-
import { getTheme } from "./theme";
|
|
2
|
+
import { getTheme, TYPE, RADIUS } from "./theme";
|
|
3
3
|
import { DocumentCapture } from "./DocumentCapture";
|
|
4
4
|
import { collectDeviceMetadata } from "../utils/device";
|
|
5
5
|
import { requiresBackSide } from "../utils/documentRules";
|
|
6
|
+
import { icon } from "./icons";
|
|
7
|
+
import { renderSpinner, renderInlineSpinner } from "./spinner";
|
|
6
8
|
const STEP_ORDER = [
|
|
7
9
|
"loading",
|
|
8
10
|
"welcome",
|
|
@@ -226,18 +228,6 @@ function _formatDocType(code) {
|
|
|
226
228
|
}
|
|
227
229
|
// SmartComplyFlow
|
|
228
230
|
// ─────────────────────────────────────────────────────────────────────
|
|
229
|
-
// Add CSS animation keyframes for spin animations
|
|
230
|
-
const style = document.createElement('style');
|
|
231
|
-
style.textContent = `
|
|
232
|
-
@keyframes sc-spin {
|
|
233
|
-
0% { transform: rotate(0deg); }
|
|
234
|
-
100% { transform: rotate(360deg); }
|
|
235
|
-
}
|
|
236
|
-
`;
|
|
237
|
-
if (!document.head.querySelector('style[data-sc-animations]')) {
|
|
238
|
-
style.setAttribute('data-sc-animations', 'true');
|
|
239
|
-
document.head.appendChild(style);
|
|
240
|
-
}
|
|
241
231
|
export class SmartComplyFlow {
|
|
242
232
|
constructor(options) {
|
|
243
233
|
this.theme = getTheme("default");
|
|
@@ -262,6 +252,11 @@ export class SmartComplyFlow {
|
|
|
262
252
|
this.idNumber = "";
|
|
263
253
|
this.documentBlob = null;
|
|
264
254
|
this.documentBackBlob = null;
|
|
255
|
+
// Whether the document's front image came from the live camera vs. a
|
|
256
|
+
// gallery/file upload — gates whether pre-warming the liveness camera on
|
|
257
|
+
// the confirm screens makes sense (reusing an already-open camera) or
|
|
258
|
+
// would surprise a user who hasn't touched their camera yet this session.
|
|
259
|
+
this._documentViaCamera = false;
|
|
265
260
|
this.identityCheckId = null;
|
|
266
261
|
this.verificationResult = null;
|
|
267
262
|
this.livenessEntryId = null;
|
|
@@ -609,27 +604,9 @@ export class SmartComplyFlow {
|
|
|
609
604
|
// ── Loading ─────────────────────────────────────────────────────
|
|
610
605
|
renderLoading(container) {
|
|
611
606
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:300px;gap:16px;";
|
|
612
|
-
|
|
613
|
-
spinnerWrap.style.cssText = "position:relative;width:60px;height:60px;flex-shrink:0;";
|
|
614
|
-
const ring = document.createElement("div");
|
|
615
|
-
ring.style.cssText = `
|
|
616
|
-
position:absolute;inset:0;border-radius:50%;
|
|
617
|
-
border:3px solid ${this.theme.border};
|
|
618
|
-
border-top-color:${this.theme.primary};
|
|
619
|
-
animation:sc-spin 0.9s linear infinite;
|
|
620
|
-
`;
|
|
621
|
-
const centre = document.createElement("div");
|
|
622
|
-
centre.style.cssText = `
|
|
623
|
-
position:absolute;inset:0;
|
|
624
|
-
display:flex;align-items:center;justify-content:center;
|
|
625
|
-
font-size:22px;
|
|
626
|
-
`;
|
|
627
|
-
centre.textContent = "\uD83D\uDEE1\uFE0F";
|
|
628
|
-
spinnerWrap.appendChild(ring);
|
|
629
|
-
spinnerWrap.appendChild(centre);
|
|
630
|
-
container.appendChild(spinnerWrap);
|
|
607
|
+
container.appendChild(renderSpinner(this.theme, { size: 60, icon: icon("shield", 22) }));
|
|
631
608
|
const label = document.createElement("div");
|
|
632
|
-
label.style.cssText = `color:${this.theme.text};font-size
|
|
609
|
+
label.style.cssText = `color:${this.theme.text};font-size:${TYPE.base}px;font-weight:600;`;
|
|
633
610
|
label.textContent = "Setting up secure session";
|
|
634
611
|
container.appendChild(label);
|
|
635
612
|
const sub = document.createElement("div");
|
|
@@ -648,11 +625,11 @@ export class SmartComplyFlow {
|
|
|
648
625
|
iconWrap.style.cssText = `
|
|
649
626
|
width:50px;height:50px;border-radius:14px;
|
|
650
627
|
display:flex;align-items:center;justify-content:center;
|
|
651
|
-
|
|
628
|
+
color:${this.theme.primary};
|
|
652
629
|
background:linear-gradient(135deg,${this.theme.primary}22,${this.theme.primaryGlow});
|
|
653
630
|
border:1.5px solid ${this.theme.primary}33;
|
|
654
631
|
`;
|
|
655
|
-
iconWrap.
|
|
632
|
+
iconWrap.innerHTML = icon(isDocFlow ? "id-card" : "shield", 24);
|
|
656
633
|
topRow.appendChild(iconWrap);
|
|
657
634
|
const badge = document.createElement("div");
|
|
658
635
|
badge.style.cssText = `
|
|
@@ -671,7 +648,7 @@ export class SmartComplyFlow {
|
|
|
671
648
|
titleWrap.style.cssText = "display:flex;flex-direction:column;gap:5px;";
|
|
672
649
|
const title = document.createElement("h2");
|
|
673
650
|
title.style.cssText = `
|
|
674
|
-
color:${this.theme.text};font-size
|
|
651
|
+
color:${this.theme.text};font-size:${TYPE.heading}px;font-weight:700;
|
|
675
652
|
margin:0;line-height:1.2;
|
|
676
653
|
`;
|
|
677
654
|
// W2: Use client brand name in title
|
|
@@ -705,7 +682,7 @@ export class SmartComplyFlow {
|
|
|
705
682
|
const stepsWrap = document.createElement("div");
|
|
706
683
|
stepsWrap.style.cssText = `
|
|
707
684
|
width:100%;display:flex;flex-direction:column;gap:0;
|
|
708
|
-
border-radius
|
|
685
|
+
border-radius:${RADIUS.md}px;overflow:hidden;
|
|
709
686
|
border:1.5px solid ${this.theme.border};
|
|
710
687
|
`;
|
|
711
688
|
steps.forEach((step, i) => {
|
|
@@ -718,7 +695,7 @@ export class SmartComplyFlow {
|
|
|
718
695
|
`;
|
|
719
696
|
const iconEl = document.createElement("div");
|
|
720
697
|
iconEl.style.cssText = `
|
|
721
|
-
width:28px;height:28px;border-radius
|
|
698
|
+
width:28px;height:28px;border-radius:${RADIUS.sm}px;flex-shrink:0;
|
|
722
699
|
display:flex;align-items:center;justify-content:center;
|
|
723
700
|
font-size:13px;
|
|
724
701
|
background:${this.theme.primary}12;
|
|
@@ -946,7 +923,7 @@ export class SmartComplyFlow {
|
|
|
946
923
|
// Dropdown field
|
|
947
924
|
const select = document.createElement("select");
|
|
948
925
|
select.style.cssText = `
|
|
949
|
-
width:100%;padding:13px 16px;border-radius
|
|
926
|
+
width:100%;padding:13px 16px;border-radius:${RADIUS.md}px;
|
|
950
927
|
font-size:15px;
|
|
951
928
|
background:${this.theme.inputBg};
|
|
952
929
|
color:${this.theme.text};
|
|
@@ -981,7 +958,7 @@ export class SmartComplyFlow {
|
|
|
981
958
|
fileInput.type = "file";
|
|
982
959
|
fileInput.accept = "image/*";
|
|
983
960
|
fileInput.style.cssText = `
|
|
984
|
-
width:100%;padding:12px 16px;border-radius
|
|
961
|
+
width:100%;padding:12px 16px;border-radius:${RADIUS.md}px;
|
|
985
962
|
font-size:14px;font-weight:500;
|
|
986
963
|
background:${this.theme.inputBg};
|
|
987
964
|
color:${this.theme.text};
|
|
@@ -1025,7 +1002,7 @@ export class SmartComplyFlow {
|
|
|
1025
1002
|
if (rule?.numeric)
|
|
1026
1003
|
input.inputMode = "numeric";
|
|
1027
1004
|
input.style.cssText = `
|
|
1028
|
-
width:100%;padding:14px 16px;border-radius
|
|
1005
|
+
width:100%;padding:14px 16px;border-radius:${RADIUS.md}px;
|
|
1029
1006
|
font-size:16px;font-weight:500;
|
|
1030
1007
|
background:${this.theme.inputBg};
|
|
1031
1008
|
color:${this.theme.text};
|
|
@@ -1087,7 +1064,7 @@ export class SmartComplyFlow {
|
|
|
1087
1064
|
errorEl.id = "sc-id-error";
|
|
1088
1065
|
errorEl.style.cssText = `
|
|
1089
1066
|
color:${this.theme.error};font-size:13px;display:none;
|
|
1090
|
-
padding:8px 12px;border-radius
|
|
1067
|
+
padding:8px 12px;border-radius:${RADIUS.sm}px;background:${this.theme.errorBg};
|
|
1091
1068
|
`;
|
|
1092
1069
|
container.appendChild(errorEl);
|
|
1093
1070
|
// Submit
|
|
@@ -1108,7 +1085,7 @@ export class SmartComplyFlow {
|
|
|
1108
1085
|
};
|
|
1109
1086
|
submitBtn.addEventListener("click", async () => {
|
|
1110
1087
|
submitBtn.disabled = true;
|
|
1111
|
-
submitBtn.innerHTML = `<span style="display:inline-flex;align-items:center;justify-content:center;gap:8px;"
|
|
1088
|
+
submitBtn.innerHTML = `<span style="display:inline-flex;align-items:center;justify-content:center;gap:8px;">${renderInlineSpinner("#fff", 13)}Verifying...</span>`;
|
|
1112
1089
|
errorEl.style.display = "none";
|
|
1113
1090
|
try {
|
|
1114
1091
|
this.verificationResult = await this.sdk.onboarding.verify({
|
|
@@ -1235,11 +1212,11 @@ export class SmartComplyFlow {
|
|
|
1235
1212
|
// W13: Pre-warm camera silently while user reads this screen
|
|
1236
1213
|
this._prewarmCamera();
|
|
1237
1214
|
const iconWrap = document.createElement("div");
|
|
1238
|
-
iconWrap.style.cssText = `width:64px;height:64px;border-radius:50%;background:${this.theme.primary}15;border:2px solid ${this.theme.primary}30;display:flex;align-items:center;justify-content:center;
|
|
1239
|
-
iconWrap.
|
|
1215
|
+
iconWrap.style.cssText = `width:64px;height:64px;border-radius:50%;background:${this.theme.primary}15;border:2px solid ${this.theme.primary}30;display:flex;align-items:center;justify-content:center;color:${this.theme.primary};`;
|
|
1216
|
+
iconWrap.innerHTML = icon("shield", 28);
|
|
1240
1217
|
container.appendChild(iconWrap);
|
|
1241
1218
|
const title = document.createElement("h2");
|
|
1242
|
-
title.style.cssText = `color:${this.theme.text};font-size
|
|
1219
|
+
title.style.cssText = `color:${this.theme.text};font-size:${TYPE.heading}px;font-weight:700;margin:0;`;
|
|
1243
1220
|
title.textContent = this._ivsName ? `Is this you?` : "Identity Confirmed";
|
|
1244
1221
|
container.appendChild(title);
|
|
1245
1222
|
if (this._ivsName) {
|
|
@@ -1301,14 +1278,32 @@ export class SmartComplyFlow {
|
|
|
1301
1278
|
this._renderRetryLimitReached(container);
|
|
1302
1279
|
return;
|
|
1303
1280
|
}
|
|
1304
|
-
// W13: Pre-warm camera while user reads
|
|
1305
|
-
|
|
1281
|
+
// W13: Pre-warm camera while user reads — but only if the document photo
|
|
1282
|
+
// itself came from the camera. Pre-warming here when the user uploaded
|
|
1283
|
+
// from gallery means requesting camera access before they've touched
|
|
1284
|
+
// their camera at all this session, which reads as an unexplained/
|
|
1285
|
+
// unexpected prompt rather than a seamless continuation.
|
|
1286
|
+
if (this._documentViaCamera)
|
|
1287
|
+
this._prewarmCamera();
|
|
1288
|
+
// Step badge — pairs with DocumentCapture.showPreview's "Step 1 of 2"
|
|
1289
|
+
// badge shown right after capture, so this doesn't read as unexplained
|
|
1290
|
+
// repetition: that screen checked photo clarity, this one checks the
|
|
1291
|
+
// OCR-extracted data.
|
|
1292
|
+
const stepBadge = document.createElement("div");
|
|
1293
|
+
stepBadge.style.cssText = `
|
|
1294
|
+
display:inline-flex;align-items:center;gap:5px;
|
|
1295
|
+
padding:3px 11px;border-radius:${RADIUS.pill}px;
|
|
1296
|
+
font-size:10.5px;font-weight:600;letter-spacing:0.2px;
|
|
1297
|
+
color:${this.theme.primary};background:${this.theme.primary}15;border:1px solid ${this.theme.primary}30;
|
|
1298
|
+
`;
|
|
1299
|
+
stepBadge.textContent = "STEP 2 OF 2 · CHECK WHAT WE READ";
|
|
1300
|
+
container.appendChild(stepBadge);
|
|
1306
1301
|
const iconWrap = document.createElement("div");
|
|
1307
|
-
iconWrap.style.cssText = `width:64px;height:64px;border-radius:50%;background:${this.theme.primary}15;border:2px solid ${this.theme.primary}30;display:flex;align-items:center;justify-content:center;
|
|
1308
|
-
iconWrap.
|
|
1302
|
+
iconWrap.style.cssText = `width:64px;height:64px;border-radius:50%;background:${this.theme.primary}15;border:2px solid ${this.theme.primary}30;display:flex;align-items:center;justify-content:center;color:${this.theme.primary};`;
|
|
1303
|
+
iconWrap.innerHTML = icon("document", 28);
|
|
1309
1304
|
container.appendChild(iconWrap);
|
|
1310
1305
|
const title = document.createElement("h2");
|
|
1311
|
-
title.style.cssText = `color:${this.theme.text};font-size
|
|
1306
|
+
title.style.cssText = `color:${this.theme.text};font-size:${TYPE.heading}px;font-weight:700;margin:0;`;
|
|
1312
1307
|
title.textContent = "Are these your details?";
|
|
1313
1308
|
container.appendChild(title);
|
|
1314
1309
|
const sub = document.createElement("p");
|
|
@@ -1400,19 +1395,10 @@ export class SmartComplyFlow {
|
|
|
1400
1395
|
// ── W6+W7+W8: OCR Gate (document verification) ───────────────────
|
|
1401
1396
|
renderOcrGate(container) {
|
|
1402
1397
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;gap:14px;padding:20px 0;text-align:center;";
|
|
1403
|
-
|
|
1404
|
-
spinnerWrap.style.cssText = "position:relative;width:52px;height:52px;flex-shrink:0;";
|
|
1405
|
-
const ring = document.createElement("div");
|
|
1406
|
-
ring.style.cssText = `position:absolute;inset:0;border-radius:50%;border:3px solid ${this.theme.border};border-top-color:${this.theme.primary};animation:sc-spin 0.9s linear infinite;`;
|
|
1407
|
-
const centre = document.createElement("div");
|
|
1408
|
-
centre.style.cssText = "position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;";
|
|
1409
|
-
centre.textContent = "📄";
|
|
1410
|
-
spinnerWrap.appendChild(ring);
|
|
1411
|
-
spinnerWrap.appendChild(centre);
|
|
1412
|
-
container.appendChild(spinnerWrap);
|
|
1398
|
+
container.appendChild(renderSpinner(this.theme, { size: 52, icon: icon("document", 20) }));
|
|
1413
1399
|
const statusEl = document.createElement("div");
|
|
1414
1400
|
statusEl.setAttribute("aria-live", "polite");
|
|
1415
|
-
statusEl.style.cssText = `color:${this.theme.text};font-size
|
|
1401
|
+
statusEl.style.cssText = `color:${this.theme.text};font-size:${TYPE.base}px;font-weight:600;`;
|
|
1416
1402
|
statusEl.textContent = "Reading your document…";
|
|
1417
1403
|
container.appendChild(statusEl);
|
|
1418
1404
|
const subEl = document.createElement("div");
|
|
@@ -1513,7 +1499,7 @@ export class SmartComplyFlow {
|
|
|
1513
1499
|
icon.textContent = "📅";
|
|
1514
1500
|
container.appendChild(icon);
|
|
1515
1501
|
const t = document.createElement("h2");
|
|
1516
|
-
t.style.cssText = `color:${this.theme.text};font-size
|
|
1502
|
+
t.style.cssText = `color:${this.theme.text};font-size:${TYPE.heading}px;font-weight:700;margin:0;`;
|
|
1517
1503
|
t.textContent = "Document Expired";
|
|
1518
1504
|
container.appendChild(t);
|
|
1519
1505
|
const d = document.createElement("p");
|
|
@@ -1539,7 +1525,7 @@ export class SmartComplyFlow {
|
|
|
1539
1525
|
icon.textContent = "🔍";
|
|
1540
1526
|
container.appendChild(icon);
|
|
1541
1527
|
const t = document.createElement("h2");
|
|
1542
|
-
t.style.cssText = `color:${this.theme.text};font-size
|
|
1528
|
+
t.style.cssText = `color:${this.theme.text};font-size:${TYPE.heading}px;font-weight:700;margin:0;`;
|
|
1543
1529
|
t.textContent = "Document Photo Unclear";
|
|
1544
1530
|
container.appendChild(t);
|
|
1545
1531
|
const msg = reason === "image_too_blurry" ? "Your document photo is too blurry. Please retake it in good lighting with a steady hand."
|
|
@@ -1576,11 +1562,11 @@ export class SmartComplyFlow {
|
|
|
1576
1562
|
verificationResult: this.verificationResult || undefined,
|
|
1577
1563
|
});
|
|
1578
1564
|
const iconWrap = document.createElement("div");
|
|
1579
|
-
iconWrap.style.cssText = `width:80px;height:80px;border-radius:50%;background:${this.theme.successBg};border:3px solid ${this.theme.success};display:flex;align-items:center;justify-content:center;
|
|
1580
|
-
iconWrap.
|
|
1565
|
+
iconWrap.style.cssText = `width:80px;height:80px;border-radius:50%;background:${this.theme.successBg};border:3px solid ${this.theme.success};display:flex;align-items:center;justify-content:center;color:${this.theme.success};animation:sc-pop 0.4s ease;`;
|
|
1566
|
+
iconWrap.innerHTML = icon("check", 36);
|
|
1581
1567
|
container.appendChild(iconWrap);
|
|
1582
1568
|
const title = document.createElement("h2");
|
|
1583
|
-
title.style.cssText = `color:${this.theme.text};font-size
|
|
1569
|
+
title.style.cssText = `color:${this.theme.text};font-size:${TYPE.headingLg}px;font-weight:700;margin:0;`;
|
|
1584
1570
|
title.textContent = "You're all done!";
|
|
1585
1571
|
container.appendChild(title);
|
|
1586
1572
|
const desc = document.createElement("p");
|
|
@@ -1607,7 +1593,7 @@ export class SmartComplyFlow {
|
|
|
1607
1593
|
icon.textContent = "⚠️";
|
|
1608
1594
|
container.appendChild(icon);
|
|
1609
1595
|
const t = document.createElement("h2");
|
|
1610
|
-
t.style.cssText = `color:${this.theme.text};font-size
|
|
1596
|
+
t.style.cssText = `color:${this.theme.text};font-size:${TYPE.heading}px;font-weight:700;margin:0;`;
|
|
1611
1597
|
t.textContent = "Unable to Complete Verification";
|
|
1612
1598
|
container.appendChild(t);
|
|
1613
1599
|
const d = document.createElement("p");
|
|
@@ -1642,6 +1628,7 @@ export class SmartComplyFlow {
|
|
|
1642
1628
|
// below so compression only happens once.
|
|
1643
1629
|
this.documentBlob = await _compressImage(result.front, 1600, 0.85);
|
|
1644
1630
|
this.documentBackBlob = result.back ? await _compressImage(result.back, 1600, 0.85) : null;
|
|
1631
|
+
this._documentViaCamera = result.viaCamera;
|
|
1645
1632
|
// Process the front image — pass the already-compressed blob
|
|
1646
1633
|
await this.processDocumentBlob(this.documentBlob, captureContainer, container);
|
|
1647
1634
|
}
|
|
@@ -1662,15 +1649,12 @@ export class SmartComplyFlow {
|
|
|
1662
1649
|
}
|
|
1663
1650
|
this.documentBlob = blob;
|
|
1664
1651
|
// Show scanning state
|
|
1665
|
-
captureContainer.innerHTML =
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
<div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;">🔍</div>
|
|
1670
|
-
</div>
|
|
1652
|
+
captureContainer.innerHTML = "";
|
|
1653
|
+
captureContainer.style.cssText += "display:flex;flex-direction:column;align-items:center;gap:14px;padding:28px 20px;";
|
|
1654
|
+
captureContainer.appendChild(renderSpinner(this.theme, { size: 52, icon: icon("search", 20) }));
|
|
1655
|
+
captureContainer.insertAdjacentHTML("beforeend", `
|
|
1671
1656
|
<div style="color:${this.theme.text};font-size:14px;font-weight:600;">Scanning document...</div>
|
|
1672
|
-
<div style="color:${this.theme.textSecondary};font-size:12px;text-align:center;max-width:200px;line-height:1.5;">Running OCR and verifying your identity</div
|
|
1673
|
-
</div>`;
|
|
1657
|
+
<div style="color:${this.theme.textSecondary};font-size:12px;text-align:center;max-width:200px;line-height:1.5;">Running OCR and verifying your identity</div>`);
|
|
1674
1658
|
// Create liveness entry with document.
|
|
1675
1659
|
// Use the first collected field value as identifier when available
|
|
1676
1660
|
// (document flow has no data-verification step, so collectedFields is
|
|
@@ -1734,15 +1718,12 @@ export class SmartComplyFlow {
|
|
|
1734
1718
|
console.log(`Retrying document processing (attempt ${retryCount}/${maxRetries})`);
|
|
1735
1719
|
// Show retry message
|
|
1736
1720
|
if (captureContainer) {
|
|
1737
|
-
captureContainer.innerHTML =
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
<div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;">🔄</div>
|
|
1742
|
-
</div>
|
|
1721
|
+
captureContainer.innerHTML = "";
|
|
1722
|
+
captureContainer.style.cssText += "display:flex;flex-direction:column;align-items:center;gap:16px;padding:28px 20px;text-align:center;";
|
|
1723
|
+
captureContainer.appendChild(renderSpinner(this.theme, { size: 52, icon: icon("refresh", 20) }));
|
|
1724
|
+
captureContainer.insertAdjacentHTML("beforeend", `
|
|
1743
1725
|
<div style="color:${this.theme.text};font-size:14px;font-weight:600;">Retrying...</div>
|
|
1744
|
-
<div style="color:${this.theme.textSecondary};font-size:12px;max-width:240px;line-height:1.5;">Attempt ${retryCount} of ${maxRetries}</div
|
|
1745
|
-
</div>`;
|
|
1726
|
+
<div style="color:${this.theme.textSecondary};font-size:12px;max-width:240px;line-height:1.5;">Attempt ${retryCount} of ${maxRetries}</div>`);
|
|
1746
1727
|
}
|
|
1747
1728
|
// Wait before retry
|
|
1748
1729
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
@@ -1804,7 +1785,7 @@ export class SmartComplyFlow {
|
|
|
1804
1785
|
const retryBtn = document.createElement("button");
|
|
1805
1786
|
retryBtn.textContent = "Try Again";
|
|
1806
1787
|
retryBtn.setAttribute("aria-label", "Retake document photo");
|
|
1807
|
-
retryBtn.style.cssText = `margin-top:8px;padding:12px 24px;border-radius
|
|
1788
|
+
retryBtn.style.cssText = `margin-top:8px;padding:12px 24px;border-radius:${RADIUS.sm}px;background:${this.theme.primary};color:#fff;border:none;font-size:14px;font-weight:600;cursor:pointer;`;
|
|
1808
1789
|
retryBtn.addEventListener("click", () => this.showStep("document_capture"));
|
|
1809
1790
|
wrap.appendChild(retryBtn);
|
|
1810
1791
|
}
|
|
@@ -1865,6 +1846,12 @@ export class SmartComplyFlow {
|
|
|
1865
1846
|
: "liveness_only",
|
|
1866
1847
|
// B4: pass pre-warmed stream so camera.open() is skipped
|
|
1867
1848
|
prewarmedStream: this._prewarmedStream || undefined,
|
|
1849
|
+
colors: {
|
|
1850
|
+
primary: this.theme.primary,
|
|
1851
|
+
success: this.theme.success,
|
|
1852
|
+
error: this.theme.error,
|
|
1853
|
+
warning: this.theme.warning,
|
|
1854
|
+
},
|
|
1868
1855
|
}, ["BLINK"], this.livenessEntryId || undefined)
|
|
1869
1856
|
.then((result) => {
|
|
1870
1857
|
// W11: After submit, end user is done — show "You're all done" screen.
|
|
@@ -1906,14 +1893,14 @@ export class SmartComplyFlow {
|
|
|
1906
1893
|
// /v1/sdk/liveness/submit/) are an operator-facing problem, not something
|
|
1907
1894
|
// the end user can act on — never show "wallet"/"balance" language to them.
|
|
1908
1895
|
const isBillingErr = /wallet|balance|insufficient.*fund|payment.*required/i.test(message);
|
|
1909
|
-
const
|
|
1910
|
-
: isNetworkErr ? "
|
|
1911
|
-
: isAuthErr ? "
|
|
1912
|
-
: isDocQuality ? "
|
|
1913
|
-
: isExpiredDoc ? "
|
|
1914
|
-
: isFaceMatch ? "
|
|
1915
|
-
: isBillingErr ? "
|
|
1916
|
-
: "
|
|
1896
|
+
const errorIconName = isCameraErr ? "camera"
|
|
1897
|
+
: isNetworkErr ? "network"
|
|
1898
|
+
: isAuthErr ? "clock"
|
|
1899
|
+
: isDocQuality ? "search"
|
|
1900
|
+
: isExpiredDoc ? "calendar"
|
|
1901
|
+
: isFaceMatch ? "face"
|
|
1902
|
+
: isBillingErr ? "warning"
|
|
1903
|
+
: "close";
|
|
1917
1904
|
const errorTitle = isCameraErr ? "Camera Access Required"
|
|
1918
1905
|
: isNetworkErr ? "Connection Problem"
|
|
1919
1906
|
: isAuthErr ? "Session Expired"
|
|
@@ -1942,14 +1929,14 @@ export class SmartComplyFlow {
|
|
|
1942
1929
|
iconWrap.style.cssText = `
|
|
1943
1930
|
width:72px;height:72px;border-radius:50%;
|
|
1944
1931
|
display:flex;align-items:center;justify-content:center;
|
|
1945
|
-
|
|
1932
|
+
color:${this.theme.error};
|
|
1946
1933
|
background:${this.theme.errorBg};
|
|
1947
1934
|
border:3px solid ${this.theme.error};
|
|
1948
1935
|
`;
|
|
1949
|
-
iconWrap.
|
|
1936
|
+
iconWrap.innerHTML = icon(errorIconName, 28);
|
|
1950
1937
|
wrapper.appendChild(iconWrap);
|
|
1951
1938
|
const title = document.createElement("h2");
|
|
1952
|
-
title.style.cssText = `color:${this.theme.text};font-size
|
|
1939
|
+
title.style.cssText = `color:${this.theme.text};font-size:${TYPE.heading}px;font-weight:700;margin:0;`;
|
|
1953
1940
|
title.textContent = errorTitle;
|
|
1954
1941
|
wrapper.appendChild(title);
|
|
1955
1942
|
const desc = document.createElement("p");
|
|
@@ -1988,7 +1975,7 @@ export class SmartComplyFlow {
|
|
|
1988
1975
|
this.headerBackBtn.innerHTML = "←";
|
|
1989
1976
|
this.headerBackBtn.setAttribute("aria-label", "Go back to previous step");
|
|
1990
1977
|
this.headerBackBtn.style.cssText = `
|
|
1991
|
-
width:30px;height:30px;border-radius
|
|
1978
|
+
width:30px;height:30px;border-radius:${RADIUS.sm}px;flex-shrink:0;
|
|
1992
1979
|
display:none;align-items:center;justify-content:center;
|
|
1993
1980
|
border:1.5px solid ${this.theme.border};cursor:pointer;
|
|
1994
1981
|
font-size:16px;line-height:1;
|
|
@@ -2046,7 +2033,7 @@ export class SmartComplyFlow {
|
|
|
2046
2033
|
closeBtn.innerHTML = "✕";
|
|
2047
2034
|
closeBtn.setAttribute("aria-label", "Close identity verification");
|
|
2048
2035
|
closeBtn.style.cssText = `
|
|
2049
|
-
width:32px;height:32px;border-radius
|
|
2036
|
+
width:32px;height:32px;border-radius:${RADIUS.sm}px;flex-shrink:0;
|
|
2050
2037
|
display:flex;align-items:center;justify-content:center;
|
|
2051
2038
|
border:none;cursor:pointer;font-size:16px;
|
|
2052
2039
|
background:${this.theme.shimmer};color:${this.theme.textMuted};
|
|
@@ -2083,7 +2070,7 @@ export class SmartComplyFlow {
|
|
|
2083
2070
|
createStepTitle(text) {
|
|
2084
2071
|
const el = document.createElement("h3");
|
|
2085
2072
|
el.style.cssText = `
|
|
2086
|
-
color:${this.theme.text};font-size
|
|
2073
|
+
color:${this.theme.text};font-size:${TYPE.heading}px;font-weight:700;
|
|
2087
2074
|
margin:0;
|
|
2088
2075
|
`;
|
|
2089
2076
|
el.textContent = text;
|
|
@@ -2093,7 +2080,7 @@ export class SmartComplyFlow {
|
|
|
2093
2080
|
const card = document.createElement("button");
|
|
2094
2081
|
card.setAttribute("aria-label", subtitle ? `${title}: ${subtitle}` : title);
|
|
2095
2082
|
card.style.cssText = `
|
|
2096
|
-
width:100%;padding:13px 16px;border-radius
|
|
2083
|
+
width:100%;padding:13px 16px;border-radius:${RADIUS.md}px;
|
|
2097
2084
|
background:${this.theme.cardBg};
|
|
2098
2085
|
border:2px solid ${this.theme.border};
|
|
2099
2086
|
cursor:pointer;text-align:left;
|
|
@@ -2133,7 +2120,7 @@ export class SmartComplyFlow {
|
|
|
2133
2120
|
const btn = document.createElement("button");
|
|
2134
2121
|
btn.textContent = text;
|
|
2135
2122
|
btn.style.cssText = `
|
|
2136
|
-
width:100%;padding:14px;border-radius
|
|
2123
|
+
width:100%;padding:14px;border-radius:${RADIUS.md}px;
|
|
2137
2124
|
font-size:15px;font-weight:600;
|
|
2138
2125
|
background:${this.theme.primary};color:#fff;
|
|
2139
2126
|
border:none;cursor:pointer;
|
|
@@ -2154,7 +2141,7 @@ export class SmartComplyFlow {
|
|
|
2154
2141
|
const btn = document.createElement("button");
|
|
2155
2142
|
btn.textContent = text;
|
|
2156
2143
|
btn.style.cssText = `
|
|
2157
|
-
width:100%;padding:12px;border-radius
|
|
2144
|
+
width:100%;padding:12px;border-radius:${RADIUS.md}px;
|
|
2158
2145
|
font-size:14px;font-weight:500;
|
|
2159
2146
|
background:transparent;color:${this.theme.textSecondary};
|
|
2160
2147
|
border:none;cursor:pointer;
|
|
@@ -2292,9 +2279,6 @@ export class SmartComplyFlow {
|
|
|
2292
2279
|
const style = document.createElement("style");
|
|
2293
2280
|
style.id = "sc-flow-styles";
|
|
2294
2281
|
style.textContent = `
|
|
2295
|
-
@keyframes sc-spin {
|
|
2296
|
-
to { transform: rotate(360deg); }
|
|
2297
|
-
}
|
|
2298
2282
|
@keyframes sc-pop {
|
|
2299
2283
|
0% { transform: scale(0.8); opacity: 0; }
|
|
2300
2284
|
50% { transform: scale(1.05); }
|